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;
021
022import org.apache.hadoop.hbase.util.Bytes;
023import org.apache.yetus.audience.InterfaceAudience;
024
025/**
026 * The metadata append to the start of data on zookeeper.
027 */
028@InterfaceAudience.Private
029public class ZKMetadata {
030
031  private ZKMetadata() {
032  }
033
034  // The metadata attached to each piece of data has the format:
035  // <magic> 1-byte constant
036  // <id length> 4-byte big-endian integer (length of next field)
037  // <id> identifier corresponding uniquely to this process
038  // It is prepended to the data supplied by the user.
039
040  // the magic number is to be backward compatible
041  private static final byte MAGIC = (byte) 0XFF;
042  private static final int MAGIC_SIZE = Bytes.SIZEOF_BYTE;
043  private static final int ID_LENGTH_OFFSET = MAGIC_SIZE;
044  private static final int ID_LENGTH_SIZE = Bytes.SIZEOF_INT;
045
046  public static byte[] appendMetaData(byte[] id, byte[] data) {
047    if (data == null || data.length == 0) {
048      return data;
049    }
050    byte[] salt = Bytes.toBytes(ThreadLocalRandom.current().nextLong());
051    int idLength = id.length + salt.length;
052    byte[] newData = new byte[MAGIC_SIZE + ID_LENGTH_SIZE + idLength + data.length];
053    int pos = 0;
054    pos = Bytes.putByte(newData, pos, MAGIC);
055    pos = Bytes.putInt(newData, pos, idLength);
056    pos = Bytes.putBytes(newData, pos, id, 0, id.length);
057    pos = Bytes.putBytes(newData, pos, salt, 0, salt.length);
058    pos = Bytes.putBytes(newData, pos, data, 0, data.length);
059    return newData;
060  }
061
062  public static byte[] removeMetaData(byte[] data) {
063    if (data == null || data.length == 0) {
064      return data;
065    }
066    // check the magic data; to be backward compatible
067    byte magic = data[0];
068    if (magic != MAGIC) {
069      return data;
070    }
071
072    int idLength = Bytes.toInt(data, ID_LENGTH_OFFSET);
073    int dataLength = data.length - MAGIC_SIZE - ID_LENGTH_SIZE - idLength;
074    int dataOffset = MAGIC_SIZE + ID_LENGTH_SIZE + idLength;
075
076    byte[] newData = new byte[dataLength];
077    System.arraycopy(data, dataOffset, newData, 0, dataLength);
078    return newData;
079  }
080}