private bool FindTagMaybeTentativeInternal(long hash, ushort tag, ref HashBucket *bucket, ref int slot) { var target_entry_word = default(long); var entry_slot_bucket = default(HashBucket *); do { // Search through the bucket looking for our key. Last entry is reserved // for the overflow pointer. for (int index = 0; index < Constants.kOverflowBucketIndex; ++index) { target_entry_word = *(((long *)bucket) + index); if (0 == target_entry_word) { continue; } HashBucketEntry entry = default(HashBucketEntry); entry.word = target_entry_word; if (tag == entry.Tag) { slot = index; return(true); } } target_entry_word = *(((long *)bucket) + Constants.kOverflowBucketIndex) & Constants.kAddressMask; // Go to next bucket in the chain if (target_entry_word == 0) { return(false); } bucket = (HashBucket *)overflowBucketsAllocator.GetPhysicalAddress(target_entry_word); } while (true); }
private bool FindTagOrFreeInternal(long hash, ushort tag, ref HashBucket *bucket, ref int slot, ref HashBucketEntry entry, long BeginAddress = 0) { var target_entry_word = default(long); var recordExists = false; var entry_slot_bucket = default(HashBucket *); do { // Search through the bucket looking for our key. Last entry is reserved // for the overflow pointer. for (int index = 0; index < Constants.kOverflowBucketIndex; ++index) { target_entry_word = *(((long *)bucket) + index); if (0 == target_entry_word) { if (slot == Constants.kInvalidEntrySlot) { slot = index; entry_slot_bucket = bucket; } continue; } entry.word = target_entry_word; if (entry.Address < BeginAddress && entry.Address != Constants.kTempInvalidAddress) { if (entry.word == Interlocked.CompareExchange(ref bucket->bucket_entries[index], Constants.kInvalidAddress, target_entry_word)) { if (slot == Constants.kInvalidEntrySlot) { slot = index; entry_slot_bucket = bucket; } continue; } } if (tag == entry.Tag && !entry.Tentative) { slot = index; recordExists = true; return(recordExists); } } target_entry_word = *(((long *)bucket) + Constants.kOverflowBucketIndex); // Go to next bucket in the chain if ((target_entry_word & Constants.kAddressMask) == 0) { if (slot == Constants.kInvalidEntrySlot) { // Allocate new bucket var logicalBucketAddress = overflowBucketsAllocator.Allocate(); var physicalBucketAddress = (HashBucket *)overflowBucketsAllocator.GetPhysicalAddress(logicalBucketAddress); long compare_word = target_entry_word; target_entry_word = logicalBucketAddress; target_entry_word |= (compare_word & ~Constants.kAddressMask); long result_word = Interlocked.CompareExchange( ref bucket->bucket_entries[Constants.kOverflowBucketIndex], target_entry_word, compare_word); if (compare_word != result_word) { // Install failed, undo allocation; use the winner's entry overflowBucketsAllocator.Free(logicalBucketAddress); target_entry_word = result_word; } else { // Install succeeded bucket = physicalBucketAddress; slot = 0; entry = default(HashBucketEntry); return(recordExists); } } else { if (!recordExists) { bucket = entry_slot_bucket; } entry = default(HashBucketEntry); break; } } bucket = (HashBucket *)overflowBucketsAllocator.GetPhysicalAddress(target_entry_word & Constants.kAddressMask); } while (true); return(recordExists); }
internal void FindOrCreateTag(long hash, ushort tag, ref HashBucket *bucket, ref int slot, ref HashBucketEntry entry, long BeginAddress) { var version = resizeInfo.version; var masked_entry_word = hash & state[version].size_mask; while (true) { bucket = state[version].tableAligned + masked_entry_word; slot = Constants.kInvalidEntrySlot; if (FindTagOrFreeInternal(hash, tag, ref bucket, ref slot, ref entry, BeginAddress)) { return; } // Install tentative tag in free slot entry = default(HashBucketEntry); entry.Tag = tag; entry.Address = Constants.kTempInvalidAddress; entry.Pending = false; entry.Tentative = true; if (0 == Interlocked.CompareExchange(ref bucket->bucket_entries[slot], entry.word, 0)) { var orig_bucket = state[version].tableAligned + masked_entry_word; var orig_slot = Constants.kInvalidEntrySlot; if (FindOtherTagMaybeTentativeInternal(hash, tag, ref orig_bucket, ref orig_slot, bucket, slot)) { bucket->bucket_entries[slot] = 0; } else { entry.Tentative = false; *((long *)bucket + slot) = entry.word; break; } } } }
internal bool FindTag(long hash, ushort tag, ref HashBucket *bucket, ref int slot, ref HashBucketEntry entry) { var target_entry_word = default(long); var entry_slot_bucket = default(HashBucket *); var version = resizeInfo.version; var masked_entry_word = hash & state[version].size_mask; bucket = state[version].tableAligned + masked_entry_word; slot = Constants.kInvalidEntrySlot; do { // Search through the bucket looking for our key. Last entry is reserved // for the overflow pointer. for (int index = 0; index < Constants.kOverflowBucketIndex; ++index) { target_entry_word = *(((long *)bucket) + index); if (0 == target_entry_word) { continue; } entry.word = target_entry_word; if (tag == entry.Tag) { slot = index; if (!entry.Tentative) { return(true); } } } target_entry_word = *(((long *)bucket) + Constants.kOverflowBucketIndex) & Constants.kAddressMask; // Go to next bucket in the chain if (target_entry_word == 0) { entry = default(HashBucketEntry); return(false); } bucket = (HashBucket *)overflowBucketsAllocator.GetPhysicalAddress(target_entry_word); } while (true); }