package hu.sztaki.ilab.longneck.bootstrap; import java.util.Calendar; import java.util.GregorianCalendar; /** * Generates keys for the error writer. * * @author Péter Molnár <molnarp@sztaki.mta.hu> */ public class BinaryKeyGenerator implements KeyGenerator { /** Number of bits representing the node. */ private int nodeBits = 3; /** Number of bits representing the current timestamp. */ private int timestampBits = 44; /** Counter for records processed at the same millisecond. */ private int serialBits = 16; /** The last timestamp. */ private long lastTimestamp; /** Last issued serial. */ private long lastSerial = 0; /** The highest serial number available. */ private long maxSerial; /** The calendar to query milliseconds from. */ private Calendar calendar = new GregorianCalendar(); /** The id of the current node. */ private long nodeId = 0; public BinaryKeyGenerator() { } public BinaryKeyGenerator(long nodeId) { assert nodeId >= 0; assert (nodeId < (1 << nodeBits)); // Assign node id and check, if it fits into node bits this.nodeId = nodeId; this.maxSerial = (1 << serialBits) - 1; } /** * Initializes the key generator. * * @param nodeId The numeric id of the node. * @param nodeBits The number of bits for the node id. * @param timestampBits The number of bits used for the timestamp. * @param serialBits The number of bits used for the serial number. * @throws AssertionError If the parts of the key do not fit into the bits specified. */ public BinaryKeyGenerator(long nodeId, int nodeBits, int timestampBits, int serialBits) { this(nodeId); assert nodeBits >= 1; assert timestampBits >= 1; assert serialBits >= 1; assert ((nodeBits + timestampBits + serialBits) <= 63); assert calendar.getTimeInMillis() < (1 << timestampBits); // Assign node id and check, if it fits into node bits this.nodeId = nodeId; assert (nodeId < (1 << nodeBits)); this.nodeBits = nodeBits; this.timestampBits = timestampBits; this.serialBits = serialBits; this.maxSerial = (1 << serialBits) - 1; } /** * Returns the next key. * * @return The generated key. * @throws AssertionError If serial incrementation results in overflow. */ @Override public long getNext() { long timestamp = calendar.getTimeInMillis(); if (lastTimestamp < timestamp) { lastTimestamp = timestamp; lastSerial = 0; } else { ++lastSerial; } assert (lastSerial <= maxSerial); return ( (nodeId << (timestampBits + serialBits)) | (lastTimestamp << serialBits) | lastSerial); } /** * Thread-safe implementation of next key. * * @return The generated key. * @throws AssertionError If serial incrementation results in overflow. */ @Override public synchronized long getNextThreadSafe() { return getNext(); } }