Skip to main content

linera_views/backends/
value_splitting.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Adds support for large values to a given store by splitting them between several keys.
5
6use linera_base::ensure;
7use thiserror::Error;
8
9#[cfg(with_metrics)]
10mod metrics {
11    use std::sync::LazyLock;
12
13    use linera_base::prometheus_util::register_int_counter;
14    use prometheus::IntCounter;
15
16    /// Number of values that were split across multiple keys.
17    pub static VALUE_SPLIT_COUNT: LazyLock<IntCounter> = LazyLock::new(|| {
18        register_int_counter(
19            "value_split_count",
20            "Number of values split across multiple keys due to size limits",
21        )
22    });
23}
24
25use crate::{
26    batch::{Batch, WriteOperation},
27    store::{
28        KeyValueDatabase, KeyValueStoreError, ReadableKeyValueStore, WithError,
29        WritableKeyValueStore,
30    },
31};
32#[cfg(with_testing)]
33use crate::{
34    memory::{MemoryStore, MemoryStoreError},
35    store::TestKeyValueDatabase,
36};
37
38/// A key-value database with no size limit for values.
39///
40/// It wraps a key-value store, potentially _with_ a size limit, and automatically
41/// splits up large values into smaller ones. A single logical key-value pair is
42/// stored as multiple smaller key-value pairs in the wrapped store.
43/// See the `README.md` for additional details.
44#[derive(Clone)]
45pub struct ValueSplittingDatabase<D> {
46    /// The underlying database.
47    database: D,
48}
49
50/// A key-value store with no size limit for values.
51#[derive(Clone)]
52pub struct ValueSplittingStore<S> {
53    /// The underlying store.
54    store: S,
55}
56
57/// The composed error type built from the inner error type.
58#[derive(Error, Debug)]
59pub enum ValueSplittingError<E> {
60    /// inner store error
61    #[error(transparent)]
62    InnerStoreError(#[from] E),
63
64    /// The key is of length less than 4, so we cannot extract the first byte
65    #[error("the key is of length less than 4, so we cannot extract the first byte")]
66    TooShortKey,
67
68    /// Value segment is missing from the database
69    #[error("value segment is missing from the database")]
70    MissingSegment,
71
72    /// No count of size `u32` is available in the value
73    #[error("no count of size u32 is available in the value")]
74    NoCountAvailable,
75}
76
77impl<E: KeyValueStoreError> From<bcs::Error> for ValueSplittingError<E> {
78    fn from(error: bcs::Error) -> Self {
79        let error = E::from(error);
80        ValueSplittingError::InnerStoreError(error)
81    }
82}
83
84impl<E: KeyValueStoreError + 'static> KeyValueStoreError for ValueSplittingError<E> {
85    const BACKEND: &'static str = "value splitting";
86
87    fn must_reload_view(&self) -> bool {
88        match self {
89            ValueSplittingError::InnerStoreError(e) => e.must_reload_view(),
90            _ => false,
91        }
92    }
93}
94
95impl<S> WithError for ValueSplittingDatabase<S>
96where
97    S: WithError,
98    S::Error: 'static,
99{
100    type Error = ValueSplittingError<S::Error>;
101}
102
103impl<D> WithError for ValueSplittingStore<D>
104where
105    D: WithError,
106    D::Error: 'static,
107{
108    type Error = ValueSplittingError<D::Error>;
109}
110
111impl<S> ReadableKeyValueStore for ValueSplittingStore<S>
112where
113    S: ReadableKeyValueStore,
114    S::Error: 'static,
115{
116    const MAX_KEY_SIZE: usize = S::MAX_KEY_SIZE - 4;
117
118    fn max_stream_queries(&self) -> usize {
119        self.store.max_stream_queries()
120    }
121
122    fn root_key(&self) -> Result<Vec<u8>, Self::Error> {
123        Ok(self.store.root_key()?)
124    }
125
126    async fn read_value_bytes(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
127        let mut big_key = key.to_vec();
128        big_key.extend(&[0, 0, 0, 0]);
129        let value = self.store.read_value_bytes(&big_key).await?;
130        let Some(value) = value else {
131            return Ok(None);
132        };
133        let count = Self::read_count_from_value(&value)?;
134        let mut big_value = value[4..].to_vec();
135        if count == 1 {
136            return Ok(Some(big_value));
137        }
138        let mut big_keys = Vec::new();
139        for i in 1..count {
140            let big_key_segment = Self::get_segment_key(key, i)?;
141            big_keys.push(big_key_segment);
142        }
143        let segments = self.store.read_multi_values_bytes(&big_keys).await?;
144        for segment in segments {
145            match segment {
146                None => {
147                    return Err(ValueSplittingError::MissingSegment);
148                }
149                Some(segment) => {
150                    big_value.extend(segment);
151                }
152            }
153        }
154        Ok(Some(big_value))
155    }
156
157    async fn contains_key(&self, key: &[u8]) -> Result<bool, Self::Error> {
158        let mut big_key = key.to_vec();
159        big_key.extend(&[0, 0, 0, 0]);
160        Ok(self.store.contains_key(&big_key).await?)
161    }
162
163    async fn contains_keys(&self, keys: &[Vec<u8>]) -> Result<Vec<bool>, Self::Error> {
164        let big_keys = keys
165            .iter()
166            .map(|key| {
167                let mut big_key = key.clone();
168                big_key.extend(&[0, 0, 0, 0]);
169                big_key
170            })
171            .collect::<Vec<_>>();
172        Ok(self.store.contains_keys(&big_keys).await?)
173    }
174
175    async fn read_multi_values_bytes(
176        &self,
177        keys: &[Vec<u8>],
178    ) -> Result<Vec<Option<Vec<u8>>>, Self::Error> {
179        let mut big_keys = Vec::new();
180        for key in keys {
181            let mut big_key = key.clone();
182            big_key.extend(&[0, 0, 0, 0]);
183            big_keys.push(big_key);
184        }
185        let values = self.store.read_multi_values_bytes(&big_keys).await?;
186        let mut big_values = Vec::<Option<Vec<u8>>>::new();
187        let mut keys_add = Vec::new();
188        let mut n_blocks = Vec::new();
189        for (key, value) in keys.iter().zip(values) {
190            match value {
191                None => {
192                    n_blocks.push(0);
193                    big_values.push(None);
194                }
195                Some(value) => {
196                    let count = Self::read_count_from_value(&value)?;
197                    let big_value = value[4..].to_vec();
198                    for i in 1..count {
199                        let big_key_segment = Self::get_segment_key(key, i)?;
200                        keys_add.push(big_key_segment);
201                    }
202                    n_blocks.push(count);
203                    big_values.push(Some(big_value));
204                }
205            }
206        }
207        if !keys_add.is_empty() {
208            let mut segments = self
209                .store
210                .read_multi_values_bytes(&keys_add)
211                .await?
212                .into_iter();
213            for (big_value, count) in big_values.iter_mut().zip(&n_blocks) {
214                if let Some(value) = big_value {
215                    for _ in 1..*count {
216                        let segment = segments.next().unwrap().unwrap();
217                        value.extend(segment);
218                    }
219                }
220            }
221        }
222        Ok(big_values)
223    }
224
225    async fn find_keys_by_prefix(&self, key_prefix: &[u8]) -> Result<Vec<Vec<u8>>, Self::Error> {
226        let mut keys = Vec::new();
227        for big_key in self.store.find_keys_by_prefix(key_prefix).await? {
228            let len = big_key.len();
229            if Self::read_index_from_key(&big_key)? == 0 {
230                let key = big_key[0..len - 4].to_vec();
231                keys.push(key);
232            }
233        }
234        Ok(keys)
235    }
236
237    async fn find_key_values_by_prefix(
238        &self,
239        key_prefix: &[u8],
240    ) -> Result<Vec<(Vec<u8>, Vec<u8>)>, Self::Error> {
241        let small_key_values = self.store.find_key_values_by_prefix(key_prefix).await?;
242        let mut small_kv_iterator = small_key_values.into_iter();
243        let mut key_values = Vec::new();
244        while let Some((mut big_key, value)) = small_kv_iterator.next() {
245            if Self::read_index_from_key(&big_key)? != 0 {
246                continue; // Leftover segment from an earlier value.
247            }
248            big_key.truncate(big_key.len() - 4);
249            let key = big_key;
250            let count = Self::read_count_from_value(&value)?;
251            let mut big_value = value[4..].to_vec();
252            for idx in 1..count {
253                let (big_key, value) = small_kv_iterator
254                    .next()
255                    .ok_or(ValueSplittingError::MissingSegment)?;
256                ensure!(
257                    Self::read_index_from_key(&big_key)? == idx
258                        && big_key.starts_with(&key)
259                        && big_key.len() == key.len() + 4,
260                    ValueSplittingError::MissingSegment
261                );
262                big_value.extend(value);
263            }
264            key_values.push((key, big_value));
265        }
266        Ok(key_values)
267    }
268}
269
270impl<K> WritableKeyValueStore for ValueSplittingStore<K>
271where
272    K: WritableKeyValueStore,
273    K::Error: 'static,
274{
275    const MAX_VALUE_SIZE: usize = usize::MAX;
276
277    async fn write_batch(&self, batch: Batch) -> Result<(), Self::Error> {
278        let mut batch_new = Batch::new();
279        for operation in batch.operations {
280            match operation {
281                WriteOperation::Delete { key } => {
282                    let mut big_key = key.to_vec();
283                    big_key.extend(&[0, 0, 0, 0]);
284                    batch_new.delete_key(big_key);
285                }
286                WriteOperation::Put { key, mut value } => {
287                    let big_key = Self::get_segment_key(&key, 0)?;
288                    let mut count: u32 = 1;
289                    let value_ext = if value.len() <= K::MAX_VALUE_SIZE - 4 {
290                        Self::get_initial_count_first_chunk(count, &value)?
291                    } else {
292                        tracing::warn!(
293                            value_len = value.len(),
294                            max_value_size = K::MAX_VALUE_SIZE,
295                            "Splitting large value across multiple keys"
296                        );
297                        #[cfg(with_metrics)]
298                        metrics::VALUE_SPLIT_COUNT.inc();
299                        let remainder = value.split_off(K::MAX_VALUE_SIZE - 4);
300                        for value_chunk in remainder.chunks(K::MAX_VALUE_SIZE) {
301                            let big_key_segment = Self::get_segment_key(&key, count)?;
302                            batch_new.put_key_value_bytes(big_key_segment, value_chunk.to_vec());
303                            count += 1;
304                        }
305                        Self::get_initial_count_first_chunk(count, &value)?
306                    };
307                    batch_new.put_key_value_bytes(big_key, value_ext);
308                }
309                WriteOperation::DeletePrefix { key_prefix } => {
310                    batch_new.delete_key_prefix(key_prefix);
311                }
312            }
313        }
314        Ok(self.store.write_batch(batch_new).await?)
315    }
316
317    async fn clear_journal(&self) -> Result<(), Self::Error> {
318        Ok(self.store.clear_journal().await?)
319    }
320}
321
322impl<D> KeyValueDatabase for ValueSplittingDatabase<D>
323where
324    D: KeyValueDatabase,
325    D::Error: 'static,
326{
327    type Config = D::Config;
328
329    type Store = ValueSplittingStore<D::Store>;
330
331    fn get_name() -> String {
332        format!("value splitting {}", D::get_name())
333    }
334
335    async fn connect(config: &Self::Config, namespace: &str) -> Result<Self, Self::Error> {
336        let database = D::connect(config, namespace).await?;
337        Ok(Self { database })
338    }
339
340    fn open_shared(&self, root_key: &[u8]) -> Result<Self::Store, Self::Error> {
341        let store = self.database.open_shared(root_key)?;
342        Ok(ValueSplittingStore { store })
343    }
344
345    fn open_exclusive(&self, root_key: &[u8]) -> Result<Self::Store, Self::Error> {
346        let store = self.database.open_exclusive(root_key)?;
347        Ok(ValueSplittingStore { store })
348    }
349
350    async fn list_all(config: &Self::Config) -> Result<Vec<String>, Self::Error> {
351        Ok(D::list_all(config).await?)
352    }
353
354    async fn list_root_keys(&self) -> Result<Vec<Vec<u8>>, Self::Error> {
355        Ok(self.database.list_root_keys().await?)
356    }
357
358    async fn delete_all(config: &Self::Config) -> Result<(), Self::Error> {
359        Ok(D::delete_all(config).await?)
360    }
361
362    async fn exists(config: &Self::Config, namespace: &str) -> Result<bool, Self::Error> {
363        Ok(D::exists(config, namespace).await?)
364    }
365
366    async fn create(config: &Self::Config, namespace: &str) -> Result<(), Self::Error> {
367        Ok(D::create(config, namespace).await?)
368    }
369
370    async fn delete(config: &Self::Config, namespace: &str) -> Result<(), Self::Error> {
371        Ok(D::delete(config, namespace).await?)
372    }
373}
374
375#[cfg(with_testing)]
376impl<D> TestKeyValueDatabase for ValueSplittingDatabase<D>
377where
378    D: TestKeyValueDatabase,
379    D::Error: 'static,
380{
381    async fn new_test_config() -> Result<D::Config, Self::Error> {
382        Ok(D::new_test_config().await?)
383    }
384}
385
386impl<D> ValueSplittingStore<D>
387where
388    D: WithError,
389{
390    /// Creates a new store that deals with big values from one that does not.
391    pub fn new(store: D) -> Self {
392        ValueSplittingStore { store }
393    }
394
395    fn get_segment_key(key: &[u8], index: u32) -> Result<Vec<u8>, ValueSplittingError<D::Error>> {
396        let mut big_key_segment = key.to_vec();
397        let mut bytes = bcs::to_bytes(&index)?;
398        bytes.reverse();
399        big_key_segment.extend(bytes);
400        Ok(big_key_segment)
401    }
402
403    fn get_initial_count_first_chunk(
404        count: u32,
405        first_chunk: &[u8],
406    ) -> Result<Vec<u8>, ValueSplittingError<D::Error>> {
407        let mut bytes = bcs::to_bytes(&count)?;
408        bytes.reverse();
409        let mut value_ext = Vec::new();
410        value_ext.extend(bytes);
411        value_ext.extend(first_chunk);
412        Ok(value_ext)
413    }
414
415    fn read_count_from_value(value: &[u8]) -> Result<u32, ValueSplittingError<D::Error>> {
416        if value.len() < 4 {
417            return Err(ValueSplittingError::NoCountAvailable);
418        }
419        let mut bytes = value[0..4].to_vec();
420        bytes.reverse();
421        Ok(bcs::from_bytes::<u32>(&bytes)?)
422    }
423
424    fn read_index_from_key(key: &[u8]) -> Result<u32, ValueSplittingError<D::Error>> {
425        let len = key.len();
426        if len < 4 {
427            return Err(ValueSplittingError::TooShortKey);
428        }
429        let mut bytes = key[len - 4..len].to_vec();
430        bytes.reverse();
431        Ok(bcs::from_bytes::<u32>(&bytes)?)
432    }
433}
434
435/// A memory store for which the values are limited to 100 bytes and can be used for tests.
436#[derive(Clone)]
437#[cfg(with_testing)]
438pub struct LimitedTestMemoryStore {
439    inner: MemoryStore,
440}
441
442#[cfg(with_testing)]
443impl Default for LimitedTestMemoryStore {
444    fn default() -> Self {
445        Self::new()
446    }
447}
448
449#[cfg(with_testing)]
450impl WithError for LimitedTestMemoryStore {
451    type Error = MemoryStoreError;
452}
453
454#[cfg(with_testing)]
455impl ReadableKeyValueStore for LimitedTestMemoryStore {
456    const MAX_KEY_SIZE: usize = usize::MAX;
457
458    fn max_stream_queries(&self) -> usize {
459        self.inner.max_stream_queries()
460    }
461
462    fn root_key(&self) -> Result<Vec<u8>, MemoryStoreError> {
463        self.inner.root_key()
464    }
465
466    async fn read_value_bytes(&self, key: &[u8]) -> Result<Option<Vec<u8>>, MemoryStoreError> {
467        self.inner.read_value_bytes(key).await
468    }
469
470    async fn contains_key(&self, key: &[u8]) -> Result<bool, MemoryStoreError> {
471        self.inner.contains_key(key).await
472    }
473
474    async fn contains_keys(&self, keys: &[Vec<u8>]) -> Result<Vec<bool>, MemoryStoreError> {
475        self.inner.contains_keys(keys).await
476    }
477
478    async fn read_multi_values_bytes(
479        &self,
480        keys: &[Vec<u8>],
481    ) -> Result<Vec<Option<Vec<u8>>>, MemoryStoreError> {
482        self.inner.read_multi_values_bytes(keys).await
483    }
484
485    async fn find_keys_by_prefix(
486        &self,
487        key_prefix: &[u8],
488    ) -> Result<Vec<Vec<u8>>, MemoryStoreError> {
489        self.inner.find_keys_by_prefix(key_prefix).await
490    }
491
492    async fn find_key_values_by_prefix(
493        &self,
494        key_prefix: &[u8],
495    ) -> Result<Vec<(Vec<u8>, Vec<u8>)>, MemoryStoreError> {
496        self.inner.find_key_values_by_prefix(key_prefix).await
497    }
498}
499
500#[cfg(with_testing)]
501impl WritableKeyValueStore for LimitedTestMemoryStore {
502    // We set up the MAX_VALUE_SIZE to the artificially low value of 100
503    // purely for testing purposes.
504    const MAX_VALUE_SIZE: usize = 100;
505
506    async fn write_batch(&self, batch: Batch) -> Result<(), MemoryStoreError> {
507        assert!(
508            batch.check_value_size(Self::MAX_VALUE_SIZE),
509            "The batch size is not adequate for this test"
510        );
511        self.inner.write_batch(batch).await
512    }
513
514    async fn clear_journal(&self) -> Result<(), MemoryStoreError> {
515        self.inner.clear_journal().await
516    }
517}
518
519#[cfg(with_testing)]
520impl LimitedTestMemoryStore {
521    /// Creates a `LimitedTestMemoryStore`
522    pub fn new() -> Self {
523        let inner = MemoryStore::new_for_testing();
524        LimitedTestMemoryStore { inner }
525    }
526}
527
528/// Provides a `LimitedTestMemoryStore<()>` that can be used for tests.
529#[cfg(with_testing)]
530pub fn create_value_splitting_memory_store() -> ValueSplittingStore<LimitedTestMemoryStore> {
531    ValueSplittingStore::new(LimitedTestMemoryStore::new())
532}
533
534#[cfg(test)]
535mod tests {
536    use linera_views::{
537        batch::Batch,
538        store::{ReadableKeyValueStore, WritableKeyValueStore},
539        value_splitting::{LimitedTestMemoryStore, ValueSplittingStore},
540    };
541    use rand::Rng;
542
543    // The key splitting means that when a key is overwritten
544    // some previous segments may still be present.
545    #[tokio::test]
546    async fn test_value_splitting1_testing_leftovers() {
547        let store = LimitedTestMemoryStore::new();
548        const MAX_LEN: usize = LimitedTestMemoryStore::MAX_VALUE_SIZE;
549        const _: () = assert!(MAX_LEN > 10);
550        let big_store = ValueSplittingStore::new(store.clone());
551        let key = vec![0, 0];
552        // Write a key with a long value
553        let mut batch = Batch::new();
554        let value = Vec::from([0; MAX_LEN + 1]);
555        batch.put_key_value_bytes(key.clone(), value.clone());
556        big_store.write_batch(batch).await.unwrap();
557        let value_read = big_store.read_value_bytes(&key).await.unwrap();
558        assert_eq!(value_read, Some(value));
559        // Write a key with a smaller value
560        let mut batch = Batch::new();
561        let value = Vec::from([0, 1]);
562        batch.put_key_value_bytes(key.clone(), value.clone());
563        big_store.write_batch(batch).await.unwrap();
564        let value_read = big_store.read_value_bytes(&key).await.unwrap();
565        assert_eq!(value_read, Some(value));
566        // Two segments are present even though only one is used
567        let keys = store.find_keys_by_prefix(&[0]).await.unwrap();
568        assert_eq!(keys, vec![vec![0, 0, 0, 0, 0], vec![0, 0, 0, 0, 1]]);
569    }
570
571    #[tokio::test]
572    async fn test_value_splitting2_testing_splitting() {
573        let store = LimitedTestMemoryStore::new();
574        const MAX_LEN: usize = LimitedTestMemoryStore::MAX_VALUE_SIZE;
575        let big_store = ValueSplittingStore::new(store.clone());
576        let key = vec![0, 0];
577        // Writing a big value
578        let mut batch = Batch::new();
579        let mut value = Vec::new();
580        let mut rng = crate::random::make_deterministic_rng();
581        for _ in 0..2 * MAX_LEN - 4 {
582            value.push(rng.gen::<u8>());
583        }
584        batch.put_key_value_bytes(key.clone(), value.clone());
585        big_store.write_batch(batch).await.unwrap();
586        let value_read = big_store.read_value_bytes(&key).await.unwrap();
587        assert_eq!(value_read, Some(value.clone()));
588        // Reading the segments and checking
589        let mut value_concat = Vec::<u8>::new();
590        for index in 0..2 {
591            let mut segment_key = key.clone();
592            let mut bytes = bcs::to_bytes(&index).unwrap();
593            bytes.reverse();
594            segment_key.extend(bytes);
595            let value_read = store.read_value_bytes(&segment_key).await.unwrap();
596            let Some(value_read) = value_read else {
597                unreachable!()
598            };
599            if index == 0 {
600                value_concat.extend(&value_read[4..]);
601            } else {
602                value_concat.extend(&value_read);
603            }
604        }
605        assert_eq!(value, value_concat);
606    }
607
608    #[tokio::test]
609    async fn test_value_splitting3_write_and_delete() {
610        let store = LimitedTestMemoryStore::new();
611        const MAX_LEN: usize = LimitedTestMemoryStore::MAX_VALUE_SIZE;
612        let big_store = ValueSplittingStore::new(store.clone());
613        let key = vec![0, 0];
614        // writing a big key
615        let mut batch = Batch::new();
616        let mut value = Vec::new();
617        let mut rng = crate::random::make_deterministic_rng();
618        for _ in 0..3 * MAX_LEN - 4 {
619            value.push(rng.gen::<u8>());
620        }
621        batch.put_key_value_bytes(key.clone(), value.clone());
622        big_store.write_batch(batch).await.unwrap();
623        // deleting it
624        let mut batch = Batch::new();
625        batch.delete_key(key.clone());
626        big_store.write_batch(batch).await.unwrap();
627        // reading everything (there are leftover keys)
628        let key_values = big_store.find_key_values_by_prefix(&[0]).await.unwrap();
629        assert_eq!(key_values.len(), 0);
630        // Two segments remain
631        let keys = store.find_keys_by_prefix(&[0]).await.unwrap();
632        assert_eq!(keys, vec![vec![0, 0, 0, 0, 1], vec![0, 0, 0, 0, 2]]);
633    }
634}