com.addthis.hydra.store.db.DBKey.java Source code

Java tutorial

Introduction

Here is the source code for com.addthis.hydra.store.db.DBKey.java

Source

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 *
 */
package com.addthis.hydra.store.db;

import javax.annotation.Nonnull;

import java.util.Arrays;

import com.addthis.basis.util.LessBytes;
import com.addthis.basis.util.Varint;

import com.addthis.hydra.store.util.Raw;

import static com.google.common.base.Preconditions.checkArgument;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

public final class DBKey implements IPageDB.Key, Comparable<DBKey> {

    private static final Raw EMPTY = Raw.get(new byte[0]);

    private final long id;
    private final Raw key;

    public DBKey(long id) {
        this(id, (Raw) null);
    }

    public DBKey(long id, String key) {
        this(id, Raw.get(key));
    }

    public DBKey(long id, Raw key) {
        checkArgument(id >= 0, "Argument was %s but expected non-negative integer", id);
        if (key == null) {
            key = EMPTY;
        }
        this.id = id;
        this.key = key;
    }

    /**
     * Create a DBKey from its serialization byte array representation.
     * If the most significant bit of the first byte is set then
     * interpret the id as a 63-bit unsigned long. Otherwise interpret the
     * id as a 31-bit unsigned int.
     *
     * @param raw
     * @return
     */
    public static DBKey fromBytes(byte[] raw) {
        byte head = raw[0];
        int numBytes;
        long id;
        if ((head >> 7) == 0) {
            id = (long) LessBytes.toInt(raw);
            numBytes = 4;
        } else {
            id = LessBytes.toLong(raw) & ~(Long.MIN_VALUE);
            numBytes = 8;
        }
        Raw key = Raw.get(LessBytes.cut(raw, numBytes, raw.length - numBytes));
        return new DBKey(id, key);
    }

    public static DBKey deltaDecode(byte[] encoding, @Nonnull IPageDB.Key baseKey) {
        ByteBuf buffer = Unpooled.copiedBuffer(encoding);
        long offset = Varint.readSignedVarLong(buffer);
        long id = offset + baseKey.id();
        Raw key;
        if (buffer.readableBytes() == 0) {
            key = null;
        } else {
            byte[] data = new byte[buffer.readableBytes()];
            buffer.readBytes(data);
            key = Raw.get(data);
        }
        return new DBKey(id, key);
    }

    @Override
    public long id() {
        return id;
    }

    @Override
    public byte[] key() {
        return key.toBytes();
    }

    @Override
    public Raw rawKey() {
        return key;
    }

    public String toString() {
        return id + ":" + key;
    }

    @Override
    public int hashCode() {
        return key.hashCode() + Long.hashCode(id);
    }

    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
        if (o instanceof DBKey) {
            DBKey k = (DBKey) o;
            return (k.id == id && k.key.equals(key));
        } else {
            return false;
        }
    }

    @Override
    public int compareTo(DBKey dk) {
        long dkId = dk.id();
        if (dkId == id) {
            return key.compareTo(dk.key);
        }
        return id > dkId ? 1 : -1;
    }

    /**
     * Generate the serialized byte array representation.
     * If the id can be represented as a 31-bit unsigned integer
     * then use a 4-byte representation. If is cannot be represented
     * in 4 bytes then use an 8-byte representation and set the
     * most significant bit of the first byte as a flag.
     *
     * @return serialized representation
     */
    @Override
    public byte[] toBytes() {
        byte[] idBytes;
        if (id <= Integer.MAX_VALUE) {
            idBytes = LessBytes.toBytes((int) id);
        } else {
            idBytes = LessBytes.toBytes(id | Long.MIN_VALUE);
        }
        if (key == null) {
            return idBytes;
        }
        return Raw.get(idBytes).cat(key).toBytes();
    }

    @Override
    public byte[] deltaEncode(@Nonnull IPageDB.Key baseKey) {
        long offset = id - baseKey.id();
        ByteBuf buffer = Unpooled.buffer();
        Varint.writeSignedVarLong(offset, buffer);
        if (key != null) {
            buffer.writeBytes(key.toBytes());
        }
        return Arrays.copyOf(buffer.array(), buffer.readableBytes());
    }

}