* ci: use actions/checkout@v5l (#1043) * feat: allow user to set checkpoint log size for flush (#1055) * upgrade to Rust edition 2024 and MSRV 1.89.0 --------- Co-authored-by: Coder <161350311+MamunC0der@users.noreply.github.com> Co-authored-by: QuantumExplorer <quantum@dash.org>
300 lines
9.8 KiB
Rust
300 lines
9.8 KiB
Rust
use rust_rocksdb::{ColumnFamilyDescriptor, DB, Options, ReadOptions, WriteOptions};
|
|
|
|
mod util;
|
|
use util::DBPath;
|
|
|
|
#[test]
|
|
fn test_single_delete() {
|
|
let path = DBPath::new("_rust_rocksdb_test_single_delete");
|
|
{
|
|
let db = DB::open_default(&path).unwrap();
|
|
|
|
// Test basic single_delete
|
|
db.put(b"k1", b"v1").unwrap();
|
|
assert_eq!(db.get(b"k1").unwrap().unwrap(), b"v1");
|
|
|
|
db.single_delete(b"k1").unwrap();
|
|
assert!(db.get(b"k1").unwrap().is_none());
|
|
|
|
// Test that single_delete doesn't affect non-existent keys
|
|
db.single_delete(b"k2").unwrap();
|
|
assert!(db.get(b"k2").unwrap().is_none());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_single_delete_opt() {
|
|
let path = DBPath::new("_rust_rocksdb_test_single_delete_opt");
|
|
{
|
|
let db = DB::open_default(&path).unwrap();
|
|
let write_opts = WriteOptions::default();
|
|
|
|
// Test single_delete with write options
|
|
db.put(b"k1", b"v1").unwrap();
|
|
assert_eq!(db.get(b"k1").unwrap().unwrap(), b"v1");
|
|
|
|
db.single_delete_opt(b"k1", &write_opts).unwrap();
|
|
assert!(db.get(b"k1").unwrap().is_none());
|
|
|
|
// Test multiple keys
|
|
db.put(b"k2", b"v2").unwrap();
|
|
db.put(b"k3", b"v3").unwrap();
|
|
|
|
db.single_delete_opt(b"k2", &write_opts).unwrap();
|
|
assert!(db.get(b"k2").unwrap().is_none());
|
|
assert_eq!(db.get(b"k3").unwrap().unwrap(), b"v3");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_single_delete_cf() {
|
|
let path = DBPath::new("_rust_rocksdb_test_single_delete_cf");
|
|
{
|
|
let mut opts = Options::default();
|
|
opts.create_if_missing(true);
|
|
opts.create_missing_column_families(true);
|
|
|
|
let cf1_descriptor = ColumnFamilyDescriptor::new("cf1", Options::default());
|
|
let cf2_descriptor = ColumnFamilyDescriptor::new("cf2", Options::default());
|
|
|
|
let db =
|
|
DB::open_cf_descriptors(&opts, &path, vec![cf1_descriptor, cf2_descriptor]).unwrap();
|
|
|
|
let cf1 = db.cf_handle("cf1").unwrap();
|
|
let cf2 = db.cf_handle("cf2").unwrap();
|
|
|
|
// Put and single_delete in cf1
|
|
db.put_cf(&cf1, b"k1", b"v1").unwrap();
|
|
assert_eq!(db.get_cf(&cf1, b"k1").unwrap().unwrap(), b"v1");
|
|
|
|
db.single_delete_cf(&cf1, b"k1").unwrap();
|
|
assert!(db.get_cf(&cf1, b"k1").unwrap().is_none());
|
|
|
|
// Put and single_delete in cf2
|
|
db.put_cf(&cf2, b"k2", b"v2").unwrap();
|
|
assert_eq!(db.get_cf(&cf2, b"k2").unwrap().unwrap(), b"v2");
|
|
|
|
db.single_delete_cf(&cf2, b"k2").unwrap();
|
|
assert!(db.get_cf(&cf2, b"k2").unwrap().is_none());
|
|
|
|
// Verify that single_delete in one cf doesn't affect another
|
|
db.put_cf(&cf1, b"k3", b"v3").unwrap();
|
|
db.put_cf(&cf2, b"k3", b"v3_cf2").unwrap();
|
|
|
|
db.single_delete_cf(&cf1, b"k3").unwrap();
|
|
assert!(db.get_cf(&cf1, b"k3").unwrap().is_none());
|
|
assert_eq!(db.get_cf(&cf2, b"k3").unwrap().unwrap(), b"v3_cf2");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_single_delete_cf_opt() {
|
|
let path = DBPath::new("_rust_rocksdb_test_single_delete_cf_opt");
|
|
{
|
|
let mut opts = Options::default();
|
|
opts.create_if_missing(true);
|
|
opts.create_missing_column_families(true);
|
|
|
|
let cf_descriptor = ColumnFamilyDescriptor::new("cf1", Options::default());
|
|
let db = DB::open_cf_descriptors(&opts, &path, vec![cf_descriptor]).unwrap();
|
|
|
|
let cf = db.cf_handle("cf1").unwrap();
|
|
let write_opts = WriteOptions::default();
|
|
|
|
// Test single_delete_cf_opt
|
|
db.put_cf(&cf, b"k1", b"v1").unwrap();
|
|
assert_eq!(db.get_cf(&cf, b"k1").unwrap().unwrap(), b"v1");
|
|
|
|
db.single_delete_cf_opt(&cf, b"k1", &write_opts).unwrap();
|
|
assert!(db.get_cf(&cf, b"k1").unwrap().is_none());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_single_delete_with_ts() {
|
|
let path = DBPath::new("_rust_rocksdb_test_single_delete_with_ts");
|
|
{
|
|
let mut opts = Options::default();
|
|
opts.create_if_missing(true);
|
|
|
|
// Set up user-defined timestamp
|
|
let comparator_name = "test_comparator";
|
|
|
|
opts.set_comparator_with_ts(
|
|
comparator_name,
|
|
8, // timestamp size
|
|
Box::new(util::U64Comparator::compare),
|
|
Box::new(util::U64Comparator::compare_ts),
|
|
Box::new(util::U64Comparator::compare_without_ts),
|
|
);
|
|
|
|
let db = DB::open(&opts, &path).unwrap();
|
|
|
|
let key = b"k1";
|
|
let val1 = b"v1";
|
|
let val2 = b"v2";
|
|
let ts1 = 1_u64.to_le_bytes();
|
|
let ts2 = 2_u64.to_le_bytes();
|
|
let ts3 = 3_u64.to_le_bytes();
|
|
|
|
// Put with timestamps
|
|
db.put_with_ts(key, ts1, val1).unwrap();
|
|
db.put_with_ts(key, ts2, val2).unwrap();
|
|
|
|
// Read at different timestamps
|
|
let mut opts = ReadOptions::default();
|
|
opts.set_timestamp(ts2);
|
|
let value = db.get_opt(key, &opts).unwrap();
|
|
assert_eq!(value.unwrap().as_slice(), val2);
|
|
|
|
// Single_delete with timestamp
|
|
db.single_delete_with_ts(key, ts3).unwrap();
|
|
opts.set_timestamp(ts3);
|
|
let value = db.get_opt(key, &opts).unwrap();
|
|
assert!(value.is_none());
|
|
|
|
// ts2 should still read data before deletion
|
|
opts.set_timestamp(ts2);
|
|
let value = db.get_opt(key, &opts).unwrap();
|
|
assert_eq!(value.unwrap().as_slice(), val2);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_single_delete_with_ts_opt() {
|
|
let path = DBPath::new("_rust_rocksdb_test_single_delete_with_ts_opt");
|
|
{
|
|
let mut opts = Options::default();
|
|
opts.create_if_missing(true);
|
|
|
|
// Set up user-defined timestamp
|
|
let comparator_name = "test_comparator";
|
|
|
|
opts.set_comparator_with_ts(
|
|
comparator_name,
|
|
8, // timestamp size
|
|
Box::new(util::U64Comparator::compare),
|
|
Box::new(util::U64Comparator::compare_ts),
|
|
Box::new(util::U64Comparator::compare_without_ts),
|
|
);
|
|
|
|
let db = DB::open(&opts, &path).unwrap();
|
|
let write_opts = WriteOptions::default();
|
|
|
|
let key = b"k1";
|
|
let val = b"v1";
|
|
let ts1 = 1_u64.to_le_bytes();
|
|
let ts2 = 2_u64.to_le_bytes();
|
|
|
|
// Put with timestamp
|
|
db.put_with_ts(key, ts1, val).unwrap();
|
|
|
|
// Single_delete with timestamp and write options
|
|
db.single_delete_with_ts_opt(key, ts2, &write_opts).unwrap();
|
|
|
|
let mut read_opts = ReadOptions::default();
|
|
read_opts.set_timestamp(ts2);
|
|
let value = db.get_opt(key, &read_opts).unwrap();
|
|
assert!(value.is_none());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_single_delete_cf_with_ts() {
|
|
let path = DBPath::new("_rust_rocksdb_test_single_delete_cf_with_ts");
|
|
{
|
|
let mut opts = Options::default();
|
|
opts.create_if_missing(true);
|
|
opts.create_missing_column_families(true);
|
|
|
|
// Set up user-defined timestamp
|
|
let comparator_name = "test_comparator";
|
|
|
|
let mut cf_opts = Options::default();
|
|
cf_opts.set_comparator_with_ts(
|
|
comparator_name,
|
|
8, // timestamp size
|
|
Box::new(util::U64Comparator::compare),
|
|
Box::new(util::U64Comparator::compare_ts),
|
|
Box::new(util::U64Comparator::compare_without_ts),
|
|
);
|
|
|
|
let cf_descriptor = ColumnFamilyDescriptor::new("cf1", cf_opts);
|
|
let db = DB::open_cf_descriptors(&opts, &path, vec![cf_descriptor]).unwrap();
|
|
|
|
let cf = db.cf_handle("cf1").unwrap();
|
|
|
|
let key = b"k1";
|
|
let val1 = b"v1";
|
|
let val2 = b"v2";
|
|
let ts1 = 1_u64.to_le_bytes();
|
|
let ts2 = 2_u64.to_le_bytes();
|
|
let ts3 = 3_u64.to_le_bytes();
|
|
|
|
// Put with timestamps in column family
|
|
db.put_cf_with_ts(&cf, key, ts1, val1).unwrap();
|
|
db.put_cf_with_ts(&cf, key, ts2, val2).unwrap();
|
|
|
|
// Read at different timestamps
|
|
let mut opts = ReadOptions::default();
|
|
opts.set_timestamp(ts2);
|
|
let value = db.get_cf_opt(&cf, key, &opts).unwrap();
|
|
assert_eq!(value.unwrap().as_slice(), val2);
|
|
|
|
// Single_delete with timestamp in column family
|
|
db.single_delete_cf_with_ts(&cf, key, ts3).unwrap();
|
|
opts.set_timestamp(ts3);
|
|
let value = db.get_cf_opt(&cf, key, &opts).unwrap();
|
|
assert!(value.is_none());
|
|
|
|
// ts2 should still read data before deletion
|
|
opts.set_timestamp(ts2);
|
|
let value = db.get_cf_opt(&cf, key, &opts).unwrap();
|
|
assert_eq!(value.unwrap().as_slice(), val2);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_single_delete_cf_with_ts_opt() {
|
|
let path = DBPath::new("_rust_rocksdb_test_single_delete_cf_with_ts_opt");
|
|
{
|
|
let mut opts = Options::default();
|
|
opts.create_if_missing(true);
|
|
opts.create_missing_column_families(true);
|
|
|
|
// Set up user-defined timestamp
|
|
let comparator_name = "test_comparator";
|
|
|
|
let mut cf_opts = Options::default();
|
|
cf_opts.set_comparator_with_ts(
|
|
comparator_name,
|
|
8, // timestamp size
|
|
Box::new(util::U64Comparator::compare),
|
|
Box::new(util::U64Comparator::compare_ts),
|
|
Box::new(util::U64Comparator::compare_without_ts),
|
|
);
|
|
|
|
let cf_descriptor = ColumnFamilyDescriptor::new("cf1", cf_opts);
|
|
let db = DB::open_cf_descriptors(&opts, &path, vec![cf_descriptor]).unwrap();
|
|
|
|
let cf = db.cf_handle("cf1").unwrap();
|
|
let write_opts = WriteOptions::default();
|
|
|
|
let key = b"k1";
|
|
let val = b"v1";
|
|
let ts1 = 1_u64.to_le_bytes();
|
|
let ts2 = 2_u64.to_le_bytes();
|
|
|
|
// Put with timestamp in column family
|
|
db.put_cf_with_ts(&cf, key, ts1, val).unwrap();
|
|
|
|
// Single_delete with timestamp and write options in column family
|
|
db.single_delete_cf_with_ts_opt(&cf, key, ts2, &write_opts)
|
|
.unwrap();
|
|
|
|
let mut read_opts = ReadOptions::default();
|
|
read_opts.set_timestamp(ts2);
|
|
let value = db.get_cf_opt(&cf, key, &read_opts).unwrap();
|
|
assert!(value.is_none());
|
|
}
|
|
}
|