linera_views/test_utils/
performance.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use linera_base::time::{Duration, Instant};
5
6use crate::{
7    batch::Batch,
8    store::{
9        KeyValueStore, ReadableKeyValueStore as _, TestKeyValueDatabase, WritableKeyValueStore as _,
10    },
11    test_utils::{add_prefix, get_random_key_values_with_small_keys},
12};
13
14// We generate about 200 keys of length 10 with a value of length 10000
15// The keys are of the form 0,x_1, ..., x_n with 0 <= x_i < 4 and n=10.
16
17/// A value to use for the keys
18const PREFIX: &[u8] = &[0];
19
20/// A value to use for the keys
21const PREFIX_SEARCH: &[u8] = &[0, 0];
22
23/// The number of keys
24const NUM_ENTRIES: usize = 200;
25
26/// The number of inserted keys
27const NUM_INSERT: usize = 70;
28
29/// The length of the keys
30const LEN_KEY: usize = 10;
31
32/// The length of the values
33const LEN_VALUE: usize = 10000;
34
35async fn clear_store<S: KeyValueStore>(store: &S) {
36    let mut batch = Batch::new();
37    batch.delete_key_prefix(PREFIX.to_vec());
38    store.write_batch(batch).await.unwrap();
39}
40
41/// Benchmarks the `contains_key` operation.
42pub async fn contains_key<D, F>(iterations: u64, f: F) -> Duration
43where
44    D: TestKeyValueDatabase,
45    D::Store: KeyValueStore,
46    F: Fn(bool) -> bool,
47{
48    let namespace = D::connect_test_namespace().await.unwrap();
49    let store = namespace.open_shared(&[]).unwrap();
50    let mut total_time = Duration::ZERO;
51    for _ in 0..iterations {
52        let key_values = add_prefix(
53            PREFIX,
54            get_random_key_values_with_small_keys(NUM_ENTRIES, LEN_KEY, LEN_VALUE),
55        );
56        let mut batch = Batch::new();
57        for key_value in &key_values[..NUM_INSERT] {
58            batch.put_key_value_bytes(key_value.0.clone(), key_value.1.clone());
59        }
60        store.write_batch(batch).await.unwrap();
61
62        let measurement = Instant::now();
63        for key_value in &key_values {
64            f(store.contains_key(&key_value.0).await.unwrap());
65        }
66        total_time += measurement.elapsed();
67
68        clear_store(&store).await;
69    }
70
71    total_time
72}
73
74/// Benchmarks the `contains_keys` operation.
75pub async fn contains_keys<D, F>(iterations: u64, f: F) -> Duration
76where
77    D: TestKeyValueDatabase,
78    D::Store: KeyValueStore,
79    F: Fn(Vec<bool>) -> Vec<bool>,
80{
81    let namespace = D::connect_test_namespace().await.unwrap();
82    let store = namespace.open_shared(&[]).unwrap();
83    let mut total_time = Duration::ZERO;
84    for _ in 0..iterations {
85        let key_values = add_prefix(
86            PREFIX,
87            get_random_key_values_with_small_keys(NUM_ENTRIES, LEN_KEY, LEN_VALUE),
88        );
89        let mut batch = Batch::new();
90        for key_value in &key_values[..NUM_INSERT] {
91            batch.put_key_value_bytes(key_value.0.clone(), key_value.1.clone());
92        }
93        store.write_batch(batch).await.unwrap();
94        let keys = key_values
95            .into_iter()
96            .map(|(key, _)| key)
97            .collect::<Vec<_>>();
98
99        let measurement = Instant::now();
100        f(store.contains_keys(keys).await.unwrap());
101        total_time += measurement.elapsed();
102
103        clear_store(&store).await;
104    }
105
106    total_time
107}
108
109/// Benchmarks the `find_keys_by_prefix` operation.
110pub async fn find_keys_by_prefix<D, F>(iterations: u64, f: F) -> Duration
111where
112    D: TestKeyValueDatabase,
113    D::Store: KeyValueStore,
114    F: Fn(Vec<Vec<u8>>) -> Vec<Vec<u8>>,
115{
116    let namespace = D::connect_test_namespace().await.unwrap();
117    let store = namespace.open_shared(&[]).unwrap();
118    let mut total_time = Duration::ZERO;
119    for _ in 0..iterations {
120        let key_values = add_prefix(
121            PREFIX,
122            get_random_key_values_with_small_keys(NUM_ENTRIES, LEN_KEY, LEN_VALUE),
123        );
124        let mut batch = Batch::new();
125        for key_value in &key_values {
126            batch.put_key_value_bytes(key_value.0.clone(), key_value.1.clone());
127        }
128        store.write_batch(batch).await.unwrap();
129
130        let measurement = Instant::now();
131        f(store.find_keys_by_prefix(PREFIX_SEARCH).await.unwrap());
132        total_time += measurement.elapsed();
133
134        clear_store(&store).await;
135    }
136
137    total_time
138}
139
140/// Benchmarks the `find_keys_by_prefix` operation.
141pub async fn find_key_values_by_prefix<D, F>(iterations: u64, f: F) -> Duration
142where
143    D: TestKeyValueDatabase,
144    D::Store: KeyValueStore,
145    F: Fn(Vec<(Vec<u8>, Vec<u8>)>) -> Vec<(Vec<u8>, Vec<u8>)>,
146{
147    let namespace = D::connect_test_namespace().await.unwrap();
148    let store = namespace.open_shared(&[]).unwrap();
149    let mut total_time = Duration::ZERO;
150    for _ in 0..iterations {
151        let key_values = add_prefix(
152            PREFIX,
153            get_random_key_values_with_small_keys(NUM_ENTRIES, LEN_KEY, LEN_VALUE),
154        );
155        let mut batch = Batch::new();
156        for key_value in &key_values {
157            batch.put_key_value_bytes(key_value.0.clone(), key_value.1.clone());
158        }
159        store.write_batch(batch).await.unwrap();
160
161        let measurement = Instant::now();
162        f(store
163            .find_key_values_by_prefix(PREFIX_SEARCH)
164            .await
165            .unwrap());
166        total_time += measurement.elapsed();
167
168        clear_store(&store).await;
169    }
170
171    total_time
172}
173
174/// Benchmarks the `read_value_bytes` operation.
175pub async fn read_value_bytes<D, F>(iterations: u64, f: F) -> Duration
176where
177    D: TestKeyValueDatabase,
178    D::Store: KeyValueStore,
179    F: Fn(Option<Vec<u8>>) -> Option<Vec<u8>>,
180{
181    let namespace = D::connect_test_namespace().await.unwrap();
182    let store = namespace.open_shared(&[]).unwrap();
183    let mut total_time = Duration::ZERO;
184    for _ in 0..iterations {
185        let key_values = add_prefix(
186            PREFIX,
187            get_random_key_values_with_small_keys(NUM_ENTRIES, LEN_KEY, LEN_VALUE),
188        );
189        let mut batch = Batch::new();
190        for key_value in &key_values {
191            batch.put_key_value_bytes(key_value.0.clone(), key_value.1.clone());
192        }
193        store.write_batch(batch).await.unwrap();
194
195        let measurement = Instant::now();
196        for (key, _) in &key_values {
197            f(store.read_value_bytes(key).await.unwrap());
198        }
199        total_time += measurement.elapsed();
200
201        clear_store(&store).await;
202    }
203
204    total_time
205}
206
207/// Benchmarks the `read_multi_values_bytes` operation.
208pub async fn read_multi_values_bytes<D, F>(iterations: u64, f: F) -> Duration
209where
210    D: TestKeyValueDatabase,
211    D::Store: KeyValueStore,
212    F: Fn(Vec<Option<Vec<u8>>>) -> Vec<Option<Vec<u8>>>,
213{
214    let namespace = D::connect_test_namespace().await.unwrap();
215    let store = namespace.open_shared(&[]).unwrap();
216    let mut total_time = Duration::ZERO;
217    for _ in 0..iterations {
218        let key_values = add_prefix(
219            PREFIX,
220            get_random_key_values_with_small_keys(NUM_ENTRIES, LEN_KEY, LEN_VALUE),
221        );
222        let mut batch = Batch::new();
223        for key_value in &key_values {
224            batch.put_key_value_bytes(key_value.0.clone(), key_value.1.clone());
225        }
226        store.write_batch(batch).await.unwrap();
227        let keys = key_values
228            .into_iter()
229            .map(|(key, _)| key)
230            .collect::<Vec<_>>();
231
232        let measurement = Instant::now();
233        f(store.read_multi_values_bytes(keys).await.unwrap());
234        total_time += measurement.elapsed();
235
236        clear_store(&store).await;
237    }
238
239    total_time
240}
241
242/// Benchmarks the `write_batch` operation.
243pub async fn write_batch<D>(iterations: u64) -> Duration
244where
245    D: TestKeyValueDatabase,
246    D::Store: KeyValueStore,
247{
248    let store = D::new_test_store().await.unwrap();
249    let mut total_time = Duration::ZERO;
250    for _ in 0..iterations {
251        let key_values = add_prefix(
252            PREFIX,
253            get_random_key_values_with_small_keys(NUM_ENTRIES, LEN_KEY, LEN_VALUE),
254        );
255        let mut batch = Batch::new();
256        for key_value in &key_values {
257            batch.put_key_value_bytes(key_value.0.clone(), key_value.1.clone());
258        }
259
260        let measurement = Instant::now();
261        store.write_batch(batch).await.unwrap();
262        total_time += measurement.elapsed();
263
264        clear_store(&store).await;
265    }
266
267    total_time
268}