Το πακέτο 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

Παράδειγμα 1 : Γράφοντας set(key,val) και διαβάζοντας .get(key)

Ας δούμε ένα απλό παράδειγμα/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 παραμέτρους.

  1. Το όνομα της μεταβλητής του περιβάλλοντος της βάσης δεδομένων

  2. Επιστρέφει ένα αντικείμενο, 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Άνοιγμα σε νέο παράθυρο για τη σημασία των άλλων παραμέτρων.

  1. Το όνομα της μακροεντολής συναλλαγής ανάγνωσης της βάσης δεδομένων, η προεπιλεγμένη τιμή είναι r

  2. Το όνομα της μακροεντολής συναλλαγής εγγραφής της βάσης δεδομένων, η προεπιλεγμένη τιμή είναι w

Οι παράμετροι 3 και 4 μπορούν να παραλειφθούν για να χρησιμοποιηθούν οι προεπιλεγμένες τιμές.

Μακροσκοπική επέκταση

Αν θέλετε να δείτε τι κάνει η μαγική μακροεντολή, μπορείτε να χρησιμοποιήσετε τη μακροεντολή cargo expand --example 01 για να την επεκτείνετε, η οποία πρέπει πρώτα να εγκατασταθεί. cargo install cargo-expand

Ένα στιγμιότυπο οθόνης του εκτεταμένου κώδικα παρουσιάζεται παρακάτω.

PDzEtT

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.

  1. Η ανάπτυξη του "χώρου (γεωμετρία)" των αρχείων της βάσης δεδομένων λειτουργεί σωστά. Αυτό είναι σημαντικό, ειδικά στα Windows. Στην LMDB πρέπει να καθορίσετε το μέγεθος του χάρτη μνήμης μία φορά εκ των προτέρων (επί του παρόντος χρησιμοποιούμε 2Tb από προεπιλογή) και αν το αρχείο βάσης δεδομένων μεγαλώσει πέρα από αυτό το όριο, η διαδικασία πρέπει να επανεκκινήσει. Στα Windows, ο ορισμός του μεγέθους του χάρτη μνήμης σε 2 TB θα έκανε το αρχείο βάσης δεδομένων εξαρχής μεγάλο κατά 2 TB, πράγμα που δεν είναι πολύ βολικό. Στο MDBX, το μέγεθος του χάρτη μνήμης αυξάνεται σε βήματα των 2 Gb. Αυτό σημαίνει περιστασιακή επαναπροσδιορισμό, αλλά έχει ως αποτέλεσμα καλύτερη εμπειρία για τον χρήστη.

  2. Το MDBX διαθέτει αυστηρότερους ελέγχους για την ταυτόχρονη χρήση της επεξεργασίας συναλλαγών και την επικάλυψη συναλλαγών ανάγνωσης και εγγραφής στο ίδιο νήμα εκτέλεσης. Αυτό μας επιτρέπει να εντοπίσουμε ορισμένα μη προφανή σφάλματα και καθιστά τη συμπεριφορά πιο προβλέψιμη.
    Σε πάνω από 5 χρόνια (από τότε που διαχωρίστηκε από την LMDB), το MDBX έχει συσσωρεύσει ένα μεγάλο αριθμό διορθώσεων ασφαλείας και διορθώσεων heisenbug που, απ' όσο γνωρίζουμε, εξακολουθούν να υπάρχουν στην LMDB. Ορισμένα από αυτά ανακαλύφθηκαν κατά τη διάρκεια των δοκιμών μας, και οι συντηρητές του MDBX τα πήραν σοβαρά υπόψη τους και τα διόρθωσαν αμέσως.

  3. Όταν πρόκειται για βάσεις δεδομένων που τροποποιούν διαρκώς δεδομένα, δημιουργούν αρκετό ανακτήσιμο χώρο (επίσης γνωστό ως "freelist" στην ορολογία της LMDB). Χρειάστηκε να επιδιορθώσουμε το LMDB για να διορθώσουμε τις πιο σοβαρές ελλείψεις στο χειρισμό του ανακτήσιμου χώρου (ανάλυση)Άνοιγμα σε νέο παράθυρο. Το MDBX έχει δώσει ιδιαίτερη προσοχή στον αποτελεσματικό χειρισμό του ανακτήσιμου χώρου και, μέχρι στιγμής, δεν έχει χρειαστεί να επιδιορθωθείΆνοιγμα σε νέο παράθυρο.

  4. Βάσει των δοκιμών μας, το MDBX είχε ελαφρώς καλύτερες επιδόσεις στους φόρτους εργασίας μας.

  5. Το MDBX αποκαλύπτει περισσότερα εσωτερικά δεδομένα τηλεμετρίας - περισσότερες μετρήσεις σχετικά με το τι συμβαίνει στο εσωτερικό της βάσης δεδομένων. Και έχουμε αυτά τα δεδομένα στο Grafana - για να λαμβάνουμε καλύτερες αποφάσεις σχετικά με το σχεδιασμό εφαρμογών. Για παράδειγμα, μετά την πλήρη μετάβαση στο MDBX (καταργώντας την υποστήριξη της LMDB), θα εφαρμόσουμε μια πολιτική "δέσμευσης μισογεμάτης συναλλαγής" για να αποφύγουμε τις επαφές υπερχείλισης/αποσυμπίεσης του δίσκου. Αυτό θα απλοποιήσει περαιτέρω τον κώδικά μας χωρίς να επηρεάσει την απόδοση.

  6. Το MDBX υποστηρίζει τη λειτουργία "Αποκλειστικό άνοιγμα" - τη χρησιμοποιούμε για μεταναστεύσεις βάσεων δεδομένων για να αποτρέψουμε την πρόσβαση άλλων αναγνωστών στη βάση δεδομένων κατά τη διάρκεια της διαδικασίας μετάβασης.


  1. Το Erigon (ο πελάτης Ethernet επόμενης γενιάς) άλλαξε πρόσφατα από LMDB σε MDBX.Άνοιγμα σε νέο παράθυρο ↩︎

Ενημερώσεις:
Από το: gcxfd