Die Funktion cf_handle
wird oft sehr häufig aufgerufen und ihre Implementierung erfordert den Erwerb einer Lesesperre für eine zugrunde liegende Karte. Wenn dies in einem Hot-Path aufgerufen wird, kann dies Auswirkungen auf die Leistung haben. Wir sollten untersuchen, ob dies auf einen Ansatz umgestellt wird, der keine Sperre erfordert. Zum Beispiel könnten wir create_cf
und drop_cf
und jede andere Funktion, die die interne Map verändert, eine veränderliche Referenz auf DB
erfordern und den Aufrufer dafür verantwortlich machen, alle Sperren in der richtigen Reihenfolge zu erwerben um das DB
zu mutieren.
so was?
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, in Paritechs Fork cf_handle
ist Copy
, was technisch nicht sicher ist (OTOH würde argumentieren, dass es schwer zu missbrauchen ist), aber die Verwendung von Sperren vermeidet.
@hjiayz Ja, sehr ähnlich.
Als ich versuchte, diese Änderung vorzunehmen (zB &mut self
beim Erstellen/Ablegen von Spaltenfamilien nehmen), stieß ich auf Probleme mit der Definition von ColumnFamily
. Es wird eine veränderliche Referenz in PhantomData
gespeichert, wodurch Code wie dieser fehlschlägt:
#[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"));
}
}
Der Fehler passiert , wenn ein Methodenaufruf zu db macht das braucht &self
, wie beispielsweise db.property_value_cf()
und Weitergabe in einem ColumnFamily
(die speichern ein &mut
im db
Feld):
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
Ich kann mir keinen sehr eleganten Weg vorstellen, aber eine Möglichkeit besteht darin, kein ColumnFamily
von create_cf
und es stattdessen von konsumierendem Code mit einem Aufruf von cf_handle()
holen zu lassen.
#[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"));
}
}
Wäre die Änderung von create_cf()
in Result<(), Error>
eine akzeptable Änderung?
@dvdplm Das Hinzufügen von Lebensdauern zu ColumnFamily
war aus ergonomischer Sicht ein Albtraum. Ich möchte einen Ansatz verfolgen, der keine Lebensdauer benötigt, aber auch nicht das Risiko eingeht, einen Spaltenfamilienzeiger zu verwenden, nachdem er gelöscht wurde. Diese Änderung wird sich wahrscheinlich darauf auswirken, wie wir Sperren von cf_handle
entfernen - Sie werden dieses Problem wahrscheinlich nicht sehen.
Stimme @iSynaptic zu. Offensichtlich ist das Zurückgeben einer Referenz auf ColumnFamily
nur in diesem Fall ein sicherer Weg.
Vielleicht kann #298 dann zusammengeführt werden?
Ist es von #314 gelöst? Gibt es Pläne für eine Veröffentlichung, wenn ja?
Ja, so ist es. Wir planen, es in naher Zukunft zu veröffentlichen.
@aleksuss Wie ist der Status der Veröffentlichung? :)
@bkchr Ich denke, wir werden es nächste Woche tun.
Hilfreichster Kommentar
Ja, so ist es. Wir planen, es in naher Zukunft zu veröffentlichen.