Fungsi cf_handle
sering disebut sangat sering dan implementasinya memerlukan perolehan kunci baca ke peta yang mendasarinya. Jika ini disebut dalam hot-path, itu dapat memiliki implikasi kinerja. Kita harus menyelidiki pengalihan ini ke pendekatan yang tidak memerlukan kunci. Sebagai contoh, kita dapat membuat create_cf
dan drop_cf
dan fungsi lain yang mengubah peta internal memerlukan referensi yang dapat diubah ke DB
dan membuat pemanggil bertanggung jawab untuk memperoleh kunci apa pun agar untuk mengubah DB
.
seperti ini?
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, di garpu paritech cf_handle
adalah Copy
, yang secara teknis tidak aman (OTOH orang akan berpendapat sulit untuk disalahgunakan), tetapi menghindari penggunaan kunci.
@hjiayz Ya, sangat mirip dengan itu.
Ketika saya mencoba membuat perubahan ini (yaitu mengambil &mut self
saat membuat/menjatuhkan keluarga kolom) saya mengalami masalah dengan cara mendefinisikan ColumnFamily
. Ini akan menyimpan referensi yang bisa berubah di PhantomData
yang membuat kode seperti ini gagal:
#[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"));
}
}
Kesalahan terjadi ketika membuat panggilan metode pada db yang membutuhkan &self
, seperti db.property_value_cf()
dan meneruskan ColumnFamily
(yang menyimpan &mut
di db
bidang):
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
Saya tidak bisa memikirkan cara yang sangat elegan untuk mengatasi ini, tetapi satu opsi adalah tidak mengembalikan ColumnFamily
dari create_cf
dan alih-alih membiarkan kode yang dikonsumsi mengambilnya dengan panggilan ke 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"));
}
}
Apakah mengubah create_cf()
untuk mengembalikan Result<(), Error>
merupakan perubahan yang dapat diterima?
@dvdplm Menambahkan masa pakai ke ColumnFamily
akhirnya menjadi sedikit mimpi buruk dari perspektif ergonomis. Saya ingin mengejar pendekatan yang tidak membutuhkan seumur hidup tetapi juga tidak mengambil risiko menggunakan penunjuk keluarga kolom setelah dihapus. Perubahan itu kemungkinan akan memengaruhi cara kami menghapus kunci dari cf_handle
- Anda mungkin tidak akan melihat masalah ini.
Setuju dengan @iSynaptic. Jelas mengembalikan referensi ke ColumnFamily
adalah cara yang aman hanya dalam kasus ini.
Mungkin #298 bisa digabung?
Apakah diselesaikan dengan # 314? Ada rencana untuk rilis jika demikian?
Ya itu. Kami berencana untuk merilisnya dalam waktu dekat.
@aleksuss apa status
@bkchr Saya pikir kami akan melakukannya minggu depan.
Komentar yang paling membantu
Ya itu. Kami berencana untuk merilisnya dalam waktu dekat.