heed/database.rs
1use std::borrow::Cow;
2use std::ops::{Bound, RangeBounds};
3use std::{any, fmt, marker, mem, ptr};
4
5use heed_traits::{Comparator, LexicographicComparator};
6use types::{DecodeIgnore, LazyDecode};
7
8use crate::cursor::MoveOperation;
9use crate::env::DefaultComparator;
10use crate::iteration_method::MoveOnCurrentKeyDuplicates;
11use crate::mdb::error::mdb_result;
12use crate::mdb::ffi;
13use crate::mdb::lmdb_flags::{AllDatabaseFlags, DatabaseFlags};
14use crate::*;
15
16/// Options and flags which can be used to configure how a [`Database`] is opened.
17///
18/// # Examples
19///
20/// Opening a file to read:
21///
22/// ```
23/// # use std::fs;
24/// # use std::path::Path;
25/// # use heed::EnvOpenOptions;
26/// use heed::types::*;
27/// use heed::byteorder::BigEndian;
28///
29/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
30/// # let dir = tempfile::tempdir()?;
31/// # let env = unsafe { EnvOpenOptions::new()
32/// # .map_size(10 * 1024 * 1024) // 10MB
33/// # .max_dbs(3000)
34/// # .open(dir.path())?
35/// # };
36/// type BEI64 = I64<BigEndian>;
37///
38/// // Imagine you have an optional name
39/// let conditional_name = Some("big-endian-iter");
40///
41/// let mut wtxn = env.write_txn()?;
42/// let mut options = env.database_options().types::<BEI64, Unit>();
43/// if let Some(name) = conditional_name {
44/// options.name(name);
45/// }
46/// let db = options.create(&mut wtxn)?;
47///
48/// # db.clear(&mut wtxn)?;
49/// db.put(&mut wtxn, &68, &())?;
50/// db.put(&mut wtxn, &35, &())?;
51/// db.put(&mut wtxn, &0, &())?;
52/// db.put(&mut wtxn, &42, &())?;
53///
54/// wtxn.commit()?;
55/// # Ok(()) }
56/// ```
57#[derive(Debug)]
58pub struct DatabaseOpenOptions<'e, 'n, KC, DC, C = DefaultComparator> {
59 env: &'e Env,
60 types: marker::PhantomData<(KC, DC, C)>,
61 name: Option<&'n str>,
62 flags: AllDatabaseFlags,
63}
64
65impl<'e> DatabaseOpenOptions<'e, 'static, Unspecified, Unspecified> {
66 /// Create an options struct to open/create a database with specific flags.
67 pub fn new(env: &'e Env) -> Self {
68 DatabaseOpenOptions {
69 env,
70 types: Default::default(),
71 name: None,
72 flags: AllDatabaseFlags::empty(),
73 }
74 }
75}
76
77impl<'e, 'n, KC, DC, C> DatabaseOpenOptions<'e, 'n, KC, DC, C> {
78 /// Change the type of the database.
79 ///
80 /// The default types are [`Unspecified`] and require a call to [`Database::remap_types`]
81 /// to use the [`Database`].
82 pub fn types<NKC, NDC>(self) -> DatabaseOpenOptions<'e, 'n, NKC, NDC> {
83 DatabaseOpenOptions {
84 env: self.env,
85 types: Default::default(),
86 name: self.name,
87 flags: self.flags,
88 }
89 }
90 /// Change the customized key compare function of the database.
91 ///
92 /// By default no customized compare function will be set when opening a database.
93 pub fn key_comparator<NC>(self) -> DatabaseOpenOptions<'e, 'n, KC, DC, NC> {
94 DatabaseOpenOptions {
95 env: self.env,
96 types: Default::default(),
97 name: self.name,
98 flags: self.flags,
99 }
100 }
101
102 /// Change the name of the database.
103 ///
104 /// By default the database is unnamed and there only is a single unnamed database.
105 pub fn name(&mut self, name: &'n str) -> &mut Self {
106 self.name = Some(name);
107 self
108 }
109
110 /// Specify the set of flags used to open the database.
111 pub fn flags(&mut self, flags: DatabaseFlags) -> &mut Self {
112 self.flags = AllDatabaseFlags::from_bits(flags.bits()).unwrap();
113 self
114 }
115
116 /// Opens a typed database that already exists in this environment.
117 ///
118 /// If the database was previously opened in this program run, types will be checked.
119 ///
120 /// ## Important Information
121 ///
122 /// LMDB has an important restriction on the unnamed database when named ones are opened.
123 /// The names of the named databases are stored as keys in the unnamed one and are immutable,
124 /// and these keys can only be read and not written.
125 ///
126 /// ## LMDB read-only access of existing database
127 ///
128 /// In the case of accessing a database in a read-only manner from another process
129 /// where you wrote, you might need to manually call [`RoTxn::commit`] to get metadata
130 /// and the database handles opened and shared with the global [`Env`] handle.
131 ///
132 /// If not done, you might raise `Io(Os { code: 22, kind: InvalidInput, message: "Invalid argument" })`
133 /// known as `EINVAL`.
134 pub fn open(&self, rtxn: &RoTxn) -> Result<Option<Database<KC, DC, C>>>
135 where
136 KC: 'static,
137 DC: 'static,
138 C: Comparator + 'static,
139 {
140 assert_eq_env_txn!(self.env, rtxn);
141
142 match self.env.raw_init_database::<C>(rtxn.txn, self.name, self.flags) {
143 Ok(dbi) => Ok(Some(Database::new(self.env.env_mut_ptr() as _, dbi))),
144 Err(Error::Mdb(e)) if e.not_found() => Ok(None),
145 Err(e) => Err(e),
146 }
147 }
148
149 /// Creates a typed database that can already exist in this environment.
150 ///
151 /// If the database was previously opened in this program run, types will be checked.
152 ///
153 /// ## Important Information
154 ///
155 /// LMDB has an important restriction on the unnamed database when named ones are opened.
156 /// The names of the named databases are stored as keys in the unnamed one and are immutable,
157 /// and these keys can only be read and not written.
158 pub fn create(&self, wtxn: &mut RwTxn) -> Result<Database<KC, DC, C>>
159 where
160 KC: 'static,
161 DC: 'static,
162 C: Comparator + 'static,
163 {
164 assert_eq_env_txn!(self.env, wtxn);
165
166 let flags = self.flags | AllDatabaseFlags::CREATE;
167 match self.env.raw_init_database::<C>(wtxn.txn.txn, self.name, flags) {
168 Ok(dbi) => Ok(Database::new(self.env.env_mut_ptr() as _, dbi)),
169 Err(e) => Err(e),
170 }
171 }
172}
173
174impl<KC, DC, C> Clone for DatabaseOpenOptions<'_, '_, KC, DC, C> {
175 fn clone(&self) -> Self {
176 *self
177 }
178}
179
180impl<KC, DC, C> Copy for DatabaseOpenOptions<'_, '_, KC, DC, C> {}
181
182/// A typed database that accepts only the types it was created with.
183///
184/// # Example: Iterate over databases entries
185///
186/// In this example we store numbers in big endian this way those are ordered.
187/// Thanks to their bytes representation, heed is able to iterate over them
188/// from the lowest to the highest.
189///
190/// ```
191/// # use std::fs;
192/// # use std::path::Path;
193/// # use heed::EnvOpenOptions;
194/// use heed::Database;
195/// use heed::types::*;
196/// use heed::byteorder::BigEndian;
197///
198/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
199/// # let dir = tempfile::tempdir()?;
200/// # let env = unsafe { EnvOpenOptions::new()
201/// # .map_size(10 * 1024 * 1024) // 10MB
202/// # .max_dbs(3000)
203/// # .open(dir.path())?
204/// # };
205/// type BEI64 = I64<BigEndian>;
206///
207/// let mut wtxn = env.write_txn()?;
208/// let db: Database<BEI64, Unit> = env.create_database(&mut wtxn, Some("big-endian-iter"))?;
209///
210/// # db.clear(&mut wtxn)?;
211/// db.put(&mut wtxn, &68, &())?;
212/// db.put(&mut wtxn, &35, &())?;
213/// db.put(&mut wtxn, &0, &())?;
214/// db.put(&mut wtxn, &42, &())?;
215///
216/// // you can iterate over database entries in order
217/// let rets: Result<_, _> = db.iter(&wtxn)?.collect();
218/// let rets: Vec<(i64, _)> = rets?;
219///
220/// let expected = vec![
221/// (0, ()),
222/// (35, ()),
223/// (42, ()),
224/// (68, ()),
225/// ];
226///
227/// assert_eq!(rets, expected);
228/// wtxn.commit()?;
229/// # Ok(()) }
230/// ```
231///
232/// # Example: Iterate over and delete ranges of entries
233///
234/// Discern also support ranges and ranges deletions.
235/// Same configuration as above, numbers are ordered, therefore it is safe to specify
236/// a range and be able to iterate over and/or delete it.
237///
238/// ```
239/// # use std::fs;
240/// # use std::path::Path;
241/// # use heed::EnvOpenOptions;
242/// use heed::Database;
243/// use heed::types::*;
244/// use heed::byteorder::BigEndian;
245///
246/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
247/// # let dir = tempfile::tempdir()?;
248/// # let env = unsafe { EnvOpenOptions::new()
249/// # .map_size(10 * 1024 * 1024) // 10MB
250/// # .max_dbs(3000)
251/// # .open(dir.path())?
252/// # };
253/// type BEI64 = I64<BigEndian>;
254///
255/// let mut wtxn = env.write_txn()?;
256/// let db: Database<BEI64, Unit> = env.create_database(&mut wtxn, Some("big-endian-iter"))?;
257///
258/// # db.clear(&mut wtxn)?;
259/// db.put(&mut wtxn, &0, &())?;
260/// db.put(&mut wtxn, &68, &())?;
261/// db.put(&mut wtxn, &35, &())?;
262/// db.put(&mut wtxn, &42, &())?;
263///
264/// // you can iterate over ranges too!!!
265/// let range = 35..=42;
266/// let rets: Result<_, _> = db.range(&wtxn, &range)?.collect();
267/// let rets: Vec<(i64, _)> = rets?;
268///
269/// let expected = vec![
270/// (35, ()),
271/// (42, ()),
272/// ];
273///
274/// assert_eq!(rets, expected);
275///
276/// // even delete a range of keys
277/// let range = 35..=42;
278/// let deleted: usize = db.delete_range(&mut wtxn, &range)?;
279///
280/// let rets: Result<_, _> = db.iter(&wtxn)?.collect();
281/// let rets: Vec<(i64, _)> = rets?;
282///
283/// let expected = vec![
284/// (0, ()),
285/// (68, ()),
286/// ];
287///
288/// assert_eq!(deleted, 2);
289/// assert_eq!(rets, expected);
290///
291/// wtxn.commit()?;
292/// # Ok(()) }
293/// ```
294pub struct Database<KC, DC, C = DefaultComparator> {
295 pub(crate) env_ident: usize,
296 pub(crate) dbi: ffi::MDB_dbi,
297 marker: marker::PhantomData<(KC, DC, C)>,
298}
299
300impl<KC, DC, C> Database<KC, DC, C> {
301 pub(crate) fn new(env_ident: usize, dbi: ffi::MDB_dbi) -> Database<KC, DC, C> {
302 Database { env_ident, dbi, marker: std::marker::PhantomData }
303 }
304
305 /// Retrieves the value associated with a key.
306 ///
307 /// If the key does not exist, then `None` is returned.
308 ///
309 /// ```
310 /// # use std::fs;
311 /// # use std::path::Path;
312 /// # use heed::EnvOpenOptions;
313 /// use heed::Database;
314 /// use heed::types::*;
315 /// use heed::byteorder::BigEndian;
316 ///
317 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
318 /// # let dir = tempfile::tempdir()?;
319 /// # let env = unsafe { EnvOpenOptions::new()
320 /// # .map_size(10 * 1024 * 1024) // 10MB
321 /// # .max_dbs(3000)
322 /// # .open(dir.path())?
323 /// # };
324 /// type BEI32= U32<BigEndian>;
325 ///
326 /// let mut wtxn = env.write_txn()?;
327 /// let db: Database<Str, BEI32> = env.create_database(&mut wtxn, Some("get-i32"))?;
328 ///
329 /// # db.clear(&mut wtxn)?;
330 /// db.put(&mut wtxn, "i-am-forty-two", &42)?;
331 /// db.put(&mut wtxn, "i-am-twenty-seven", &27)?;
332 ///
333 /// let ret = db.get(&wtxn, "i-am-forty-two")?;
334 /// assert_eq!(ret, Some(42));
335 ///
336 /// let ret = db.get(&wtxn, "i-am-twenty-one")?;
337 /// assert_eq!(ret, None);
338 ///
339 /// wtxn.commit()?;
340 /// # Ok(()) }
341 /// ```
342 pub fn get<'a, 'txn>(&self, txn: &'txn RoTxn, key: &'a KC::EItem) -> Result<Option<DC::DItem>>
343 where
344 KC: BytesEncode<'a>,
345 DC: BytesDecode<'txn>,
346 {
347 assert_eq_env_db_txn!(self, txn);
348
349 let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
350
351 let mut key_val = unsafe { crate::into_val(&key_bytes) };
352 let mut data_val = mem::MaybeUninit::uninit();
353
354 let result = unsafe {
355 mdb_result(ffi::mdb_get(txn.txn, self.dbi, &mut key_val, data_val.as_mut_ptr()))
356 };
357
358 match result {
359 Ok(()) => {
360 let data = unsafe { crate::from_val(data_val.assume_init()) };
361 let data = DC::bytes_decode(data).map_err(Error::Decoding)?;
362 Ok(Some(data))
363 }
364 Err(e) if e.not_found() => Ok(None),
365 Err(e) => Err(e.into()),
366 }
367 }
368
369 /// Returns an iterator over all of the values of a single key.
370 ///
371 /// You can make this iterator `Send`able between threads by
372 /// using the `read-txn-no-tls` crate feature.
373 ///
374 /// ```
375 /// # use std::fs;
376 /// # use std::path::Path;
377 /// # use heed::{DatabaseFlags, EnvOpenOptions};
378 /// use heed::types::*;
379 /// use heed::byteorder::BigEndian;
380 ///
381 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
382 /// # let dir = tempfile::tempdir()?;
383 /// # let env = unsafe { EnvOpenOptions::new()
384 /// # .map_size(10 * 1024 * 1024) // 10MB
385 /// # .max_dbs(3000)
386 /// # .open(dir.path())?
387 /// # };
388 /// type BEI64 = I64<BigEndian>;
389 ///
390 /// let mut wtxn = env.write_txn()?;
391 /// let db = env.database_options()
392 /// .types::<BEI64, BEI64>()
393 /// .flags(DatabaseFlags::DUP_SORT)
394 /// .name("dup-sort")
395 /// .create(&mut wtxn)?;
396 ///
397 /// # db.clear(&mut wtxn)?;
398 /// db.put(&mut wtxn, &68, &120)?;
399 /// db.put(&mut wtxn, &68, &121)?;
400 /// db.put(&mut wtxn, &68, &122)?;
401 /// db.put(&mut wtxn, &68, &123)?;
402 /// db.put(&mut wtxn, &92, &32)?;
403 /// db.put(&mut wtxn, &35, &120)?;
404 /// db.put(&mut wtxn, &0, &120)?;
405 /// db.put(&mut wtxn, &42, &120)?;
406 ///
407 /// let mut iter = db.get_duplicates(&wtxn, &68)?.expect("the key exists");
408 /// assert_eq!(iter.next().transpose()?, Some((68, 120)));
409 /// assert_eq!(iter.next().transpose()?, Some((68, 121)));
410 /// assert_eq!(iter.next().transpose()?, Some((68, 122)));
411 /// assert_eq!(iter.next().transpose()?, Some((68, 123)));
412 /// assert_eq!(iter.next().transpose()?, None);
413 /// drop(iter);
414 ///
415 /// let mut iter = db.get_duplicates(&wtxn, &68)?.expect("the key exists");
416 /// assert_eq!(iter.last().transpose()?, Some((68, 123)));
417 ///
418 /// wtxn.commit()?;
419 /// # Ok(()) }
420 /// ```
421 pub fn get_duplicates<'a, 'txn>(
422 &self,
423 txn: &'txn RoTxn,
424 key: &'a KC::EItem,
425 ) -> Result<Option<RoIter<'txn, KC, DC, MoveOnCurrentKeyDuplicates>>>
426 where
427 KC: BytesEncode<'a>,
428 {
429 assert_eq_env_db_txn!(self, txn);
430
431 let mut cursor = RoCursor::new(txn, self.dbi)?;
432 let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
433 if cursor.move_on_key(&key_bytes)? {
434 Ok(Some(RoIter::new(cursor)))
435 } else {
436 Ok(None)
437 }
438 }
439
440 /// Retrieves the key/value pair lower than the given one in this database.
441 ///
442 /// If the database if empty or there is no key lower than the given one,
443 /// then `None` is returned.
444 ///
445 /// Comparisons are made by using the bytes representation of the key.
446 ///
447 /// ```
448 /// # use std::fs;
449 /// # use std::path::Path;
450 /// # use heed::EnvOpenOptions;
451 /// use heed::Database;
452 /// use heed::types::*;
453 /// use heed::byteorder::BigEndian;
454 ///
455 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
456 /// # let dir = tempfile::tempdir()?;
457 /// # let env = unsafe { EnvOpenOptions::new()
458 /// # .map_size(10 * 1024 * 1024) // 10MB
459 /// # .max_dbs(3000)
460 /// # .open(dir.path())?
461 /// # };
462 /// type BEU32 = U32<BigEndian>;
463 ///
464 /// let mut wtxn = env.write_txn()?;
465 /// let db = env.create_database::<BEU32, Unit>(&mut wtxn, Some("get-lt-u32"))?;
466 ///
467 /// # db.clear(&mut wtxn)?;
468 /// db.put(&mut wtxn, &27, &())?;
469 /// db.put(&mut wtxn, &42, &())?;
470 /// db.put(&mut wtxn, &43, &())?;
471 ///
472 /// let ret = db.get_lower_than(&wtxn, &4404)?;
473 /// assert_eq!(ret, Some((43, ())));
474 ///
475 /// let ret = db.get_lower_than(&wtxn, &43)?;
476 /// assert_eq!(ret, Some((42, ())));
477 ///
478 /// let ret = db.get_lower_than(&wtxn, &27)?;
479 /// assert_eq!(ret, None);
480 ///
481 /// wtxn.commit()?;
482 /// # Ok(()) }
483 /// ```
484 pub fn get_lower_than<'a, 'txn>(
485 &self,
486 txn: &'txn RoTxn,
487 key: &'a KC::EItem,
488 ) -> Result<Option<(KC::DItem, DC::DItem)>>
489 where
490 KC: BytesEncode<'a> + BytesDecode<'txn>,
491 DC: BytesDecode<'txn>,
492 {
493 assert_eq_env_db_txn!(self, txn);
494
495 let mut cursor = RoCursor::new(txn, self.dbi)?;
496 let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
497 cursor.move_on_key_greater_than_or_equal_to(&key_bytes)?;
498
499 match cursor.move_on_prev(MoveOperation::NoDup) {
500 Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
501 (Ok(key), Ok(data)) => Ok(Some((key, data))),
502 (Err(e), _) | (_, Err(e)) => Err(Error::Decoding(e)),
503 },
504 Ok(None) => Ok(None),
505 Err(e) => Err(e),
506 }
507 }
508
509 /// Retrieves the key/value pair lower than or equal to the given one in this database.
510 ///
511 /// If the database if empty or there is no key lower than or equal to the given one,
512 /// then `None` is returned.
513 ///
514 /// Comparisons are made by using the bytes representation of the key.
515 ///
516 /// ```
517 /// # use std::fs;
518 /// # use std::path::Path;
519 /// # use heed::EnvOpenOptions;
520 /// use heed::Database;
521 /// use heed::types::*;
522 /// use heed::byteorder::BigEndian;
523 ///
524 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
525 /// # let dir = tempfile::tempdir()?;
526 /// # let env = unsafe { EnvOpenOptions::new()
527 /// # .map_size(10 * 1024 * 1024) // 10MB
528 /// # .max_dbs(3000)
529 /// # .open(dir.path())?
530 /// # };
531 /// type BEU32 = U32<BigEndian>;
532 ///
533 /// let mut wtxn = env.write_txn()?;
534 /// let db = env.create_database::<BEU32, Unit>(&mut wtxn, Some("get-lt-u32"))?;
535 ///
536 /// # db.clear(&mut wtxn)?;
537 /// db.put(&mut wtxn, &27, &())?;
538 /// db.put(&mut wtxn, &42, &())?;
539 /// db.put(&mut wtxn, &43, &())?;
540 ///
541 /// let ret = db.get_lower_than_or_equal_to(&wtxn, &4404)?;
542 /// assert_eq!(ret, Some((43, ())));
543 ///
544 /// let ret = db.get_lower_than_or_equal_to(&wtxn, &43)?;
545 /// assert_eq!(ret, Some((43, ())));
546 ///
547 /// let ret = db.get_lower_than_or_equal_to(&wtxn, &26)?;
548 /// assert_eq!(ret, None);
549 ///
550 /// wtxn.commit()?;
551 /// # Ok(()) }
552 /// ```
553 pub fn get_lower_than_or_equal_to<'a, 'txn>(
554 &self,
555 txn: &'txn RoTxn,
556 key: &'a KC::EItem,
557 ) -> Result<Option<(KC::DItem, DC::DItem)>>
558 where
559 KC: BytesEncode<'a> + BytesDecode<'txn>,
560 DC: BytesDecode<'txn>,
561 {
562 assert_eq_env_db_txn!(self, txn);
563
564 let mut cursor = RoCursor::new(txn, self.dbi)?;
565 let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
566 let result = match cursor.move_on_key_greater_than_or_equal_to(&key_bytes) {
567 Ok(Some((key, data))) if key == &key_bytes[..] => Ok(Some((key, data))),
568 Ok(_) => cursor.move_on_prev(MoveOperation::NoDup),
569 Err(e) => Err(e),
570 };
571
572 match result {
573 Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
574 (Ok(key), Ok(data)) => Ok(Some((key, data))),
575 (Err(e), _) | (_, Err(e)) => Err(Error::Decoding(e)),
576 },
577 Ok(None) => Ok(None),
578 Err(e) => Err(e),
579 }
580 }
581
582 /// Retrieves the key/value pair greater than the given one in this database.
583 ///
584 /// If the database if empty or there is no key greater than the given one,
585 /// then `None` is returned.
586 ///
587 /// Comparisons are made by using the bytes representation of the key.
588 ///
589 /// ```
590 /// # use std::fs;
591 /// # use std::path::Path;
592 /// # use heed::EnvOpenOptions;
593 /// use heed::Database;
594 /// use heed::types::*;
595 /// use heed::byteorder::BigEndian;
596 ///
597 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
598 /// # let dir = tempfile::tempdir()?;
599 /// # let env = unsafe { EnvOpenOptions::new()
600 /// # .map_size(10 * 1024 * 1024) // 10MB
601 /// # .max_dbs(3000)
602 /// # .open(dir.path())?
603 /// # };
604 /// type BEU32 = U32<BigEndian>;
605 ///
606 /// let mut wtxn = env.write_txn()?;
607 /// let db = env.create_database::<BEU32, Unit>(&mut wtxn, Some("get-lt-u32"))?;
608 ///
609 /// # db.clear(&mut wtxn)?;
610 /// db.put(&mut wtxn, &27, &())?;
611 /// db.put(&mut wtxn, &42, &())?;
612 /// db.put(&mut wtxn, &43, &())?;
613 ///
614 /// let ret = db.get_greater_than(&wtxn, &0)?;
615 /// assert_eq!(ret, Some((27, ())));
616 ///
617 /// let ret = db.get_greater_than(&wtxn, &42)?;
618 /// assert_eq!(ret, Some((43, ())));
619 ///
620 /// let ret = db.get_greater_than(&wtxn, &43)?;
621 /// assert_eq!(ret, None);
622 ///
623 /// wtxn.commit()?;
624 /// # Ok(()) }
625 /// ```
626 pub fn get_greater_than<'a, 'txn>(
627 &self,
628 txn: &'txn RoTxn,
629 key: &'a KC::EItem,
630 ) -> Result<Option<(KC::DItem, DC::DItem)>>
631 where
632 KC: BytesEncode<'a> + BytesDecode<'txn>,
633 DC: BytesDecode<'txn>,
634 {
635 assert_eq_env_db_txn!(self, txn);
636
637 let mut cursor = RoCursor::new(txn, self.dbi)?;
638 let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
639 let entry = match cursor.move_on_key_greater_than_or_equal_to(&key_bytes)? {
640 Some((key, data)) if key > &key_bytes[..] => Some((key, data)),
641 Some((_key, _data)) => cursor.move_on_next(MoveOperation::NoDup)?,
642 None => None,
643 };
644
645 match entry {
646 Some((key, data)) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
647 (Ok(key), Ok(data)) => Ok(Some((key, data))),
648 (Err(e), _) | (_, Err(e)) => Err(Error::Decoding(e)),
649 },
650 None => Ok(None),
651 }
652 }
653
654 /// Retrieves the key/value pair greater than or equal to the given one in this database.
655 ///
656 /// If the database if empty or there is no key greater than or equal to the given one,
657 /// then `None` is returned.
658 ///
659 /// Comparisons are made by using the bytes representation of the key.
660 ///
661 /// ```
662 /// # use std::fs;
663 /// # use std::path::Path;
664 /// # use heed::EnvOpenOptions;
665 /// use heed::Database;
666 /// use heed::types::*;
667 /// use heed::byteorder::BigEndian;
668 ///
669 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
670 /// # let dir = tempfile::tempdir()?;
671 /// # let env = unsafe { EnvOpenOptions::new()
672 /// # .map_size(10 * 1024 * 1024) // 10MB
673 /// # .max_dbs(3000)
674 /// # .open(dir.path())?
675 /// # };
676 /// type BEU32 = U32<BigEndian>;
677 ///
678 /// let mut wtxn = env.write_txn()?;
679 /// let db = env.create_database::<BEU32, Unit>(&mut wtxn, Some("get-lt-u32"))?;
680 ///
681 /// # db.clear(&mut wtxn)?;
682 /// db.put(&mut wtxn, &27, &())?;
683 /// db.put(&mut wtxn, &42, &())?;
684 /// db.put(&mut wtxn, &43, &())?;
685 ///
686 /// let ret = db.get_greater_than_or_equal_to(&wtxn, &0)?;
687 /// assert_eq!(ret, Some((27, ())));
688 ///
689 /// let ret = db.get_greater_than_or_equal_to(&wtxn, &42)?;
690 /// assert_eq!(ret, Some((42, ())));
691 ///
692 /// let ret = db.get_greater_than_or_equal_to(&wtxn, &44)?;
693 /// assert_eq!(ret, None);
694 ///
695 /// wtxn.commit()?;
696 /// # Ok(()) }
697 /// ```
698 pub fn get_greater_than_or_equal_to<'a, 'txn>(
699 &self,
700 txn: &'txn RoTxn,
701 key: &'a KC::EItem,
702 ) -> Result<Option<(KC::DItem, DC::DItem)>>
703 where
704 KC: BytesEncode<'a> + BytesDecode<'txn>,
705 DC: BytesDecode<'txn>,
706 {
707 assert_eq_env_db_txn!(self, txn);
708
709 let mut cursor = RoCursor::new(txn, self.dbi)?;
710 let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
711 match cursor.move_on_key_greater_than_or_equal_to(&key_bytes) {
712 Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
713 (Ok(key), Ok(data)) => Ok(Some((key, data))),
714 (Err(e), _) | (_, Err(e)) => Err(Error::Decoding(e)),
715 },
716 Ok(None) => Ok(None),
717 Err(e) => Err(e),
718 }
719 }
720
721 /// Retrieves the first key/value pair of this database.
722 ///
723 /// If the database if empty, then `None` is returned.
724 ///
725 /// Comparisons are made by using the bytes representation of the key.
726 ///
727 /// ```
728 /// # use std::fs;
729 /// # use std::path::Path;
730 /// # use heed::EnvOpenOptions;
731 /// use heed::Database;
732 /// use heed::types::*;
733 /// use heed::byteorder::BigEndian;
734 ///
735 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
736 /// # let dir = tempfile::tempdir()?;
737 /// # let env = unsafe { EnvOpenOptions::new()
738 /// # .map_size(10 * 1024 * 1024) // 10MB
739 /// # .max_dbs(3000)
740 /// # .open(dir.path())?
741 /// # };
742 /// type BEI32 = I32<BigEndian>;
743 ///
744 /// let mut wtxn = env.write_txn()?;
745 /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("first-i32"))?;
746 ///
747 /// # db.clear(&mut wtxn)?;
748 /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
749 /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
750 ///
751 /// let ret = db.first(&wtxn)?;
752 /// assert_eq!(ret, Some((27, "i-am-twenty-seven")));
753 ///
754 /// wtxn.commit()?;
755 /// # Ok(()) }
756 /// ```
757 pub fn first<'txn>(&self, txn: &'txn RoTxn) -> Result<Option<(KC::DItem, DC::DItem)>>
758 where
759 KC: BytesDecode<'txn>,
760 DC: BytesDecode<'txn>,
761 {
762 assert_eq_env_db_txn!(self, txn);
763
764 let mut cursor = RoCursor::new(txn, self.dbi)?;
765 match cursor.move_on_first(MoveOperation::Any) {
766 Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
767 (Ok(key), Ok(data)) => Ok(Some((key, data))),
768 (Err(e), _) | (_, Err(e)) => Err(Error::Decoding(e)),
769 },
770 Ok(None) => Ok(None),
771 Err(e) => Err(e),
772 }
773 }
774
775 /// Retrieves the last key/value pair of this database.
776 ///
777 /// If the database if empty, then `None` is returned.
778 ///
779 /// Comparisons are made by using the bytes representation of the key.
780 ///
781 /// ```
782 /// # use std::fs;
783 /// # use std::path::Path;
784 /// # use heed::EnvOpenOptions;
785 /// use heed::Database;
786 /// use heed::types::*;
787 /// use heed::byteorder::BigEndian;
788 ///
789 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
790 /// # let dir = tempfile::tempdir()?;
791 /// # let env = unsafe { EnvOpenOptions::new()
792 /// # .map_size(10 * 1024 * 1024) // 10MB
793 /// # .max_dbs(3000)
794 /// # .open(dir.path())?
795 /// # };
796 /// type BEI32 = I32<BigEndian>;
797 ///
798 /// let mut wtxn = env.write_txn()?;
799 /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("last-i32"))?;
800 ///
801 /// # db.clear(&mut wtxn)?;
802 /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
803 /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
804 ///
805 /// let ret = db.last(&wtxn)?;
806 /// assert_eq!(ret, Some((42, "i-am-forty-two")));
807 ///
808 /// wtxn.commit()?;
809 /// # Ok(()) }
810 /// ```
811 pub fn last<'txn>(&self, txn: &'txn RoTxn) -> Result<Option<(KC::DItem, DC::DItem)>>
812 where
813 KC: BytesDecode<'txn>,
814 DC: BytesDecode<'txn>,
815 {
816 assert_eq_env_db_txn!(self, txn);
817
818 let mut cursor = RoCursor::new(txn, self.dbi)?;
819 match cursor.move_on_last(MoveOperation::Any) {
820 Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
821 (Ok(key), Ok(data)) => Ok(Some((key, data))),
822 (Err(e), _) | (_, Err(e)) => Err(Error::Decoding(e)),
823 },
824 Ok(None) => Ok(None),
825 Err(e) => Err(e),
826 }
827 }
828
829 /// Returns the number of elements in this database.
830 ///
831 /// ```
832 /// # use std::fs;
833 /// # use std::path::Path;
834 /// # use heed::EnvOpenOptions;
835 /// use heed::Database;
836 /// use heed::types::*;
837 /// use heed::byteorder::BigEndian;
838 ///
839 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
840 /// # let dir = tempfile::tempdir()?;
841 /// # let env = unsafe { EnvOpenOptions::new()
842 /// # .map_size(10 * 1024 * 1024) // 10MB
843 /// # .max_dbs(3000)
844 /// # .open(dir.path())?
845 /// # };
846 /// type BEI32 = I32<BigEndian>;
847 ///
848 /// let mut wtxn = env.write_txn()?;
849 /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
850 ///
851 /// # db.clear(&mut wtxn)?;
852 /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
853 /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
854 /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
855 /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
856 ///
857 /// let ret = db.len(&wtxn)?;
858 /// assert_eq!(ret, 4);
859 ///
860 /// db.delete(&mut wtxn, &27)?;
861 ///
862 /// let ret = db.len(&wtxn)?;
863 /// assert_eq!(ret, 3);
864 ///
865 /// wtxn.commit()?;
866 /// # Ok(()) }
867 /// ```
868 pub fn len(&self, txn: &RoTxn) -> Result<u64> {
869 self.stat(txn).map(|stat| stat.entries as u64)
870 }
871
872 /// Returns `true` if and only if this database is empty.
873 ///
874 /// ```
875 /// # use std::fs;
876 /// # use std::path::Path;
877 /// # use heed::EnvOpenOptions;
878 /// use heed::Database;
879 /// use heed::types::*;
880 /// use heed::byteorder::BigEndian;
881 ///
882 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
883 /// # let dir = tempfile::tempdir()?;
884 /// # let env = unsafe { EnvOpenOptions::new()
885 /// # .map_size(10 * 1024 * 1024) // 10MB
886 /// # .max_dbs(3000)
887 /// # .open(dir.path())?
888 /// # };
889 /// type BEI32 = I32<BigEndian>;
890 ///
891 /// let mut wtxn = env.write_txn()?;
892 /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
893 ///
894 /// # db.clear(&mut wtxn)?;
895 /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
896 /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
897 /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
898 /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
899 ///
900 /// let ret = db.is_empty(&wtxn)?;
901 /// assert_eq!(ret, false);
902 ///
903 /// db.clear(&mut wtxn)?;
904 ///
905 /// let ret = db.is_empty(&wtxn)?;
906 /// assert_eq!(ret, true);
907 ///
908 /// wtxn.commit()?;
909 /// # Ok(()) }
910 /// ```
911 pub fn is_empty(&self, txn: &RoTxn) -> Result<bool> {
912 self.len(txn).map(|l| l == 0)
913 }
914
915 /// Returns some statistics for this database.
916 ///
917 /// ```
918 /// # use std::fs;
919 /// # use std::path::Path;
920 /// # use heed::EnvOpenOptions;
921 /// use heed::Database;
922 /// use heed::types::*;
923 /// use heed::byteorder::BigEndian;
924 ///
925 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
926 /// # let dir = tempfile::tempdir()?;
927 /// # let env = unsafe { EnvOpenOptions::new()
928 /// # .map_size(10 * 1024 * 1024) // 10MB
929 /// # .max_dbs(3000)
930 /// # .open(dir.path())?
931 /// # };
932 /// type BEI32 = I32<BigEndian>;
933 ///
934 /// let mut wtxn = env.write_txn()?;
935 /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
936 ///
937 /// # db.clear(&mut wtxn)?;
938 /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
939 /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
940 /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
941 /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
942 ///
943 /// let stat = db.stat(&wtxn)?;
944 /// assert_eq!(stat.depth, 1);
945 /// assert_eq!(stat.branch_pages, 0);
946 /// assert_eq!(stat.leaf_pages, 1);
947 /// assert_eq!(stat.overflow_pages, 0);
948 /// assert_eq!(stat.entries, 4);
949 ///
950 /// wtxn.commit()?;
951 /// # Ok(()) }
952 /// ```
953 pub fn stat(&self, txn: &RoTxn) -> Result<DatabaseStat> {
954 assert_eq_env_db_txn!(self, txn);
955
956 let mut db_stat = mem::MaybeUninit::uninit();
957 let result = unsafe { mdb_result(ffi::mdb_stat(txn.txn, self.dbi, db_stat.as_mut_ptr())) };
958
959 match result {
960 Ok(()) => {
961 let stats = unsafe { db_stat.assume_init() };
962 Ok(DatabaseStat {
963 page_size: stats.ms_psize,
964 depth: stats.ms_depth,
965 branch_pages: stats.ms_branch_pages,
966 leaf_pages: stats.ms_leaf_pages,
967 overflow_pages: stats.ms_overflow_pages,
968 entries: stats.ms_entries,
969 })
970 }
971 Err(e) => Err(e.into()),
972 }
973 }
974
975 /// Return a lexicographically ordered iterator of all key-value pairs in this database.
976 ///
977 /// You can make this iterator `Send`able between threads by
978 /// using the `read-txn-no-tls` crate feature.
979 ///
980 /// ```
981 /// # use std::fs;
982 /// # use std::path::Path;
983 /// # use heed::EnvOpenOptions;
984 /// use heed::Database;
985 /// use heed::types::*;
986 /// use heed::byteorder::BigEndian;
987 ///
988 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
989 /// # let dir = tempfile::tempdir()?;
990 /// # let env = unsafe { EnvOpenOptions::new()
991 /// # .map_size(10 * 1024 * 1024) // 10MB
992 /// # .max_dbs(3000)
993 /// # .open(dir.path())?
994 /// # };
995 /// type BEI32 = I32<BigEndian>;
996 ///
997 /// let mut wtxn = env.write_txn()?;
998 /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
999 ///
1000 /// # db.clear(&mut wtxn)?;
1001 /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
1002 /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
1003 /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
1004 ///
1005 /// let mut iter = db.iter(&wtxn)?;
1006 /// assert_eq!(iter.next().transpose()?, Some((13, "i-am-thirteen")));
1007 /// assert_eq!(iter.next().transpose()?, Some((27, "i-am-twenty-seven")));
1008 /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-forty-two")));
1009 /// assert_eq!(iter.next().transpose()?, None);
1010 ///
1011 /// drop(iter);
1012 /// wtxn.commit()?;
1013 /// # Ok(()) }
1014 /// ```
1015 pub fn iter<'txn>(&self, txn: &'txn RoTxn) -> Result<RoIter<'txn, KC, DC>> {
1016 assert_eq_env_db_txn!(self, txn);
1017 RoCursor::new(txn, self.dbi).map(|cursor| RoIter::new(cursor))
1018 }
1019
1020 /// Return a mutable lexicographically ordered iterator of all key-value pairs in this database.
1021 ///
1022 /// ```
1023 /// # use std::fs;
1024 /// # use std::path::Path;
1025 /// # use heed::EnvOpenOptions;
1026 /// use heed::Database;
1027 /// use heed::types::*;
1028 /// use heed::byteorder::BigEndian;
1029 ///
1030 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1031 /// # let dir = tempfile::tempdir()?;
1032 /// # let env = unsafe { EnvOpenOptions::new()
1033 /// # .map_size(10 * 1024 * 1024) // 10MB
1034 /// # .max_dbs(3000)
1035 /// # .open(dir.path())?
1036 /// # };
1037 /// type BEI32 = I32<BigEndian>;
1038 ///
1039 /// let mut wtxn = env.write_txn()?;
1040 /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1041 ///
1042 /// # db.clear(&mut wtxn)?;
1043 /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
1044 /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
1045 /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
1046 ///
1047 /// let mut iter = db.iter_mut(&mut wtxn)?;
1048 /// assert_eq!(iter.next().transpose()?, Some((13, "i-am-thirteen")));
1049 /// let ret = unsafe { iter.del_current()? };
1050 /// assert!(ret);
1051 ///
1052 /// assert_eq!(iter.next().transpose()?, Some((27, "i-am-twenty-seven")));
1053 /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-forty-two")));
1054 /// let ret = unsafe { iter.put_current(&42, "i-am-the-new-forty-two")? };
1055 /// assert!(ret);
1056 ///
1057 /// assert_eq!(iter.next().transpose()?, None);
1058 ///
1059 /// drop(iter);
1060 ///
1061 /// let ret = db.get(&wtxn, &13)?;
1062 /// assert_eq!(ret, None);
1063 ///
1064 /// let ret = db.get(&wtxn, &42)?;
1065 /// assert_eq!(ret, Some("i-am-the-new-forty-two"));
1066 ///
1067 /// wtxn.commit()?;
1068 /// # Ok(()) }
1069 /// ```
1070 pub fn iter_mut<'txn>(&self, txn: &'txn mut RwTxn) -> Result<RwIter<'txn, KC, DC>> {
1071 assert_eq_env_db_txn!(self, txn);
1072
1073 RwCursor::new(txn, self.dbi).map(|cursor| RwIter::new(cursor))
1074 }
1075
1076 /// Return a reversed lexicographically ordered iterator of all key-value pairs in this database.
1077 ///
1078 /// You can make this iterator `Send`able between threads by
1079 /// using the `read-txn-no-tls` crate feature.
1080 ///
1081 /// ```
1082 /// # use std::fs;
1083 /// # use std::path::Path;
1084 /// # use heed::EnvOpenOptions;
1085 /// use heed::Database;
1086 /// use heed::types::*;
1087 /// use heed::byteorder::BigEndian;
1088 ///
1089 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1090 /// # let dir = tempfile::tempdir()?;
1091 /// # let env = unsafe { EnvOpenOptions::new()
1092 /// # .map_size(10 * 1024 * 1024) // 10MB
1093 /// # .max_dbs(3000)
1094 /// # .open(dir.path())?
1095 /// # };
1096 /// type BEI32 = I32<BigEndian>;
1097 ///
1098 /// let mut wtxn = env.write_txn()?;
1099 /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1100 ///
1101 /// # db.clear(&mut wtxn)?;
1102 /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
1103 /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
1104 /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
1105 ///
1106 /// let mut iter = db.rev_iter(&wtxn)?;
1107 /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-forty-two")));
1108 /// assert_eq!(iter.next().transpose()?, Some((27, "i-am-twenty-seven")));
1109 /// assert_eq!(iter.next().transpose()?, Some((13, "i-am-thirteen")));
1110 /// assert_eq!(iter.next().transpose()?, None);
1111 ///
1112 /// drop(iter);
1113 /// wtxn.commit()?;
1114 /// # Ok(()) }
1115 /// ```
1116 pub fn rev_iter<'txn>(&self, txn: &'txn RoTxn) -> Result<RoRevIter<'txn, KC, DC>> {
1117 assert_eq_env_db_txn!(self, txn);
1118
1119 RoCursor::new(txn, self.dbi).map(|cursor| RoRevIter::new(cursor))
1120 }
1121
1122 /// Return a mutable reversed lexicographically ordered iterator of all key-value\
1123 /// pairs in this database.
1124 ///
1125 /// ```
1126 /// # use std::fs;
1127 /// # use std::path::Path;
1128 /// # use heed::EnvOpenOptions;
1129 /// use heed::Database;
1130 /// use heed::types::*;
1131 /// use heed::byteorder::BigEndian;
1132 ///
1133 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1134 /// # let dir = tempfile::tempdir()?;
1135 /// # let env = unsafe { EnvOpenOptions::new()
1136 /// # .map_size(10 * 1024 * 1024) // 10MB
1137 /// # .max_dbs(3000)
1138 /// # .open(dir.path())?
1139 /// # };
1140 /// type BEI32 = I32<BigEndian>;
1141 ///
1142 /// let mut wtxn = env.write_txn()?;
1143 /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1144 ///
1145 /// # db.clear(&mut wtxn)?;
1146 /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
1147 /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
1148 /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
1149 ///
1150 /// let mut iter = db.rev_iter_mut(&mut wtxn)?;
1151 /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-forty-two")));
1152 /// let ret = unsafe { iter.del_current()? };
1153 /// assert!(ret);
1154 ///
1155 /// assert_eq!(iter.next().transpose()?, Some((27, "i-am-twenty-seven")));
1156 /// assert_eq!(iter.next().transpose()?, Some((13, "i-am-thirteen")));
1157 /// let ret = unsafe { iter.put_current(&13, "i-am-the-new-thirteen")? };
1158 /// assert!(ret);
1159 ///
1160 /// assert_eq!(iter.next().transpose()?, None);
1161 ///
1162 /// drop(iter);
1163 ///
1164 /// let ret = db.get(&wtxn, &42)?;
1165 /// assert_eq!(ret, None);
1166 ///
1167 /// let ret = db.get(&wtxn, &13)?;
1168 /// assert_eq!(ret, Some("i-am-the-new-thirteen"));
1169 ///
1170 /// wtxn.commit()?;
1171 /// # Ok(()) }
1172 /// ```
1173 pub fn rev_iter_mut<'txn>(&self, txn: &'txn mut RwTxn) -> Result<RwRevIter<'txn, KC, DC>> {
1174 assert_eq_env_db_txn!(self, txn);
1175
1176 RwCursor::new(txn, self.dbi).map(|cursor| RwRevIter::new(cursor))
1177 }
1178
1179 /// Return a lexicographically ordered iterator of a range of key-value pairs in this database.
1180 ///
1181 /// Comparisons are made by using the bytes representation of the key.
1182 ///
1183 /// You can make this iterator `Send`able between threads by
1184 /// using the `read-txn-no-tls` crate feature.
1185 ///
1186 /// ```
1187 /// # use std::fs;
1188 /// # use std::path::Path;
1189 /// # use heed::EnvOpenOptions;
1190 /// use heed::Database;
1191 /// use heed::types::*;
1192 /// use heed::byteorder::BigEndian;
1193 ///
1194 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1195 /// # let dir = tempfile::tempdir()?;
1196 /// # let env = unsafe { EnvOpenOptions::new()
1197 /// # .map_size(10 * 1024 * 1024) // 10MB
1198 /// # .max_dbs(3000)
1199 /// # .open(dir.path())?
1200 /// # };
1201 /// type BEI32 = I32<BigEndian>;
1202 ///
1203 /// let mut wtxn = env.write_txn()?;
1204 /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1205 ///
1206 /// # db.clear(&mut wtxn)?;
1207 /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
1208 /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
1209 /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
1210 /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
1211 ///
1212 /// let range = 27..=42;
1213 /// let mut iter = db.range(&wtxn, &range)?;
1214 /// assert_eq!(iter.next().transpose()?, Some((27, "i-am-twenty-seven")));
1215 /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-forty-two")));
1216 /// assert_eq!(iter.next().transpose()?, None);
1217 ///
1218 /// drop(iter);
1219 /// wtxn.commit()?;
1220 /// # Ok(()) }
1221 /// ```
1222 pub fn range<'a, 'txn, R>(
1223 &self,
1224 txn: &'txn RoTxn,
1225 range: &'a R,
1226 ) -> Result<RoRange<'txn, KC, DC>>
1227 where
1228 KC: BytesEncode<'a>,
1229 R: RangeBounds<KC::EItem>,
1230 {
1231 assert_eq_env_db_txn!(self, txn);
1232
1233 let start_bound = match range.start_bound() {
1234 Bound::Included(bound) => {
1235 let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1236 Bound::Included(bytes.into_owned())
1237 }
1238 Bound::Excluded(bound) => {
1239 let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1240 Bound::Excluded(bytes.into_owned())
1241 }
1242 Bound::Unbounded => Bound::Unbounded,
1243 };
1244
1245 let end_bound = match range.end_bound() {
1246 Bound::Included(bound) => {
1247 let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1248 Bound::Included(bytes.into_owned())
1249 }
1250 Bound::Excluded(bound) => {
1251 let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1252 Bound::Excluded(bytes.into_owned())
1253 }
1254 Bound::Unbounded => Bound::Unbounded,
1255 };
1256
1257 RoCursor::new(txn, self.dbi).map(|cursor| RoRange::new(cursor, start_bound, end_bound))
1258 }
1259
1260 /// Return a mutable lexicographically ordered iterator of a range of
1261 /// key-value pairs in this database.
1262 ///
1263 /// Comparisons are made by using the bytes representation of the key.
1264 ///
1265 /// ```
1266 /// # use std::fs;
1267 /// # use std::path::Path;
1268 /// # use heed::EnvOpenOptions;
1269 /// use heed::Database;
1270 /// use heed::types::*;
1271 /// use heed::byteorder::BigEndian;
1272 ///
1273 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1274 /// # let dir = tempfile::tempdir()?;
1275 /// # let env = unsafe { EnvOpenOptions::new()
1276 /// # .map_size(10 * 1024 * 1024) // 10MB
1277 /// # .max_dbs(3000)
1278 /// # .open(dir.path())?
1279 /// # };
1280 /// type BEI32 = I32<BigEndian>;
1281 ///
1282 /// let mut wtxn = env.write_txn()?;
1283 /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1284 ///
1285 /// # db.clear(&mut wtxn)?;
1286 /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
1287 /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
1288 /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
1289 /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
1290 ///
1291 /// let range = 27..=42;
1292 /// let mut range = db.range_mut(&mut wtxn, &range)?;
1293 /// assert_eq!(range.next().transpose()?, Some((27, "i-am-twenty-seven")));
1294 /// let ret = unsafe { range.del_current()? };
1295 /// assert!(ret);
1296 /// assert_eq!(range.next().transpose()?, Some((42, "i-am-forty-two")));
1297 /// let ret = unsafe { range.put_current(&42, "i-am-the-new-forty-two")? };
1298 /// assert!(ret);
1299 ///
1300 /// assert_eq!(range.next().transpose()?, None);
1301 /// drop(range);
1302 ///
1303 ///
1304 /// let mut iter = db.iter(&wtxn)?;
1305 /// assert_eq!(iter.next().transpose()?, Some((13, "i-am-thirteen")));
1306 /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-the-new-forty-two")));
1307 /// assert_eq!(iter.next().transpose()?, Some((521, "i-am-five-hundred-and-twenty-one")));
1308 /// assert_eq!(iter.next().transpose()?, None);
1309 ///
1310 /// drop(iter);
1311 /// wtxn.commit()?;
1312 /// # Ok(()) }
1313 /// ```
1314 pub fn range_mut<'a, 'txn, R>(
1315 &self,
1316 txn: &'txn mut RwTxn,
1317 range: &'a R,
1318 ) -> Result<RwRange<'txn, KC, DC>>
1319 where
1320 KC: BytesEncode<'a>,
1321 R: RangeBounds<KC::EItem>,
1322 {
1323 assert_eq_env_db_txn!(self, txn);
1324
1325 let start_bound = match range.start_bound() {
1326 Bound::Included(bound) => {
1327 let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1328 Bound::Included(bytes.into_owned())
1329 }
1330 Bound::Excluded(bound) => {
1331 let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1332 Bound::Excluded(bytes.into_owned())
1333 }
1334 Bound::Unbounded => Bound::Unbounded,
1335 };
1336
1337 let end_bound = match range.end_bound() {
1338 Bound::Included(bound) => {
1339 let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1340 Bound::Included(bytes.into_owned())
1341 }
1342 Bound::Excluded(bound) => {
1343 let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1344 Bound::Excluded(bytes.into_owned())
1345 }
1346 Bound::Unbounded => Bound::Unbounded,
1347 };
1348
1349 RwCursor::new(txn, self.dbi).map(|cursor| RwRange::new(cursor, start_bound, end_bound))
1350 }
1351
1352 /// Return a reversed lexicographically ordered iterator of a range of key-value
1353 /// pairs in this database.
1354 ///
1355 /// Comparisons are made by using the bytes representation of the key.
1356 ///
1357 /// You can make this iterator `Send`able between threads by
1358 /// using the `read-txn-no-tls` crate feature.
1359 ///
1360 /// ```
1361 /// # use std::fs;
1362 /// # use std::path::Path;
1363 /// # use heed::EnvOpenOptions;
1364 /// use heed::Database;
1365 /// use heed::types::*;
1366 /// use heed::byteorder::BigEndian;
1367 ///
1368 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1369 /// # let dir = tempfile::tempdir()?;
1370 /// # let env = unsafe { EnvOpenOptions::new()
1371 /// # .map_size(10 * 1024 * 1024) // 10MB
1372 /// # .max_dbs(3000)
1373 /// # .open(dir.path())?
1374 /// # };
1375 /// type BEI32 = I32<BigEndian>;
1376 ///
1377 /// let mut wtxn = env.write_txn()?;
1378 /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1379 ///
1380 /// # db.clear(&mut wtxn)?;
1381 /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
1382 /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
1383 /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
1384 /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
1385 ///
1386 /// let range = 27..=43;
1387 /// let mut iter = db.rev_range(&wtxn, &range)?;
1388 /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-forty-two")));
1389 /// assert_eq!(iter.next().transpose()?, Some((27, "i-am-twenty-seven")));
1390 /// assert_eq!(iter.next().transpose()?, None);
1391 ///
1392 /// drop(iter);
1393 /// wtxn.commit()?;
1394 /// # Ok(()) }
1395 /// ```
1396 pub fn rev_range<'a, 'txn, R>(
1397 &self,
1398 txn: &'txn RoTxn,
1399 range: &'a R,
1400 ) -> Result<RoRevRange<'txn, KC, DC>>
1401 where
1402 KC: BytesEncode<'a>,
1403 R: RangeBounds<KC::EItem>,
1404 {
1405 assert_eq_env_db_txn!(self, txn);
1406
1407 let start_bound = match range.start_bound() {
1408 Bound::Included(bound) => {
1409 let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1410 Bound::Included(bytes.into_owned())
1411 }
1412 Bound::Excluded(bound) => {
1413 let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1414 Bound::Excluded(bytes.into_owned())
1415 }
1416 Bound::Unbounded => Bound::Unbounded,
1417 };
1418
1419 let end_bound = match range.end_bound() {
1420 Bound::Included(bound) => {
1421 let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1422 Bound::Included(bytes.into_owned())
1423 }
1424 Bound::Excluded(bound) => {
1425 let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1426 Bound::Excluded(bytes.into_owned())
1427 }
1428 Bound::Unbounded => Bound::Unbounded,
1429 };
1430
1431 RoCursor::new(txn, self.dbi).map(|cursor| RoRevRange::new(cursor, start_bound, end_bound))
1432 }
1433
1434 /// Return a mutable reversed lexicographically ordered iterator of a range of
1435 /// key-value pairs in this database.
1436 ///
1437 /// Comparisons are made by using the bytes representation of the key.
1438 ///
1439 /// ```
1440 /// # use std::fs;
1441 /// # use std::path::Path;
1442 /// # use heed::EnvOpenOptions;
1443 /// use heed::Database;
1444 /// use heed::types::*;
1445 /// use heed::byteorder::BigEndian;
1446 ///
1447 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1448 /// # let dir = tempfile::tempdir()?;
1449 /// # let env = unsafe { EnvOpenOptions::new()
1450 /// # .map_size(10 * 1024 * 1024) // 10MB
1451 /// # .max_dbs(3000)
1452 /// # .open(dir.path())?
1453 /// # };
1454 /// type BEI32 = I32<BigEndian>;
1455 ///
1456 /// let mut wtxn = env.write_txn()?;
1457 /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1458 ///
1459 /// # db.clear(&mut wtxn)?;
1460 /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
1461 /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
1462 /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
1463 /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
1464 ///
1465 /// let range = 27..=42;
1466 /// let mut range = db.rev_range_mut(&mut wtxn, &range)?;
1467 /// assert_eq!(range.next().transpose()?, Some((42, "i-am-forty-two")));
1468 /// let ret = unsafe { range.del_current()? };
1469 /// assert!(ret);
1470 /// assert_eq!(range.next().transpose()?, Some((27, "i-am-twenty-seven")));
1471 /// let ret = unsafe { range.put_current(&27, "i-am-the-new-twenty-seven")? };
1472 /// assert!(ret);
1473 ///
1474 /// assert_eq!(range.next().transpose()?, None);
1475 /// drop(range);
1476 ///
1477 ///
1478 /// let mut iter = db.iter(&wtxn)?;
1479 /// assert_eq!(iter.next().transpose()?, Some((13, "i-am-thirteen")));
1480 /// assert_eq!(iter.next().transpose()?, Some((27, "i-am-the-new-twenty-seven")));
1481 /// assert_eq!(iter.next().transpose()?, Some((521, "i-am-five-hundred-and-twenty-one")));
1482 /// assert_eq!(iter.next().transpose()?, None);
1483 ///
1484 /// drop(iter);
1485 /// wtxn.commit()?;
1486 /// # Ok(()) }
1487 /// ```
1488 pub fn rev_range_mut<'a, 'txn, R>(
1489 &self,
1490 txn: &'txn mut RwTxn,
1491 range: &'a R,
1492 ) -> Result<RwRevRange<'txn, KC, DC>>
1493 where
1494 KC: BytesEncode<'a>,
1495 R: RangeBounds<KC::EItem>,
1496 {
1497 assert_eq_env_db_txn!(self, txn);
1498
1499 let start_bound = match range.start_bound() {
1500 Bound::Included(bound) => {
1501 let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1502 Bound::Included(bytes.into_owned())
1503 }
1504 Bound::Excluded(bound) => {
1505 let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1506 Bound::Excluded(bytes.into_owned())
1507 }
1508 Bound::Unbounded => Bound::Unbounded,
1509 };
1510
1511 let end_bound = match range.end_bound() {
1512 Bound::Included(bound) => {
1513 let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1514 Bound::Included(bytes.into_owned())
1515 }
1516 Bound::Excluded(bound) => {
1517 let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1518 Bound::Excluded(bytes.into_owned())
1519 }
1520 Bound::Unbounded => Bound::Unbounded,
1521 };
1522
1523 RwCursor::new(txn, self.dbi).map(|cursor| RwRevRange::new(cursor, start_bound, end_bound))
1524 }
1525
1526 /// Return a lexicographically ordered iterator of all key-value pairs
1527 /// in this database that starts with the given prefix.
1528 ///
1529 /// Comparisons are made by using the bytes representation of the key.
1530 ///
1531 /// You can make this iterator `Send`able between threads by
1532 /// using the `read-txn-no-tls` crate feature.
1533 ///
1534 /// ```
1535 /// # use std::fs;
1536 /// # use std::path::Path;
1537 /// # use heed::EnvOpenOptions;
1538 /// use heed::Database;
1539 /// use heed::types::*;
1540 /// use heed::byteorder::BigEndian;
1541 ///
1542 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1543 /// # let dir = tempfile::tempdir()?;
1544 /// # let env = unsafe { EnvOpenOptions::new()
1545 /// # .map_size(10 * 1024 * 1024) // 10MB
1546 /// # .max_dbs(3000)
1547 /// # .open(dir.path())?
1548 /// # };
1549 /// type BEI32 = I32<BigEndian>;
1550 ///
1551 /// let mut wtxn = env.write_txn()?;
1552 /// let db: Database<Str, BEI32> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1553 ///
1554 /// # db.clear(&mut wtxn)?;
1555 /// db.put(&mut wtxn, "i-am-twenty-eight", &28)?;
1556 /// db.put(&mut wtxn, "i-am-twenty-seven", &27)?;
1557 /// db.put(&mut wtxn, "i-am-twenty-nine", &29)?;
1558 /// db.put(&mut wtxn, "i-am-forty-one", &41)?;
1559 /// db.put(&mut wtxn, "i-am-forty-two", &42)?;
1560 ///
1561 /// let mut iter = db.prefix_iter(&mut wtxn, "i-am-twenty")?;
1562 /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-eight", 28)));
1563 /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-nine", 29)));
1564 /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-seven", 27)));
1565 /// assert_eq!(iter.next().transpose()?, None);
1566 ///
1567 /// drop(iter);
1568 /// wtxn.commit()?;
1569 /// # Ok(()) }
1570 /// ```
1571 pub fn prefix_iter<'a, 'txn>(
1572 &self,
1573 txn: &'txn RoTxn,
1574 prefix: &'a KC::EItem,
1575 ) -> Result<RoPrefix<'txn, KC, DC, C>>
1576 where
1577 KC: BytesEncode<'a>,
1578 C: LexicographicComparator,
1579 {
1580 assert_eq_env_db_txn!(self, txn);
1581
1582 let prefix_bytes = KC::bytes_encode(prefix).map_err(Error::Encoding)?;
1583 let prefix_bytes = prefix_bytes.into_owned();
1584 RoCursor::new(txn, self.dbi).map(|cursor| RoPrefix::new(cursor, prefix_bytes))
1585 }
1586
1587 /// Return a mutable lexicographically ordered iterator of all key-value pairs
1588 /// in this database that starts with the given prefix.
1589 ///
1590 /// Comparisons are made by using the bytes representation of the key.
1591 ///
1592 /// ```
1593 /// # use std::fs;
1594 /// # use std::path::Path;
1595 /// # use heed::EnvOpenOptions;
1596 /// use heed::Database;
1597 /// use heed::types::*;
1598 /// use heed::byteorder::BigEndian;
1599 ///
1600 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1601 /// # let dir = tempfile::tempdir()?;
1602 /// # let env = unsafe { EnvOpenOptions::new()
1603 /// # .map_size(10 * 1024 * 1024) // 10MB
1604 /// # .max_dbs(3000)
1605 /// # .open(dir.path())?
1606 /// # };
1607 /// type BEI32 = I32<BigEndian>;
1608 ///
1609 /// let mut wtxn = env.write_txn()?;
1610 /// let db: Database<Str, BEI32> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1611 ///
1612 /// # db.clear(&mut wtxn)?;
1613 /// db.put(&mut wtxn, "i-am-twenty-eight", &28)?;
1614 /// db.put(&mut wtxn, "i-am-twenty-seven", &27)?;
1615 /// db.put(&mut wtxn, "i-am-twenty-nine", &29)?;
1616 /// db.put(&mut wtxn, "i-am-forty-one", &41)?;
1617 /// db.put(&mut wtxn, "i-am-forty-two", &42)?;
1618 ///
1619 /// let mut iter = db.prefix_iter_mut(&mut wtxn, "i-am-twenty")?;
1620 /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-eight", 28)));
1621 /// let ret = unsafe { iter.del_current()? };
1622 /// assert!(ret);
1623 ///
1624 /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-nine", 29)));
1625 /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-seven", 27)));
1626 /// let ret = unsafe { iter.put_current("i-am-twenty-seven", &27000)? };
1627 /// assert!(ret);
1628 ///
1629 /// assert_eq!(iter.next().transpose()?, None);
1630 ///
1631 /// drop(iter);
1632 ///
1633 /// let ret = db.get(&wtxn, "i-am-twenty-eight")?;
1634 /// assert_eq!(ret, None);
1635 ///
1636 /// let ret = db.get(&wtxn, "i-am-twenty-seven")?;
1637 /// assert_eq!(ret, Some(27000));
1638 ///
1639 /// wtxn.commit()?;
1640 /// # Ok(()) }
1641 /// ```
1642 pub fn prefix_iter_mut<'a, 'txn>(
1643 &self,
1644 txn: &'txn mut RwTxn,
1645 prefix: &'a KC::EItem,
1646 ) -> Result<RwPrefix<'txn, KC, DC, C>>
1647 where
1648 KC: BytesEncode<'a>,
1649 C: LexicographicComparator,
1650 {
1651 assert_eq_env_db_txn!(self, txn);
1652
1653 let prefix_bytes = KC::bytes_encode(prefix).map_err(Error::Encoding)?;
1654 let prefix_bytes = prefix_bytes.into_owned();
1655 RwCursor::new(txn, self.dbi).map(|cursor| RwPrefix::new(cursor, prefix_bytes))
1656 }
1657
1658 /// Return a reversed lexicographically ordered iterator of all key-value pairs
1659 /// in this database that starts with the given prefix.
1660 ///
1661 /// Comparisons are made by using the bytes representation of the key.
1662 ///
1663 /// You can make this iterator `Send`able between threads by
1664 /// using the `read-txn-no-tls` crate feature.
1665 ///
1666 /// ```
1667 /// # use std::fs;
1668 /// # use std::path::Path;
1669 /// # use heed::EnvOpenOptions;
1670 /// use heed::Database;
1671 /// use heed::types::*;
1672 /// use heed::byteorder::BigEndian;
1673 ///
1674 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1675 /// # let dir = tempfile::tempdir()?;
1676 /// # let env = unsafe { EnvOpenOptions::new()
1677 /// # .map_size(10 * 1024 * 1024) // 10MB
1678 /// # .max_dbs(3000)
1679 /// # .open(dir.path())?
1680 /// # };
1681 /// type BEI32 = I32<BigEndian>;
1682 ///
1683 /// let mut wtxn = env.write_txn()?;
1684 /// let db: Database<Str, BEI32> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1685 ///
1686 /// # db.clear(&mut wtxn)?;
1687 /// db.put(&mut wtxn, "i-am-twenty-eight", &28)?;
1688 /// db.put(&mut wtxn, "i-am-twenty-seven", &27)?;
1689 /// db.put(&mut wtxn, "i-am-twenty-nine", &29)?;
1690 /// db.put(&mut wtxn, "i-am-forty-one", &41)?;
1691 /// db.put(&mut wtxn, "i-am-forty-two", &42)?;
1692 ///
1693 /// let mut iter = db.rev_prefix_iter(&mut wtxn, "i-am-twenty")?;
1694 /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-seven", 27)));
1695 /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-nine", 29)));
1696 /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-eight", 28)));
1697 /// assert_eq!(iter.next().transpose()?, None);
1698 ///
1699 /// drop(iter);
1700 /// wtxn.commit()?;
1701 /// # Ok(()) }
1702 /// ```
1703 pub fn rev_prefix_iter<'a, 'txn>(
1704 &self,
1705 txn: &'txn RoTxn,
1706 prefix: &'a KC::EItem,
1707 ) -> Result<RoRevPrefix<'txn, KC, DC, C>>
1708 where
1709 KC: BytesEncode<'a>,
1710 C: LexicographicComparator,
1711 {
1712 assert_eq_env_db_txn!(self, txn);
1713
1714 let prefix_bytes = KC::bytes_encode(prefix).map_err(Error::Encoding)?;
1715 let prefix_bytes = prefix_bytes.into_owned();
1716 RoCursor::new(txn, self.dbi).map(|cursor| RoRevPrefix::new(cursor, prefix_bytes))
1717 }
1718
1719 /// Return a mutable reversed lexicographically ordered iterator of all key-value pairs
1720 /// in this database that starts with the given prefix.
1721 ///
1722 /// Comparisons are made by using the bytes representation of the key.
1723 ///
1724 /// ```
1725 /// # use std::fs;
1726 /// # use std::path::Path;
1727 /// # use heed::EnvOpenOptions;
1728 /// use heed::Database;
1729 /// use heed::types::*;
1730 /// use heed::byteorder::BigEndian;
1731 ///
1732 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1733 /// # let dir = tempfile::tempdir()?;
1734 /// # let env = unsafe { EnvOpenOptions::new()
1735 /// # .map_size(10 * 1024 * 1024) // 10MB
1736 /// # .max_dbs(3000)
1737 /// # .open(dir.path())?
1738 /// # };
1739 /// type BEI32 = I32<BigEndian>;
1740 ///
1741 /// let mut wtxn = env.write_txn()?;
1742 /// let db: Database<Str, BEI32> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1743 ///
1744 /// # db.clear(&mut wtxn)?;
1745 /// db.put(&mut wtxn, "i-am-twenty-eight", &28)?;
1746 /// db.put(&mut wtxn, "i-am-twenty-seven", &27)?;
1747 /// db.put(&mut wtxn, "i-am-twenty-nine", &29)?;
1748 /// db.put(&mut wtxn, "i-am-forty-one", &41)?;
1749 /// db.put(&mut wtxn, "i-am-forty-two", &42)?;
1750 ///
1751 /// let mut iter = db.rev_prefix_iter_mut(&mut wtxn, "i-am-twenty")?;
1752 /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-seven", 27)));
1753 /// let ret = unsafe { iter.del_current()? };
1754 /// assert!(ret);
1755 ///
1756 /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-nine", 29)));
1757 /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-eight", 28)));
1758 /// let ret = unsafe { iter.put_current("i-am-twenty-eight", &28000)? };
1759 /// assert!(ret);
1760 ///
1761 /// assert_eq!(iter.next().transpose()?, None);
1762 ///
1763 /// drop(iter);
1764 ///
1765 /// let ret = db.get(&wtxn, "i-am-twenty-seven")?;
1766 /// assert_eq!(ret, None);
1767 ///
1768 /// let ret = db.get(&wtxn, "i-am-twenty-eight")?;
1769 /// assert_eq!(ret, Some(28000));
1770 ///
1771 /// wtxn.commit()?;
1772 /// # Ok(()) }
1773 /// ```
1774 pub fn rev_prefix_iter_mut<'a, 'txn>(
1775 &self,
1776 txn: &'txn mut RwTxn,
1777 prefix: &'a KC::EItem,
1778 ) -> Result<RwRevPrefix<'txn, KC, DC, C>>
1779 where
1780 KC: BytesEncode<'a>,
1781 C: LexicographicComparator,
1782 {
1783 assert_eq_env_db_txn!(self, txn);
1784
1785 let prefix_bytes = KC::bytes_encode(prefix).map_err(Error::Encoding)?;
1786 let prefix_bytes = prefix_bytes.into_owned();
1787 RwCursor::new(txn, self.dbi).map(|cursor| RwRevPrefix::new(cursor, prefix_bytes))
1788 }
1789
1790 /// Insert a key-value pair in this database, replacing any previous value. The entry is
1791 /// written with no specific flag.
1792 ///
1793 /// ```
1794 /// # use std::fs;
1795 /// # use std::path::Path;
1796 /// # use heed::EnvOpenOptions;
1797 /// use heed::Database;
1798 /// use heed::types::*;
1799 /// use heed::byteorder::BigEndian;
1800 ///
1801 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1802 /// # let dir = tempfile::tempdir()?;
1803 /// # let env = unsafe { EnvOpenOptions::new()
1804 /// # .map_size(10 * 1024 * 1024) // 10MB
1805 /// # .max_dbs(3000)
1806 /// # .open(dir.path())?
1807 /// # };
1808 /// type BEI32 = I32<BigEndian>;
1809 ///
1810 /// let mut wtxn = env.write_txn()?;
1811 /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1812 ///
1813 /// # db.clear(&mut wtxn)?;
1814 /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
1815 /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
1816 /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
1817 /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
1818 ///
1819 /// let ret = db.get(&mut wtxn, &27)?;
1820 /// assert_eq!(ret, Some("i-am-twenty-seven"));
1821 ///
1822 /// wtxn.commit()?;
1823 /// # Ok(()) }
1824 /// ```
1825 pub fn put<'a>(&self, txn: &mut RwTxn, key: &'a KC::EItem, data: &'a DC::EItem) -> Result<()>
1826 where
1827 KC: BytesEncode<'a>,
1828 DC: BytesEncode<'a>,
1829 {
1830 assert_eq_env_db_txn!(self, txn);
1831
1832 let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
1833 let data_bytes: Cow<[u8]> = DC::bytes_encode(data).map_err(Error::Encoding)?;
1834
1835 let mut key_val = unsafe { crate::into_val(&key_bytes) };
1836 let mut data_val = unsafe { crate::into_val(&data_bytes) };
1837 let flags = 0;
1838
1839 unsafe {
1840 mdb_result(ffi::mdb_put(txn.txn.txn, self.dbi, &mut key_val, &mut data_val, flags))?
1841 }
1842
1843 Ok(())
1844 }
1845
1846 /// Insert a key-value pair where the value can directly be written to disk, replacing any
1847 /// previous value.
1848 ///
1849 /// ```
1850 /// # use std::fs;
1851 /// # use std::path::Path;
1852 /// # use heed::EnvOpenOptions;
1853 /// use std::io::Write;
1854 /// use heed::Database;
1855 /// use heed::types::*;
1856 /// use heed::byteorder::BigEndian;
1857 ///
1858 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1859 /// # let dir = tempfile::tempdir()?;
1860 /// # let env = unsafe { EnvOpenOptions::new()
1861 /// # .map_size(10 * 1024 * 1024) // 10MB
1862 /// # .max_dbs(3000)
1863 /// # .open(dir.path())?
1864 /// # };
1865 /// type BEI32 = I32<BigEndian>;
1866 ///
1867 /// let mut wtxn = env.write_txn()?;
1868 /// let db = env.create_database::<BEI32, Str>(&mut wtxn, Some("number-string"))?;
1869 ///
1870 /// # db.clear(&mut wtxn)?;
1871 /// let value = "I am a long long long value";
1872 /// db.put_reserved(&mut wtxn, &42, value.len(), |reserved| {
1873 /// reserved.write_all(value.as_bytes())
1874 /// })?;
1875 ///
1876 /// let ret = db.get(&mut wtxn, &42)?;
1877 /// assert_eq!(ret, Some(value));
1878 ///
1879 /// wtxn.commit()?;
1880 /// # Ok(()) }
1881 /// ```
1882 pub fn put_reserved<'a, F>(
1883 &self,
1884 txn: &mut RwTxn,
1885 key: &'a KC::EItem,
1886 data_size: usize,
1887 write_func: F,
1888 ) -> Result<()>
1889 where
1890 KC: BytesEncode<'a>,
1891 F: FnOnce(&mut ReservedSpace) -> io::Result<()>,
1892 {
1893 assert_eq_env_db_txn!(self, txn);
1894
1895 let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
1896 let mut key_val = unsafe { crate::into_val(&key_bytes) };
1897 let mut reserved = ffi::reserve_size_val(data_size);
1898 let flags = ffi::MDB_RESERVE;
1899
1900 unsafe {
1901 mdb_result(ffi::mdb_put(txn.txn.txn, self.dbi, &mut key_val, &mut reserved, flags))?
1902 }
1903
1904 let mut reserved = unsafe { ReservedSpace::from_val(reserved) };
1905 write_func(&mut reserved)?;
1906 if reserved.remaining() == 0 {
1907 Ok(())
1908 } else {
1909 Err(io::Error::from(io::ErrorKind::UnexpectedEof).into())
1910 }
1911 }
1912
1913 /// Insert a key-value pair in this database, replacing any previous value. The entry is
1914 /// written with the specified flags.
1915 ///
1916 /// ```
1917 /// # use std::fs;
1918 /// # use std::path::Path;
1919 /// # use heed::EnvOpenOptions;
1920 /// use heed::{Database, PutFlags, DatabaseFlags, Error, MdbError};
1921 /// use heed::types::*;
1922 /// use heed::byteorder::BigEndian;
1923 ///
1924 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1925 /// # let dir = tempfile::tempdir()?;
1926 /// # let env = unsafe { EnvOpenOptions::new()
1927 /// # .map_size(10 * 1024 * 1024) // 10MB
1928 /// # .max_dbs(3000)
1929 /// # .open(dir.path())?
1930 /// # };
1931 /// type BEI32 = I32<BigEndian>;
1932 ///
1933 /// let mut wtxn = env.write_txn()?;
1934 /// let db = env.database_options()
1935 /// .types::<BEI32, Str>()
1936 /// .name("dup-i32")
1937 /// .flags(DatabaseFlags::DUP_SORT)
1938 /// .create(&mut wtxn)?;
1939 ///
1940 /// # db.clear(&mut wtxn)?;
1941 /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
1942 /// db.put(&mut wtxn, &42, "i-am-so-cool")?;
1943 /// db.put(&mut wtxn, &42, "i-am-the-king")?;
1944 /// db.put(&mut wtxn, &42, "i-am-fun")?;
1945 /// db.put_with_flags(&mut wtxn, PutFlags::APPEND, &54, "i-am-older-than-you")?;
1946 /// db.put_with_flags(&mut wtxn, PutFlags::APPEND_DUP, &54, "ok-but-i-am-better-than-you")?;
1947 /// // You can compose flags by OR'ing them
1948 /// db.put_with_flags(&mut wtxn, PutFlags::APPEND_DUP | PutFlags::NO_OVERWRITE, &55, "welcome")?;
1949 ///
1950 /// // The NO_DUP_DATA flag will return KeyExist if we try to insert the exact same key/value pair.
1951 /// let ret = db.put_with_flags(&mut wtxn, PutFlags::NO_DUP_DATA, &54, "ok-but-i-am-better-than-you");
1952 /// assert!(matches!(ret, Err(Error::Mdb(MdbError::KeyExist))));
1953 ///
1954 /// // The NO_OVERWRITE flag will return KeyExist if we try to insert something with an already existing key.
1955 /// let ret = db.put_with_flags(&mut wtxn, PutFlags::NO_OVERWRITE, &54, "there-can-be-only-one-data");
1956 /// assert!(matches!(ret, Err(Error::Mdb(MdbError::KeyExist))));
1957 ///
1958 /// let mut iter = db.iter(&wtxn)?;
1959 /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-forty-two")));
1960 /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-fun")));
1961 /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-so-cool")));
1962 /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-the-king")));
1963 /// assert_eq!(iter.next().transpose()?, Some((54, "i-am-older-than-you")));
1964 /// assert_eq!(iter.next().transpose()?, Some((54, "ok-but-i-am-better-than-you")));
1965 /// assert_eq!(iter.next().transpose()?, Some((55, "welcome")));
1966 /// assert_eq!(iter.next().transpose()?, None);
1967 ///
1968 /// drop(iter);
1969 /// wtxn.commit()?;
1970 /// # Ok(()) }
1971 /// ```
1972 pub fn put_with_flags<'a>(
1973 &self,
1974 txn: &mut RwTxn,
1975 flags: PutFlags,
1976 key: &'a KC::EItem,
1977 data: &'a DC::EItem,
1978 ) -> Result<()>
1979 where
1980 KC: BytesEncode<'a>,
1981 DC: BytesEncode<'a>,
1982 {
1983 assert_eq_env_db_txn!(self, txn);
1984
1985 let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
1986 let data_bytes: Cow<[u8]> = DC::bytes_encode(data).map_err(Error::Encoding)?;
1987
1988 let mut key_val = unsafe { crate::into_val(&key_bytes) };
1989 let mut data_val = unsafe { crate::into_val(&data_bytes) };
1990 let flags = flags.bits();
1991
1992 unsafe {
1993 mdb_result(ffi::mdb_put(txn.txn.txn, self.dbi, &mut key_val, &mut data_val, flags))?
1994 }
1995
1996 Ok(())
1997 }
1998
1999 /// Attempt to insert a key-value pair in this database, or if a value already exists for the
2000 /// key, returns the previous value.
2001 ///
2002 /// The entry is always written with the [`NO_OVERWRITE`](PutFlags::NO_OVERWRITE) flag.
2003 ///
2004 /// ```
2005 /// # use heed::EnvOpenOptions;
2006 /// use heed::Database;
2007 /// use heed::types::*;
2008 /// use heed::byteorder::BigEndian;
2009 ///
2010 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
2011 /// # let dir = tempfile::tempdir()?;
2012 /// # let env = unsafe { EnvOpenOptions::new()
2013 /// # .map_size(10 * 1024 * 1024) // 10MB
2014 /// # .max_dbs(3000)
2015 /// # .open(dir.path())?
2016 /// # };
2017 /// type BEI32 = I32<BigEndian>;
2018 ///
2019 /// let mut wtxn = env.write_txn()?;
2020 /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
2021 ///
2022 /// # db.clear(&mut wtxn)?;
2023 /// assert_eq!(db.get_or_put(&mut wtxn, &42, "i-am-forty-two")?, None);
2024 /// assert_eq!(db.get_or_put(&mut wtxn, &42, "the meaning of life")?, Some("i-am-forty-two"));
2025 ///
2026 /// let ret = db.get(&mut wtxn, &42)?;
2027 /// assert_eq!(ret, Some("i-am-forty-two"));
2028 ///
2029 /// wtxn.commit()?;
2030 /// # Ok(()) }
2031 /// ```
2032 pub fn get_or_put<'a, 'txn>(
2033 &'txn self,
2034 txn: &mut RwTxn,
2035 key: &'a KC::EItem,
2036 data: &'a DC::EItem,
2037 ) -> Result<Option<DC::DItem>>
2038 where
2039 KC: BytesEncode<'a>,
2040 DC: BytesEncode<'a> + BytesDecode<'a>,
2041 {
2042 self.get_or_put_with_flags(txn, PutFlags::empty(), key, data)
2043 }
2044
2045 /// Attempt to insert a key-value pair in this database, or if a value already exists for the
2046 /// key, returns the previous value.
2047 ///
2048 /// The entry is written with the specified flags, in addition to
2049 /// [`NO_OVERWRITE`](PutFlags::NO_OVERWRITE) which is always used.
2050 ///
2051 /// ```
2052 /// # use heed::EnvOpenOptions;
2053 /// use heed::{Database, PutFlags};
2054 /// use heed::types::*;
2055 /// use heed::byteorder::BigEndian;
2056 ///
2057 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
2058 /// # let dir = tempfile::tempdir()?;
2059 /// # let env = unsafe { EnvOpenOptions::new()
2060 /// # .map_size(10 * 1024 * 1024) // 10MB
2061 /// # .max_dbs(3000)
2062 /// # .open(dir.path())?
2063 /// # };
2064 /// type BEI32 = I32<BigEndian>;
2065 ///
2066 /// let mut wtxn = env.write_txn()?;
2067 /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
2068 ///
2069 /// # db.clear(&mut wtxn)?;
2070 /// assert_eq!(db.get_or_put_with_flags(&mut wtxn, PutFlags::empty(), &42, "i-am-forty-two")?, None);
2071 /// assert_eq!(db.get_or_put_with_flags(&mut wtxn, PutFlags::empty(), &42, "the meaning of life")?, Some("i-am-forty-two"));
2072 ///
2073 /// let ret = db.get(&mut wtxn, &42)?;
2074 /// assert_eq!(ret, Some("i-am-forty-two"));
2075 ///
2076 /// wtxn.commit()?;
2077 /// # Ok(()) }
2078 /// ```
2079 pub fn get_or_put_with_flags<'a, 'txn>(
2080 &'txn self,
2081 txn: &mut RwTxn,
2082 flags: PutFlags,
2083 key: &'a KC::EItem,
2084 data: &'a DC::EItem,
2085 ) -> Result<Option<DC::DItem>>
2086 where
2087 KC: BytesEncode<'a>,
2088 DC: BytesEncode<'a> + BytesDecode<'a>,
2089 {
2090 assert_eq_env_db_txn!(self, txn);
2091
2092 let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
2093 let data_bytes: Cow<[u8]> = DC::bytes_encode(data).map_err(Error::Encoding)?;
2094
2095 let mut key_val = unsafe { crate::into_val(&key_bytes) };
2096 let mut data_val = unsafe { crate::into_val(&data_bytes) };
2097 let flags = (flags | PutFlags::NO_OVERWRITE).bits();
2098
2099 let result = unsafe {
2100 mdb_result(ffi::mdb_put(txn.txn.txn, self.dbi, &mut key_val, &mut data_val, flags))
2101 };
2102
2103 match result {
2104 // the value was successfully inserted
2105 Ok(()) => Ok(None),
2106 // the key already exists: the previous value is stored in the data parameter
2107 Err(MdbError::KeyExist) => {
2108 let bytes = unsafe { crate::from_val(data_val) };
2109 let data = DC::bytes_decode(bytes).map_err(Error::Decoding)?;
2110 Ok(Some(data))
2111 }
2112 Err(error) => Err(error.into()),
2113 }
2114 }
2115
2116 /// Attempt to insert a key-value pair in this database, where the value can be directly
2117 /// written to disk, or if a value already exists for the key, returns the previous value.
2118 ///
2119 /// The entry is always written with the [`NO_OVERWRITE`](PutFlags::NO_OVERWRITE) and
2120 /// [`MDB_RESERVE`](lmdb_master_sys::MDB_RESERVE) flags.
2121 ///
2122 /// ```
2123 /// # use heed::EnvOpenOptions;
2124 /// use std::io::Write;
2125 /// use heed::{Database, PutFlags};
2126 /// use heed::types::*;
2127 /// use heed::byteorder::BigEndian;
2128 ///
2129 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
2130 /// # let dir = tempfile::tempdir()?;
2131 /// # let env = unsafe { EnvOpenOptions::new()
2132 /// # .map_size(10 * 1024 * 1024) // 10MB
2133 /// # .max_dbs(3000)
2134 /// # .open(dir.path())?
2135 /// # };
2136 /// type BEI32 = I32<BigEndian>;
2137 ///
2138 /// let mut wtxn = env.write_txn()?;
2139 /// let db = env.create_database::<BEI32, Str>(&mut wtxn, Some("number-string"))?;
2140 ///
2141 /// # db.clear(&mut wtxn)?;
2142 /// let long = "I am a long long long value";
2143 /// assert_eq!(
2144 /// db.get_or_put_reserved(&mut wtxn, &42, long.len(), |reserved| {
2145 /// reserved.write_all(long.as_bytes())
2146 /// })?,
2147 /// None
2148 /// );
2149 ///
2150 /// let longer = "I am an even longer long long long value";
2151 /// assert_eq!(
2152 /// db.get_or_put_reserved(&mut wtxn, &42, longer.len(), |reserved| {
2153 /// unreachable!()
2154 /// })?,
2155 /// Some(long)
2156 /// );
2157 ///
2158 /// let ret = db.get(&mut wtxn, &42)?;
2159 /// assert_eq!(ret, Some(long));
2160 ///
2161 /// wtxn.commit()?;
2162 /// # Ok(()) }
2163 /// ```
2164 pub fn get_or_put_reserved<'a, 'txn, F>(
2165 &'txn self,
2166 txn: &mut RwTxn,
2167 key: &'a KC::EItem,
2168 data_size: usize,
2169 write_func: F,
2170 ) -> Result<Option<DC::DItem>>
2171 where
2172 KC: BytesEncode<'a>,
2173 F: FnOnce(&mut ReservedSpace) -> io::Result<()>,
2174 DC: BytesDecode<'a>,
2175 {
2176 self.get_or_put_reserved_with_flags(txn, PutFlags::empty(), key, data_size, write_func)
2177 }
2178
2179 /// Attempt to insert a key-value pair in this database, where the value can be directly
2180 /// written to disk, or if a value already exists for the key, returns the previous value.
2181 ///
2182 /// The entry is written with the specified flags, in addition to
2183 /// [`NO_OVERWRITE`](PutFlags::NO_OVERWRITE) and [`MDB_RESERVE`](lmdb_master_sys::MDB_RESERVE)
2184 /// which are always used.
2185 ///
2186 /// ```
2187 /// # use heed::EnvOpenOptions;
2188 /// use std::io::Write;
2189 /// use heed::{Database, PutFlags};
2190 /// use heed::types::*;
2191 /// use heed::byteorder::BigEndian;
2192 ///
2193 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
2194 /// # let dir = tempfile::tempdir()?;
2195 /// # let env = unsafe { EnvOpenOptions::new()
2196 /// # .map_size(10 * 1024 * 1024) // 10MB
2197 /// # .max_dbs(3000)
2198 /// # .open(dir.path())?
2199 /// # };
2200 /// type BEI32 = I32<BigEndian>;
2201 ///
2202 /// let mut wtxn = env.write_txn()?;
2203 /// let db = env.create_database::<BEI32, Str>(&mut wtxn, Some("number-string"))?;
2204 ///
2205 /// # db.clear(&mut wtxn)?;
2206 /// let long = "I am a long long long value";
2207 /// assert_eq!(
2208 /// db.get_or_put_reserved_with_flags(&mut wtxn, PutFlags::empty(), &42, long.len(), |reserved| {
2209 /// reserved.write_all(long.as_bytes())
2210 /// })?,
2211 /// None
2212 /// );
2213 ///
2214 /// let longer = "I am an even longer long long long value";
2215 /// assert_eq!(
2216 /// db.get_or_put_reserved_with_flags(&mut wtxn, PutFlags::empty(), &42, longer.len(), |reserved| {
2217 /// unreachable!()
2218 /// })?,
2219 /// Some(long)
2220 /// );
2221 ///
2222 /// let ret = db.get(&mut wtxn, &42)?;
2223 /// assert_eq!(ret, Some(long));
2224 ///
2225 /// wtxn.commit()?;
2226 /// # Ok(()) }
2227 /// ```
2228 pub fn get_or_put_reserved_with_flags<'a, 'txn, F>(
2229 &'txn self,
2230 txn: &mut RwTxn,
2231 flags: PutFlags,
2232 key: &'a KC::EItem,
2233 data_size: usize,
2234 write_func: F,
2235 ) -> Result<Option<DC::DItem>>
2236 where
2237 KC: BytesEncode<'a>,
2238 F: FnOnce(&mut ReservedSpace) -> io::Result<()>,
2239 DC: BytesDecode<'a>,
2240 {
2241 assert_eq_env_db_txn!(self, txn);
2242
2243 let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
2244
2245 let mut key_val = unsafe { crate::into_val(&key_bytes) };
2246 let mut reserved = ffi::reserve_size_val(data_size);
2247 let flags = (flags | PutFlags::NO_OVERWRITE).bits() | lmdb_master_sys::MDB_RESERVE;
2248
2249 let result = unsafe {
2250 mdb_result(ffi::mdb_put(txn.txn.txn, self.dbi, &mut key_val, &mut reserved, flags))
2251 };
2252
2253 match result {
2254 // value was inserted: fill the reserved space
2255 Ok(()) => {
2256 let mut reserved = unsafe { ReservedSpace::from_val(reserved) };
2257 write_func(&mut reserved)?;
2258 if reserved.remaining() == 0 {
2259 Ok(None)
2260 } else {
2261 Err(io::Error::from(io::ErrorKind::UnexpectedEof).into())
2262 }
2263 }
2264 // the key already exists: the previous value is stored in the data parameter
2265 Err(MdbError::KeyExist) => {
2266 let bytes = unsafe { crate::from_val(reserved) };
2267 let data = DC::bytes_decode(bytes).map_err(Error::Decoding)?;
2268 Ok(Some(data))
2269 }
2270 Err(error) => Err(error.into()),
2271 }
2272 }
2273
2274 /// Deletes an entry or every duplicate data items of a key
2275 /// if the database supports duplicate data items.
2276 ///
2277 /// If the entry does not exist, then `false` is returned.
2278 ///
2279 /// ```
2280 /// # use std::fs;
2281 /// # use std::path::Path;
2282 /// # use heed::EnvOpenOptions;
2283 /// use heed::Database;
2284 /// use heed::types::*;
2285 /// use heed::byteorder::BigEndian;
2286 ///
2287 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
2288 /// # let dir = tempfile::tempdir()?;
2289 /// # let env = unsafe { EnvOpenOptions::new()
2290 /// # .map_size(10 * 1024 * 1024) // 10MB
2291 /// # .max_dbs(3000)
2292 /// # .open(dir.path())?
2293 /// # };
2294 /// type BEI32 = I32<BigEndian>;
2295 ///
2296 /// let mut wtxn = env.write_txn()?;
2297 /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
2298 ///
2299 /// # db.clear(&mut wtxn)?;
2300 /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
2301 /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
2302 /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
2303 /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
2304 ///
2305 /// let ret = db.delete(&mut wtxn, &27)?;
2306 /// assert_eq!(ret, true);
2307 ///
2308 /// let ret = db.get(&mut wtxn, &27)?;
2309 /// assert_eq!(ret, None);
2310 ///
2311 /// let ret = db.delete(&mut wtxn, &467)?;
2312 /// assert_eq!(ret, false);
2313 ///
2314 /// wtxn.commit()?;
2315 /// # Ok(()) }
2316 /// ```
2317 pub fn delete<'a>(&self, txn: &mut RwTxn, key: &'a KC::EItem) -> Result<bool>
2318 where
2319 KC: BytesEncode<'a>,
2320 {
2321 assert_eq_env_db_txn!(self, txn);
2322
2323 let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
2324 let mut key_val = unsafe { crate::into_val(&key_bytes) };
2325
2326 let result = unsafe {
2327 mdb_result(ffi::mdb_del(txn.txn.txn, self.dbi, &mut key_val, ptr::null_mut()))
2328 };
2329
2330 match result {
2331 Ok(()) => Ok(true),
2332 Err(e) if e.not_found() => Ok(false),
2333 Err(e) => Err(e.into()),
2334 }
2335 }
2336
2337 /// Deletes a single key-value pair in this database.
2338 ///
2339 /// If the database doesn't support duplicate data items the data is ignored.
2340 /// If the key does not exist, then `false` is returned.
2341 ///
2342 /// ```
2343 /// # use std::fs;
2344 /// # use std::path::Path;
2345 /// # use heed::{DatabaseFlags, EnvOpenOptions};
2346 /// use heed::types::*;
2347 /// use heed::byteorder::BigEndian;
2348 ///
2349 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
2350 /// # let dir = tempfile::tempdir()?;
2351 /// # let env = unsafe { EnvOpenOptions::new()
2352 /// # .map_size(10 * 1024 * 1024) // 10MB
2353 /// # .max_dbs(3000)
2354 /// # .open(dir.path())?
2355 /// # };
2356 /// type BEI64 = I64<BigEndian>;
2357 ///
2358 /// let mut wtxn = env.write_txn()?;
2359 /// let db = env.database_options()
2360 /// .types::<BEI64, BEI64>()
2361 /// .flags(DatabaseFlags::DUP_SORT)
2362 /// .name("dup-sort")
2363 /// .create(&mut wtxn)?;
2364 ///
2365 /// # db.clear(&mut wtxn)?;
2366 /// db.put(&mut wtxn, &68, &120)?;
2367 /// db.put(&mut wtxn, &68, &121)?;
2368 /// db.put(&mut wtxn, &68, &122)?;
2369 /// db.put(&mut wtxn, &68, &123)?;
2370 /// db.put(&mut wtxn, &92, &32)?;
2371 /// db.put(&mut wtxn, &35, &120)?;
2372 /// db.put(&mut wtxn, &0, &120)?;
2373 /// db.put(&mut wtxn, &42, &120)?;
2374 ///
2375 /// let mut iter = db.get_duplicates(&wtxn, &68)?.expect("the key exists");
2376 /// assert_eq!(iter.next().transpose()?, Some((68, 120)));
2377 /// assert_eq!(iter.next().transpose()?, Some((68, 121)));
2378 /// assert_eq!(iter.next().transpose()?, Some((68, 122)));
2379 /// assert_eq!(iter.next().transpose()?, Some((68, 123)));
2380 /// assert_eq!(iter.next().transpose()?, None);
2381 /// drop(iter);
2382 ///
2383 /// assert!(db.delete_one_duplicate(&mut wtxn, &68, &121)?, "The entry must exist");
2384 ///
2385 /// let mut iter = db.get_duplicates(&wtxn, &68)?.expect("the key exists");
2386 /// assert_eq!(iter.next().transpose()?, Some((68, 120)));
2387 /// // No more (68, 121) returned here!
2388 /// assert_eq!(iter.next().transpose()?, Some((68, 122)));
2389 /// assert_eq!(iter.next().transpose()?, Some((68, 123)));
2390 /// assert_eq!(iter.next().transpose()?, None);
2391 /// drop(iter);
2392 ///
2393 /// wtxn.commit()?;
2394 /// # Ok(()) }
2395 /// ```
2396 pub fn delete_one_duplicate<'a>(
2397 &self,
2398 txn: &mut RwTxn,
2399 key: &'a KC::EItem,
2400 data: &'a DC::EItem,
2401 ) -> Result<bool>
2402 where
2403 KC: BytesEncode<'a>,
2404 DC: BytesEncode<'a>,
2405 {
2406 assert_eq_env_db_txn!(self, txn);
2407
2408 let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
2409 let data_bytes: Cow<[u8]> = DC::bytes_encode(data).map_err(Error::Encoding)?;
2410 let mut key_val = unsafe { crate::into_val(&key_bytes) };
2411 let mut data_val = unsafe { crate::into_val(&data_bytes) };
2412
2413 let result =
2414 unsafe { mdb_result(ffi::mdb_del(txn.txn.txn, self.dbi, &mut key_val, &mut data_val)) };
2415
2416 match result {
2417 Ok(()) => Ok(true),
2418 Err(e) if e.not_found() => Ok(false),
2419 Err(e) => Err(e.into()),
2420 }
2421 }
2422
2423 /// Deletes a range of key-value pairs in this database.
2424 ///
2425 /// Prefer using [`clear`] instead of a call to this method with a full range ([`..`]).
2426 ///
2427 /// Comparisons are made by using the bytes representation of the key.
2428 ///
2429 /// [`clear`]: crate::Database::clear
2430 /// [`..`]: std::ops::RangeFull
2431 ///
2432 /// ```
2433 /// # use std::fs;
2434 /// # use std::path::Path;
2435 /// # use heed::EnvOpenOptions;
2436 /// use heed::Database;
2437 /// use heed::types::*;
2438 /// use heed::byteorder::BigEndian;
2439 ///
2440 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
2441 /// # let dir = tempfile::tempdir()?;
2442 /// # let env = unsafe { EnvOpenOptions::new()
2443 /// # .map_size(10 * 1024 * 1024) // 10MB
2444 /// # .max_dbs(3000)
2445 /// # .open(dir.path())?
2446 /// # };
2447 /// type BEI32 = I32<BigEndian>;
2448 ///
2449 /// let mut wtxn = env.write_txn()?;
2450 /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
2451 ///
2452 /// # db.clear(&mut wtxn)?;
2453 /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
2454 /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
2455 /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
2456 /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
2457 ///
2458 /// let range = 27..=42;
2459 /// let ret = db.delete_range(&mut wtxn, &range)?;
2460 /// assert_eq!(ret, 2);
2461 ///
2462 ///
2463 /// let mut iter = db.iter(&wtxn)?;
2464 /// assert_eq!(iter.next().transpose()?, Some((13, "i-am-thirteen")));
2465 /// assert_eq!(iter.next().transpose()?, Some((521, "i-am-five-hundred-and-twenty-one")));
2466 /// assert_eq!(iter.next().transpose()?, None);
2467 ///
2468 /// drop(iter);
2469 /// wtxn.commit()?;
2470 /// # Ok(()) }
2471 /// ```
2472 pub fn delete_range<'a, 'txn, R>(&self, txn: &'txn mut RwTxn, range: &'a R) -> Result<usize>
2473 where
2474 KC: BytesEncode<'a> + BytesDecode<'txn>,
2475 R: RangeBounds<KC::EItem>,
2476 {
2477 assert_eq_env_db_txn!(self, txn);
2478
2479 let mut count = 0;
2480 let mut iter = self.remap_data_type::<DecodeIgnore>().range_mut(txn, range)?;
2481
2482 while iter.next().is_some() {
2483 // safety: We do not keep any reference from the database while using `del_current`.
2484 // The user can't keep any reference inside of the database as we ask for a
2485 // mutable reference to the `txn`.
2486 unsafe { iter.del_current()? };
2487 count += 1;
2488 }
2489
2490 Ok(count)
2491 }
2492
2493 /// Deletes all key/value pairs in this database.
2494 ///
2495 /// Prefer using this method instead of a call to [`delete_range`] with a full range ([`..`]).
2496 ///
2497 /// [`delete_range`]: crate::Database::delete_range
2498 /// [`..`]: std::ops::RangeFull
2499 ///
2500 /// ```
2501 /// # use std::fs;
2502 /// # use std::path::Path;
2503 /// # use heed::EnvOpenOptions;
2504 /// use heed::Database;
2505 /// use heed::types::*;
2506 /// use heed::byteorder::BigEndian;
2507 ///
2508 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
2509 /// # let dir = tempfile::tempdir()?;
2510 /// # let env = unsafe { EnvOpenOptions::new()
2511 /// # .map_size(10 * 1024 * 1024) // 10MB
2512 /// # .max_dbs(3000)
2513 /// # .open(dir.path())?
2514 /// # };
2515 /// type BEI32 = I32<BigEndian>;
2516 ///
2517 /// let mut wtxn = env.write_txn()?;
2518 /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
2519 ///
2520 /// # db.clear(&mut wtxn)?;
2521 /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
2522 /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
2523 /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
2524 /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
2525 ///
2526 /// db.clear(&mut wtxn)?;
2527 ///
2528 /// let ret = db.is_empty(&wtxn)?;
2529 /// assert!(ret);
2530 ///
2531 /// wtxn.commit()?;
2532 /// # Ok(()) }
2533 /// ```
2534 pub fn clear(&self, txn: &mut RwTxn) -> Result<()> {
2535 assert_eq_env_db_txn!(self, txn);
2536
2537 unsafe { mdb_result(ffi::mdb_drop(txn.txn.txn, self.dbi, 0)).map_err(Into::into) }
2538 }
2539
2540 /// Change the codec types of this database, specifying the codecs.
2541 ///
2542 /// # Safety
2543 ///
2544 /// It is up to you to ensure that the data read and written using the polymorphic
2545 /// handle correspond to the the typed, uniform one. If an invalid write is made,
2546 /// it can corrupt the database from the eyes of heed.
2547 ///
2548 /// # Example
2549 ///
2550 /// ```
2551 /// # use std::fs;
2552 /// # use std::path::Path;
2553 /// # use heed::EnvOpenOptions;
2554 /// use heed::Database;
2555 /// use heed::types::*;
2556 /// use heed::byteorder::BigEndian;
2557 ///
2558 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
2559 /// # let dir = tempfile::tempdir()?;
2560 /// # let env = unsafe { EnvOpenOptions::new()
2561 /// # .map_size(10 * 1024 * 1024) // 10MB
2562 /// # .max_dbs(3000)
2563 /// # .open(dir.path())?
2564 /// # };
2565 /// type BEI32 = I32<BigEndian>;
2566 ///
2567 /// let mut wtxn = env.write_txn()?;
2568 /// let db: Database<Unit, Unit> = env.create_database(&mut wtxn, Some("iter-i32"))?;
2569 ///
2570 /// # db.clear(&mut wtxn)?;
2571 /// // We remap the types for ease of use.
2572 /// let db = db.remap_types::<BEI32, Str>();
2573 /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
2574 /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
2575 /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
2576 /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
2577 ///
2578 /// wtxn.commit()?;
2579 /// # Ok(()) }
2580 /// ```
2581 pub fn remap_types<KC2, DC2>(&self) -> Database<KC2, DC2, C> {
2582 Database::new(self.env_ident, self.dbi)
2583 }
2584
2585 /// Change the key codec type of this database, specifying the new codec.
2586 pub fn remap_key_type<KC2>(&self) -> Database<KC2, DC, C> {
2587 self.remap_types::<KC2, DC>()
2588 }
2589
2590 /// Change the data codec type of this database, specifying the new codec.
2591 pub fn remap_data_type<DC2>(&self) -> Database<KC, DC2, C> {
2592 self.remap_types::<KC, DC2>()
2593 }
2594
2595 /// Wrap the data bytes into a lazy decoder.
2596 pub fn lazily_decode_data(&self) -> Database<KC, LazyDecode<DC>, C> {
2597 self.remap_types::<KC, LazyDecode<DC>>()
2598 }
2599}
2600
2601impl<KC, DC, C> Clone for Database<KC, DC, C> {
2602 fn clone(&self) -> Database<KC, DC, C> {
2603 *self
2604 }
2605}
2606
2607impl<KC, DC, C> Copy for Database<KC, DC, C> {}
2608
2609impl<KC, DC, C> fmt::Debug for Database<KC, DC, C> {
2610 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2611 f.debug_struct("Database")
2612 .field("key_codec", &any::type_name::<KC>())
2613 .field("data_codec", &any::type_name::<DC>())
2614 .field("comparator", &any::type_name::<C>())
2615 .finish()
2616 }
2617}
2618
2619/// Statistics for a database in the environment.
2620#[derive(Debug, Clone, Copy)]
2621pub struct DatabaseStat {
2622 /// Size of a database page.
2623 /// This is currently the same for all databases.
2624 pub page_size: u32,
2625 /// Depth (height) of the B-tree.
2626 pub depth: u32,
2627 /// Number of internal (non-leaf) pages
2628 pub branch_pages: usize,
2629 /// Number of leaf pages.
2630 pub leaf_pages: usize,
2631 /// Number of overflow pages.
2632 pub overflow_pages: usize,
2633 /// Number of data items.
2634 pub entries: usize,
2635}
2636
2637#[cfg(test)]
2638mod tests {
2639 use heed_types::*;
2640
2641 use super::*;
2642
2643 #[test]
2644 fn put_overwrite() -> Result<()> {
2645 let dir = tempfile::tempdir()?;
2646 let env = unsafe { EnvOpenOptions::new().open(dir.path())? };
2647 let mut txn = env.write_txn()?;
2648 let db = env.create_database::<Bytes, Bytes>(&mut txn, None)?;
2649
2650 assert_eq!(db.get(&txn, b"hello").unwrap(), None);
2651
2652 db.put(&mut txn, b"hello", b"hi").unwrap();
2653 assert_eq!(db.get(&txn, b"hello").unwrap(), Some(&b"hi"[..]));
2654
2655 db.put(&mut txn, b"hello", b"bye").unwrap();
2656 assert_eq!(db.get(&txn, b"hello").unwrap(), Some(&b"bye"[..]));
2657
2658 Ok(())
2659 }
2660
2661 #[test]
2662 #[cfg(feature = "longer-keys")]
2663 fn longer_keys() -> Result<()> {
2664 let dir = tempfile::tempdir()?;
2665 let env = unsafe { EnvOpenOptions::new().open(dir.path())? };
2666 let mut txn = env.write_txn()?;
2667 let db = env.create_database::<Bytes, Bytes>(&mut txn, None)?;
2668
2669 // Try storing a key larger than 511 bytes (the default if MDB_MAXKEYSIZE is not set)
2670 let long_key = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut pharetra sit amet aliquam. Sit amet nisl purus in mollis nunc. Eget egestas purus viverra accumsan in nisl nisi scelerisque. Duis ultricies lacus sed turpis tincidunt. Sem nulla pharetra diam sit. Leo vel orci porta non pulvinar. Erat pellentesque adipiscing commodo elit at imperdiet dui. Suspendisse ultrices gravida dictum fusce ut placerat orci nulla. Diam donec adipiscing tristique risus nec feugiat. In fermentum et sollicitudin ac orci. Ut sem nulla pharetra diam sit amet. Aliquam purus sit amet luctus venenatis lectus. Erat pellentesque adipiscing commodo elit at imperdiet dui accumsan. Urna duis convallis convallis tellus id interdum velit laoreet id. Ac feugiat sed lectus vestibulum mattis ullamcorper velit sed. Tincidunt arcu non sodales neque. Habitant morbi tristique senectus et netus et malesuada fames.";
2671
2672 assert_eq!(db.get(&txn, long_key).unwrap(), None);
2673
2674 db.put(&mut txn, long_key, b"hi").unwrap();
2675 assert_eq!(db.get(&txn, long_key).unwrap(), Some(&b"hi"[..]));
2676
2677 db.put(&mut txn, long_key, b"bye").unwrap();
2678 assert_eq!(db.get(&txn, long_key).unwrap(), Some(&b"bye"[..]));
2679
2680 Ok(())
2681 }
2682}