Skip to content

Commit fbfe22c

Browse files
prestwichclaude
andauthored
fix(hot): MemKvRwTx read cursor now sees queued writes (#32)
`HotKvRead for MemKvRwTx` previously returned `MemKvCursor` which only sees committed data. This caused read cursors on write transactions to miss pending writes, creating an inconsistency with `raw_get` which already checked queued ops. Change `Traverse` type to `MemKvCursorMut` which merges committed data with queued writes. Also fix a pre-existing bug in `MemKvCursorMut::last_of_k1` where the k1 comparison used full MAX_KEY_SIZE bytes against the shorter encoded key, causing it to always return None. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9c3b2b8 commit fbfe22c

File tree

2 files changed

+17
-20
lines changed

2 files changed

+17
-20
lines changed

Cargo.toml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ members = ["crates/*"]
33
resolver = "2"
44

55
[workspace.package]
6-
version = "0.6.1"
6+
version = "0.6.2"
77
edition = "2024"
88
rust-version = "1.92"
99
authors = ["init4"]
@@ -35,13 +35,13 @@ incremental = false
3535

3636
[workspace.dependencies]
3737
# internal
38-
signet-hot = { version = "0.6.1", path = "./crates/hot" }
39-
signet-hot-mdbx = { version = "0.6.1", path = "./crates/hot-mdbx" }
40-
signet-cold = { version = "0.6.1", path = "./crates/cold" }
41-
signet-cold-mdbx = { version = "0.6.1", path = "./crates/cold-mdbx" }
42-
signet-cold-sql = { version = "0.6.1", path = "./crates/cold-sql" }
43-
signet-storage = { version = "0.6.1", path = "./crates/storage" }
44-
signet-storage-types = { version = "0.6.1", path = "./crates/types" }
38+
signet-hot = { version = "0.6.2", path = "./crates/hot" }
39+
signet-hot-mdbx = { version = "0.6.2", path = "./crates/hot-mdbx" }
40+
signet-cold = { version = "0.6.2", path = "./crates/cold" }
41+
signet-cold-mdbx = { version = "0.6.2", path = "./crates/cold-mdbx" }
42+
signet-cold-sql = { version = "0.6.2", path = "./crates/cold-sql" }
43+
signet-storage = { version = "0.6.2", path = "./crates/storage" }
44+
signet-storage-types = { version = "0.6.2", path = "./crates/types" }
4545

4646
# External, in-house
4747
signet-libmdbx = { version = "0.8.0" }

crates/hot/src/mem.rs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,7 +1057,9 @@ impl<'a> DualKeyTraverse<MemKvError> for MemKvCursorMut<'a> {
10571057
return Ok(None);
10581058
};
10591059
let (found_k1, found_k2) = MemKv::split_dual_key(&found_key);
1060-
if found_k1.as_ref() != key1 {
1060+
// Compare only the relevant prefix of found_k1 with key1
1061+
// found_k1 is MAX_KEY_SIZE bytes, key1 may be shorter
1062+
if &found_k1.as_ref()[..key1.len()] != key1 {
10611063
self.clear_current_key();
10621064
return Ok(None);
10631065
}
@@ -1265,11 +1267,10 @@ impl MemKvRoTx {
12651267
impl HotKvRead for MemKvRwTx {
12661268
type Error = MemKvError;
12671269

1268-
type Traverse<'a> = MemKvCursor<'a>;
1270+
type Traverse<'a> = MemKvCursorMut<'a>;
12691271

12701272
fn raw_traverse<'a>(&'a self, table: &str) -> Result<Self::Traverse<'a>, Self::Error> {
1271-
let table_data = self.guard.get(table).unwrap_or(&EMPTY_TABLE);
1272-
Ok(MemKvCursor::new(table_data))
1273+
self.cursor_mut(table)
12731274
}
12741275

12751276
fn raw_get<'a>(
@@ -1318,14 +1319,10 @@ impl HotKvRead for MemKvRwTx {
13181319
}
13191320

13201321
impl MemKvRwTx {
1321-
/// Get a read-only cursor for the specified table
1322-
/// Note: This cursor will NOT see pending writes from this transaction
1323-
pub fn cursor<'a>(&'a self, table: &str) -> Result<MemKvCursor<'a>, MemKvError> {
1324-
if let Some(table_data) = self.guard.get(table) {
1325-
Ok(MemKvCursor::new(table_data))
1326-
} else {
1327-
Err(MemKvError::HotKv(HotKvError::Inner(format!("Table '{}' not found", table).into())))
1328-
}
1322+
/// Get a cursor for the specified table that sees both committed data
1323+
/// and pending writes from this transaction.
1324+
pub fn cursor<'a>(&'a self, table: &str) -> Result<MemKvCursorMut<'a>, MemKvError> {
1325+
self.cursor_mut(table)
13291326
}
13301327

13311328
/// Get a mutable cursor for the specified table

0 commit comments

Comments
 (0)