001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.zookeeper;
019
020import java.util.concurrent.ThreadLocalRandom;
021import org.apache.hadoop.hbase.util.Bytes;
022import org.apache.yetus.audience.InterfaceAudience;
023
024/**
025 * The metadata append to the start of data on zookeeper.
026 */
027@InterfaceAudience.Private
028public class ZKMetadata {
029
030  private ZKMetadata() {
031  }
032
033  // The metadata attached to each piece of data has the format:
034  // <magic> 1-byte constant
035  // <id length> 4-byte big-endian integer (length of next field)
036  // <id> identifier corresponding uniquely to this process
037  // It is prepended to the data supplied by the user.
038
039  // the magic number is to be backward compatible
040  private static final byte MAGIC = (byte) 0XFF;
041  private static final int MAGIC_SIZE = Bytes.SIZEOF_BYTE;
042  private static final int ID_LENGTH_OFFSET = MAGIC_SIZE;
043  private static final int ID_LENGTH_SIZE = Bytes.SIZEOF_INT;
044
045  public static byte[] appendMetaData(byte[] id, byte[] data) {
046    if (data == null || data.length == 0) {
047      return data;
048    }
049    byte[] salt = Bytes.toBytes(ThreadLocalRandom.current().nextLong());
050    int idLength = id.length + salt.length;
051    byte[] newData = new byte[MAGIC_SIZE + ID_LENGTH_SIZE + idLength + data.length];
052    int pos = 0;
053    pos = Bytes.putByte(newData, pos, MAGIC);
054    pos = Bytes.putInt(newData, pos, idLength);
055    pos = Bytes.putBytes(newData, pos, id, 0, id.length);
056    pos = Bytes.putBytes(newData, pos, salt, 0, salt.length);
057    pos = Bytes.putBytes(newData, pos, data, 0, data.length);
058    return newData;
059  }
060
061  public static byte[] removeMetaData(byte[] data) {
062    if (data == null || data.length == 0) {
063      return data;
064    }
065    // check the magic data; to be backward compatible
066    byte magic = data[0];
067    if (magic != MAGIC) {
068      return data;
069    }
070
071    int idLength = Bytes.toInt(data, ID_LENGTH_OFFSET);
072    int dataLength = data.length - MAGIC_SIZE - ID_LENGTH_SIZE - idLength;
073    int dataOffset = MAGIC_SIZE + ID_LENGTH_SIZE + idLength;
074
075    byte[] newData = new byte[dataLength];
076    System.arraycopy(data, dataOffset, newData, 0, dataLength);
077    return newData;
078  }
079}