Skip to content

Commit

Permalink
Implement list_root_keys to the AdminKeyValueStore (#3142)
Browse files Browse the repository at this point in the history
## Motivation

We need to have the feature of accessing to the list of root keys in
order to have mutation function and accessing to the list of chain ids
of a storage.

Fixes #3085 

## Proposal

The implementation causes some problems:
* For ScyllaDb the implementation is very easy since the root_key is
used as a partition key.
* For DynamoDb we can implement the root_key as a partition key, but
DynamoDb forbids iterating and determining all the partition keys. So,
we need to keep track of the keys.
* For RocksDb / StorageService / IndexedDb we need to keep track of the
list of root_keys.
* For RocksDb, this led to a simplification since the edge case of
having a key of the form `[255, ..., 255]` disappears. This corrects a
problem and a test is added to detect it.
* The result of the `list_root_keys` will not be the same on different
storage. If storage has been created with `fn create`, some keys were
written but later deleted then in DynamoDb, RocksDb, storage-service,
IndexedDb the root key will show up as existing while in ScyllaDb, the
root key will not be visible.

The writing of the root key occurs when a `write_batch` is done.

## Test Plan

One test has been added for this feature.

## Release Plan

No impact on the TestNet / DevNet. It can follow the normal release
plan.

## Links

None.
  • Loading branch information
MathieuDutSik authored Feb 6, 2025
1 parent 9e23c72 commit 8ef379f
Show file tree
Hide file tree
Showing 24 changed files with 656 additions and 276 deletions.
14 changes: 14 additions & 0 deletions CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ This document contains the help content for the `linera` command-line program.
* [`linera storage initialize`](#linera-storage-initialize)
* [`linera storage list_namespaces`](#linera-storage-list_namespaces)
* [`linera storage list_blob_ids`](#linera-storage-list_blob_ids)
* [`linera storage list_root_keys`](#linera-storage-list_root_keys)

## `linera`

Expand Down Expand Up @@ -964,6 +965,7 @@ Operation on the storage
* `initialize` — Initialize a namespace in the database
* `list_namespaces` — List the namespaces of the database
* `list_blob_ids` — List the blobs of the database
* `list_root_keys` — List the root keys of the database



Expand Down Expand Up @@ -1051,6 +1053,18 @@ List the blobs of the database



## `linera storage list_root_keys`

List the root keys of the database

**Usage:** `linera storage list_root_keys --storage <STORAGE_CONFIG>`

###### **Options:**

* `--storage <STORAGE_CONFIG>` — Storage configuration for the blockchain history



<hr/>

<small><i>
Expand Down
36 changes: 18 additions & 18 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ async-lock = "3.3.0"
async-trait = "0.1.77"
async-tungstenite = { version = "0.22", features = ["tokio-runtime"] }
aws-config = "1.1.7"
aws-sdk-dynamodb = "1.16.0"
aws-sdk-dynamodb = "1.60.0"
aws-sdk-s3 = "1.17.0"
aws-smithy-http = "0.60.6"
aws-types = "1.1.7"
Expand Down
9 changes: 9 additions & 0 deletions linera-client/src/client_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,14 @@ pub enum DatabaseToolCommand {
#[arg(long = "storage")]
storage_config: String,
},

/// List the root keys of the database
#[command(name = "list_root_keys")]
ListRootKeys {
/// Storage configuration for the blockchain history.
#[arg(long = "storage")]
storage_config: String,
},
}

impl DatabaseToolCommand {
Expand All @@ -1010,6 +1018,7 @@ impl DatabaseToolCommand {
DatabaseToolCommand::Initialize { storage_config } => storage_config,
DatabaseToolCommand::ListNamespaces { storage_config } => storage_config,
DatabaseToolCommand::ListBlobIds { storage_config } => storage_config,
DatabaseToolCommand::ListRootKeys { storage_config } => storage_config,
};
Ok(storage_config.parse::<StorageConfigNamespace>()?)
}
Expand Down
26 changes: 26 additions & 0 deletions linera-client/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,32 @@ impl StoreConfig {
}
}
}

/// Lists all root keys of the storage
pub async fn list_root_keys(self) -> Result<Vec<Vec<u8>>, ViewError> {
match self {
StoreConfig::Memory(_, _) => Err(ViewError::StoreError {
backend: "memory".to_string(),
error: "list_root_keys is not supported for the memory storage".to_string(),
}),
#[cfg(feature = "storage-service")]
StoreConfig::Service(config, namespace) => {
Ok(ServiceStoreClient::list_root_keys(&config, &namespace).await?)
}
#[cfg(feature = "rocksdb")]
StoreConfig::RocksDb(config, namespace) => {
Ok(RocksDbStore::list_root_keys(&config, &namespace).await?)
}
#[cfg(feature = "dynamodb")]
StoreConfig::DynamoDb(config, namespace) => {
Ok(DynamoDbStore::list_root_keys(&config, &namespace).await?)
}
#[cfg(feature = "scylladb")]
StoreConfig::ScyllaDb(config, namespace) => {
Ok(ScyllaDbStore::list_root_keys(&config, &namespace).await?)
}
}
}
}

#[async_trait]
Expand Down
8 changes: 8 additions & 0 deletions linera-service/src/linera/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1784,6 +1784,14 @@ async fn run(options: &ClientOptions) -> Result<i32, anyhow::Error> {
info!("Blob IDs listed in {} ms", start_time.elapsed().as_millis());
println!("The list of blob IDs is {:?}", blob_ids);
}
DatabaseToolCommand::ListRootKeys { .. } => {
let root_keys = Box::pin(full_storage_config.list_root_keys()).await?;
info!(
"Root keys listed in {} ms",
start_time.elapsed().as_millis()
);
println!("The list of root keys is {:?}", root_keys);
}
}
Ok(0)
}
Expand Down
32 changes: 13 additions & 19 deletions linera-storage-service/proto/key_value_store.proto
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
syntax = "proto3";
package key_value_store.v1;

import "google/protobuf/empty.proto";

message KeyValue {
bytes key = 1;
bytes value = 2;
Expand Down Expand Up @@ -92,9 +94,6 @@ message RequestWriteBatchExtended {
repeated Statement statements = 1;
}

message ReplyWriteBatchExtended {
}


message RequestSpecificChunk {
int64 message_index = 1;
Expand All @@ -110,9 +109,6 @@ message RequestCreateNamespace {
bytes namespace = 1;
}

message ReplyCreateNamespace {
}


message RequestExistsNamespace {
bytes namespace = 1;
Expand All @@ -127,36 +123,34 @@ message RequestDeleteNamespace {
bytes namespace = 1;
}

message ReplyDeleteNamespace {
}


message RequestListAll {
}

message ReplyListAll {
repeated bytes namespaces = 1;
}


message RequestDeleteAll {
message RequestListRootKeys {
bytes namespace = 1;
}

message ReplyDeleteAll {
message ReplyListRootKeys {
repeated bytes root_keys = 1;
}


service StoreProcessor {
rpc ProcessReadValue (RequestReadValue) returns (ReplyReadValue) {}
rpc ProcessContainsKey (RequestContainsKey) returns (ReplyContainsKey) {}
rpc ProcessContainsKeys (RequestContainsKeys) returns (ReplyContainsKeys) {}
rpc ProcessReadMultiValues (RequestReadMultiValues) returns (ReplyReadMultiValues) {}
rpc ProcessFindKeysByPrefix (RequestFindKeysByPrefix) returns (ReplyFindKeysByPrefix) {}
rpc ProcessFindKeyValuesByPrefix (RequestFindKeyValuesByPrefix) returns (ReplyFindKeyValuesByPrefix) {}
rpc ProcessWriteBatchExtended (RequestWriteBatchExtended) returns (ReplyWriteBatchExtended) {}
rpc ProcessWriteBatchExtended (RequestWriteBatchExtended) returns (google.protobuf.Empty) {}
rpc ProcessSpecificChunk (RequestSpecificChunk) returns (ReplySpecificChunk) {}
rpc ProcessCreateNamespace (RequestCreateNamespace) returns (ReplyCreateNamespace) {}
rpc ProcessCreateNamespace (RequestCreateNamespace) returns (google.protobuf.Empty) {}
rpc ProcessExistsNamespace (RequestExistsNamespace) returns (ReplyExistsNamespace) {}
rpc ProcessDeleteNamespace (RequestDeleteNamespace) returns (ReplyDeleteNamespace) {}
rpc ProcessListAll (RequestListAll) returns (ReplyListAll) {}
rpc ProcessDeleteAll (RequestDeleteAll) returns (ReplyDeleteAll) {}
rpc ProcessDeleteNamespace (RequestDeleteNamespace) returns (google.protobuf.Empty) {}
rpc ProcessListAll (google.protobuf.Empty) returns (ReplyListAll) {}
rpc ProcessListRootKeys (RequestListRootKeys) returns (ReplyListRootKeys) {}
rpc ProcessDeleteAll (google.protobuf.Empty) returns (google.protobuf.Empty) {}
}
Loading

0 comments on commit 8ef379f

Please sign in to comment.