use rocksolid::cf_store::{CFOperations, RocksDbCFStore};
use rocksolid::config::{BaseCfConfig, RocksDbCFStoreConfig};
use rocksolid::StoreResult;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use tempfile::tempdir;
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
struct Product {
id: u32,
name: String,
}
const PRODUCTS_CF: &str = "products_cf_for_batching";
const DEFAULT_CF: &str = rocksdb::DEFAULT_COLUMN_FAMILY_NAME;
const METADATA_CF: &str = "metadata_cf_for_batching";
fn main() -> StoreResult<()> {
let temp_dir = tempdir().expect("Failed to create temp dir");
let db_path = temp_dir.path().join("batch_db_new_api");
println!("Batching DB path: {}", db_path.display());
let mut cf_configs = HashMap::new();
cf_configs.insert(PRODUCTS_CF.to_string(), BaseCfConfig::default());
cf_configs.insert(METADATA_CF.to_string(), BaseCfConfig::default());
cf_configs.insert(DEFAULT_CF.to_string(), BaseCfConfig::default());
let config = RocksDbCFStoreConfig {
path: db_path.to_str().unwrap().to_string(),
create_if_missing: true,
column_families_to_open: vec![DEFAULT_CF.to_string(), PRODUCTS_CF.to_string(), METADATA_CF.to_string()],
column_family_configs: cf_configs,
..Default::default()
};
let store = RocksDbCFStore::open(config)?;
println!("\nBuilding batch for CF: '{}'", PRODUCTS_CF);
let mut products_writer = store.batch_writer(PRODUCTS_CF);
let product1 = Product {
id: 1,
name: "Gadget".into(),
};
let product2 = Product {
id: 2,
name: "Thingamajig".into(),
};
products_writer.set("product:1", &product1)?;
products_writer.set("product:2", &product2)?;
products_writer.delete("product:old")?;
println!("Committing batch for '{}'...", PRODUCTS_CF);
products_writer.commit()?;
println!("Batch for '{}' committed.", PRODUCTS_CF);
println!("\nBuilding batch for CF: '{}'", METADATA_CF);
let mut metadata_writer = store.batch_writer(METADATA_CF);
metadata_writer.set_raw("version", b"2.0")?;
metadata_writer.set_raw("status", b"ready")?;
println!("Committing batch for '{}'...", METADATA_CF);
metadata_writer.commit()?;
println!("Batch for '{}' committed.", METADATA_CF);
let p1: Option<Product> = store.get(PRODUCTS_CF, "product:1")?;
let p2: Option<Product> = store.get(PRODUCTS_CF, "product:2")?;
let p_old: Option<Product> = store.get(PRODUCTS_CF, "product:old")?;
let version: Option<Vec<u8>> = store.get_raw(METADATA_CF, "version")?;
let status: Option<Vec<u8>> = store.get_raw(METADATA_CF, "status")?;
println!(" Post-batch Get product:1 from CF '{}' = {:?}", PRODUCTS_CF, p1);
println!(" Post-batch Get product:2 from CF '{}' = {:?}", PRODUCTS_CF, p2);
println!(" Post-batch Get product:old from CF '{}' = {:?}", PRODUCTS_CF, p_old);
println!(
" Post-batch Get version from CF '{}' = {:?}",
METADATA_CF,
version.as_ref().map(|bytes| String::from_utf8_lossy(bytes))
);
println!(
" Post-batch Get status from CF '{}' = {:?}",
METADATA_CF,
status.as_ref().map(|bytes| String::from_utf8_lossy(bytes))
);
assert_eq!(p1, Some(product1));
assert_eq!(p2, Some(product2));
assert!(p_old.is_none());
assert_eq!(version, Some(b"2.0".to_vec()));
assert_eq!(status, Some(b"ready".to_vec()));
println!("\nBuilding batch for '{}' to discard...", PRODUCTS_CF);
let mut discard_writer = store.batch_writer(PRODUCTS_CF);
discard_writer.set(
"product:3",
&Product {
id: 3,
name: "Wonkavator".into(),
},
)?;
discard_writer.discard(); println!("Batch discarded.");
let p3: Option<Product> = store.get(PRODUCTS_CF, "product:3")?;
assert!(p3.is_none());
println!("\nBuilding batch for '{}' with raw access...", PRODUCTS_CF);
let mut raw_example_writer = store.batch_writer(PRODUCTS_CF);
let product4 = Product {
id: 4,
name: "Doohickey".into(),
};
raw_example_writer.set("product:4", &product4)?;
{
let raw_batch = raw_example_writer.raw_batch_mut()?;
let products_cf_handle = store.get_cf_handle(PRODUCTS_CF)?;
let key_bytes_raw_named = rocksolid::serialization::serialize_key("raw:example_in_products_cf")?;
raw_batch.put_cf(&products_cf_handle, key_bytes_raw_named, b"raw_payload_for_products_cf");
}
raw_example_writer.commit()?;
println!("Raw access batch committed.");
let p4: Option<Product> = store.get(PRODUCTS_CF, "product:4")?;
let raw_ex_named = store.get_raw(PRODUCTS_CF, "raw:example_in_products_cf")?;
assert_eq!(p4, Some(product4));
assert_eq!(raw_ex_named, Some(b"raw_payload_for_products_cf".to_vec()));
println!("\nBuilding a single ATOMIC batch across multiple CFs using raw_batch_mut()...");
let mut multi_cf_atomic_writer = store.batch_writer(DEFAULT_CF);
let product5 = Product {
id: 5,
name: "MultiGadget".into(),
};
multi_cf_atomic_writer.set("default_key_in_multi_batch", &"default_value".to_string())?;
{
let raw_batch = multi_cf_atomic_writer.raw_batch_mut()?;
let products_cf_handle = store.get_cf_handle(PRODUCTS_CF)?;
let p5_key_bytes = rocksolid::serialization::serialize_key("product:5")?;
let p5_val_bytes = rocksolid::serialization::serialize_value(&product5)?;
raw_batch.put_cf(&products_cf_handle, p5_key_bytes, p5_val_bytes);
let metadata_cf_handle = store.get_cf_handle(METADATA_CF)?;
let meta_key_bytes = rocksolid::serialization::serialize_key("multi_batch_flag")?;
raw_batch.put_cf(&metadata_cf_handle, meta_key_bytes, b"true");
}
multi_cf_atomic_writer.commit()?;
println!("Multi-CF atomic batch committed.");
let default_val_check: Option<String> = store.get(DEFAULT_CF, "default_key_in_multi_batch")?;
let p5_check: Option<Product> = store.get(PRODUCTS_CF, "product:5")?;
let meta_flag_check: Option<Vec<u8>> = store.get_raw(METADATA_CF, "multi_batch_flag")?;
assert_eq!(default_val_check, Some("default_value".to_string()));
assert_eq!(p5_check, Some(product5));
assert_eq!(meta_flag_check, Some(b"true".to_vec()));
println!("Multi-CF atomic batch verified.");
Ok(())
}