Skip to content

Commit 4580a10

Browse files
committed
increase ID generations to 32-bits
1 parent 66bbb88 commit 4580a10

File tree

4 files changed

+32
-71
lines changed

4 files changed

+32
-71
lines changed

src/id.rs

Lines changed: 10 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,8 @@ use crate::zalsa::Zalsa;
66

77
/// The `Id` of a salsa struct in the database [`Table`](`crate::table::Table`).
88
///
9-
/// The high-order bits of an `Id` store a 16-bit generation counter
10-
/// as well as an optional 16-bit ingredient index.
11-
///
12-
/// The low-order bits pack a [`PageIndex`](`crate::table::PageIndex`) and
9+
/// The high-order bits of an `Id` store a 32-bit generation counter, while
10+
/// the low-order bits pack a [`PageIndex`](`crate::table::PageIndex`) and
1311
/// [`SlotIndex`](`crate::table::SlotIndex`) within the page.
1412
///
1513
/// The low-order bits of `Id` are a `u32` ranging from `0..Id::MAX_U32`.
@@ -28,9 +26,6 @@ impl Id {
2826
pub const MAX_U32: u32 = u32::MAX - 0xFF;
2927
pub const MAX_USIZE: usize = Self::MAX_U32 as usize;
3028

31-
const INGREDIENT_MASK: u64 = 0x0000FFFFFFFFFFFF;
32-
const GENERATION_MASK: u64 = 0xFFFF0000FFFFFFFF;
33-
3429
/// Create a `salsa::Id` from a u32 value, without a generation. This
3530
/// value should be less than [`Self::MAX_U32`].
3631
///
@@ -77,10 +72,10 @@ impl Id {
7772
/// but will differ from other identifiers of the slot based on the
7873
/// provided generation.
7974
#[inline]
80-
pub fn with_generation(self, generation: u16) -> Id {
75+
pub fn with_generation(self, generation: u32) -> Id {
8176
let mut value = self.value.get();
8277

83-
value &= Id::GENERATION_MASK;
78+
value &= 0xFFFFFFFF;
8479
value |= (generation as u64) << 32;
8580

8681
Id {
@@ -89,26 +84,6 @@ impl Id {
8984
}
9085
}
9186

92-
/// Mark the `Id` with an ingredient index.
93-
#[inline]
94-
pub fn with_ingredient_index(self, ingredient: u16) -> Id {
95-
let mut value = self.value.get();
96-
97-
value &= Id::INGREDIENT_MASK;
98-
value |= (ingredient as u64) << 48;
99-
100-
Id {
101-
// SAFETY: The niche of `value` is in the lower bits, which we did not touch.
102-
value: unsafe { NonZeroU64::new_unchecked(value) },
103-
}
104-
}
105-
106-
/// Return the internal `u64` representation of this `Id`.
107-
#[inline]
108-
pub const fn as_bits(self) -> u64 {
109-
self.value.get()
110-
}
111-
11287
/// Return the data portion of this `Id`.
11388
#[inline]
11489
pub const fn data(self) -> u32 {
@@ -118,14 +93,15 @@ impl Id {
11893

11994
/// Return the generation of this `Id`.
12095
#[inline]
121-
pub const fn generation(self) -> u16 {
122-
((self.value.get() & !Id::GENERATION_MASK) >> 32) as u16
96+
pub const fn generation(self) -> u32 {
97+
// Shift away the low-order bits.
98+
(self.value.get() >> 32) as u32
12399
}
124100

125-
/// Return the ingredient index of this `Id`.
101+
/// Return the internal `u64` representation of this `Id`.
126102
#[inline]
127-
pub const fn ingredient_index(self) -> u16 {
128-
(self.value.get() >> 48) as u16
103+
pub const fn as_bits(self) -> u64 {
104+
self.value.get()
129105
}
130106
}
131107

src/key.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,29 @@ use crate::{Database, Id};
1212
/// only for inserting into maps and the like.
1313
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
1414
pub struct DatabaseKeyIndex {
15-
packed_key_index: Id,
15+
key_index: u32,
16+
key_generation: u32,
17+
ingredient_index: IngredientIndex,
1618
}
1719
// ANCHOR_END: DatabaseKeyIndex
1820

1921
impl DatabaseKeyIndex {
2022
#[inline]
2123
pub(crate) fn new(ingredient_index: IngredientIndex, key_index: Id) -> Self {
2224
Self {
23-
// Pack the ingredient index with the key.
24-
packed_key_index: key_index.with_ingredient_index(ingredient_index.as_u16()),
25+
key_index: key_index.data(),
26+
key_generation: key_index.generation(),
27+
ingredient_index,
2528
}
2629
}
2730

2831
pub fn ingredient_index(self) -> IngredientIndex {
29-
IngredientIndex::from(self.packed_key_index.ingredient_index() as usize)
32+
self.ingredient_index
3033
}
3134

3235
pub fn key_index(self) -> Id {
33-
// Clear the ingredient index from the key as it not part of the dependency.
34-
self.packed_key_index.with_ingredient_index(0)
36+
// SAFETY: `self.key_index` was returned by `Id::data`.
37+
unsafe { Id::from_data(self.key_index) }.with_generation(self.key_generation)
3538
}
3639

3740
pub(crate) fn maybe_changed_after(

src/tracked_struct.rs

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -434,14 +434,17 @@ where
434434
memos: Default::default(),
435435
};
436436

437-
if let Some(id) = self.free_list.pop() {
437+
while let Some(id) = self.free_list.pop() {
438438
// Increment the ID generation before reusing it, as if we have allocated a new
439439
// slot in the table.
440440
//
441-
// If the generation will wrap, we instead saturate to the generation `u16::MAX`.
442-
// "Leaked" IDs may be reused with the same generation.
443-
let id = id.with_generation(id.generation().saturating_add(1));
441+
// If the generation will wrap, we are forced to leak the slot. We reserve enough
442+
// bits for the generation that this should not be a problem in practice.
443+
let Some(generation) = id.generation().checked_add(1) else {
444+
continue;
445+
};
444446

447+
let id = id.with_generation(generation);
445448
return Self::data_raw(zalsa.table(), id).with_mut(|data_raw| {
446449
let data_raw = data_raw.cast::<Value<C>>();
447450

@@ -727,7 +730,7 @@ where
727730
db: &'db dyn crate::Database,
728731
s: C::Struct<'db>,
729732
) -> &'db C::Fields<'db> {
730-
let (zalsa, zalsa_local) = db.zalsas();
733+
let zalsa = db.zalsa();
731734
let id = AsId::as_id(&s);
732735
let data = Self::data(zalsa.table(), id);
733736

@@ -736,17 +739,6 @@ where
736739
// Note that we do not need to add a dependency on the tracked struct
737740
// in general, as IDs that are reused increment their generation,
738741
// invalidating any dependent queries directly.
739-
//
740-
// However, IDs that have hit the maximum generation are "leaked", and may
741-
// be reused without a new generation, and so a dependency must be created
742-
// on any query that reads from them.
743-
if id.generation() == u16::MAX {
744-
zalsa_local.report_tracked_read_simple(
745-
DatabaseKeyIndex::new(self.ingredient_index, id),
746-
data.durability,
747-
data.created_at,
748-
);
749-
}
750742

751743
data.fields()
752744
}

src/zalsa.rs

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -76,32 +76,22 @@ crate::loom::maybe_lazy_static! {
7676
/// The database contains a number of jars, and each jar contains a number of ingredients.
7777
/// Each ingredient is given a unique index as the database is being created.
7878
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
79-
pub struct IngredientIndex(u16);
79+
pub struct IngredientIndex(u32);
8080

8181
impl IngredientIndex {
8282
/// Create an ingredient index from a usize.
8383
pub(crate) fn from(v: usize) -> Self {
84-
assert!(v <= u16::MAX as usize);
85-
Self(v as u16)
84+
assert!(v <= u32::MAX as usize);
85+
Self(v as u32)
8686
}
8787

8888
/// Convert the ingredient index back into a usize.
8989
pub(crate) fn as_usize(self) -> usize {
9090
self.0 as usize
9191
}
9292

93-
/// Convert the ingredient index back into a usize.
94-
pub(crate) fn as_u16(self) -> u16 {
95-
self.0
96-
}
97-
9893
pub fn successor(self, index: usize) -> Self {
99-
let index = self
100-
.0
101-
.checked_add((1 + index) as u16)
102-
.expect("exceeded maximum number of ingredients");
103-
104-
IngredientIndex(index)
94+
IngredientIndex(self.0 + 1 + index as u32)
10595
}
10696
}
10797

@@ -508,7 +498,7 @@ where
508498
let nonce = Nonce::<StorageNonce>::from_u32(unsafe {
509499
NonZeroU32::new_unchecked((cached_data >> u32::BITS) as u32)
510500
});
511-
let mut index = IngredientIndex(cached_data as u16);
501+
let mut index = IngredientIndex(cached_data as u32);
512502

513503
if zalsa.nonce() != nonce {
514504
index = create_index();

0 commit comments

Comments
 (0)