Rust-rocksdb: 使 `cf_handle` 无锁

创建于 2019-03-13  ·  12评论  ·  资料来源: rust-rocksdb/rust-rocksdb

cf_handle函数经常被频繁调用,它的实现需要获取底层映射的读锁。 如果在热路径中调用它,则会对性能产生影响。 我们应该研究将其转换为不需要锁定的方法。 例如,我们可以使create_cfdrop_cf以及任何其他改变内部映射的函数都需要对DB的可变引用,并使调用者负责按顺序获取任何锁改变DB

最有用的评论

是的。 我们计划在不久的将来发布它。

所有12条评论

像这样?

use std::collections::HashMap;

#[derive(Debug)]
struct ColumnFamily(i32);

struct DB {
    cfs:HashMap<i32,ColumnFamily>,
}

impl DB {
    fn new()->DB{
        let mut cfs = HashMap::new();
        cfs.insert(1,ColumnFamily(1));
        cfs.insert(2,ColumnFamily(2));
        DB{
            cfs
        }
    }
    fn get(&self,key:i32)->&ColumnFamily{
        self.cfs.get(&key).unwrap()
    }
    fn drop_key(&mut self,key:i32){
        self.cfs.remove(&key);
    }
}

fn main() {
    let mut f = DB::new();
    let a = f.get(1);
    println!("{:?}",a);
    f.drop_key(1);
    let c = f.get(2);
    println!("{:?}",c);
}

FWIW,在 paritech 的分支中cf_handleCopy ,这在技术上并不安全(OTOH 人会认为它很难被滥用),但避免使用锁。

@hjiayz是的,非常相似。

当我尝试进行此更改时(即在创建/删除列族时使用&mut self )时,我遇到了ColumnFamily定义方式的问题。 它将在PhantomData存储一个可变引用,这会使这样的代码失败:

#[test]
fn property_cf_test() {
    let n = DBPath::new("_rust_rocksdb_property_cf_test");
    {
        let opts = Options::default();
        let mut db = DB::open_default(&n).unwrap(); // Notice the `mut`
        let cf = db.create_cf("cf1", &opts).unwrap();
        let value = db.property_value_cf(cf, "rocksdb.stats").unwrap().unwrap();

        assert!(value.contains("Stats"));
    }
}

当在 db 上调用需要&self的方法时会发生错误,例如db.property_value_cf()并传入ColumnFamily (它将&mutdb字段):

error[E0502]: cannot borrow `db` as immutable because it is also borrowed as mutable
  --> tests/test_property.rs:39:21
   |
38 |         let cf = db.create_cf("cf1", &opts).unwrap();
   |                  -- mutable borrow occurs here
39 |         let value = db.property_value_cf(cf, "rocksdb.stats").unwrap().unwrap();
   |                     ^^                   -- mutable borrow later used here
   |                     |
   |                     immutable borrow occurs here

我想不出一个非常优雅的方法来解决这个问题,但一个选择是不从create_cf返回ColumnFamily而是让消费代码通过调用cf_handle()来获取它

#[test]
fn property_cf_test() {
    let n = DBPath::new("_rust_rocksdb_property_cf_test");
    {
        let opts = Options::default();
        let mut db = DB::open_default(&n).unwrap();
        db.create_cf("cf1", &opts).unwrap();
        let cf = db.cf_handle("cf1").unwrap(); // Get the CF
        let value = db.property_value_cf(cf, "rocksdb.stats").unwrap().unwrap();

        assert!(value.contains("Stats"));
    }
}

create_cf()更改为返回Result<(), Error>是可以接受的更改吗?

@dvdplm从人体工程学的角度来看,将生命周期添加到ColumnFamily最终有点像一场噩梦。 我想追求一种不需要终生但也不会冒着在删除后使用列族指针的风险的方法。 这一变化可能会影响我们如何从cf_handle移除锁——你可能不会看到这个问题。

同意@iSynaptic。 显然,仅在这种情况下,返回对ColumnFamily的引用是一种安全的方法。

那么#298可以合并吗?

314

#314 解决了吗? 如果有,有没有计划发布?

是的。 我们计划在不久的将来发布它。

@aleksuss发布它的状态是什么? :)

@bkchr我想我们会在下周这样做。

此页面是否有帮助?
0 / 5 - 0 等级