final int searchHashCode = hash(this.buildSideComparator.hash(record));
final int posHashCode = searchHashCode % this.numBuckets;
// get the bucket for the given hash code
MemorySegment originalBucket = this.buckets[posHashCode >> this.bucketsPerSegmentBits];
int originalBucketOffset = (posHashCode & this.bucketsPerSegmentMask) << NUM_INTRA_BUCKET_BITS;
MemorySegment bucket = originalBucket;
int bucketInSegmentOffset = originalBucketOffset;
// get the basic characteristics of the bucket
final int partitionNumber = bucket.get(bucketInSegmentOffset + HEADER_PARTITION_OFFSET);
InMemoryPartition<T> partition = this.partitions.get(partitionNumber);
final MemorySegment[] overflowSegments = partition.overflowSegments;
this.buildSideComparator.setReference(record);
int countInSegment = bucket.getInt(bucketInSegmentOffset + HEADER_COUNT_OFFSET);
int numInSegment = 0;
int posInSegment = bucketInSegmentOffset + BUCKET_HEADER_LENGTH;
long currentForwardPointer = BUCKET_FORWARD_POINTER_NOT_SET;
// loop over all segments that are involved in the bucket (original bucket plus overflow buckets)
while (true) {
while (numInSegment < countInSegment) {
final int thisCode = bucket.getInt(posInSegment);
posInSegment += HASH_CODE_LEN;
// check if the hash code matches
if (thisCode == searchHashCode) {
// get the pointer to the pair
final int pointerOffset = bucketInSegmentOffset + BUCKET_POINTER_START_OFFSET + (numInSegment * POINTER_LEN);
final long pointer = bucket.getLong(pointerOffset);
numInSegment++;
// deserialize the key to check whether it is really equal, or whether we had only a hash collision
try {
tempHolder = partition.readRecordAt(pointer, tempHolder);
if (this.buildSideComparator.equalToReference(tempHolder)) {
long newPointer = partition.appendRecord(record);
bucket.putLong(pointerOffset, newPointer);
partition.setCompaction(false);
if((newPointer >> this.pageSizeInBits) > this.compactionMemory.getBlockCount()) {
this.compactionMemory.allocateSegments((int)(newPointer >> this.pageSizeInBits));
}
return;
}
} catch (EOFException e) {
// system is out of memory so we attempt to reclaim memory with a copy compact run
long newPointer;
try {
compactPartition(partition.getPartitionNumber());
// retry append
partition = this.partitions.get(partitionNumber); // compaction invalidates reference
newPointer = partition.appendRecord(record);
} catch (EOFException ex) {
throw new RuntimeException("Memory ran out. Compaction failed. " +
getMemoryConsumptionString() +
" Message: " + ex.getMessage());
} catch (IndexOutOfBoundsException ex) {
throw new RuntimeException("Memory ran out. Compaction failed. " +
getMemoryConsumptionString() +
" Message: " + ex.getMessage());
}
bucket.putLong(pointerOffset, newPointer);
return;
} catch (IndexOutOfBoundsException e) {
// system is out of memory so we attempt to reclaim memory with a copy compact run
long newPointer;
try {
compactPartition(partition.getPartitionNumber());
// retry append
partition = this.partitions.get(partitionNumber); // compaction invalidates reference
newPointer = partition.appendRecord(record);
} catch (EOFException ex) {
throw new RuntimeException("Memory ran out. Compaction failed. " +
getMemoryConsumptionString() +
" Message: " + ex.getMessage());
} catch (IndexOutOfBoundsException ex) {
throw new RuntimeException("Memory ran out. Compaction failed. " +
getMemoryConsumptionString() +
" Message: " + ex.getMessage());
}
bucket.putLong(pointerOffset, newPointer);
return;
} catch (IOException e) {
throw new RuntimeException("Error deserializing record from the hashtable: " + e.getMessage(), e);
}
}
else {
numInSegment++;
}
}
// this segment is done. check if there is another chained bucket
long newForwardPointer = bucket.getLong(bucketInSegmentOffset + HEADER_FORWARD_OFFSET);
if (newForwardPointer == BUCKET_FORWARD_POINTER_NOT_SET) {
// nothing found. append and insert
long pointer = partition.appendRecord(record);
//insertBucketEntryFromStart(partition, originalBucket, originalBucketOffset, searchHashCode, pointer);
insertBucketEntryFromSearch(partition, originalBucket, bucket, originalBucketOffset, bucketInSegmentOffset, countInSegment, currentForwardPointer, searchHashCode, pointer);
if((pointer >> this.pageSizeInBits) > this.compactionMemory.getBlockCount()) {
this.compactionMemory.allocateSegments((int)(pointer >> this.pageSizeInBits));
}
return;
}
final int overflowSegNum = (int) (newForwardPointer >>> 32);
bucket = overflowSegments[overflowSegNum];
bucketInSegmentOffset = (int) (newForwardPointer & 0xffffffff);
countInSegment = bucket.getInt(bucketInSegmentOffset + HEADER_COUNT_OFFSET);
posInSegment = bucketInSegmentOffset + BUCKET_HEADER_LENGTH;
numInSegment = 0;
currentForwardPointer = newForwardPointer;
}
}