use std::{
fmt,
hint::spin_loop,
mem::forget,
result::Result,
sync::atomic::{AtomicU64, Ordering, fence},
thread::yield_now,
};
use crate::entry::HashBucketEntry;
#[repr(C, align(64))]
pub struct HashBucket {
pub entries: [AtomicU64; 8],
}
pub const ENTRIES_PER_BUCKET: usize = 8;
pub const OVERFLOW_INDEX: usize = 7;
pub const DATA_ENTRIES: usize = 7;
impl HashBucket {
pub const DATA_ENTRIES: usize = DATA_ENTRIES;
pub const OVERFLOW_INDEX: usize = OVERFLOW_INDEX;
pub const MAX_LOCK_SPINS: usize = 128;
pub const MAX_READER_DRAIN_SPINS: usize = 1024;
pub const SPIN_THRESHOLD: usize = 32;
pub const DRAIN_RETRIES_THRESHOLD: usize = 16;
pub const SHARED_LATCH_BITS: u32 = 15;
pub const SHARED_LATCH_SHIFT: u32 = HashBucketEntry::ADDRESS_BITS;
pub const SHARED_LATCH_MASK: u64 =
((1u64 << Self::SHARED_LATCH_BITS) - 1) << Self::SHARED_LATCH_SHIFT;
pub const SHARED_LATCH_INC: u64 = 1u64 << Self::SHARED_LATCH_SHIFT;
pub const EXCLUSIVE_LATCH_SHIFT: u32 = 63;
pub const EXCLUSIVE_LATCH_MASK: u64 = 1u64 << Self::EXCLUSIVE_LATCH_SHIFT;
pub const LATCH_MASK: u64 = Self::SHARED_LATCH_MASK | Self::EXCLUSIVE_LATCH_MASK;
pub const fn new() -> Self {
Self {
entries: [const { AtomicU64::new(0) }; ENTRIES_PER_BUCKET],
}
}
pub fn try_lock_shared(&self) -> bool {
for i in 0..Self::MAX_LOCK_SPINS {
let curr = self.entries[OVERFLOW_INDEX].load(Ordering::Acquire);
if (curr & Self::EXCLUSIVE_LATCH_MASK) == 0
&& (curr & Self::SHARED_LATCH_MASK) != Self::SHARED_LATCH_MASK
{
let new_val = curr + Self::SHARED_LATCH_INC;
if self.entries[OVERFLOW_INDEX]
.compare_exchange_weak(curr, new_val, Ordering::AcqRel, Ordering::Acquire)
.is_ok()
{
return true;
}
}
if i < Self::SPIN_THRESHOLD {
spin_loop();
} else {
yield_now();
}
}
false
}
pub fn unlock_shared(&self) {
let prev = self.entries[OVERFLOW_INDEX].fetch_sub(Self::SHARED_LATCH_INC, Ordering::Release);
debug_assert!(
(prev & Self::SHARED_LATCH_MASK) != 0,
"试图释放未持有的共享锁"
);
debug_assert!(
(prev & Self::LATCH_MASK) != Self::EXCLUSIVE_LATCH_MASK,
"试图对仅持独占锁的桶释放共享锁"
);
}
pub fn try_lock_exclusive(&self) -> bool {
let mut acquired_bit = false;
for i in 0..Self::MAX_LOCK_SPINS {
let curr = self.entries[OVERFLOW_INDEX].load(Ordering::Acquire);
if (curr & Self::EXCLUSIVE_LATCH_MASK) == 0 {
let new_val = curr | Self::EXCLUSIVE_LATCH_MASK;
if self.entries[OVERFLOW_INDEX]
.compare_exchange_weak(curr, new_val, Ordering::AcqRel, Ordering::Acquire)
.is_ok()
{
acquired_bit = true;
break;
}
}
if i < Self::SPIN_THRESHOLD {
spin_loop();
} else {
yield_now();
}
}
if !acquired_bit {
return false;
}
for i in 0..Self::MAX_READER_DRAIN_SPINS {
let curr = self.entries[OVERFLOW_INDEX].load(Ordering::Acquire);
if (curr & Self::SHARED_LATCH_MASK) == 0 {
return true;
}
if i < Self::SPIN_THRESHOLD {
spin_loop();
} else {
yield_now();
}
}
self.entries[OVERFLOW_INDEX].fetch_and(!Self::EXCLUSIVE_LATCH_MASK, Ordering::Release);
false
}
pub fn try_promote_latch(&self) -> bool {
let mut acquired_bit = false;
for i in 0..Self::MAX_LOCK_SPINS {
let curr = self.entries[OVERFLOW_INDEX].load(Ordering::Acquire);
if (curr & Self::SHARED_LATCH_MASK) == 0 {
return false;
}
if (curr & Self::EXCLUSIVE_LATCH_MASK) == 0 {
let new_val = (curr | Self::EXCLUSIVE_LATCH_MASK) - Self::SHARED_LATCH_INC;
if self.entries[OVERFLOW_INDEX]
.compare_exchange_weak(curr, new_val, Ordering::AcqRel, Ordering::Acquire)
.is_ok()
{
acquired_bit = true;
break;
}
}
if i < Self::SPIN_THRESHOLD {
spin_loop();
} else {
yield_now();
}
}
if !acquired_bit {
return false;
}
for i in 0..Self::MAX_READER_DRAIN_SPINS {
let curr = self.entries[OVERFLOW_INDEX].load(Ordering::Acquire);
if (curr & Self::SHARED_LATCH_MASK) == 0 {
return true;
}
if i < Self::SPIN_THRESHOLD {
spin_loop();
} else {
yield_now();
}
}
let mut curr = self.entries[OVERFLOW_INDEX].load(Ordering::Acquire);
let mut retries = 0usize;
loop {
let new_val = (curr & !Self::EXCLUSIVE_LATCH_MASK) + Self::SHARED_LATCH_INC;
match self.entries[OVERFLOW_INDEX].compare_exchange_weak(
curr,
new_val,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => break,
Err(actual) => {
curr = actual;
retries += 1;
if retries < Self::DRAIN_RETRIES_THRESHOLD {
spin_loop();
} else {
yield_now();
}
}
}
}
false
}
pub fn downgrade_latch(&self) {
let mut curr = self.entries[OVERFLOW_INDEX].load(Ordering::Acquire);
loop {
debug_assert!(
(curr & Self::EXCLUSIVE_LATCH_MASK) != 0,
"尝试降级未持有独占锁的桶"
);
let new_val = (curr & !Self::EXCLUSIVE_LATCH_MASK) + Self::SHARED_LATCH_INC;
match self.entries[OVERFLOW_INDEX].compare_exchange_weak(
curr,
new_val,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => break,
Err(actual) => curr = actual,
}
spin_loop();
}
}
pub fn unlock_exclusive(&self) {
let prev =
self.entries[OVERFLOW_INDEX].fetch_and(!Self::EXCLUSIVE_LATCH_MASK, Ordering::Release);
debug_assert!(
(prev & Self::EXCLUSIVE_LATCH_MASK) != 0,
"试图释放未持有的独占锁"
);
}
#[inline]
pub fn is_latched_exclusive(&self) -> bool {
(self.entries[OVERFLOW_INDEX].load(Ordering::Acquire) & Self::EXCLUSIVE_LATCH_MASK) != 0
}
#[inline]
pub fn is_latched_shared(&self) -> bool {
(self.entries[OVERFLOW_INDEX].load(Ordering::Acquire) & Self::SHARED_LATCH_MASK) != 0
}
#[inline]
pub fn num_latched_shared(&self) -> u16 {
((self.entries[OVERFLOW_INDEX].load(Ordering::Acquire) & Self::SHARED_LATCH_MASK)
>> Self::SHARED_LATCH_SHIFT) as u16
}
#[inline]
pub fn is_latched(&self) -> bool {
(self.entries[OVERFLOW_INDEX].load(Ordering::Acquire) & Self::LATCH_MASK) != 0
}
#[inline]
pub fn overflow_index(&self) -> u64 {
self.entries[OVERFLOW_INDEX].load(Ordering::Acquire) & HashBucketEntry::ADDRESS_MASK
}
pub fn set_overflow_index(&self, overflow_idx: u64) -> bool {
if overflow_idx == 0 {
return false;
}
let target_addr = overflow_idx & HashBucketEntry::ADDRESS_MASK;
let mut curr = self.entries[OVERFLOW_INDEX].load(Ordering::Acquire);
loop {
if (curr & HashBucketEntry::ADDRESS_MASK) != 0 {
return false;
}
let new_val = curr | target_addr;
match self.entries[OVERFLOW_INDEX].compare_exchange_weak(
curr,
new_val,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => return true,
Err(actual) => {
curr = actual;
spin_loop();
}
}
}
}
#[inline]
pub fn find_tag_address(&self, tag: u16) -> Option<u64> {
let expected_hi = (tag as u64) & HashBucketEntry::TAG_MASK;
for item in &self.entries[..DATA_ENTRIES] {
let raw = item.load(Ordering::Relaxed);
if (raw >> HashBucketEntry::TAG_SHIFT) == expected_hi {
let addr = raw & HashBucketEntry::ADDRESS_MASK;
if addr != 0 {
fence(Ordering::Acquire);
return Some(addr);
}
}
}
None
}
#[inline]
pub fn find_entry_by_address(&self, tag: u16, address: u64) -> Option<(usize, HashBucketEntry)> {
let target_raw = HashBucketEntry::new(address, tag, false).as_raw();
for (slot, item) in self.entries[..DATA_ENTRIES].iter().enumerate() {
let raw = item.load(Ordering::Relaxed);
if raw == target_raw {
fence(Ordering::Acquire);
return Some((slot, HashBucketEntry::from_raw(raw)));
}
}
None
}
#[inline]
pub fn find_empty_slot(&self) -> Option<usize> {
for (slot, item) in self.entries[..DATA_ENTRIES].iter().enumerate() {
if item.load(Ordering::Relaxed) == 0 {
return Some(slot);
}
}
None
}
#[inline]
pub fn try_insert(&self, slot: usize, tag: u16, address: u64) -> bool {
if slot >= DATA_ENTRIES {
return false;
}
let entry = HashBucketEntry::new(address, tag, false);
self.entries[slot]
.compare_exchange(0, entry.as_raw(), Ordering::AcqRel, Ordering::Acquire)
.is_ok()
}
pub fn lock_shared_guard(&self) -> Option<BucketSharedGuard<'_>> {
BucketSharedGuard::new(self)
}
pub fn lock_exclusive_guard(&self) -> Option<BucketExclusiveGuard<'_>> {
BucketExclusiveGuard::new(self)
}
}
impl Default for HashBucket {
fn default() -> Self {
Self::new()
}
}
pub struct BucketSharedGuard<'a> {
bucket: &'a HashBucket,
}
impl<'a> BucketSharedGuard<'a> {
pub fn new(bucket: &'a HashBucket) -> Option<Self> {
if bucket.try_lock_shared() {
Some(Self { bucket })
} else {
None
}
}
pub fn try_promote(self) -> Result<BucketExclusiveGuard<'a>, Self> {
if self.bucket.try_promote_latch() {
let bucket = self.bucket;
forget(self);
Ok(BucketExclusiveGuard { bucket })
} else {
Err(self)
}
}
}
impl Drop for BucketSharedGuard<'_> {
fn drop(&mut self) {
self.bucket.unlock_shared();
}
}
pub struct BucketExclusiveGuard<'a> {
bucket: &'a HashBucket,
}
impl<'a> BucketExclusiveGuard<'a> {
pub fn new(bucket: &'a HashBucket) -> Option<Self> {
if bucket.try_lock_exclusive() {
Some(Self { bucket })
} else {
None
}
}
pub fn downgrade(self) -> BucketSharedGuard<'a> {
self.bucket.downgrade_latch();
let bucket = self.bucket;
forget(self);
BucketSharedGuard { bucket }
}
}
impl Drop for BucketExclusiveGuard<'_> {
fn drop(&mut self) {
self.bucket.unlock_exclusive();
}
}
impl fmt::Debug for HashBucket {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("HashBucket")
.field("exclusive", &self.is_latched_exclusive())
.field("shared_readers", &self.num_latched_shared())
.field("overflow_index", &self.overflow_index())
.finish()
}
}
impl fmt::Debug for BucketSharedGuard<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BucketSharedGuard")
.field("readers", &self.bucket.num_latched_shared())
.finish()
}
}
impl fmt::Debug for BucketExclusiveGuard<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BucketExclusiveGuard")
.field("exclusive", &self.bucket.is_latched_exclusive())
.finish()
}
}