/** * implementation for map.put(Key,Value) * * @param keyBytes * @param value * @param hash2 a hash code relating to the {@keyBytes} ( not the natural hash of {@keyBytes} ) * @param replaceIfPresent * @return */ V put(final DirectBytes keyBytes, final V value, int hash2, boolean replaceIfPresent) { lock(); try { hash2 = hashLookup.startSearch(hash2); while (true) { final int pos = hashLookup.nextPos(); if (pos < 0) { putEntry(keyBytes, value, hash2); return null; } else { final long offset = entriesOffset + pos * entrySize; tmpBytes.storePositionAndSize(bytes, offset, entrySize); if (!keyEquals(keyBytes, tmpBytes)) continue; final long keyLength = keyBytes.remaining(); tmpBytes.skip(keyLength); if (replaceIfPresent) { if (putReturnsNull) { appendInstance(keyBytes, value); return null; } long valuePosition = tmpBytes.position(); tmpBytes.readStopBit(); final long alignPosition = align(tmpBytes.position()); tmpBytes.position(alignPosition); final V v = readObjectUsing(null, offset + alignPosition); tmpBytes.position(valuePosition); appendInstance(keyBytes, value); return v; } else { if (putReturnsNull) { return null; } return readObjectUsing(null, offset + keyLength); } } } } finally { unlock(); } }
/** * implementation for map.replace(Key,Value) and map.replace(Key,Old,New) * * @param keyBytes the key of the entry to be replaced * @param expectedValue the expected value to replaced * @param newValue the new value that will only be set if the existing value in the map equals * the {@param expectedValue} or {@param expectedValue} is null * @param hash2 a hash code relating to the {@keyBytes} ( not the natural hash of {@keyBytes} ) * @return null if the value was not replaced, else the value that is replaced is returned */ V replace( final DirectBytes keyBytes, final V expectedValue, final V newValue, final int hash2) { lock(); try { hashLookup.startSearch(hash2); while (true) { final int pos = hashLookup.nextPos(); if (pos < 0) { return null; } else { final long offset = entriesOffset + pos * entrySize; tmpBytes.storePositionAndSize(bytes, offset, entrySize); if (!keyEquals(keyBytes, tmpBytes)) continue; final long keyLength = keyBytes.remaining(); tmpBytes.skip(keyLength); long valuePosition = tmpBytes.position(); tmpBytes.readStopBit(); final long alignPosition = align(tmpBytes.position()); tmpBytes.position(alignPosition); final V valueRead = readObjectUsing(null, offset + keyLength); if (valueRead == null) return null; if (expectedValue == null || expectedValue.equals(valueRead)) { tmpBytes.position(valuePosition); appendInstance(keyBytes, newValue); } return valueRead; } } } finally { unlock(); } }
/** * used to acquire and object of type V from the map, * * <p>when {@param create }== true, this method is equivalent to : * * <pre> * Object value = map.get("Key"); * * if ( counter == null ) { * value = new Object(); * map.put("Key", value); * } * * return value; * </pre> * * @param keyBytes the key of the entry * @param value an object to be reused, null creates a new object. * @param hash2 a hash code relating to the {@keyBytes} ( not the natural hash of {@keyBytes} ) * @param create false - if the {@keyBytes} can not be found null will be returned, true - if * the {@keyBytes} can not be found an value will be acquired * @return an entry.value whose entry.key equals {@param keyBytes} */ V acquire(DirectBytes keyBytes, V value, int hash2, boolean create) { lock(); try { hash2 = hashLookup.startSearch(hash2); while (true) { int pos = hashLookup.nextPos(); if (pos < 0) { return create ? acquireEntry(keyBytes, value, hash2) : null; } else { final long offset = entriesOffset + pos * entrySize; tmpBytes.storePositionAndSize(bytes, offset, entrySize); final boolean miss; if (LOGGER.isLoggable(Level.FINE)) { final long start0 = System.nanoTime(); miss = !keyEquals(keyBytes, tmpBytes); final long time0 = System.nanoTime() - start0; if (time0 > 1e6) LOGGER.fine("startsWith took " + time0 / 100000 / 10.0 + " ms."); } else { miss = !keyEquals(keyBytes, tmpBytes); } if (miss) continue; long valueLengthOffset = keyBytes.remaining() + tmpBytes.position(); tmpBytes.position(valueLengthOffset); // skip the value length // todo use the value length to limit reading below long valueLength = tmpBytes.readStopBit(); final long valueOffset = align(tmpBytes.position()); // includes the stop bit length. tmpBytes.position(valueOffset); return readObjectUsing(value, offset + valueOffset); } } } finally { unlock(); } }
boolean keyEquals(Bytes keyBytes, MultiStoreBytes tmpBytes) { // check the length is the same. long keyLength = tmpBytes.readStopBit(); return keyLength == keyBytes.remaining() && tmpBytes.startsWith(keyBytes); }