Skip to content

Commit c4fd2b3

Browse files
Correct a bug in root_key handling in RocksDb. (#4859)
## Motivation The bug addressed in PR #4858 is also present in `RocksDb`. ## Proposal The same solution is applied. The test code inserted in `linera-storage-service` is added to `root_key_admin_test` so that all storage are now tested on this possible issue. ## Test Plan The CI. ## Release Plan This PR should NOT be merged into TestNet Conway. The reason is that while the bug being addressed is real, correcting it means that we lose access to the RocksDB storage, through the standard API. Backport in TestNet Conway after main. ## Links None.
1 parent ce6ecfd commit c4fd2b3

File tree

3 files changed

+25
-21
lines changed

3 files changed

+25
-21
lines changed

linera-storage-service/tests/store_test.rs

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,10 @@
44
#![cfg(feature = "storage-service")]
55

66
use anyhow::Result;
7-
use linera_storage_service::client::{StorageServiceDatabase, StorageServiceDatabaseInternal};
7+
use linera_storage_service::client::StorageServiceDatabaseInternal;
88
use linera_views::{
99
batch::Batch,
10-
store::{
11-
KeyValueDatabase as _, ReadableKeyValueStore as _, TestKeyValueDatabase as _,
12-
WritableKeyValueStore as _,
13-
},
10+
store::TestKeyValueDatabase as _,
1411
test_utils::{
1512
get_random_byte_vector, get_random_test_scenarios, namespace_admin_test,
1613
root_key_admin_test, run_reads, run_test_batch_from_blank, run_writes_from_blank,
@@ -63,17 +60,3 @@ async fn test_storage_service_big_raw_write() -> Result<()> {
6360
run_test_batch_from_blank(&store, key_prefix, batch).await;
6461
Ok(())
6562
}
66-
67-
#[tokio::test]
68-
async fn test_storage_service_open_shared() -> Result<()> {
69-
let database = StorageServiceDatabase::connect_test_namespace().await?;
70-
let store1 = database.open_shared(&[2, 3, 4, 5])?;
71-
let mut batch = Batch::new();
72-
batch.put_key_value_bytes(vec![6, 7], vec![123, 135]);
73-
store1.write_batch(batch).await?;
74-
75-
let store2 = database.open_shared(&[])?;
76-
let key_values = store2.find_key_values_by_prefix(&[2]).await?;
77-
assert_eq!(key_values.len(), 0);
78-
Ok(())
79-
}

linera-views/src/backends/rocks_db.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ impl KeyValueDatabase for RocksDbDatabaseInternal {
547547

548548
fn open_shared(&self, root_key: &[u8]) -> Result<Self::Store, RocksDbStoreInternalError> {
549549
let mut start_key = ROOT_KEY_DOMAIN.to_vec();
550-
start_key.extend(root_key);
550+
start_key.extend(bcs::to_bytes(root_key)?);
551551
let mut executor = self.executor.clone();
552552
executor.start_key = start_key;
553553
Ok(RocksDbStoreInternal {
@@ -585,7 +585,13 @@ impl KeyValueDatabase for RocksDbDatabaseInternal {
585585
async fn list_root_keys(&self) -> Result<Vec<Vec<u8>>, RocksDbStoreInternalError> {
586586
let mut store = self.open_shared(&[])?;
587587
store.executor.start_key = vec![STORED_ROOT_KEYS_PREFIX];
588-
store.find_keys_by_prefix(&[]).await
588+
let bcs_root_keys = store.find_keys_by_prefix(&[]).await?;
589+
let mut root_keys = Vec::new();
590+
for bcs_root_key in bcs_root_keys {
591+
let root_key = bcs::from_bytes::<Vec<u8>>(&bcs_root_key)?;
592+
root_keys.push(root_key);
593+
}
594+
Ok(root_keys)
589595
}
590596

591597
async fn delete_all(config: &Self::Config) -> Result<(), RocksDbStoreInternalError> {

linera-views/src/test_utils/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,21 @@ where
834834
}
835835
}
836836
assert_eq!(keys, read_keys);
837+
838+
// Checking prefix freeness of the (root_key, key). This is a
839+
// common problem that needs to be tested.
840+
let database = D::connect_test_namespace().await.expect("database");
841+
let store1 = database.open_shared(&[2, 3, 4, 5]).expect("store1");
842+
let mut batch = Batch::new();
843+
batch.put_key_value_bytes(vec![6, 7], vec![123, 135]);
844+
store1.write_batch(batch).await.expect("write_batch");
845+
846+
let store2 = database.open_shared(&[]).expect("store2");
847+
let key_values = store2
848+
.find_key_values_by_prefix(&[2])
849+
.await
850+
.expect("key_values");
851+
assert_eq!(key_values.len(), 0);
837852
}
838853

839854
/// A store can be in exclusive access where it stores the absence of values

0 commit comments

Comments
 (0)