in cs/src/core/Index/FASTER/FASTERImpl.cs [2063:2203]
private void SplitChunk(
HashBucket* _src_start,
HashBucket* _dest_start0,
HashBucket* _dest_start1,
long chunkSize)
{
for (int i = 0; i < chunkSize; i++)
{
var src_start = _src_start + i;
long* left = (long*)(_dest_start0 + i);
long* right = (long*)(_dest_start1 + i);
long* left_end = left + Constants.kOverflowBucketIndex;
long* right_end = right + Constants.kOverflowBucketIndex;
HashBucketEntry entry = default;
do
{
for (int index = 0; index < Constants.kOverflowBucketIndex; ++index)
{
entry.word = *(((long*)src_start) + index);
if (Constants.kInvalidEntry == entry.word)
{
continue;
}
var logicalAddress = entry.Address;
long physicalAddress = 0;
if (entry.ReadCache && (entry.Address & ~Constants.kReadCacheBitMask) >= readcache.HeadAddress)
physicalAddress = readcache.GetPhysicalAddress(entry.Address & ~Constants.kReadCacheBitMask);
else if (logicalAddress >= hlog.HeadAddress)
physicalAddress = hlog.GetPhysicalAddress(logicalAddress);
// It is safe to always use hlog instead of readcache for some calls such
// as GetKey and GetInfo
if (physicalAddress != 0)
{
var hash = comparer.GetHashCode64(ref hlog.GetKey(physicalAddress));
if ((hash & state[resizeInfo.version].size_mask) >> (state[resizeInfo.version].size_bits - 1) == 0)
{
// Insert in left
if (left == left_end)
{
var new_bucket_logical = overflowBucketsAllocator.Allocate();
var new_bucket = (HashBucket*)overflowBucketsAllocator.GetPhysicalAddress(new_bucket_logical);
*left = new_bucket_logical;
left = (long*)new_bucket;
left_end = left + Constants.kOverflowBucketIndex;
}
*left = entry.word;
left++;
// Insert previous address in right
entry.Address = TraceBackForOtherChainStart(hlog.GetInfo(physicalAddress).PreviousAddress, 1);
if ((entry.Address != Constants.kInvalidAddress) && (entry.Address != Constants.kTempInvalidAddress))
{
if (right == right_end)
{
var new_bucket_logical = overflowBucketsAllocator.Allocate();
var new_bucket = (HashBucket*)overflowBucketsAllocator.GetPhysicalAddress(new_bucket_logical);
*right = new_bucket_logical;
right = (long*)new_bucket;
right_end = right + Constants.kOverflowBucketIndex;
}
*right = entry.word;
right++;
}
}
else
{
// Insert in right
if (right == right_end)
{
var new_bucket_logical = overflowBucketsAllocator.Allocate();
var new_bucket = (HashBucket*)overflowBucketsAllocator.GetPhysicalAddress(new_bucket_logical);
*right = new_bucket_logical;
right = (long*)new_bucket;
right_end = right + Constants.kOverflowBucketIndex;
}
*right = entry.word;
right++;
// Insert previous address in left
entry.Address = TraceBackForOtherChainStart(hlog.GetInfo(physicalAddress).PreviousAddress, 0);
if ((entry.Address != Constants.kInvalidAddress) && (entry.Address != Constants.kTempInvalidAddress))
{
if (left == left_end)
{
var new_bucket_logical = overflowBucketsAllocator.Allocate();
var new_bucket = (HashBucket*)overflowBucketsAllocator.GetPhysicalAddress(new_bucket_logical);
*left = new_bucket_logical;
left = (long*)new_bucket;
left_end = left + Constants.kOverflowBucketIndex;
}
*left = entry.word;
left++;
}
}
}
else
{
// Insert in both new locations
// Insert in left
if (left == left_end)
{
var new_bucket_logical = overflowBucketsAllocator.Allocate();
var new_bucket = (HashBucket*)overflowBucketsAllocator.GetPhysicalAddress(new_bucket_logical);
*left = new_bucket_logical;
left = (long*)new_bucket;
left_end = left + Constants.kOverflowBucketIndex;
}
*left = entry.word;
left++;
// Insert in right
if (right == right_end)
{
var new_bucket_logical = overflowBucketsAllocator.Allocate();
var new_bucket = (HashBucket*)overflowBucketsAllocator.GetPhysicalAddress(new_bucket_logical);
*right = new_bucket_logical;
right = (long*)new_bucket;
right_end = right + Constants.kOverflowBucketIndex;
}
*right = entry.word;
right++;
}
}
if (*(((long*)src_start) + Constants.kOverflowBucketIndex) == 0) break;
src_start = (HashBucket*)overflowBucketsAllocatorResize.GetPhysicalAddress(*(((long*)src_start) + Constants.kOverflowBucketIndex));
} while (true);
}
}