Το πακέτο rust για το libmdbx
Το περιτύλιγμα rust
για τη βάση δεδομένων libmdbx.
Κατάλογος :
Αποσπάσματα
Καθώς έγραφα το 'rmw.link ', ένιωσα ότι χρειαζόμουν μια ενσωματωμένη βάση δεδομένων.
Λόγω της ταχύτητας μετάδοσης δικτύου που συνεπάγεται η συχνή εγγραφή, ανάγνωση και εγγραφή, το sqlite3
ήταν πολύ προηγμένο για λόγους απόδοσης.
Έτσι, μια βάση δεδομένων κλειδιών-τιμών χαμηλότερου επιπέδου ήταν πιο κατάλληλη (η lmdb είναι 10 φορές ταχύτερη από την sqlite ) .
Τελικά, επέλεξα τη μαγική εκδοχή του lmdb
- mdbx
.
Επί του παρόντος, το υπάρχον πακέτο rust
του mdbx-rs (mdbx-sys) από το mdbx
δεν υποστηρίζει τα Windows, οπότε ανέλαβα να βάλω σε πακέτο μια έκδοση με υποστήριξη για τα Windows.
Υποστήριξη για την αποθήκευση προσαρμοσμένων τύπων σκουριάς. Υποστηρίζει πολυνηματική πρόσβαση.
Η βάση δεδομένων μπορεί να οριστεί σε μια ενότητα χρησιμοποιώντας το lazy_static
και στη συνέχεια να εισαχθεί και να χρησιμοποιηθεί με κάτι σαν :
use db::User;
let id = 1234;
let user = r!(User.get id);
Τι είναι η libmdbx;
Το mdbx είναι μια δευτερεύουσα βάση δεδομένων βασισμένη στο lmdb, του Ρώσου Леонид Юрьев (Leonid Yuriev ).
Η lmdb είναι μια εξαιρετικά γρήγορη ενσωματωμένη βάση δεδομένων κλειδιών-τιμών.
Η μηχανή αναζήτησης πλήρους κειμένου MeiliSearch βασίζεται στην lmdb.
Το πλαίσιο βαθιάς μάθησης caffe χρησιμοποιεί επίσης το lmdb ως χώρο αποθήκευσης δεδομένων.
Το mdbx είναι 30% ταχύτερο από το lmdb στο ενσωματωμένο τεστ απόδοσης ioarena.
Ταυτόχρονα, το mdbx βελτιώνει πολλές από τις αδυναμίες του lmdb, οπότε το Erigon (ο πελάτης ethereum επόμενης γενιάς) μεταπήδησε πρόσφατα από το LMDB στο MDBX [1].
Σεμινάρια
Πώς να εκτελέσετε το παράδειγμα
Πρώτα κλωνοποιήστε την βάση κώδικα git clone git@github.com:rmw-lib/mdbx.git --depth=1 && cd mdbx
Στη συνέχεια, εκτελέστε το cargo run --example 01
και θα τρέξει examples/01.rs
Εάν πρόκειται για το δικό σας έργο, παρακαλούμε να το εκτελέσετε πρώτα :
cargo install cargo-edit
cargo add mdbx lazy_static ctor paste
set(key,val)
και διαβάζοντας .get(key)
Παράδειγμα 1 : Γράφοντας Ας δούμε ένα απλό παράδειγμα/01.rs
Κωδικός
use db::User;
let id = 1234;
let user = r!(User.get id);
use anyhow::{Ok, Result};
use mdbx::prelude::*;
env_rw!(
MDBX,
{
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
},
r,
w
);
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
fn main() -> Result<()> {
// Εξαγωγή του αριθμού έκδοσης της libmdbx
unsafe {
println!(
"mdbx version https://github.com/erthink/libmdbx/releases/tag/v{}.{}.{}",
mdbx_version.major, mdbx_version.minor, mdbx_version.release
);
}
// Πολυνηματική ανάγνωση και εγγραφή
let t = std::thread::spawn(|| {
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t: &[u8] = &val;
println!("{:?}", t);
}
None => unreachable!(),
}
Ok(())
});
t.join().unwrap()?;
Ok(())
}
Εκτελέστε την έξοδο
mdbx file path /Users/z/rmw/mdbx/target/debug/examples/01.mdb
mdbx version https://github.com/erthink/libmdbx/releases/tag/v0.11.2
test1 get Ok(Some(Bin([6])))
[6]
Περιγραφή κωδικού
env_rw!
Ορισμός της βάσης δεδομένων
Ο κώδικας ξεκινά με μια μακροεντολή env_rw, η οποία έχει 4 παραμέτρους.
Το όνομα της μεταβλητής του περιβάλλοντος της βάσης δεδομένων
Επιστρέφει ένα αντικείμενο, mdbx:: env:: Config.
Χρησιμοποιούμε την προεπιλεγμένη διαμόρφωση, καθώς το Env
υλοποιεί το From<Into<PathBuf>>
, οπότε αρκεί η διαδρομή της βάσης δεδομένων into()
, και η προεπιλεγμένη διαμόρφωση έχει ως εξής.
use db::User;
let id = 1234;
let user = r!(User.get id);
use anyhow::{Ok, Result};
use mdbx::prelude::*;
env_rw!(
MDBX,
{
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
},
r,
w
);
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
fn main() -> Result<()> {
// Εξαγωγή του αριθμού έκδοσης της libmdbx
unsafe {
println!(
"mdbx version https://github.com/erthink/libmdbx/releases/tag/v{}.{}.{}",
mdbx_version.major, mdbx_version.minor, mdbx_version.release
);
}
// Πολυνηματική ανάγνωση και εγγραφή
let t = std::thread::spawn(|| {
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t: &[u8] = &val;
println!("{:?}", t);
}
None => unreachable!(),
}
Ok(())
});
t.join().unwrap()?;
Ok(())
}
#[derive(Clone, Debug)]
pub struct Config {
path: PathBuf,
mode: ffi::mdbx_mode_t,
flag: flag::ENV,
sync_period: u64,
sync_bytes: u64,
max_db: u64,
pagesize: isize,
}
lazy_static! {
pub static ref ENV_CONFIG_DEFAULT: Config = Config {
path:PathBuf::new(),
mode: 0o600,
//https://github.com/erthink/libmdbx/issues/248
sync_period : 65536, // Σε 1/65536 του δευτερολέπτου
sync_bytes : 65536,
max_db : 256,
flag : (
flag::ENV::MDBX_EXCLUSIVE
| flag::ENV::MDBX_LIFORECLAIM
| flag::ENV::MDBX_COALESCE
| flag::ENV::MDBX_NOMEMINIT
| flag::ENV::MDBX_NOSUBDIR
| flag::ENV::MDBX_SAFE_NOSYNC
// | flag::ENV::MDBX_SYNC_DURABLE
),
pagesize:-1
};
}
max_db
Αυτή η ρύθμιση μπορεί να μηδενιστεί κάθε φορά που ανοίγει η βάση δεδομένων, αλλά η υπερβολική ρύθμιση θα επηρεάσει την απόδοση, απλά ρυθμίστε την όπως απαιτείται.
Ανατρέξτε στην τεκμηρίωση της libmdbx για τη σημασία των άλλων παραμέτρων.
Το όνομα της μακροεντολής συναλλαγής ανάγνωσης της βάσης δεδομένων, η προεπιλεγμένη τιμή είναι
r
Το όνομα της μακροεντολής συναλλαγής εγγραφής της βάσης δεδομένων, η προεπιλεγμένη τιμή είναι
w
Οι παράμετροι 3 και 4 μπορούν να παραλειφθούν για να χρησιμοποιηθούν οι προεπιλεγμένες τιμές.
Μακροσκοπική επέκταση
Αν θέλετε να δείτε τι κάνει η μαγική μακροεντολή, μπορείτε να χρησιμοποιήσετε τη μακροεντολή cargo expand --example 01
για να την επεκτείνετε, η οποία πρέπει πρώτα να εγκατασταθεί. cargo install cargo-expand
Ένα στιγμιότυπο οθόνης του εκτεταμένου κώδικα παρουσιάζεται παρακάτω.
anyhow και lazy_static
Από το εκτεταμένο στιγμιότυπο οθόνης, μπορείτε να δείτε ότι χρησιμοποιούνται οι διευθύνσεις lazy_static
και anyhow
.
anyhow είναι η βιβλιοθήκη χειρισμού σφαλμάτων για την rust.
Η lazy_static είναι μια στατική μεταβλητή με καθυστερημένη αρχικοποίηση .
Αυτές οι δύο βιβλιοθήκες είναι πολύ κοινές και δεν θα επεκταθώ σε αυτές.
Η μακροεντολή mdbx!
mdbx!
είναι μια μακροεντολή διαδικασίας.
use db::User;
let id = 1234;
let user = r!(User.get id);
use anyhow::{Ok, Result};
use mdbx::prelude::*;
env_rw!(
MDBX,
{
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
},
r,
w
);
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
fn main() -> Result<()> {
// Εξαγωγή του αριθμού έκδοσης της libmdbx
unsafe {
println!(
"mdbx version https://github.com/erthink/libmdbx/releases/tag/v{}.{}.{}",
mdbx_version.major, mdbx_version.minor, mdbx_version.release
);
}
// Πολυνηματική ανάγνωση και εγγραφή
let t = std::thread::spawn(|| {
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t: &[u8] = &val;
println!("{:?}", t);
}
None => unreachable!(),
}
Ok(())
});
t.join().unwrap()?;
Ok(())
}
#[derive(Clone, Debug)]
pub struct Config {
path: PathBuf,
mode: ffi::mdbx_mode_t,
flag: flag::ENV,
sync_period: u64,
sync_bytes: u64,
max_db: u64,
pagesize: isize,
}
lazy_static! {
pub static ref ENV_CONFIG_DEFAULT: Config = Config {
path:PathBuf::new(),
mode: 0o600,
//https://github.com/erthink/libmdbx/issues/248
sync_period : 65536, // Σε 1/65536 του δευτερολέπτου
sync_bytes : 65536,
max_db : 256,
flag : (
flag::ENV::MDBX_EXCLUSIVE
| flag::ENV::MDBX_LIFORECLAIM
| flag::ENV::MDBX_COALESCE
| flag::ENV::MDBX_NOMEMINIT
| flag::ENV::MDBX_NOSUBDIR
| flag::ENV::MDBX_SAFE_NOSYNC
// | flag::ENV::MDBX_SYNC_DURABLE
),
pagesize:-1
};
}
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
Η πρώτη γραμμή είναι το όνομα της μεταβλητής του περιβάλλοντος της βάσης δεδομένων
Η δεύτερη γραμμή είναι το όνομα της βάσης δεδομένων
Μπορούν να υπάρχουν περισσότερες από μία βάσεις δεδομένων, μία γραμμή για κάθε
Νήματα και συναλλαγές
Ο παραπάνω κώδικας επιδεικνύει την ανάγνωση και εγγραφή με πολλαπλά νήματα.
Είναι σημαντικό να σημειωθεί ότι μπορεί να υπάρχει μόνο μία συναλλαγή στο ίδιο νήμα ανά πάσα στιγμή, εάν ένα νήμα έχει περισσότερες από μία συναλλαγές ανοιχτές, το πρόγραμμα θα καταρρεύσει.
Η συναλλαγή θα δεσμευτεί στο τέλος του πεδίου εφαρμογής.
Ανάγνωση και εγγραφή δυαδικών δεδομένων
use db::User;
let id = 1234;
let user = r!(User.get id);
use anyhow::{Ok, Result};
use mdbx::prelude::*;
env_rw!(
MDBX,
{
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
},
r,
w
);
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
fn main() -> Result<()> {
// Εξαγωγή του αριθμού έκδοσης της libmdbx
unsafe {
println!(
"mdbx version https://github.com/erthink/libmdbx/releases/tag/v{}.{}.{}",
mdbx_version.major, mdbx_version.minor, mdbx_version.release
);
}
// Πολυνηματική ανάγνωση και εγγραφή
let t = std::thread::spawn(|| {
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t: &[u8] = &val;
println!("{:?}", t);
}
None => unreachable!(),
}
Ok(())
});
t.join().unwrap()?;
Ok(())
}
#[derive(Clone, Debug)]
pub struct Config {
path: PathBuf,
mode: ffi::mdbx_mode_t,
flag: flag::ENV,
sync_period: u64,
sync_bytes: u64,
max_db: u64,
pagesize: isize,
}
lazy_static! {
pub static ref ENV_CONFIG_DEFAULT: Config = Config {
path:PathBuf::new(),
mode: 0o600,
//https://github.com/erthink/libmdbx/issues/248
sync_period : 65536, // Σε 1/65536 του δευτερολέπτου
sync_bytes : 65536,
max_db : 256,
flag : (
flag::ENV::MDBX_EXCLUSIVE
| flag::ENV::MDBX_LIFORECLAIM
| flag::ENV::MDBX_COALESCE
| flag::ENV::MDBX_NOMEMINIT
| flag::ENV::MDBX_NOSUBDIR
| flag::ENV::MDBX_SAFE_NOSYNC
// | flag::ENV::MDBX_SYNC_DURABLE
),
pagesize:-1
};
}
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t:&[u8] = &val;
println!("{:?}",t);
},
None => unreachable!()
}
set
είναι μια εγγραφή, get
είναι μια ανάγνωση, και κάθε αντικείμενο που υλοποιεί το AsRef<[u8]>
αντικείμενο μπορεί να εγγραφεί στη βάση δεδομένων.
get
Αυτό που βγαίνει είναι το Ok(Some(Bin([6])))
το οποίο μπορεί να μετατραπεί σε &[u8]
.
Παράδειγμα 2: Τύποι δεδομένων, σημαίες βάσης δεδομένων, διαγραφή, διάσχιση
Ας δούμε το δεύτερο παράδειγμα examples/02.rs:
Σε αυτό το παράδειγμα, το env_rw!
παραλείπεται και το τρίτο και το τέταρτο όρισμα ( r
, w
) παραλείπονται.
Κωδικός
use db::User;
let id = 1234;
let user = r!(User.get id);
use anyhow::{Ok, Result};
use mdbx::prelude::*;
env_rw!(
MDBX,
{
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
},
r,
w
);
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
fn main() -> Result<()> {
// Εξαγωγή του αριθμού έκδοσης της libmdbx
unsafe {
println!(
"mdbx version https://github.com/erthink/libmdbx/releases/tag/v{}.{}.{}",
mdbx_version.major, mdbx_version.minor, mdbx_version.release
);
}
// Πολυνηματική ανάγνωση και εγγραφή
let t = std::thread::spawn(|| {
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t: &[u8] = &val;
println!("{:?}", t);
}
None => unreachable!(),
}
Ok(())
});
t.join().unwrap()?;
Ok(())
}
#[derive(Clone, Debug)]
pub struct Config {
path: PathBuf,
mode: ffi::mdbx_mode_t,
flag: flag::ENV,
sync_period: u64,
sync_bytes: u64,
max_db: u64,
pagesize: isize,
}
lazy_static! {
pub static ref ENV_CONFIG_DEFAULT: Config = Config {
path:PathBuf::new(),
mode: 0o600,
//https://github.com/erthink/libmdbx/issues/248
sync_period : 65536, // Σε 1/65536 του δευτερολέπτου
sync_bytes : 65536,
max_db : 256,
flag : (
flag::ENV::MDBX_EXCLUSIVE
| flag::ENV::MDBX_LIFORECLAIM
| flag::ENV::MDBX_COALESCE
| flag::ENV::MDBX_NOMEMINIT
| flag::ENV::MDBX_NOSUBDIR
| flag::ENV::MDBX_SAFE_NOSYNC
// | flag::ENV::MDBX_SYNC_DURABLE
),
pagesize:-1
};
}
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t:&[u8] = &val;
println!("{:?}",t);
},
None => unreachable!()
}
use anyhow::{Ok, Result};
use mdbx::prelude::*;
env_rw!(MDBX, {
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
});
mdbx! {
MDBX // Ονόματα μεταβλητών για τη βάση δεδομένων ENV
Test1
Test2
key Str
val Str
Test3
key i32
val u64
Test4
key u64
val u16
flag DUPSORT
}
fn main() -> Result<()> {
// Γρήγορη γραφή
w!(Test1.set [2, 3],[4, 5]);
// Γρήγορη ανάγνωση
match r!(Test1.get [2, 3]) {
Some(r) => {
println!(
"\nu16::from_le_bytes({:?}) = {}",
r,
u16::from_le_bytes((*r).try_into()?)
);
}
None => unreachable!(),
}
// Πολλαπλές λειτουργίες σε πολλαπλές βάσεις δεδομένων στην ίδια συναλλαγή
{
let tx = w!();
let test1 = tx | Test1;
test1.set(&[9], &[10, 12])?;
test1.set([8, 1], [9])?;
test1.set("rmw.link", "Down with Data Hegemony")?;
test1.set(&"abc", &"012")?;
println!("\n-- loop test1");
for (k, v) in test1 {
println!("{} = {}", k, v);
}
dbg!(test1.del_val([8, 1], [3])?);
dbg!(test1.get([8, 1])?.unwrap());
dbg!(test1.del_val([8, 1], [9])?);
dbg!(test1.get([8, 1])?);
dbg!(test1.del([9])?);
dbg!(test1.get([9])?);
dbg!(test1.del([9])?);
let test2 = tx | Test2;
test2.set("rmw.link", "Down with Data Hegemony")?;
test2.set(&"abc", &"012")?;
println!("\n-- loop test2");
for (k, v) in test2 {
println!("{} = {}", k, v);
}
let test3 = tx | Test3;
test3.set(13, 32)?;
test3.set(16, 32)?;
test3.set(-15, 6)?;
test3.set(-10, 6)?;
test3.set(-12, 6)?;
test3.set(0, 6)?;
test3.set(10, 5)?;
println!("\n-- loop test3");
for (k, v) in test3 {
println!("{:?} = {:?}", k, v);
}
let test4 = tx | Test4;
test4.set(10, 5)?;
test4.set(10, 0)?;
test4.set(13, 32)?;
test4.set(16, 2)?;
test4.set(16, 1)?;
test4.set(16, 3)?;
test4.set(0, 6)?;
test4.set(10, 5)?;
test4.set(0, 2)?;
dbg!(test4.del_val(0, 2)?);
dbg!(test4.del_val(0, 2)?);
println!("\n-- loop test4 rev");
for (k, v) in test4.rev() {
println!("{:?} = {:?}", k, v);
}
for i in test4.dup(16) {
println!("dup(16) {:?}", i);
}
// Η συναλλαγή θα δεσμευτεί στο τέλος του πεδίου εφαρμογής
}
Ok(())
}
Εκτελέστε την έξοδο
mdbx file path /Users/z/rmw/mdbx/target/debug/examples/02.mdb
u16::from_le_bytes(Bin([4, 5])) = 1284
-- loop test1
[2] = [3]
[2, 3] = [4, 5]
[8, 1] = [9]
[9] = [10, 12]
[97, 98, 99] = [48, 49, 50]
[114, 109, 119, 46, 108, 105, 110, 107] = [68, 111, 119, 110, 32, 119, 105, 116, 104, 32, 68, 97, 116, 97, 32, 72, 101, 103, 101, 109, 111, 110, 121]
[examples/02.rs:57] test1.del_val([8, 1], [3])? = false
[examples/02.rs:58] test1.get([8, 1])?.unwrap() = Bin(
[
9,
],
)
[examples/02.rs:59] test1.del_val([8, 1], [9])? = true
[examples/02.rs:60] test1.get([8, 1])? = None
[examples/02.rs:62] test1.del([9])? = true
[examples/02.rs:63] test1.get([9])? = None
[examples/02.rs:64] test1.del([9])? = false
-- loop test2
abc = 012
rmw.link = Down with Data Hegemony
-- loop test3
0 = 6
10 = 5
13 = 32
16 = 32
-15 = 6
-12 = 6
-10 = 6
[examples/02.rs:100] test4.del_val(0, 2)? = true
[examples/02.rs:101] test4.del_val(0, 2)? = false
-- loop test4 rev
16 = 3
16 = 2
16 = 1
13 = 32
10 = 5
10 = 0
0 = 6
dup(16) 1
dup(16) 2
dup(16) 3
Γρήγορες αναγνώσεις και εγγραφές
Αν θέλουμε απλώς να διαβάσουμε ή να γράψουμε μια μόνο γραμμή δεδομένων, μπορούμε να χρησιμοποιήσουμε τη συντακτική ζάχαρη μιας μακροεντολής.
Διαβάστε δεδομένα
r!(Test1.get [2, 3])
Γράφοντας δεδομένα
use db::User;
let id = 1234;
let user = r!(User.get id);
use anyhow::{Ok, Result};
use mdbx::prelude::*;
env_rw!(
MDBX,
{
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
},
r,
w
);
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
fn main() -> Result<()> {
// Εξαγωγή του αριθμού έκδοσης της libmdbx
unsafe {
println!(
"mdbx version https://github.com/erthink/libmdbx/releases/tag/v{}.{}.{}",
mdbx_version.major, mdbx_version.minor, mdbx_version.release
);
}
// Πολυνηματική ανάγνωση και εγγραφή
let t = std::thread::spawn(|| {
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t: &[u8] = &val;
println!("{:?}", t);
}
None => unreachable!(),
}
Ok(())
});
t.join().unwrap()?;
Ok(())
}
#[derive(Clone, Debug)]
pub struct Config {
path: PathBuf,
mode: ffi::mdbx_mode_t,
flag: flag::ENV,
sync_period: u64,
sync_bytes: u64,
max_db: u64,
pagesize: isize,
}
lazy_static! {
pub static ref ENV_CONFIG_DEFAULT: Config = Config {
path:PathBuf::new(),
mode: 0o600,
//https://github.com/erthink/libmdbx/issues/248
sync_period : 65536, // Σε 1/65536 του δευτερολέπτου
sync_bytes : 65536,
max_db : 256,
flag : (
flag::ENV::MDBX_EXCLUSIVE
| flag::ENV::MDBX_LIFORECLAIM
| flag::ENV::MDBX_COALESCE
| flag::ENV::MDBX_NOMEMINIT
| flag::ENV::MDBX_NOSUBDIR
| flag::ENV::MDBX_SAFE_NOSYNC
// | flag::ENV::MDBX_SYNC_DURABLE
),
pagesize:-1
};
}
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t:&[u8] = &val;
println!("{:?}",t);
},
None => unreachable!()
}
use anyhow::{Ok, Result};
use mdbx::prelude::*;
env_rw!(MDBX, {
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
});
mdbx! {
MDBX // Ονόματα μεταβλητών για τη βάση δεδομένων ENV
Test1
Test2
key Str
val Str
Test3
key i32
val u64
Test4
key u64
val u16
flag DUPSORT
}
fn main() -> Result<()> {
// Γρήγορη γραφή
w!(Test1.set [2, 3],[4, 5]);
// Γρήγορη ανάγνωση
match r!(Test1.get [2, 3]) {
Some(r) => {
println!(
"\nu16::from_le_bytes({:?}) = {}",
r,
u16::from_le_bytes((*r).try_into()?)
);
}
None => unreachable!(),
}
// Πολλαπλές λειτουργίες σε πολλαπλές βάσεις δεδομένων στην ίδια συναλλαγή
{
let tx = w!();
let test1 = tx | Test1;
test1.set(&[9], &[10, 12])?;
test1.set([8, 1], [9])?;
test1.set("rmw.link", "Down with Data Hegemony")?;
test1.set(&"abc", &"012")?;
println!("\n-- loop test1");
for (k, v) in test1 {
println!("{} = {}", k, v);
}
dbg!(test1.del_val([8, 1], [3])?);
dbg!(test1.get([8, 1])?.unwrap());
dbg!(test1.del_val([8, 1], [9])?);
dbg!(test1.get([8, 1])?);
dbg!(test1.del([9])?);
dbg!(test1.get([9])?);
dbg!(test1.del([9])?);
let test2 = tx | Test2;
test2.set("rmw.link", "Down with Data Hegemony")?;
test2.set(&"abc", &"012")?;
println!("\n-- loop test2");
for (k, v) in test2 {
println!("{} = {}", k, v);
}
let test3 = tx | Test3;
test3.set(13, 32)?;
test3.set(16, 32)?;
test3.set(-15, 6)?;
test3.set(-10, 6)?;
test3.set(-12, 6)?;
test3.set(0, 6)?;
test3.set(10, 5)?;
println!("\n-- loop test3");
for (k, v) in test3 {
println!("{:?} = {:?}", k, v);
}
let test4 = tx | Test4;
test4.set(10, 5)?;
test4.set(10, 0)?;
test4.set(13, 32)?;
test4.set(16, 2)?;
test4.set(16, 1)?;
test4.set(16, 3)?;
test4.set(0, 6)?;
test4.set(10, 5)?;
test4.set(0, 2)?;
dbg!(test4.del_val(0, 2)?);
dbg!(test4.del_val(0, 2)?);
println!("\n-- loop test4 rev");
for (k, v) in test4.rev() {
println!("{:?} = {:?}", k, v);
}
for i in test4.dup(16) {
println!("dup(16) {:?}", i);
}
// Η συναλλαγή θα δεσμευτεί στο τέλος του πεδίου εφαρμογής
}
Ok(())
}
w!(Test1.set [2, 3],[4, 5])
Όλα σε μία γραμμή, όπως γράφεται στο examples/02.rs.
Τύποι δεδομένων
Στο examples/02 . rs, ο ορισμός της βάσης δεδομένων έχει την εξής μορφή :
use db::User;
let id = 1234;
let user = r!(User.get id);
use anyhow::{Ok, Result};
use mdbx::prelude::*;
env_rw!(
MDBX,
{
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
},
r,
w
);
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
fn main() -> Result<()> {
// Εξαγωγή του αριθμού έκδοσης της libmdbx
unsafe {
println!(
"mdbx version https://github.com/erthink/libmdbx/releases/tag/v{}.{}.{}",
mdbx_version.major, mdbx_version.minor, mdbx_version.release
);
}
// Πολυνηματική ανάγνωση και εγγραφή
let t = std::thread::spawn(|| {
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t: &[u8] = &val;
println!("{:?}", t);
}
None => unreachable!(),
}
Ok(())
});
t.join().unwrap()?;
Ok(())
}
#[derive(Clone, Debug)]
pub struct Config {
path: PathBuf,
mode: ffi::mdbx_mode_t,
flag: flag::ENV,
sync_period: u64,
sync_bytes: u64,
max_db: u64,
pagesize: isize,
}
lazy_static! {
pub static ref ENV_CONFIG_DEFAULT: Config = Config {
path:PathBuf::new(),
mode: 0o600,
//https://github.com/erthink/libmdbx/issues/248
sync_period : 65536, // Σε 1/65536 του δευτερολέπτου
sync_bytes : 65536,
max_db : 256,
flag : (
flag::ENV::MDBX_EXCLUSIVE
| flag::ENV::MDBX_LIFORECLAIM
| flag::ENV::MDBX_COALESCE
| flag::ENV::MDBX_NOMEMINIT
| flag::ENV::MDBX_NOSUBDIR
| flag::ENV::MDBX_SAFE_NOSYNC
// | flag::ENV::MDBX_SYNC_DURABLE
),
pagesize:-1
};
}
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t:&[u8] = &val;
println!("{:?}",t);
},
None => unreachable!()
}
use anyhow::{Ok, Result};
use mdbx::prelude::*;
env_rw!(MDBX, {
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
});
mdbx! {
MDBX // Ονόματα μεταβλητών για τη βάση δεδομένων ENV
Test1
Test2
key Str
val Str
Test3
key i32
val u64
Test4
key u64
val u16
flag DUPSORT
}
fn main() -> Result<()> {
// Γρήγορη γραφή
w!(Test1.set [2, 3],[4, 5]);
// Γρήγορη ανάγνωση
match r!(Test1.get [2, 3]) {
Some(r) => {
println!(
"\nu16::from_le_bytes({:?}) = {}",
r,
u16::from_le_bytes((*r).try_into()?)
);
}
None => unreachable!(),
}
// Πολλαπλές λειτουργίες σε πολλαπλές βάσεις δεδομένων στην ίδια συναλλαγή
{
let tx = w!();
let test1 = tx | Test1;
test1.set(&[9], &[10, 12])?;
test1.set([8, 1], [9])?;
test1.set("rmw.link", "Down with Data Hegemony")?;
test1.set(&"abc", &"012")?;
println!("\n-- loop test1");
for (k, v) in test1 {
println!("{} = {}", k, v);
}
dbg!(test1.del_val([8, 1], [3])?);
dbg!(test1.get([8, 1])?.unwrap());
dbg!(test1.del_val([8, 1], [9])?);
dbg!(test1.get([8, 1])?);
dbg!(test1.del([9])?);
dbg!(test1.get([9])?);
dbg!(test1.del([9])?);
let test2 = tx | Test2;
test2.set("rmw.link", "Down with Data Hegemony")?;
test2.set(&"abc", &"012")?;
println!("\n-- loop test2");
for (k, v) in test2 {
println!("{} = {}", k, v);
}
let test3 = tx | Test3;
test3.set(13, 32)?;
test3.set(16, 32)?;
test3.set(-15, 6)?;
test3.set(-10, 6)?;
test3.set(-12, 6)?;
test3.set(0, 6)?;
test3.set(10, 5)?;
println!("\n-- loop test3");
for (k, v) in test3 {
println!("{:?} = {:?}", k, v);
}
let test4 = tx | Test4;
test4.set(10, 5)?;
test4.set(10, 0)?;
test4.set(13, 32)?;
test4.set(16, 2)?;
test4.set(16, 1)?;
test4.set(16, 3)?;
test4.set(0, 6)?;
test4.set(10, 5)?;
test4.set(0, 2)?;
dbg!(test4.del_val(0, 2)?);
dbg!(test4.del_val(0, 2)?);
println!("\n-- loop test4 rev");
for (k, v) in test4.rev() {
println!("{:?} = {:?}", k, v);
}
for i in test4.dup(16) {
println!("dup(16) {:?}", i);
}
// Η συναλλαγή θα δεσμευτεί στο τέλος του πεδίου εφαρμογής
}
Ok(())
}
w!(Test1.set [2, 3],[4, 5])
Test2
key Str
val Str
Test3
key i32
val u64
Test4
key u64
val u16
flag DUPSORT
όπου key
και val
ορίζουν τους τύπους δεδομένων για τα κλειδιά και τις τιμές αντίστοιχα.
Αν προσπαθήσετε να γράψετε έναν τύπο δεδομένων που δεν ταιριάζει με τον τύπο που έχει οριστεί, θα αναφερθεί ένα σφάλμα, όπως φαίνεται στο παρακάτω στιγμιότυπο :
Ο προεπιλεγμένος τύπος δεδομένων είναι Bin
, μπορούν να εγγραφούν οποιαδήποτε δεδομένα που υλοποιούν το AsRef<[u8]>
.
Εάν το κλειδί ή η τιμή είναι συμβολοσειρά utf8
, ο τύπος δεδομένων μπορεί να οριστεί σε Str
.
Η αποδέσμευση του Str
θα επιστρέψει ένα αλφαριθμητικό, παρόμοιο με το let k:&str = &k;
.
Επιπλέον, το Str
εφαρμόζει επίσης std::fmt::Display
, το println!("{}",k)
θα εξάγει μια αναγνώσιμη συμβολοσειρά.
Προκαθορισμένοι τύποι δεδομένων
Εκτός από τα Str
και Bin
, το περιτύλιγμα διαθέτει επίσης υποστήριξη δεδομένων για usize, u128, u64, u32, u16, u8, isize, i128, i64, i32, i16, i8, f32, f64.
Σημαίες βάσης δεδομένων
Μπορείτε να δείτε τις σημαίες της βάσης δεδομένων που προστίθενται στα δεδομένα στο examples/02.rs στη διεύθυνση Test4
. flag DUPSORT
Η βάση δεδομένων libmdbx έχει μια σειρά από σημαίες ( MDBX_db_flags_t
) που μπορούν να οριστούν.
- Το REVERSEKEY χρησιμοποιεί αντίστροφη σύγκριση συμβολοσειρών για τα κλειδιά. (χρήσιμο όταν χρησιμοποιούνται μικροί κωδικοποιημένοι αριθμοί ως κλειδιά)
- Το DUPSORT χρησιμοποιεί ταξινομημένα αντίγραφα, δηλαδή επιτρέπει πολλαπλές τιμές για ένα κλειδί.
- INTEGERKEY Μητρικό αριθμητικό κλειδί σε διάταξη byte uint32_t ή uint64_t. Τα κλειδιά πρέπει να έχουν το ίδιο μέγεθος και να είναι ευθυγραμμισμένα όταν περνούν ως ορίσματα.
- DUPFIXED Το μέγεθος των τιμών των δεδομένων πρέπει να είναι το ίδιο εάν χρησιμοποιείται DUPSORT (επιτρέπει μια γρήγορη καταμέτρηση του αριθμού των τιμών).
- Οι DUPSORT και DUPFIXED απαιτούνται για την INTEGERDUP- οι τιμές είναι ακέραιοι αριθμοί (παρόμοιες με την INTEGERKEY). Οι τιμές δεδομένων πρέπει να έχουν όλες το ίδιο μέγεθος και να είναι ευθυγραμμισμένες όταν περνούν ως παράμετροι.
- Το REVERSEDUP χρησιμοποιεί το DUPSORT- η αντίστροφη σύγκριση συμβολοσειρών χρησιμοποιείται για τις τιμές δεδομένων.
- Η CREATE δημιουργεί τη ΒΔ αν δεν υπάρχει (προστίθεται από προεπιλογή).
- DB_ACCEDE Ανοίγει μια υπάρχουσα υπο-βάση δεδομένων που δημιουργήθηκε με τη χρήση της σημαίας unknown.
Αυτή η σημαία DB_ACCEDE προορίζεται για το άνοιγμα υφιστάμενων υπο-βάσεων δεδομένων που έχουν δημιουργηθεί με άγνωστες σημαίες (REVERSEKEY, DUPSORT, INTEGERKEY, DUPFIXED, INTEGERDUP και REVERSEDUP).
Σε αυτή την περίπτωση, η υποβάση δεδομένων δεν θα επιστρέψει σφάλμα INCOMPATIBLE, αλλά θα ανοίξει με τις σημαίες που χρησιμοποιήθηκαν για τη δημιουργία της και η εφαρμογή μπορεί στη συνέχεια να προσδιορίσει τις πραγματικές σημαίες με την mdbx_dbi_flags().
DUPSORT : Ένα κλειδί αντιστοιχεί σε περισσότερες από μία τιμές
DUPSORT
σημαίνει ότι ένα κλειδί μπορεί να αντιστοιχεί σε περισσότερες από μία τιμές.
Αν θέλετε να ορίσετε πολλαπλές σημαίες, γράψτε ως εξής flag DUPSORT | DUPFIXED
.dup(key)
iterator που επιστρέφει όλες τις τιμές που αντιστοιχούν σε ένα κλειδί
Η λειτουργία αυτή είναι διαθέσιμη μόνο για βάσεις δεδομένων με την ένδειξη DUPSORT
, όπου ένα κλειδί μπορεί να αντιστοιχεί σε περισσότερες από μία τιμές.
Για τις βάσεις δεδομένων DUPSORT
, το get
επιστρέφει μόνο την πρώτη τιμή για αυτό το κλειδί. Για να λάβετε όλες τις τιμές, χρησιμοποιήστε το dup
.
Προεπιλεγμένες σημαίες βάσης δεδομένων που προσαρτώνται αυτόματα
Όταν ο τύπος δεδομένων είναι u32
/ u64
/ usize
, η σημαία βάσης δεδομένων προστίθεται αυτόματα. INTEGERKEY
.
Σε μηχανήματα με κωδικοποίηση μικρού άκρου, προστίθενται αυτόματα άλλοι αριθμητικοί τύποι REVERSEKEY
Η σημαία βάσης δεδομένων προστίθεται αυτόματα όταν ο τύπος δεδομένων είναι / / .
Διαγραφή δεδομένων
.del(key)
Διαγραφή ενός πλήκτρου
.del(val)
Διαγράφει την τιμή που αντιστοιχεί σε ένα κλειδί.
Εάν η βάση δεδομένων έχει τη σημαία DUPSORT
, όλες οι τιμές κάτω από αυτό το κλειδί θα διαγραφούν.
Επιστρέφει true
εάν έχουν διαγραφεί δεδομένα και false
εάν όχι.
.del_val(key,val)
Διαγραφή ακριβούς αντιστοιχίας
.del_val(key,val)
Διαγράφει ζεύγη κλειδιών-τιμών που ταιριάζουν ακριβώς με τις παραμέτρους εισόδου.
Επιστρέφει true
εάν έχουν διαγραφεί δεδομένα και false
εάν όχι.
Διαδρομή
διαδοχική διάσχιση
Λόγω της εφαρμογής του std::iter::IntoIterator
. μπορείτε να διασχίσετε απευθείας ως εξής :
for (k, v) in test1
.rev()
Αντίστροφη διάσχιση σειράς
for (k, v) in test4.rev()
Ταξινόμηση
Τα κλειδιά της libmdbx είναι ταξινομημένα κατά σειρά λεξικού.
Για αριθμούς χωρίς πρόσημο
ταξινομούνται από το μικρότερο προς το μεγαλύτερο, επειδή οι σημαίες της βάσης δεδομένων προστίθενται αυτόματα (
u32
/u64
/usize
προστίθενται στοINTEGERKEY
, ενώ άλλες προστίθενται στοREVERSEKEY
ανάλογα με τον κώδικα μηχανής).Για προσημασμένους αριθμούς
η σειρά είναι: πρώτα το 0, μετά όλοι οι θετικοί αριθμοί από τον μικρότερο προς τον μεγαλύτερο, μετά όλοι οι αρνητικοί αριθμοί από τον μικρότερο προς τον μεγαλύτερο.
Επαναλήπτες διαστήματος
use db::User;
let id = 1234;
let user = r!(User.get id);
use anyhow::{Ok, Result};
use mdbx::prelude::*;
env_rw!(
MDBX,
{
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
},
r,
w
);
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
fn main() -> Result<()> {
// Εξαγωγή του αριθμού έκδοσης της libmdbx
unsafe {
println!(
"mdbx version https://github.com/erthink/libmdbx/releases/tag/v{}.{}.{}",
mdbx_version.major, mdbx_version.minor, mdbx_version.release
);
}
// Πολυνηματική ανάγνωση και εγγραφή
let t = std::thread::spawn(|| {
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t: &[u8] = &val;
println!("{:?}", t);
}
None => unreachable!(),
}
Ok(())
});
t.join().unwrap()?;
Ok(())
}
#[derive(Clone, Debug)]
pub struct Config {
path: PathBuf,
mode: ffi::mdbx_mode_t,
flag: flag::ENV,
sync_period: u64,
sync_bytes: u64,
max_db: u64,
pagesize: isize,
}
lazy_static! {
pub static ref ENV_CONFIG_DEFAULT: Config = Config {
path:PathBuf::new(),
mode: 0o600,
//https://github.com/erthink/libmdbx/issues/248
sync_period : 65536, // Σε 1/65536 του δευτερολέπτου
sync_bytes : 65536,
max_db : 256,
flag : (
flag::ENV::MDBX_EXCLUSIVE
| flag::ENV::MDBX_LIFORECLAIM
| flag::ENV::MDBX_COALESCE
| flag::ENV::MDBX_NOMEMINIT
| flag::ENV::MDBX_NOSUBDIR
| flag::ENV::MDBX_SAFE_NOSYNC
// | flag::ENV::MDBX_SYNC_DURABLE
),
pagesize:-1
};
}
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t:&[u8] = &val;
println!("{:?}",t);
},
None => unreachable!()
}
use anyhow::{Ok, Result};
use mdbx::prelude::*;
env_rw!(MDBX, {
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
});
mdbx! {
MDBX // Ονόματα μεταβλητών για τη βάση δεδομένων ENV
Test1
Test2
key Str
val Str
Test3
key i32
val u64
Test4
key u64
val u16
flag DUPSORT
}
fn main() -> Result<()> {
// Γρήγορη γραφή
w!(Test1.set [2, 3],[4, 5]);
// Γρήγορη ανάγνωση
match r!(Test1.get [2, 3]) {
Some(r) => {
println!(
"\nu16::from_le_bytes({:?}) = {}",
r,
u16::from_le_bytes((*r).try_into()?)
);
}
None => unreachable!(),
}
// Πολλαπλές λειτουργίες σε πολλαπλές βάσεις δεδομένων στην ίδια συναλλαγή
{
let tx = w!();
let test1 = tx | Test1;
test1.set(&[9], &[10, 12])?;
test1.set([8, 1], [9])?;
test1.set("rmw.link", "Down with Data Hegemony")?;
test1.set(&"abc", &"012")?;
println!("\n-- loop test1");
for (k, v) in test1 {
println!("{} = {}", k, v);
}
dbg!(test1.del_val([8, 1], [3])?);
dbg!(test1.get([8, 1])?.unwrap());
dbg!(test1.del_val([8, 1], [9])?);
dbg!(test1.get([8, 1])?);
dbg!(test1.del([9])?);
dbg!(test1.get([9])?);
dbg!(test1.del([9])?);
let test2 = tx | Test2;
test2.set("rmw.link", "Down with Data Hegemony")?;
test2.set(&"abc", &"012")?;
println!("\n-- loop test2");
for (k, v) in test2 {
println!("{} = {}", k, v);
}
let test3 = tx | Test3;
test3.set(13, 32)?;
test3.set(16, 32)?;
test3.set(-15, 6)?;
test3.set(-10, 6)?;
test3.set(-12, 6)?;
test3.set(0, 6)?;
test3.set(10, 5)?;
println!("\n-- loop test3");
for (k, v) in test3 {
println!("{:?} = {:?}", k, v);
}
let test4 = tx | Test4;
test4.set(10, 5)?;
test4.set(10, 0)?;
test4.set(13, 32)?;
test4.set(16, 2)?;
test4.set(16, 1)?;
test4.set(16, 3)?;
test4.set(0, 6)?;
test4.set(10, 5)?;
test4.set(0, 2)?;
dbg!(test4.del_val(0, 2)?);
dbg!(test4.del_val(0, 2)?);
println!("\n-- loop test4 rev");
for (k, v) in test4.rev() {
println!("{:?} = {:?}", k, v);
}
for i in test4.dup(16) {
println!("dup(16) {:?}", i);
}
// Η συναλλαγή θα δεσμευτεί στο τέλος του πεδίου εφαρμογής
}
Ok(())
}
w!(Test1.set [2, 3],[4, 5])
Test2
key Str
val Str
Test3
key i32
val u64
Test4
key u64
val u16
flag DUPSORT
use anyhow::Result;
use mdbx::prelude::*;
env_rw!(MDBX, {
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
});
mdbx! {
MDBX
Test0
Test1
key u16
val u64
flag DUPSORT
Test2
key u32
val u64
}
macro_rules! range_rev {
($var:ident, $range:expr) => {
println!("\n# {}.rev_range({:?})", stringify!($var), $range);
for i in $var.range_rev($range) {
println!("{:?}", i);
}
};
}
macro_rules! range {
($var:ident, $range:expr) => {
println!("\n# {}.range({:?})", stringify!($var), $range);
for i in $var.range($range) {
println!("{:?}", i);
}
};
}
fn main() -> Result<()> {
{
println!("\n> Test0");
let tx = &MDBX.w()?;
let test0 = tx | Test0;
test0.set([0], [0, 1])?;
test0.set([1], [1, 2])?;
test0.set([2], [2, 3])?;
test0.set([1, 1], [1, 3])?;
test0.set([1, 2], [1, 3])?;
test0.set([3], [])?;
range!(test0, [1]..);
let begin: &[u8] = &[1, 1];
range!(test0, begin..=&[2]);
}
{
let tx = &MDBX.w()?;
let test1 = tx | Test1;
test1.set(2, 9)?;
test1.set(2, 4)?;
test1.set(9, 7)?;
test1.set(3, 0)?;
test1.set(3, 8)?;
test1.set(5, 3)?;
test1.set(5, 8)?;
test1.set(9, 1)?;
println!("-- all");
for i in test1 {
println!("{:?}", i);
}
range!(test1, 1..3);
range!(test1, 5..2);
range!(test1, 1..=3);
range!(test1, ..3);
range!(test1, 3..);
range_rev!(test1, ..1);
range_rev!(test1, ..=1);
}
{
println!("\n> Test2");
let tx = &MDBX.w()?;
let test2 = tx | Test2;
test2.set(2, 9)?;
test2.set(1, 2)?;
test2.set(2, 4)?;
test2.set(1, 5)?;
test2.set(9, 7)?;
test2.set(9, 1)?;
test2.set(0, 0)?;
range!(test2, 1..3);
range!(test2, 1..=3);
range!(test2, ..3);
range!(test2, 2..);
range_rev!(test2, ..1);
range_rev!(test2, 2..);
range_rev!(test2, ..=1);
}
Ok(())
}
Εκτελέστε την έξοδο του
mdbx file path /Users/z/rmw/mdbx/target/debug/examples/range.mdb
> Test0
# test0.range([1]..)
(Bin([1]), Bin([1, 2]))
(Bin([1, 1]), Bin([1, 3]))
(Bin([1, 2]), Bin([1, 3]))
(Bin([2]), Bin([2, 3]))
(Bin([3]), Bin([]))
# test0.range([1, 1]..=[2])
(Bin([1, 1]), Bin([1, 3]))
(Bin([1, 2]), Bin([1, 3]))
(Bin([2]), Bin([2, 3]))
-- all
(2, 4)
(2, 9)
(3, 0)
(3, 8)
(5, 3)
(5, 8)
(9, 1)
(9, 2)
(9, 7)
# test1.range(1..3)
(2, 4)
(2, 9)
# test1.range(5..2)
(5, 8)
(5, 3)
(3, 8)
(3, 0)
# test1.range(1..=3)
(2, 4)
(2, 9)
(3, 0)
(3, 8)
# test1.range(..3)
(2, 4)
(2, 9)
# test1.range(3..)
(3, 0)
(3, 8)
(5, 3)
(5, 8)
(9, 1)
(9, 2)
(9, 7)
# test1.rev_range(..1)
(9, 7)
(9, 2)
(9, 1)
(5, 8)
(5, 3)
(3, 8)
(3, 0)
(2, 9)
(2, 4)
# test1.rev_range(..=1)
(9, 7)
(9, 2)
(9, 1)
(5, 8)
(5, 3)
(3, 8)
(3, 0)
(2, 9)
(2, 4)
> Test2
# test2.range(1..3)
(1, 5)
(2, 4)
# test2.range(1..=3)
(1, 5)
(2, 4)
# test2.range(..3)
(0, 0)
(1, 5)
(2, 4)
# test2.range(2..)
(2, 4)
(9, 1)
# test2.rev_range(..1)
(9, 1)
(2, 4)
# test2.rev_range(2..)
(2, 4)
(1, 5)
(0, 0)
# test2.rev_range(..=1)
(9, 1)
(2, 4)
(1, 5)
.range(begin..end)
Διάστημα επανάληψης
Για τους αριθμούς, ένα διάστημα είναι ένα αριθμητικό διάστημα.
Για το δυαδικό σύστημα, το ίδιο διάστημα μπορεί να κατασκευαστεί, π.χ.
let begin : &[u8] = &[1,1];
for (k,v) in test0.range(begin..=&[2]) {}
Εάν το begin
είναι μεγαλύτερο από το end
, θα γίνει επανάληψη προς τα πίσω.
Για παράδειγμα, το test1.range(5..2)
θα βγάλει τα εξής :
use db::User;
let id = 1234;
let user = r!(User.get id);
use anyhow::{Ok, Result};
use mdbx::prelude::*;
env_rw!(
MDBX,
{
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
},
r,
w
);
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
fn main() -> Result<()> {
// Εξαγωγή του αριθμού έκδοσης της libmdbx
unsafe {
println!(
"mdbx version https://github.com/erthink/libmdbx/releases/tag/v{}.{}.{}",
mdbx_version.major, mdbx_version.minor, mdbx_version.release
);
}
// Πολυνηματική ανάγνωση και εγγραφή
let t = std::thread::spawn(|| {
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t: &[u8] = &val;
println!("{:?}", t);
}
None => unreachable!(),
}
Ok(())
});
t.join().unwrap()?;
Ok(())
}
#[derive(Clone, Debug)]
pub struct Config {
path: PathBuf,
mode: ffi::mdbx_mode_t,
flag: flag::ENV,
sync_period: u64,
sync_bytes: u64,
max_db: u64,
pagesize: isize,
}
lazy_static! {
pub static ref ENV_CONFIG_DEFAULT: Config = Config {
path:PathBuf::new(),
mode: 0o600,
//https://github.com/erthink/libmdbx/issues/248
sync_period : 65536, // Σε 1/65536 του δευτερολέπτου
sync_bytes : 65536,
max_db : 256,
flag : (
flag::ENV::MDBX_EXCLUSIVE
| flag::ENV::MDBX_LIFORECLAIM
| flag::ENV::MDBX_COALESCE
| flag::ENV::MDBX_NOMEMINIT
| flag::ENV::MDBX_NOSUBDIR
| flag::ENV::MDBX_SAFE_NOSYNC
// | flag::ENV::MDBX_SYNC_DURABLE
),
pagesize:-1
};
}
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t:&[u8] = &val;
println!("{:?}",t);
},
None => unreachable!()
}
use anyhow::{Ok, Result};
use mdbx::prelude::*;
env_rw!(MDBX, {
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
});
mdbx! {
MDBX // Ονόματα μεταβλητών για τη βάση δεδομένων ENV
Test1
Test2
key Str
val Str
Test3
key i32
val u64
Test4
key u64
val u16
flag DUPSORT
}
fn main() -> Result<()> {
// Γρήγορη γραφή
w!(Test1.set [2, 3],[4, 5]);
// Γρήγορη ανάγνωση
match r!(Test1.get [2, 3]) {
Some(r) => {
println!(
"\nu16::from_le_bytes({:?}) = {}",
r,
u16::from_le_bytes((*r).try_into()?)
);
}
None => unreachable!(),
}
// Πολλαπλές λειτουργίες σε πολλαπλές βάσεις δεδομένων στην ίδια συναλλαγή
{
let tx = w!();
let test1 = tx | Test1;
test1.set(&[9], &[10, 12])?;
test1.set([8, 1], [9])?;
test1.set("rmw.link", "Down with Data Hegemony")?;
test1.set(&"abc", &"012")?;
println!("\n-- loop test1");
for (k, v) in test1 {
println!("{} = {}", k, v);
}
dbg!(test1.del_val([8, 1], [3])?);
dbg!(test1.get([8, 1])?.unwrap());
dbg!(test1.del_val([8, 1], [9])?);
dbg!(test1.get([8, 1])?);
dbg!(test1.del([9])?);
dbg!(test1.get([9])?);
dbg!(test1.del([9])?);
let test2 = tx | Test2;
test2.set("rmw.link", "Down with Data Hegemony")?;
test2.set(&"abc", &"012")?;
println!("\n-- loop test2");
for (k, v) in test2 {
println!("{} = {}", k, v);
}
let test3 = tx | Test3;
test3.set(13, 32)?;
test3.set(16, 32)?;
test3.set(-15, 6)?;
test3.set(-10, 6)?;
test3.set(-12, 6)?;
test3.set(0, 6)?;
test3.set(10, 5)?;
println!("\n-- loop test3");
for (k, v) in test3 {
println!("{:?} = {:?}", k, v);
}
let test4 = tx | Test4;
test4.set(10, 5)?;
test4.set(10, 0)?;
test4.set(13, 32)?;
test4.set(16, 2)?;
test4.set(16, 1)?;
test4.set(16, 3)?;
test4.set(0, 6)?;
test4.set(10, 5)?;
test4.set(0, 2)?;
dbg!(test4.del_val(0, 2)?);
dbg!(test4.del_val(0, 2)?);
println!("\n-- loop test4 rev");
for (k, v) in test4.rev() {
println!("{:?} = {:?}", k, v);
}
for i in test4.dup(16) {
println!("dup(16) {:?}", i);
}
// Η συναλλαγή θα δεσμευτεί στο τέλος του πεδίου εφαρμογής
}
Ok(())
}
w!(Test1.set [2, 3],[4, 5])
Test2
key Str
val Str
Test3
key i32
val u64
Test4
key u64
val u16
flag DUPSORT
use anyhow::Result;
use mdbx::prelude::*;
env_rw!(MDBX, {
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
});
mdbx! {
MDBX
Test0
Test1
key u16
val u64
flag DUPSORT
Test2
key u32
val u64
}
macro_rules! range_rev {
($var:ident, $range:expr) => {
println!("\n# {}.rev_range({:?})", stringify!($var), $range);
for i in $var.range_rev($range) {
println!("{:?}", i);
}
};
}
macro_rules! range {
($var:ident, $range:expr) => {
println!("\n# {}.range({:?})", stringify!($var), $range);
for i in $var.range($range) {
println!("{:?}", i);
}
};
}
fn main() -> Result<()> {
{
println!("\n> Test0");
let tx = &MDBX.w()?;
let test0 = tx | Test0;
test0.set([0], [0, 1])?;
test0.set([1], [1, 2])?;
test0.set([2], [2, 3])?;
test0.set([1, 1], [1, 3])?;
test0.set([1, 2], [1, 3])?;
test0.set([3], [])?;
range!(test0, [1]..);
let begin: &[u8] = &[1, 1];
range!(test0, begin..=&[2]);
}
{
let tx = &MDBX.w()?;
let test1 = tx | Test1;
test1.set(2, 9)?;
test1.set(2, 4)?;
test1.set(9, 7)?;
test1.set(3, 0)?;
test1.set(3, 8)?;
test1.set(5, 3)?;
test1.set(5, 8)?;
test1.set(9, 1)?;
println!("-- all");
for i in test1 {
println!("{:?}", i);
}
range!(test1, 1..3);
range!(test1, 5..2);
range!(test1, 1..=3);
range!(test1, ..3);
range!(test1, 3..);
range_rev!(test1, ..1);
range_rev!(test1, ..=1);
}
{
println!("\n> Test2");
let tx = &MDBX.w()?;
let test2 = tx | Test2;
test2.set(2, 9)?;
test2.set(1, 2)?;
test2.set(2, 4)?;
test2.set(1, 5)?;
test2.set(9, 7)?;
test2.set(9, 1)?;
test2.set(0, 0)?;
range!(test2, 1..3);
range!(test2, 1..=3);
range!(test2, ..3);
range!(test2, 2..);
range_rev!(test2, ..1);
range_rev!(test2, 2..);
range_rev!(test2, ..=1);
}
Ok(())
}
(5, 8)
(5, 3)
(3, 8)
(3, 0)
Δεν υποστηρίζεται η διαλειμματική επανάληψη RangeFull
, δηλ. η χρήση του ..
δεν υποστηρίζεται, χρησιμοποιήστε αντ' αυτού την προαναφερθείσα αντιστροφή.
.rev_range
Αντεστραμμένα διαστήματα
Αν θέλετε να λάβετε ένα ανεστραμμένο διάστημα που είναι μικρότερο ή ίσο από μια τιμή, μπορείτε να κάνετε το εξής
test2.rev_range(2..)
Η έξοδος θα είναι
(2, 4)
(1, 5)
(0, 0)
Ένα από τα begin
ή end
δεν πρέπει να οριστεί για το ανεστραμμένο διάστημα, διότι αν οριστούν και τα δύο, μπορείτε πάντα να χρησιμοποιήσετε το range(end..begin)
για να επιτύχετε το ίδιο αποτέλεσμα.
Προσαρμογή τύπων δεδομένων
Ο κώδικας επίδειξης είναι διαθέσιμος στη διεύθυνση github.com/rmw-lib/mdbx-example/01
use db::User;
let id = 1234;
let user = r!(User.get id);
use anyhow::{Ok, Result};
use mdbx::prelude::*;
env_rw!(
MDBX,
{
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
},
r,
w
);
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
fn main() -> Result<()> {
// Εξαγωγή του αριθμού έκδοσης της libmdbx
unsafe {
println!(
"mdbx version https://github.com/erthink/libmdbx/releases/tag/v{}.{}.{}",
mdbx_version.major, mdbx_version.minor, mdbx_version.release
);
}
// Πολυνηματική ανάγνωση και εγγραφή
let t = std::thread::spawn(|| {
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t: &[u8] = &val;
println!("{:?}", t);
}
None => unreachable!(),
}
Ok(())
});
t.join().unwrap()?;
Ok(())
}
#[derive(Clone, Debug)]
pub struct Config {
path: PathBuf,
mode: ffi::mdbx_mode_t,
flag: flag::ENV,
sync_period: u64,
sync_bytes: u64,
max_db: u64,
pagesize: isize,
}
lazy_static! {
pub static ref ENV_CONFIG_DEFAULT: Config = Config {
path:PathBuf::new(),
mode: 0o600,
//https://github.com/erthink/libmdbx/issues/248
sync_period : 65536, // Σε 1/65536 του δευτερολέπτου
sync_bytes : 65536,
max_db : 256,
flag : (
flag::ENV::MDBX_EXCLUSIVE
| flag::ENV::MDBX_LIFORECLAIM
| flag::ENV::MDBX_COALESCE
| flag::ENV::MDBX_NOMEMINIT
| flag::ENV::MDBX_NOSUBDIR
| flag::ENV::MDBX_SAFE_NOSYNC
// | flag::ENV::MDBX_SYNC_DURABLE
),
pagesize:-1
};
}
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t:&[u8] = &val;
println!("{:?}",t);
},
None => unreachable!()
}
use anyhow::{Ok, Result};
use mdbx::prelude::*;
env_rw!(MDBX, {
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
});
mdbx! {
MDBX // Ονόματα μεταβλητών για τη βάση δεδομένων ENV
Test1
Test2
key Str
val Str
Test3
key i32
val u64
Test4
key u64
val u16
flag DUPSORT
}
fn main() -> Result<()> {
// Γρήγορη γραφή
w!(Test1.set [2, 3],[4, 5]);
// Γρήγορη ανάγνωση
match r!(Test1.get [2, 3]) {
Some(r) => {
println!(
"\nu16::from_le_bytes({:?}) = {}",
r,
u16::from_le_bytes((*r).try_into()?)
);
}
None => unreachable!(),
}
// Πολλαπλές λειτουργίες σε πολλαπλές βάσεις δεδομένων στην ίδια συναλλαγή
{
let tx = w!();
let test1 = tx | Test1;
test1.set(&[9], &[10, 12])?;
test1.set([8, 1], [9])?;
test1.set("rmw.link", "Down with Data Hegemony")?;
test1.set(&"abc", &"012")?;
println!("\n-- loop test1");
for (k, v) in test1 {
println!("{} = {}", k, v);
}
dbg!(test1.del_val([8, 1], [3])?);
dbg!(test1.get([8, 1])?.unwrap());
dbg!(test1.del_val([8, 1], [9])?);
dbg!(test1.get([8, 1])?);
dbg!(test1.del([9])?);
dbg!(test1.get([9])?);
dbg!(test1.del([9])?);
let test2 = tx | Test2;
test2.set("rmw.link", "Down with Data Hegemony")?;
test2.set(&"abc", &"012")?;
println!("\n-- loop test2");
for (k, v) in test2 {
println!("{} = {}", k, v);
}
let test3 = tx | Test3;
test3.set(13, 32)?;
test3.set(16, 32)?;
test3.set(-15, 6)?;
test3.set(-10, 6)?;
test3.set(-12, 6)?;
test3.set(0, 6)?;
test3.set(10, 5)?;
println!("\n-- loop test3");
for (k, v) in test3 {
println!("{:?} = {:?}", k, v);
}
let test4 = tx | Test4;
test4.set(10, 5)?;
test4.set(10, 0)?;
test4.set(13, 32)?;
test4.set(16, 2)?;
test4.set(16, 1)?;
test4.set(16, 3)?;
test4.set(0, 6)?;
test4.set(10, 5)?;
test4.set(0, 2)?;
dbg!(test4.del_val(0, 2)?);
dbg!(test4.del_val(0, 2)?);
println!("\n-- loop test4 rev");
for (k, v) in test4.rev() {
println!("{:?} = {:?}", k, v);
}
for i in test4.dup(16) {
println!("dup(16) {:?}", i);
}
// Η συναλλαγή θα δεσμευτεί στο τέλος του πεδίου εφαρμογής
}
Ok(())
}
w!(Test1.set [2, 3],[4, 5])
Test2
key Str
val Str
Test3
key i32
val u64
Test4
key u64
val u16
flag DUPSORT
use anyhow::Result;
use mdbx::prelude::*;
env_rw!(MDBX, {
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
});
mdbx! {
MDBX
Test0
Test1
key u16
val u64
flag DUPSORT
Test2
key u32
val u64
}
macro_rules! range_rev {
($var:ident, $range:expr) => {
println!("\n# {}.rev_range({:?})", stringify!($var), $range);
for i in $var.range_rev($range) {
println!("{:?}", i);
}
};
}
macro_rules! range {
($var:ident, $range:expr) => {
println!("\n# {}.range({:?})", stringify!($var), $range);
for i in $var.range($range) {
println!("{:?}", i);
}
};
}
fn main() -> Result<()> {
{
println!("\n> Test0");
let tx = &MDBX.w()?;
let test0 = tx | Test0;
test0.set([0], [0, 1])?;
test0.set([1], [1, 2])?;
test0.set([2], [2, 3])?;
test0.set([1, 1], [1, 3])?;
test0.set([1, 2], [1, 3])?;
test0.set([3], [])?;
range!(test0, [1]..);
let begin: &[u8] = &[1, 1];
range!(test0, begin..=&[2]);
}
{
let tx = &MDBX.w()?;
let test1 = tx | Test1;
test1.set(2, 9)?;
test1.set(2, 4)?;
test1.set(9, 7)?;
test1.set(3, 0)?;
test1.set(3, 8)?;
test1.set(5, 3)?;
test1.set(5, 8)?;
test1.set(9, 1)?;
println!("-- all");
for i in test1 {
println!("{:?}", i);
}
range!(test1, 1..3);
range!(test1, 5..2);
range!(test1, 1..=3);
range!(test1, ..3);
range!(test1, 3..);
range_rev!(test1, ..1);
range_rev!(test1, ..=1);
}
{
println!("\n> Test2");
let tx = &MDBX.w()?;
let test2 = tx | Test2;
test2.set(2, 9)?;
test2.set(1, 2)?;
test2.set(2, 4)?;
test2.set(1, 5)?;
test2.set(9, 7)?;
test2.set(9, 1)?;
test2.set(0, 0)?;
range!(test2, 1..3);
range!(test2, 1..=3);
range!(test2, ..3);
range!(test2, 2..);
range_rev!(test2, ..1);
range_rev!(test2, 2..);
range_rev!(test2, ..=1);
}
Ok(())
}
(5, 8)
(5, 3)
(3, 8)
(3, 0)
use anyhow::Result;
use mdbx::prelude::*;
use speedy::{Readable, Writable};
#[derive(PartialEq, Debug, Readable, Writable)]
pub struct City {
name: String,
lnglat: (u32, u32),
}
impl FromMdbx for City {
fn from_mdbx(_: PtrTx, val: MDBX_val) -> Self {
Self::read_from_buffer(val_bytes!(val)).unwrap()
}
}
impl ToAsRef<City, Vec<u8>> for City {
fn to_as_ref(&self) -> Vec<u8> {
self.write_to_vec().unwrap()
}
}
env_rw!(MDBX, {
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
db_path.into()
});
mdbx! {
MDBX
Test
key u16
val City
}
fn main() -> Result<()> {
let city = City {
name: "BeiJing".into(),
lnglat: (11640, 3990),
};
let tx = w!();
let test = tx | Test;
test.set(1, city)?;
println!("{:?}", test.get(1)?);
Ok(())
}
Η έξοδος έχει ως εξής
Some(City { name: "BeiJing", lnglat: (11640, 3990) })
Στο παράδειγμα προσαρμοσμένου τύπου, χρησιμοποιούμε speedy
να κάνει τη σειροθέτηση ( speedy
επανεξέταση επιδόσεων ) .
Εφαρμογή προσαρμοσμένου τύπου FromMdbx
και ToAsRef
μπορεί στη συνέχεια να αποθηκευτεί στη διεύθυνση mdbx
.
Εάν χρησιμοποιείτε μια συγκεκριμένη βιβλιοθήκη σειριοποίησης, μπορείτε επίσης να προσαρμόσετε τις μακροεντολές χαρακτηριστικών για να απλοποιήσετε τη διαδικασία.
Απλοποίηση προσαρμοσμένων τύπων με μακροεντολές χαρακτηριστικών
Η υλοποίηση μιας μακροεντολής χαρακτηριστικών είναι τόσο απλή όσο mdbx_speedy
Ο κωδικός της μακροεντολής έχει ως εξής :
use db::User;
let id = 1234;
let user = r!(User.get id);
use anyhow::{Ok, Result};
use mdbx::prelude::*;
env_rw!(
MDBX,
{
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
},
r,
w
);
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
fn main() -> Result<()> {
// Εξαγωγή του αριθμού έκδοσης της libmdbx
unsafe {
println!(
"mdbx version https://github.com/erthink/libmdbx/releases/tag/v{}.{}.{}",
mdbx_version.major, mdbx_version.minor, mdbx_version.release
);
}
// Πολυνηματική ανάγνωση και εγγραφή
let t = std::thread::spawn(|| {
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t: &[u8] = &val;
println!("{:?}", t);
}
None => unreachable!(),
}
Ok(())
});
t.join().unwrap()?;
Ok(())
}
#[derive(Clone, Debug)]
pub struct Config {
path: PathBuf,
mode: ffi::mdbx_mode_t,
flag: flag::ENV,
sync_period: u64,
sync_bytes: u64,
max_db: u64,
pagesize: isize,
}
lazy_static! {
pub static ref ENV_CONFIG_DEFAULT: Config = Config {
path:PathBuf::new(),
mode: 0o600,
//https://github.com/erthink/libmdbx/issues/248
sync_period : 65536, // Σε 1/65536 του δευτερολέπτου
sync_bytes : 65536,
max_db : 256,
flag : (
flag::ENV::MDBX_EXCLUSIVE
| flag::ENV::MDBX_LIFORECLAIM
| flag::ENV::MDBX_COALESCE
| flag::ENV::MDBX_NOMEMINIT
| flag::ENV::MDBX_NOSUBDIR
| flag::ENV::MDBX_SAFE_NOSYNC
// | flag::ENV::MDBX_SYNC_DURABLE
),
pagesize:-1
};
}
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t:&[u8] = &val;
println!("{:?}",t);
},
None => unreachable!()
}
use anyhow::{Ok, Result};
use mdbx::prelude::*;
env_rw!(MDBX, {
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
});
mdbx! {
MDBX // Ονόματα μεταβλητών για τη βάση δεδομένων ENV
Test1
Test2
key Str
val Str
Test3
key i32
val u64
Test4
key u64
val u16
flag DUPSORT
}
fn main() -> Result<()> {
// Γρήγορη γραφή
w!(Test1.set [2, 3],[4, 5]);
// Γρήγορη ανάγνωση
match r!(Test1.get [2, 3]) {
Some(r) => {
println!(
"\nu16::from_le_bytes({:?}) = {}",
r,
u16::from_le_bytes((*r).try_into()?)
);
}
None => unreachable!(),
}
// Πολλαπλές λειτουργίες σε πολλαπλές βάσεις δεδομένων στην ίδια συναλλαγή
{
let tx = w!();
let test1 = tx | Test1;
test1.set(&[9], &[10, 12])?;
test1.set([8, 1], [9])?;
test1.set("rmw.link", "Down with Data Hegemony")?;
test1.set(&"abc", &"012")?;
println!("\n-- loop test1");
for (k, v) in test1 {
println!("{} = {}", k, v);
}
dbg!(test1.del_val([8, 1], [3])?);
dbg!(test1.get([8, 1])?.unwrap());
dbg!(test1.del_val([8, 1], [9])?);
dbg!(test1.get([8, 1])?);
dbg!(test1.del([9])?);
dbg!(test1.get([9])?);
dbg!(test1.del([9])?);
let test2 = tx | Test2;
test2.set("rmw.link", "Down with Data Hegemony")?;
test2.set(&"abc", &"012")?;
println!("\n-- loop test2");
for (k, v) in test2 {
println!("{} = {}", k, v);
}
let test3 = tx | Test3;
test3.set(13, 32)?;
test3.set(16, 32)?;
test3.set(-15, 6)?;
test3.set(-10, 6)?;
test3.set(-12, 6)?;
test3.set(0, 6)?;
test3.set(10, 5)?;
println!("\n-- loop test3");
for (k, v) in test3 {
println!("{:?} = {:?}", k, v);
}
let test4 = tx | Test4;
test4.set(10, 5)?;
test4.set(10, 0)?;
test4.set(13, 32)?;
test4.set(16, 2)?;
test4.set(16, 1)?;
test4.set(16, 3)?;
test4.set(0, 6)?;
test4.set(10, 5)?;
test4.set(0, 2)?;
dbg!(test4.del_val(0, 2)?);
dbg!(test4.del_val(0, 2)?);
println!("\n-- loop test4 rev");
for (k, v) in test4.rev() {
println!("{:?} = {:?}", k, v);
}
for i in test4.dup(16) {
println!("dup(16) {:?}", i);
}
// Η συναλλαγή θα δεσμευτεί στο τέλος του πεδίου εφαρμογής
}
Ok(())
}
w!(Test1.set [2, 3],[4, 5])
Test2
key Str
val Str
Test3
key i32
val u64
Test4
key u64
val u16
flag DUPSORT
use anyhow::Result;
use mdbx::prelude::*;
env_rw!(MDBX, {
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
});
mdbx! {
MDBX
Test0
Test1
key u16
val u64
flag DUPSORT
Test2
key u32
val u64
}
macro_rules! range_rev {
($var:ident, $range:expr) => {
println!("\n# {}.rev_range({:?})", stringify!($var), $range);
for i in $var.range_rev($range) {
println!("{:?}", i);
}
};
}
macro_rules! range {
($var:ident, $range:expr) => {
println!("\n# {}.range({:?})", stringify!($var), $range);
for i in $var.range($range) {
println!("{:?}", i);
}
};
}
fn main() -> Result<()> {
{
println!("\n> Test0");
let tx = &MDBX.w()?;
let test0 = tx | Test0;
test0.set([0], [0, 1])?;
test0.set([1], [1, 2])?;
test0.set([2], [2, 3])?;
test0.set([1, 1], [1, 3])?;
test0.set([1, 2], [1, 3])?;
test0.set([3], [])?;
range!(test0, [1]..);
let begin: &[u8] = &[1, 1];
range!(test0, begin..=&[2]);
}
{
let tx = &MDBX.w()?;
let test1 = tx | Test1;
test1.set(2, 9)?;
test1.set(2, 4)?;
test1.set(9, 7)?;
test1.set(3, 0)?;
test1.set(3, 8)?;
test1.set(5, 3)?;
test1.set(5, 8)?;
test1.set(9, 1)?;
println!("-- all");
for i in test1 {
println!("{:?}", i);
}
range!(test1, 1..3);
range!(test1, 5..2);
range!(test1, 1..=3);
range!(test1, ..3);
range!(test1, 3..);
range_rev!(test1, ..1);
range_rev!(test1, ..=1);
}
{
println!("\n> Test2");
let tx = &MDBX.w()?;
let test2 = tx | Test2;
test2.set(2, 9)?;
test2.set(1, 2)?;
test2.set(2, 4)?;
test2.set(1, 5)?;
test2.set(9, 7)?;
test2.set(9, 1)?;
test2.set(0, 0)?;
range!(test2, 1..3);
range!(test2, 1..=3);
range!(test2, ..3);
range!(test2, 2..);
range_rev!(test2, ..1);
range_rev!(test2, 2..);
range_rev!(test2, ..=1);
}
Ok(())
}
(5, 8)
(5, 3)
(3, 8)
(3, 0)
use anyhow::Result;
use mdbx::prelude::*;
use speedy::{Readable, Writable};
#[derive(PartialEq, Debug, Readable, Writable)]
pub struct City {
name: String,
lnglat: (u32, u32),
}
impl FromMdbx for City {
fn from_mdbx(_: PtrTx, val: MDBX_val) -> Self {
Self::read_from_buffer(val_bytes!(val)).unwrap()
}
}
impl ToAsRef<City, Vec<u8>> for City {
fn to_as_ref(&self) -> Vec<u8> {
self.write_to_vec().unwrap()
}
}
env_rw!(MDBX, {
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
db_path.into()
});
mdbx! {
MDBX
Test
key u16
val City
}
fn main() -> Result<()> {
let city = City {
name: "BeiJing".into(),
lnglat: (11640, 3990),
};
let tx = w!();
let test = tx | Test;
test.set(1, city)?;
println!("{:?}", test.get(1)?);
Ok(())
}
extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;
use proc_macro::TokenStream;
#[proc_macro_derive(MdbxSpeedy)]
pub fn mdbx_speedy(ts: TokenStream) -> TokenStream {
let ast: syn::DeriveInput = syn::parse(ts).unwrap();
let name = &ast.ident;
quote! {
impl mdbx::prelude::FromMdbx for #name {
fn from_mdbx(_: mdbx::prelude::PtrTx, val: mdbx::prelude::MDBX_val) -> Self {
Self::read_from_buffer(val_bytes!(val)).unwrap()
}
}
impl mdbx::prelude::ToAsRef<#name, Vec<u8>> for #name {
fn to_as_ref(&self) -> Vec<u8> {
self.write_to_vec().unwrap()
}
}
}
.into()
}
Ξεκινήστε με το cargo add mdbx-speedy
στο δικό σας έργο και στη συνέχεια μπορείτε να προσαρμόσετε γρήγορα τον τύπο (δείτε github.com/rmw-lib/mdbx-example/02 για κώδικα επίδειξης) .
use db::User;
let id = 1234;
let user = r!(User.get id);
use anyhow::{Ok, Result};
use mdbx::prelude::*;
env_rw!(
MDBX,
{
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
},
r,
w
);
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
fn main() -> Result<()> {
// Εξαγωγή του αριθμού έκδοσης της libmdbx
unsafe {
println!(
"mdbx version https://github.com/erthink/libmdbx/releases/tag/v{}.{}.{}",
mdbx_version.major, mdbx_version.minor, mdbx_version.release
);
}
// Πολυνηματική ανάγνωση και εγγραφή
let t = std::thread::spawn(|| {
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t: &[u8] = &val;
println!("{:?}", t);
}
None => unreachable!(),
}
Ok(())
});
t.join().unwrap()?;
Ok(())
}
#[derive(Clone, Debug)]
pub struct Config {
path: PathBuf,
mode: ffi::mdbx_mode_t,
flag: flag::ENV,
sync_period: u64,
sync_bytes: u64,
max_db: u64,
pagesize: isize,
}
lazy_static! {
pub static ref ENV_CONFIG_DEFAULT: Config = Config {
path:PathBuf::new(),
mode: 0o600,
//https://github.com/erthink/libmdbx/issues/248
sync_period : 65536, // Σε 1/65536 του δευτερολέπτου
sync_bytes : 65536,
max_db : 256,
flag : (
flag::ENV::MDBX_EXCLUSIVE
| flag::ENV::MDBX_LIFORECLAIM
| flag::ENV::MDBX_COALESCE
| flag::ENV::MDBX_NOMEMINIT
| flag::ENV::MDBX_NOSUBDIR
| flag::ENV::MDBX_SAFE_NOSYNC
// | flag::ENV::MDBX_SYNC_DURABLE
),
pagesize:-1
};
}
mdbx! {
MDBX // Όνομα μεταβλητής της βάσης δεδομένων Env
Test // Δοκιμή βάσης δεδομένων
}
let tx = w!();
let test = tx | Test;
test.set([1, 2], [6])?;
println!("test1 get {:?}", test.get([1, 2]));
match test.get([1, 2])? {
Some(val) => {
let t:&[u8] = &val;
println!("{:?}",t);
},
None => unreachable!()
}
use anyhow::{Ok, Result};
use mdbx::prelude::*;
env_rw!(MDBX, {
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
});
mdbx! {
MDBX // Ονόματα μεταβλητών για τη βάση δεδομένων ENV
Test1
Test2
key Str
val Str
Test3
key i32
val u64
Test4
key u64
val u16
flag DUPSORT
}
fn main() -> Result<()> {
// Γρήγορη γραφή
w!(Test1.set [2, 3],[4, 5]);
// Γρήγορη ανάγνωση
match r!(Test1.get [2, 3]) {
Some(r) => {
println!(
"\nu16::from_le_bytes({:?}) = {}",
r,
u16::from_le_bytes((*r).try_into()?)
);
}
None => unreachable!(),
}
// Πολλαπλές λειτουργίες σε πολλαπλές βάσεις δεδομένων στην ίδια συναλλαγή
{
let tx = w!();
let test1 = tx | Test1;
test1.set(&[9], &[10, 12])?;
test1.set([8, 1], [9])?;
test1.set("rmw.link", "Down with Data Hegemony")?;
test1.set(&"abc", &"012")?;
println!("\n-- loop test1");
for (k, v) in test1 {
println!("{} = {}", k, v);
}
dbg!(test1.del_val([8, 1], [3])?);
dbg!(test1.get([8, 1])?.unwrap());
dbg!(test1.del_val([8, 1], [9])?);
dbg!(test1.get([8, 1])?);
dbg!(test1.del([9])?);
dbg!(test1.get([9])?);
dbg!(test1.del([9])?);
let test2 = tx | Test2;
test2.set("rmw.link", "Down with Data Hegemony")?;
test2.set(&"abc", &"012")?;
println!("\n-- loop test2");
for (k, v) in test2 {
println!("{} = {}", k, v);
}
let test3 = tx | Test3;
test3.set(13, 32)?;
test3.set(16, 32)?;
test3.set(-15, 6)?;
test3.set(-10, 6)?;
test3.set(-12, 6)?;
test3.set(0, 6)?;
test3.set(10, 5)?;
println!("\n-- loop test3");
for (k, v) in test3 {
println!("{:?} = {:?}", k, v);
}
let test4 = tx | Test4;
test4.set(10, 5)?;
test4.set(10, 0)?;
test4.set(13, 32)?;
test4.set(16, 2)?;
test4.set(16, 1)?;
test4.set(16, 3)?;
test4.set(0, 6)?;
test4.set(10, 5)?;
test4.set(0, 2)?;
dbg!(test4.del_val(0, 2)?);
dbg!(test4.del_val(0, 2)?);
println!("\n-- loop test4 rev");
for (k, v) in test4.rev() {
println!("{:?} = {:?}", k, v);
}
for i in test4.dup(16) {
println!("dup(16) {:?}", i);
}
// Η συναλλαγή θα δεσμευτεί στο τέλος του πεδίου εφαρμογής
}
Ok(())
}
w!(Test1.set [2, 3],[4, 5])
Test2
key Str
val Str
Test3
key i32
val u64
Test4
key u64
val u16
flag DUPSORT
use anyhow::Result;
use mdbx::prelude::*;
env_rw!(MDBX, {
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
println!("mdbx file path {}", db_path.display());
db_path.into()
});
mdbx! {
MDBX
Test0
Test1
key u16
val u64
flag DUPSORT
Test2
key u32
val u64
}
macro_rules! range_rev {
($var:ident, $range:expr) => {
println!("\n# {}.rev_range({:?})", stringify!($var), $range);
for i in $var.range_rev($range) {
println!("{:?}", i);
}
};
}
macro_rules! range {
($var:ident, $range:expr) => {
println!("\n# {}.range({:?})", stringify!($var), $range);
for i in $var.range($range) {
println!("{:?}", i);
}
};
}
fn main() -> Result<()> {
{
println!("\n> Test0");
let tx = &MDBX.w()?;
let test0 = tx | Test0;
test0.set([0], [0, 1])?;
test0.set([1], [1, 2])?;
test0.set([2], [2, 3])?;
test0.set([1, 1], [1, 3])?;
test0.set([1, 2], [1, 3])?;
test0.set([3], [])?;
range!(test0, [1]..);
let begin: &[u8] = &[1, 1];
range!(test0, begin..=&[2]);
}
{
let tx = &MDBX.w()?;
let test1 = tx | Test1;
test1.set(2, 9)?;
test1.set(2, 4)?;
test1.set(9, 7)?;
test1.set(3, 0)?;
test1.set(3, 8)?;
test1.set(5, 3)?;
test1.set(5, 8)?;
test1.set(9, 1)?;
println!("-- all");
for i in test1 {
println!("{:?}", i);
}
range!(test1, 1..3);
range!(test1, 5..2);
range!(test1, 1..=3);
range!(test1, ..3);
range!(test1, 3..);
range_rev!(test1, ..1);
range_rev!(test1, ..=1);
}
{
println!("\n> Test2");
let tx = &MDBX.w()?;
let test2 = tx | Test2;
test2.set(2, 9)?;
test2.set(1, 2)?;
test2.set(2, 4)?;
test2.set(1, 5)?;
test2.set(9, 7)?;
test2.set(9, 1)?;
test2.set(0, 0)?;
range!(test2, 1..3);
range!(test2, 1..=3);
range!(test2, ..3);
range!(test2, 2..);
range_rev!(test2, ..1);
range_rev!(test2, 2..);
range_rev!(test2, ..=1);
}
Ok(())
}
(5, 8)
(5, 3)
(3, 8)
(3, 0)
use anyhow::Result;
use mdbx::prelude::*;
use speedy::{Readable, Writable};
#[derive(PartialEq, Debug, Readable, Writable)]
pub struct City {
name: String,
lnglat: (u32, u32),
}
impl FromMdbx for City {
fn from_mdbx(_: PtrTx, val: MDBX_val) -> Self {
Self::read_from_buffer(val_bytes!(val)).unwrap()
}
}
impl ToAsRef<City, Vec<u8>> for City {
fn to_as_ref(&self) -> Vec<u8> {
self.write_to_vec().unwrap()
}
}
env_rw!(MDBX, {
let mut db_path = std::env::current_exe().unwrap();
db_path.set_extension("mdb");
db_path.into()
});
mdbx! {
MDBX
Test
key u16
val City
}
fn main() -> Result<()> {
let city = City {
name: "BeiJing".into(),
lnglat: (11640, 3990),
};
let tx = w!();
let test = tx | Test;
test.set(1, city)?;
println!("{:?}", test.get(1)?);
Ok(())
}
extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;
use proc_macro::TokenStream;
#[proc_macro_derive(MdbxSpeedy)]
pub fn mdbx_speedy(ts: TokenStream) -> TokenStream {
let ast: syn::DeriveInput = syn::parse(ts).unwrap();
let name = &ast.ident;
quote! {
impl mdbx::prelude::FromMdbx for #name {
fn from_mdbx(_: mdbx::prelude::PtrTx, val: mdbx::prelude::MDBX_val) -> Self {
Self::read_from_buffer(val_bytes!(val)).unwrap()
}
}
impl mdbx::prelude::ToAsRef<#name, Vec<u8>> for #name {
fn to_as_ref(&self) -> Vec<u8> {
self.write_to_vec().unwrap()
}
}
}
.into()
}
use anyhow::Result;
use mdbx::prelude::*;
use mdbx_speedy::MdbxSpeedy;
use speedy::{Readable, Writable};
#[derive(PartialEq, Debug, Readable, Writable, MdbxSpeedy)]
pub struct City {
name: String,
lnglat: (u32, u32),
}
Φυσικά, εξακολουθεί να είναι ενοχλητικό να γράφετε το #[derive(PartialEq, Debug, Readable, Writable, MdbxSpeedy)]
επανειλημμένα, οπότε μπορείτε να χρησιμοποιήσετε το derive_alias
για περαιτέρω απλοποίηση του κώδικα.
Σημείωση σχετικά με τη χρήση της
Το μήκος του κλειδιού
- Ελάχιστο 0, μέγιστο ≈ ½ μέγεθος σελίδας (προεπιλεγμένο μέγεθος σελίδας 4Κ το μέγιστο μέγεθος κλειδιού είναι 2022 bytes), ορίζεται κατά την αρχικοποίηση της βάσης δεδομένων
pagesize
μπορεί να ρυθμιστεί σε όχι περισσότερο από65536
και πρέπει να είναι δύναμη του 2.
Υποσημειώσεις
Αναφέρουν τα πλεονεκτήματα της μετάβασης από την LMDB στην MDBX.
Η Erigon ξεκίνησε με ένα backend βάσης δεδομένων BoltDB, στη συνέχεια πρόσθεσε υποστήριξη για BadgerDB και τελικά μεταφέρθηκε πλήρως σε LMDB.Σε κάποιο σημείο αντιμετωπίσαμε προβλήματα σταθερότητας που προκλήθηκαν από τη χρήση της LMDB και τα οποία δεν είχαν προβλεφθεί από τους δημιουργούς της. Από τότε εξετάζουμε ένα καλά υποστηριζόμενο παράγωγο της LMDB που ονομάζεται MDBX και ελπίζουμε να χρησιμοποιήσουμε τις βελτιώσεις σταθερότητας και ενδεχομένως να συνεργαστούμε περισσότερο στο μέλλον.Η ενσωμάτωση του MDBX έχει πλέον ολοκληρωθεί και είναι καιρός για περισσότερες δοκιμές και τεκμηρίωση.
Οφέλη από τη μετάβαση από την LMDB στην MDBX.
Η ανάπτυξη του "χώρου (γεωμετρία)" των αρχείων της βάσης δεδομένων λειτουργεί σωστά. Αυτό είναι σημαντικό, ειδικά στα Windows. Στην LMDB πρέπει να καθορίσετε το μέγεθος του χάρτη μνήμης μία φορά εκ των προτέρων (επί του παρόντος χρησιμοποιούμε 2Tb από προεπιλογή) και αν το αρχείο βάσης δεδομένων μεγαλώσει πέρα από αυτό το όριο, η διαδικασία πρέπει να επανεκκινήσει. Στα Windows, ο ορισμός του μεγέθους του χάρτη μνήμης σε 2 TB θα έκανε το αρχείο βάσης δεδομένων εξαρχής μεγάλο κατά 2 TB, πράγμα που δεν είναι πολύ βολικό. Στο MDBX, το μέγεθος του χάρτη μνήμης αυξάνεται σε βήματα των 2 Gb. Αυτό σημαίνει περιστασιακή επαναπροσδιορισμό, αλλά έχει ως αποτέλεσμα καλύτερη εμπειρία για τον χρήστη.
Το MDBX διαθέτει αυστηρότερους ελέγχους για την ταυτόχρονη χρήση της επεξεργασίας συναλλαγών και την επικάλυψη συναλλαγών ανάγνωσης και εγγραφής στο ίδιο νήμα εκτέλεσης. Αυτό μας επιτρέπει να εντοπίσουμε ορισμένα μη προφανή σφάλματα και καθιστά τη συμπεριφορά πιο προβλέψιμη.
Σε πάνω από 5 χρόνια (από τότε που διαχωρίστηκε από την LMDB), το MDBX έχει συσσωρεύσει ένα μεγάλο αριθμό διορθώσεων ασφαλείας και διορθώσεων heisenbug που, απ' όσο γνωρίζουμε, εξακολουθούν να υπάρχουν στην LMDB. Ορισμένα από αυτά ανακαλύφθηκαν κατά τη διάρκεια των δοκιμών μας, και οι συντηρητές του MDBX τα πήραν σοβαρά υπόψη τους και τα διόρθωσαν αμέσως.Όταν πρόκειται για βάσεις δεδομένων που τροποποιούν διαρκώς δεδομένα, δημιουργούν αρκετό ανακτήσιμο χώρο (επίσης γνωστό ως "freelist" στην ορολογία της LMDB). Χρειάστηκε να επιδιορθώσουμε το LMDB για να διορθώσουμε τις πιο σοβαρές ελλείψεις στο χειρισμό του ανακτήσιμου χώρου (ανάλυση). Το MDBX έχει δώσει ιδιαίτερη προσοχή στον αποτελεσματικό χειρισμό του ανακτήσιμου χώρου και, μέχρι στιγμής, δεν έχει χρειαστεί να επιδιορθωθεί.
Βάσει των δοκιμών μας, το MDBX είχε ελαφρώς καλύτερες επιδόσεις στους φόρτους εργασίας μας.
Το MDBX αποκαλύπτει περισσότερα εσωτερικά δεδομένα τηλεμετρίας - περισσότερες μετρήσεις σχετικά με το τι συμβαίνει στο εσωτερικό της βάσης δεδομένων. Και έχουμε αυτά τα δεδομένα στο Grafana - για να λαμβάνουμε καλύτερες αποφάσεις σχετικά με το σχεδιασμό εφαρμογών. Για παράδειγμα, μετά την πλήρη μετάβαση στο MDBX (καταργώντας την υποστήριξη της LMDB), θα εφαρμόσουμε μια πολιτική "δέσμευσης μισογεμάτης συναλλαγής" για να αποφύγουμε τις επαφές υπερχείλισης/αποσυμπίεσης του δίσκου. Αυτό θα απλοποιήσει περαιτέρω τον κώδικά μας χωρίς να επηρεάσει την απόδοση.
Το MDBX υποστηρίζει τη λειτουργία "Αποκλειστικό άνοιγμα" - τη χρησιμοποιούμε για μεταναστεύσεις βάσεων δεδομένων για να αποτρέψουμε την πρόσβαση άλλων αναγνωστών στη βάση δεδομένων κατά τη διάρκεια της διαδικασίας μετάβασης.