use foundationdb::tuple::Subspace;
use foundationdb::{Database, RangeOption};
use futures::TryStreamExt;
use rand::RngExt;
use rand::distr::Uniform;
async fn clear_subspace(db: &Database, subspace: &Subspace) {
db.run(|trx, _maybe_committed| async move {
trx.clear_subspace_range(subspace);
Ok(())
})
.await
.expect("Unable to commit transaction");
}
static CHUNK_SIZE: usize = 1024;
async fn write_blob(db: &Database, subspace: &Subspace, data: &[u8]) {
db.run(|trx, _maybe_committed| async move {
let mut chunk_number = 0;
data.chunks(CHUNK_SIZE).for_each(|chunk| {
let start = chunk_number * CHUNK_SIZE;
let end = start + chunk.len();
let key = subspace.pack(&(start));
trx.set(&key, &data[start..end]);
chunk_number += 1;
});
Ok(())
})
.await
.expect("Unable to commit transaction");
}
async fn read_blob(db: &Database, subspace: &Subspace) -> Vec<u8> {
db.run(|trx, _maybe_committed| async move {
let range = RangeOption::from(subspace.range());
let mut data: Vec<u8> = vec![];
let mut stream = trx.get_ranges_keyvalues(range, false);
while let Some(result) = stream.try_next().await? {
data.extend(result.value().iter());
}
Ok(data)
})
.await
.expect("Unable to read blob")
}
async fn test_blob_storing(db: &Database, subspace: &Subspace, iteration: usize) {
let data: Vec<u8> = rand::rng()
.sample_iter(Uniform::new_inclusive(0, 255).expect("Unable to create random generator"))
.map(|x| x as u8)
.take(10000)
.collect();
let subspace = subspace.subspace(&(iteration));
write_blob(db, &subspace, &data).await;
let result = read_blob(db, &subspace).await;
assert_eq!(&data, &result);
}
#[tokio::main]
async fn main() {
let _guard = unsafe { foundationdb::boot() };
let db = Database::new_compat(None)
.await
.expect("Unable to create database");
db.set_option(foundationdb::options::DatabaseOption::TransactionTimeout(
5000,
))
.expect("failed to set transaction timeout");
db.set_option(foundationdb::options::DatabaseOption::TransactionRetryLimit(3))
.expect("failed to set transaction retry limit");
let subspace = Subspace::all().subspace(&("example-blob"));
clear_subspace(&db, &subspace).await;
for i in 1..=100 {
println!("Iteration #{i}");
test_blob_storing(&db, &subspace, i).await;
}
}