linera_views/
store.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! This provides the trait definitions for the stores.
5
6use std::{fmt::Debug, future::Future};
7
8use serde::de::DeserializeOwned;
9
10#[cfg(with_testing)]
11use crate::random::generate_test_namespace;
12use crate::{batch::Batch, common::from_bytes_option, ViewError};
13
14/// The error type for the key-value stores.
15pub trait KeyValueStoreError:
16    std::error::Error + From<bcs::Error> + Debug + Send + Sync + 'static
17{
18    /// The name of the backend.
19    const BACKEND: &'static str;
20}
21
22impl<E: KeyValueStoreError> From<E> for ViewError {
23    fn from(error: E) -> Self {
24        Self::StoreError {
25            backend: E::BACKEND,
26            error: Box::new(error),
27        }
28    }
29}
30
31/// Define an associated [`KeyValueStoreError`].
32pub trait WithError {
33    /// The error type.
34    type Error: KeyValueStoreError;
35}
36
37/// Low-level, asynchronous read key-value operations. Useful for storage APIs not based on views.
38#[cfg_attr(not(web), trait_variant::make(Send + Sync))]
39pub trait ReadableKeyValueStore: WithError {
40    /// The maximal size of keys that can be stored.
41    const MAX_KEY_SIZE: usize;
42
43    /// Retrieve the number of stream queries.
44    fn max_stream_queries(&self) -> usize;
45
46    /// Retrieves a `Vec<u8>` from the database using the provided `key`.
47    async fn read_value_bytes(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error>;
48
49    /// Tests whether a key exists in the database
50    async fn contains_key(&self, key: &[u8]) -> Result<bool, Self::Error>;
51
52    /// Tests whether a list of keys exist in the database
53    async fn contains_keys(&self, keys: Vec<Vec<u8>>) -> Result<Vec<bool>, Self::Error>;
54
55    /// Retrieves multiple `Vec<u8>` from the database using the provided `keys`.
56    async fn read_multi_values_bytes(
57        &self,
58        keys: Vec<Vec<u8>>,
59    ) -> Result<Vec<Option<Vec<u8>>>, Self::Error>;
60
61    /// Finds the `key` matching the prefix. The prefix is not included in the returned keys.
62    async fn find_keys_by_prefix(&self, key_prefix: &[u8]) -> Result<Vec<Vec<u8>>, Self::Error>;
63
64    /// Finds the `(key,value)` pairs matching the prefix. The prefix is not included in the returned keys.
65    async fn find_key_values_by_prefix(
66        &self,
67        key_prefix: &[u8],
68    ) -> Result<Vec<(Vec<u8>, Vec<u8>)>, Self::Error>;
69
70    // We can't use `async fn` here in the below implementations due to
71    // https://github.com/rust-lang/impl-trait-utils/issues/17, but once that bug is fixed
72    // we can revert them to `async fn` syntax, which is neater.
73
74    /// Reads a single `key` and deserializes the result if present.
75    fn read_value<V: DeserializeOwned>(
76        &self,
77        key: &[u8],
78    ) -> impl Future<Output = Result<Option<V>, Self::Error>> {
79        async { Ok(from_bytes_option(&self.read_value_bytes(key).await?)?) }
80    }
81
82    /// Reads multiple `keys` and deserializes the results if present.
83    fn read_multi_values<V: DeserializeOwned + Send + Sync>(
84        &self,
85        keys: Vec<Vec<u8>>,
86    ) -> impl Future<Output = Result<Vec<Option<V>>, Self::Error>> {
87        async {
88            let mut values = Vec::with_capacity(keys.len());
89            for entry in self.read_multi_values_bytes(keys).await? {
90                values.push(from_bytes_option(&entry)?);
91            }
92            Ok(values)
93        }
94    }
95}
96
97/// Low-level, asynchronous write key-value operations. Useful for storage APIs not based on views.
98#[cfg_attr(not(web), trait_variant::make(Send + Sync))]
99pub trait WritableKeyValueStore: WithError {
100    /// The maximal size of values that can be stored.
101    const MAX_VALUE_SIZE: usize;
102
103    /// Writes the `batch` in the database.
104    async fn write_batch(&self, batch: Batch) -> Result<(), Self::Error>;
105
106    /// Clears any journal entry that may remain.
107    /// The journal is located at the `root_key`.
108    async fn clear_journal(&self) -> Result<(), Self::Error>;
109}
110
111/// Low-level trait for the administration of stores and their namespaces.
112#[cfg_attr(not(web), trait_variant::make(Send + Sync))]
113pub trait AdminKeyValueStore: WithError + Sized {
114    /// The configuration needed to interact with a new store.
115    type Config: Send + Sync;
116    /// The name of this class of stores
117    fn get_name() -> String;
118
119    /// Connects to an existing namespace using the given configuration.
120    async fn connect(config: &Self::Config, namespace: &str) -> Result<Self, Self::Error>;
121
122    /// Opens the key partition starting at `root_key` and returns a clone of the
123    /// connection to work in this partition.
124    ///
125    /// IMPORTANT: It is assumed that the returned connection is the only user of the
126    /// partition (for both read and write) and will remain so until it is ended. Future
127    /// implementations of this method may fail if this is not the case.
128    fn open_exclusive(&self, root_key: &[u8]) -> Result<Self, Self::Error>;
129
130    /// Obtains the list of existing namespaces.
131    async fn list_all(config: &Self::Config) -> Result<Vec<String>, Self::Error>;
132
133    /// Lists the root keys of the namespace.
134    /// It is possible that some root keys have no keys.
135    async fn list_root_keys(
136        config: &Self::Config,
137        namespace: &str,
138    ) -> Result<Vec<Vec<u8>>, Self::Error>;
139
140    /// Deletes all the existing namespaces.
141    fn delete_all(config: &Self::Config) -> impl Future<Output = Result<(), Self::Error>> {
142        async {
143            let namespaces = Self::list_all(config).await?;
144            for namespace in namespaces {
145                Self::delete(config, &namespace).await?;
146            }
147            Ok(())
148        }
149    }
150
151    /// Tests if a given namespace exists.
152    async fn exists(config: &Self::Config, namespace: &str) -> Result<bool, Self::Error>;
153
154    /// Creates a namespace. Returns an error if the namespace exists.
155    async fn create(config: &Self::Config, namespace: &str) -> Result<(), Self::Error>;
156
157    /// Deletes the given namespace.
158    async fn delete(config: &Self::Config, namespace: &str) -> Result<(), Self::Error>;
159
160    /// Initializes a storage if missing and provides it.
161    fn maybe_create_and_connect(
162        config: &Self::Config,
163        namespace: &str,
164    ) -> impl Future<Output = Result<Self, Self::Error>> {
165        async {
166            if !Self::exists(config, namespace).await? {
167                Self::create(config, namespace).await?;
168            }
169            Self::connect(config, namespace).await
170        }
171    }
172
173    /// Creates a new storage. Overwrites it if this namespace already exists.
174    fn recreate_and_connect(
175        config: &Self::Config,
176        namespace: &str,
177    ) -> impl Future<Output = Result<Self, Self::Error>> {
178        async {
179            if Self::exists(config, namespace).await? {
180                Self::delete(config, namespace).await?;
181            }
182            Self::create(config, namespace).await?;
183            Self::connect(config, namespace).await
184        }
185    }
186}
187
188/// Low-level, asynchronous write and read key-value operations. Useful for storage APIs not based on views.
189pub trait RestrictedKeyValueStore: ReadableKeyValueStore + WritableKeyValueStore {}
190
191impl<T> RestrictedKeyValueStore for T where T: ReadableKeyValueStore + WritableKeyValueStore {}
192
193/// Low-level, asynchronous write and read key-value operations. Useful for storage APIs not based on views.
194pub trait KeyValueStore:
195    ReadableKeyValueStore + WritableKeyValueStore + AdminKeyValueStore
196{
197}
198
199impl<T> KeyValueStore for T where
200    T: ReadableKeyValueStore + WritableKeyValueStore + AdminKeyValueStore
201{
202}
203
204/// The functions needed for testing purposes
205#[cfg(with_testing)]
206pub trait TestKeyValueStore: KeyValueStore {
207    /// Obtains a test config
208    async fn new_test_config() -> Result<Self::Config, Self::Error>;
209
210    /// Creates a store for testing purposes
211    async fn new_test_store() -> Result<Self, Self::Error> {
212        let config = Self::new_test_config().await?;
213        let namespace = generate_test_namespace();
214        Self::recreate_and_connect(&config, &namespace).await
215    }
216}