in src/main/java/com/spotify/sparkey/IndexHash.java [551:654]
private static void put(
final ReadWriteData indexData, final IndexHeader header, final long hashCapacity,
int keyLen, byte[] key,
final BlockRandomInput logData,
byte[] keyBuf,
final HashType hashData,
final AddressSize addressData,
final int entryIndexBitmask,
final int entryIndexBits,
long hash,
long address) throws IOException {
if (header.getNumEntries() >= hashCapacity) {
throw new IOException("No free slots in the hash: " + header.getNumEntries() + " >= " + hashCapacity);
}
long wantedSlot = getWantedSlot(hash, hashCapacity);
long pos = wantedSlot * header.getSlotSize();
indexData.seek(pos);
long displacement = 0;
long tries = hashCapacity;
long slot = wantedSlot;
int entryIndex = (int) (address) & entryIndexBitmask;
long position = address >>> entryIndexBits;
boolean mightBeCollision = true;
while (--tries >= 0) {
long hash2 = hashData.readHash(indexData);
long address2 = addressData.readAddress(indexData);
if (address2 == 0) {
indexData.seek(pos);
hashData.writeHash(hash, indexData);
addressData.writeAddress(address, indexData);
header.addedEntry();
return;
}
int entryIndex2 = (int) (address2) & entryIndexBitmask;
long position2 = address2 >>> entryIndexBits;
if (mightBeCollision && hash == hash2) {
if (keyLen == -1) {
logData.seek(position);
skipStuff(entryIndex, logData);
keyLen = Util.readUnsignedVLQInt(logData) - 1;
if (keyLen == -1) {
// This was a delete?
throw new RuntimeException("Corrupt data");
}
Util.readUnsignedVLQInt(logData); // Ignore value length
logData.readFully(key, 0, keyLen);
}
logData.seek(position2);
skipStuff(entryIndex2, logData);
int keyLen2 = Util.readUnsignedVLQInt(logData);
int valueLen2 = Util.readUnsignedVLQInt(logData);
if (keyLen2 == 0) {
throw new RuntimeException("Invalid data - reference to delete entry");
}
keyLen2--;
if (keyLen == keyLen2) {
logData.readFully(keyBuf, 0, keyLen2);
if (Util.equals(keyLen, key, keyBuf)) {
indexData.seek(pos);
hashData.writeHash(hash, indexData);
addressData.writeAddress(address, indexData);
header.replacedEntry(keyLen2, valueLen2);
return;
}
}
}
long otherDisplacement = getDisplacement(hashCapacity, slot, hash2);
// TODO: skip the address < address2 - only useful for generating deterministic hash tables
if (displacement > otherDisplacement || (displacement == otherDisplacement && address < address2)) {
// Steal the slot, and move the other one
indexData.seek(pos);
hashData.writeHash(hash, indexData);
addressData.writeAddress(address, indexData);
position = position2;
entryIndex = entryIndex2;
address = address2;
displacement = otherDisplacement;
hash = hash2;
mightBeCollision = false;
}
pos += header.getSlotSize();
displacement++;
slot++;
if (slot >= hashCapacity) {
indexData.seek(0);
pos = 0;
slot = 0;
}
}
throw new IOException("No free slots in the hash");
}