protected OffHeapChainStorageEngine(PageSource source, Portability<? super K> keyPortability, int minPageSize, int maxPageSize, boolean thief, boolean victim, final ByteBuffer emptyExtendedChainHeader) { this.storage = new OffHeapStorageArea(PointerSize.LONG, new StorageOwner(), source, minPageSize, maxPageSize, thief, victim); this.keyPortability = keyPortability; this.extendedChainHeaderSize = emptyExtendedChainHeader.remaining(); this.emptyExtendedChainHeader = emptyExtendedChainHeader; this.totalChainHeaderSize = CHAIN_HEADER_SIZE + this.extendedChainHeaderSize; }
private Long createAttachedChain(ByteBuffer keyBuffer, int hash, ByteBuffer elemBuffer) { long chain = storage.allocate(keyBuffer.remaining() + elemBuffer.remaining() + this.totalChainHeaderSize + ELEMENT_HEADER_SIZE); if (chain < 0) { return null; } int keySize = keyBuffer.remaining(); storage.writeInt(chain + CHAIN_HEADER_KEY_HASH_OFFSET, hash); storage.writeInt(chain + CHAIN_HEADER_KEY_LENGTH_OFFSET, Integer.MIN_VALUE | keySize); storage.writeBuffer(chain + this.totalChainHeaderSize + ELEMENT_HEADER_SIZE + elemBuffer.remaining(), keyBuffer); if (extendedChainHeaderSize > 0) { storage.writeBuffer(chain + CHAIN_HEADER_SIZE, emptyExtendedChainHeader.duplicate()); } long element = chain + this.totalChainHeaderSize; writeElement(element, elemBuffer); storage.writeLong(element + ELEMENT_HEADER_NEXT_OFFSET, chain); storage.writeLong(chain + CHAIN_HEADER_TAIL_OFFSET, element); return chain; }
void replayIntoMap(ReadWriteLockedOffHeapClockCache<K, InternalChain> newMap) { Lock l = newMap.writeLock(); l.lock(); try { chainAddresses.forEach((a) -> { ExtendedHeaderForTest hdr = createAtExtensionAddress(a); long address = hdr.getAddress(); int keyLength = extendedArea.readInt(address + STORAGE_KEY_LENGTH_OFFSET); int valueLength = extendedArea.readInt(address + STORAGE_VALUE_LENGTH_OFFSET); ByteBuffer keyBuffer = extendedArea.readBuffer(address + STORAGE_HEADER_OFFSET, keyLength); ByteBuffer valueBuffer = extendedArea.readBuffer(address + STORAGE_HEADER_OFFSET + keyLength, valueLength); newMap.installMappingForHashAndEncoding(hdr.getHash(), keyBuffer, valueBuffer, 0); }); } finally { l.unlock(); } }
private long writeElement(long address, ByteBuffer element) { storage.writeLong(address + ELEMENT_HEADER_SEQUENCE_OFFSET, nextSequenceNumber++); storage.writeInt(address + ELEMENT_HEADER_LENGTH_OFFSET, element.remaining()); storage.writeBuffer(address + ELEMENT_HEADER_SIZE, element.duplicate()); return address; }
@Override public ByteBuffer readBinaryValue(long chain) { // first get total element size and allocate buffer long element = chain + this.totalChainHeaderSize; int totalLength = DETACHED_CONTIGUOUS_CHAIN_HEADER_SIZE; do { totalLength += ELEMENT_HEADER_SIZE + readElementLength(element); element = storage.readLong(element + ELEMENT_HEADER_NEXT_OFFSET); } while (element != chain); final ByteBuffer detachedContiguousBuffer = ByteBuffer.allocate(totalLength); // one way for layers above to extract encoding is to put the encoding of the chain address in the value detachedContiguousBuffer.putLong(chain); // now add the elements to the buffer element = chain + this.totalChainHeaderSize; do { final int startPosition = detachedContiguousBuffer.position(); detachedContiguousBuffer.put(storage.readBuffer(element, ELEMENT_HEADER_SIZE + readElementLength(element))); detachedContiguousBuffer.mark(); detachedContiguousBuffer.putLong(startPosition + ELEMENT_HEADER_NEXT_OFFSET, -1L); detachedContiguousBuffer.reset(); element = storage.readLong(element + ELEMENT_HEADER_NEXT_OFFSET); } while (element != chain); return (ByteBuffer)detachedContiguousBuffer.flip(); }
@Override protected Integer writeBuffer(ByteBuffer buffer, int hash) { int length = buffer.remaining(); int address = (int) storageArea.allocate(length + HEADER_LENGTH); if (address >= 0) { storageArea.writeInt(address + KEY_HASH_OFFSET, hash); storageArea.writeInt(address + LENGTH_OFFSET, length); storageArea.writeBuffer(address + DATA_OFFSET, buffer); return address; } else { return null; } }
private int readElementLength(long element) { // The most significant bit (MSB) of element length is used to signify whether an element is explicitly allocated // (msb clear) or part of a contiguous chain (msb set). Clear the msb when returning length. return Integer.MAX_VALUE & storage.readInt(element + ELEMENT_HEADER_LENGTH_OFFSET); }
long ceiling = addressForPage(Math.max(0, pageIndexFor(target) - 2)) + 1; long startAt = random.nextLong() % ceiling; //check for negative results?? if (relocated >= 0) { if (relocated < target) { writeBuffers(relocated, readBuffers(target, sizeOfArea)); if (!owner.moved(target, relocated)) { throw new AssertionError("Failure to move mapping during release"); if (relocated >= 0) { if (relocated < target) { writeBuffer(relocated, readBuffer(target, sizeOfArea)); owner.moved(target, relocated); allocator.free(target);
private void writeToExtendedArea(long chainAddress, int hash, ByteBuffer keyBuffer, ByteBuffer valueBuffer) { ExtendedHeaderForTest hdr = createAtExtensionAddress(chainAddress); long address = hdr.getAddress(); if (address != NULL_ENCODING) { // free previous extendedArea.free(address); } else { chainAddresses.add(chainAddress); } int size = (2 * Integer.BYTES) + keyBuffer.remaining() + valueBuffer.remaining(); address = extendedArea.allocate(size); hdr.setAddress(address); hdr.setHashAndSize(hash, size); extendedArea.writeInt(address + STORAGE_KEY_LENGTH_OFFSET, keyBuffer.remaining()); extendedArea.writeInt(address + STORAGE_VALUE_LENGTH_OFFSET, valueBuffer.remaining()); extendedArea.writeBuffer(address + STORAGE_HEADER_OFFSET, keyBuffer.duplicate()); extendedArea.writeBuffer(address + STORAGE_HEADER_OFFSET + keyBuffer.remaining(), valueBuffer.duplicate()); }
private void backward(int p, int value) { storage.writeInt(p + 12, value); }
@Override protected Long writeMappingBuffersGathering(ByteBuffer[] keyBuffers, ByteBuffer[] valueBuffers, int hash) { int keyLength = totalLength(keyBuffers); int valueLength = totalLength(valueBuffers); long address = storageArea.allocate(keyLength + valueLength + HEADER_SIZE); if (address >= 0) { storageArea.writeInt(address + KEY_HASH_OFFSET, hash); storageArea.writeInt(address + KEY_LENGTH_OFFSET, keyLength); storageArea.writeInt(address + VALUE_LENGTH_OFFSET, valueLength); storageArea.writeBuffers(address + DATA_OFFSET, keyBuffers); storageArea.writeBuffers(address + DATA_OFFSET + keyLength, valueBuffers); return address; } else { return null; } }
private boolean expandData() { int newPageSize = nextPageSize(); if (getAllocatedMemory() + newPageSize > allocator.getMaximumAddress()) { return false; } Page newPage = pageSource.allocate(newPageSize, thief, victim, this); if (newPage == null) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Data area expansion from {} failed", getAllocatedMemory()); } return false; } else if (pages.put(pages.size(), newPage) == null) { validatePages(); allocator.expand(newPageSize); if (LOGGER.isDebugEnabled()) { long before = getAllocatedMemory(); long after = before + newPageSize; LOGGER.debug("Data area expanded from {}B to {}B [occupation={}]", toBase2SuffixedString(before), toBase2SuffixedString(after), ((float) allocator.occupied()) / after); } return true; } else { freePage(newPage); validatePages(); throw new AssertionError(); } }
@Override public long getAllocatedMemory() { return storage.getAllocatedMemory(); }
private void localRemove(long chainAddress) { ExtendedHeaderForTest node = createAtExtensionAddress(chainAddress); long address = node.getAddress(); if (address != NULL_ENCODING) { extendedArea.free(node.getAddress()); chainAddresses.remove(chainAddress); } node.setAddress(NULL_ENCODING); }
@Override public void destroy() { storage.destroy(); }
@Override public void clear() { storage.clear(); }
private ByteBuffer readKeyBuffer(long encoding) { int keyLength = readKeySize(encoding); int elemLength = readElementLength(encoding + this.totalChainHeaderSize); return storage.readBuffer(encoding + this.totalChainHeaderSize + ELEMENT_HEADER_SIZE + elemLength, keyLength); }
public void writeBuffers(long address, ByteBuffer[] data) { for (ByteBuffer buffer : data) { int length = buffer.remaining(); writeBuffer(address, buffer); address += length; } }
@Override protected Integer writeBuffer(ByteBuffer buffer, int hash) { int length = buffer.remaining(); int address = (int) storageArea.allocate(length + HEADER_LENGTH); if (address >= 0) { storageArea.writeInt(address + KEY_HASH_OFFSET, hash); storageArea.writeInt(address + LENGTH_OFFSET, length); storageArea.writeBuffer(address + DATA_OFFSET, buffer); return address; } else { return null; } }
@Override public int readKeyHash(long encoding) { return storage.readInt(encoding + CHAIN_HEADER_KEY_HASH_OFFSET); }