Skip to content

Commit

Permalink
Introduce MemoryPoolChunk.Slot to improve safety and simplify the Mem…
Browse files Browse the repository at this point in the history
…oryPool

  MemoryPoolChunk.Slot is introduced in order to encapsulate
  access to a slot.  This leads to cleaner code in
  SegmentWithMemoryPool as it no longer needs to manage
  slotOffset information and weave that between the chunk
  and MemoryPoolAddress.  The result is significantly
  safer as well, the slot offset is hidden inside the Slot
  and can not accidentally cause out of bounds access.

  This reduces the number of places we have to validate the
  offset in a typical operation which may improve performance
  slightly as well, and if not at least decreases the exception
  paths to test.
  • Loading branch information
Scott Carey committed Dec 6, 2019
1 parent e20a6e0 commit c3b61ca
Show file tree
Hide file tree
Showing 4 changed files with 277 additions and 236 deletions.
209 changes: 96 additions & 113 deletions src/main/java/com/oath/halodb/MemoryPoolChunk.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,56 +85,17 @@ public int chunkId() {
return chunkId;
}

MemoryPoolAddress getNextAddress(int slotOffset) {

byte chunk = Uns.getByte(address, slotOffset + ENTRY_OFF_NEXT_CHUNK_INDEX);
int slot = Uns.getInt(address, slotOffset + ENTRY_OFF_NEXT_CHUNK_OFFSET);

return new MemoryPoolAddress(chunk, slot);
}

void setNextAddress(int slotOffset, MemoryPoolAddress next) {

Uns.putByte(address, slotOffset + ENTRY_OFF_NEXT_CHUNK_INDEX, (byte) next.chunkIndex);
Uns.putInt(address, slotOffset + ENTRY_OFF_NEXT_CHUNK_OFFSET, next.slot);
Slot slotFor(int slot) {
return new Slot(slot);
}

int allocateSlot() {
Slot allocateSlot() {
if (isFull()) {
throw new IllegalStateException("can not allocate a slot when already full");
}
int writtenSlot = writeSlot;
Slot slot = slotFor(writeSlot);
writeSlot++;
return writtenSlot;
}

/**
* Absolute put method. Writes to the slot pointed to by the offset.
*/
void fillSlot(int slot, byte[] key, E entry, MemoryPoolAddress nextAddress) {
int slotOffset = slotToOffset(slot);
// pointer to next slot
setNextAddress(slotOffset, nextAddress);
// key and value sizes
entry.serializeSizes(sizeAddress(slotOffset));
// key data, in fixed slot
setKey(slotOffset, key, Math.min(key.length, fixedKeyLength));
// entry metadata
entry.serializeLocation(locationAddress(slotOffset));
}

void fillOverflowSlot(int slot, byte[] key, int keyoffset, int len, MemoryPoolAddress nextAddress) {
int slotOffset = slotToOffset(slot);
//poiner to next slot
setNextAddress(slotOffset, nextAddress);
// set key data
setExtendedKey(slotOffset, key, keyoffset, len);
}

void setEntry(int slotOffset, E entry) {

entry.serializeSizes(sizeAddress(slotOffset));
entry.serializeLocation(locationAddress(slotOffset));
return slot;
}

int getWriteOffset() {
Expand All @@ -149,106 +110,128 @@ int remainingSlots() {
return slots - writeSlot;
}

E readEntry(int slotOffset) {
return serializer.deserialize(sizeAddress(slotOffset), locationAddress(slotOffset));
}

int slotToOffset(int slot) {
private int slotToOffset(int slot) {
if (slot > slots) {
throw new IllegalArgumentException("Invalid request. slot - " + slot + " total slots - " + slots);
}
return slot * slotSize;
}

private long sizeAddress(int slotOffset) {
return address + slotOffset + sizesOffset;
}
/** Represents a valid Slot within a MemoryPoolChunk **/
class Slot {
private final int slot;
private final int offset;
private Slot(int slot) {
this.slot = slot;
this.offset = slotToOffset(slot);
}

private long locationAddress(int slotOffset) {
return address + slotOffset + locationOffset;
}
MemoryPoolAddress toAddress() {
return new MemoryPoolAddress((byte) chunkId, slot);
}

private long keyAddress(int slotOffset) {
return address + slotOffset + fixedKeyOffset;
}
short getKeyLength() {
return serializer.readKeySize(sizeAddress());
}

private long extendedKeyAddress(int slotOffset) {
return sizeAddress(slotOffset);
}
MemoryPoolAddress getNextAddress() {
byte chunk = Uns.getByte(address, offset + ENTRY_OFF_NEXT_CHUNK_INDEX);
int slot = Uns.getInt(address, offset + ENTRY_OFF_NEXT_CHUNK_OFFSET);
return new MemoryPoolAddress(chunk, slot);
}

private void setKey(int slotOffset, byte[] key, int len) {
if (len > fixedKeyLength) {
throw new IllegalArgumentException("Invalid key write beyond fixedKeyLength, length - " + len);
void setNextAddress(MemoryPoolAddress next) {
Uns.putByte(address, offset + ENTRY_OFF_NEXT_CHUNK_INDEX, (byte) next.chunkIndex);
Uns.putInt(address, offset + ENTRY_OFF_NEXT_CHUNK_OFFSET, next.slot);
}
Uns.copyMemory(key, 0, keyAddress(slotOffset), 0, len);
}

private void setExtendedKey(int slotOffset, byte[] key, int keyoffset, int len) {
if (len > slotSize - sizesOffset) {
throw new IllegalArgumentException("Invalid key write beyond slot with extended key, length - " + len);
void fillSlot(byte[] key, E entry, MemoryPoolAddress nextAddress) {
// pointer to next slot
setNextAddress(nextAddress);
// key and value sizes
entry.serializeSizes(sizeAddress());
// key data, in fixed slot
setKey(key, Math.min(key.length, fixedKeyLength));
// entry metadata
entry.serializeLocation(locationAddress());
}
Uns.copyMemory(key, keyoffset, extendedKeyAddress(slotOffset), 0, len);
}

long computeFixedKeyHash(int slotOffset, Hasher hasher, int keySize) {
return hasher.hash(keyAddress(slotOffset), 0, keySize);
}
void fillOverflowSlot(byte[] key, int keyoffset, int len, MemoryPoolAddress nextAddress) {
//poiner to next slot
setNextAddress(nextAddress);
// set key data
setExtendedKey(key, keyoffset, len);
}

void copyEntireFixedKey(int slotOffset, long destinationAddress) {
Uns.copyMemory(keyAddress(slotOffset), 0, destinationAddress, 0, fixedKeyLength);
}
void setEntry(E entry) {
entry.serializeSizes(sizeAddress());
entry.serializeLocation(locationAddress());
}

int copyExtendedKey(int slotOffset, long destinationAddress, int destinationOffset, int len) {
int copied = Math.min(len, slotSize - sizesOffset);
Uns.copyMemory(extendedKeyAddress(slotOffset), 0, destinationAddress, destinationOffset, copied);
return copied;
}
E readEntry() {
return serializer.deserialize(sizeAddress(), locationAddress());
}

boolean compareFixedKey(int slotOffset, byte[] key, int len) {
if (len > fixedKeyLength) {
throw new IllegalArgumentException("Invalid request. key fragment larger than fixedKeyLength - " + len);
long computeFixedKeyHash(Hasher hasher, int keySize) {
return hasher.hash(keyAddress(), 0, keySize);
}
return compare(keyAddress(slotOffset), key, 0, len);
}

boolean compareExtendedKey(int slotOffset, byte[] key, int keyoffset, int len) {
if (len > fixedKeyLength + serializer.entrySize()) {
throw new IllegalArgumentException("Invalid request. key fragment larger than slot capacity - " + len);
void copyEntireFixedKey(long destinationAddress) {
Uns.copyMemory(keyAddress(), 0, destinationAddress, 0, fixedKeyLength);
}
return compare(extendedKeyAddress(slotOffset), key, keyoffset, len);
}

boolean compareEntry(int slotOffset, E entry) {
return entry.compare(sizeAddress(slotOffset), locationAddress(slotOffset));
}
int copyExtendedKey(long destinationAddress, int destinationOffset, int len) {
int copied = Math.min(len, slotSize - sizesOffset);
Uns.copyMemory(extendedKeyAddress(), 0, destinationAddress, destinationOffset, copied);
return copied;
}

private boolean compare(long address, byte[] array, int arrayoffset, int len) {
int p = 0, length = len;
for (; length - p >= 8; p += 8) {
if (Uns.getLong(address, p) != Uns.getLongFromByteArray(array, p + arrayoffset)) {
return false;
boolean compareFixedKey(byte[] key, int len) {
if (len > fixedKeyLength) {
throw new IllegalArgumentException("Invalid request. key fragment larger than fixedKeyLength: " + len);
}
return Uns.compare(keyAddress(), key, 0, len);
}
for (; length - p >= 4; p += 4) {
if (Uns.getInt(address, p) != Uns.getIntFromByteArray(array, p + arrayoffset)) {
return false;

boolean compareExtendedKey(byte[] key, int keyoffset, int len) {
if (len > fixedKeyLength + serializer.entrySize()) {
throw new IllegalArgumentException("Invalid request. key fragment larger than slot capacity: " + len);
}
return Uns.compare(extendedKeyAddress(), key, keyoffset, len);
}
for (; length - p >= 2; p += 2) {
if (Uns.getShort(address, p) != Uns.getShortFromByteArray(array, p + arrayoffset)) {
return false;

boolean compareEntry(E entry) {
return entry.compare(sizeAddress(), locationAddress());
}

private void setKey(byte[] key, int len) {
if (len > fixedKeyLength) {
throw new IllegalArgumentException("Invalid key write beyond fixedKeyLength, length: " + len);
}
Uns.copyMemory(key, 0, keyAddress(), 0, len);
}
for (; length - p >= 1; p += 1) {
if (Uns.getByte(address, p) != array[p + arrayoffset]) {
return false;

private void setExtendedKey(byte[] key, int keyoffset, int len) {
if (len > slotSize - sizesOffset) {
throw new IllegalArgumentException("Invalid key write beyond slot with extended key, length: " + len);
}
Uns.copyMemory(key, keyoffset, extendedKeyAddress(), 0, len);
}
return true;
}

short getKeyLength(int slotOffset) {
private long sizeAddress() {
return address + offset + sizesOffset;
}

return serializer.readKeySize(sizeAddress(slotOffset));
private long locationAddress() {
return address + offset + locationOffset;
}

private long keyAddress() {
return address + offset + fixedKeyOffset;
}

private long extendedKeyAddress() {
return sizeAddress();
}
}
}
Loading

0 comments on commit c3b61ca

Please sign in to comment.