leveldb_rs/
lib.rs

1/*!
2 * Rust bindings for [LevelDB](https://code.google.com/p/leveldb/), a fast and
3 * lightweight key/value database library from Google.
4 *
5 * Warning: Some portions of this library are still unsafe to use, in that it
6 * is possible to call methods from LevelDB with stale pointers, or otherwise
7 * cause memory-unsafety.  If you'd like to avoid this, and until I fix them,
8 * please don't use:
9 *
10 * - Custom comparators
11 * - DB snapshots
12 *
13 * And please be careful with write batches.  Patches are welcome!
14 */
15#![crate_type = "lib"]
16#![warn(missing_docs)]
17#![warn(non_upper_case_globals)]
18#![warn(unused_qualifications)]
19
20extern crate libc;
21extern crate leveldb_sys;
22
23use std::cmp::Ordering;
24use std::ffi::{CStr,CString};
25use std::path::Path;
26use std::mem::transmute;
27use std::ptr;
28use std::slice;
29use std::sync::Arc;
30use std::str;
31
32use libc::{c_char, c_int, c_uchar, c_void, size_t};
33
34use leveldb_sys as cffi;
35
36
37/// Our error type
38#[derive(Clone, Hash, PartialEq, Eq, Debug)]
39pub enum LevelDBError {
40    /// An error from the LevelDB C library.
41    LibraryError(String),
42
43    /// Out of memory.
44    OutOfMemoryError,
45}
46
47impl std::fmt::Display for LevelDBError {
48    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
49        match *self {
50            LevelDBError::LibraryError(ref msg) => msg.fmt(f),
51            LevelDBError::OutOfMemoryError      => write!(f, "Out of memory"),
52        }
53    }
54}
55
56impl LevelDBError {
57    fn lib_error(errptr: *mut c_char) -> LevelDBError {
58        // Convert to a rust String, then free the LevelDB string.
59        let p = errptr as *const c_char;
60        let slice = unsafe { CStr::from_ptr(p) };
61        let err = str::from_utf8(slice.to_bytes()).unwrap_or("Invalid error message").to_string();
62        unsafe { cffi::leveldb_free(errptr as *mut c_void) };
63
64        LevelDBError::LibraryError(err)
65    }
66}
67
68/// An alias for `Result<T, LevelDBError>`
69pub type LevelDBResult<T> = Result<T, LevelDBError>;
70
71// Provides an errptr for use with LevelDB, and properly returns a Result if
72// it's non-null.
73fn with_errptr<F, T>(mut f: F) -> LevelDBResult<T>
74    where F: FnMut(*mut *mut c_char) -> T
75{
76    let mut errptr: *mut c_char = ptr::null_mut();
77
78    let ret = f(&mut errptr as *mut *mut c_char);
79
80    if !errptr.is_null() {
81        Err(LevelDBError::lib_error(errptr))
82    } else {
83        Ok(ret)
84    }
85}
86
87fn bool_to_uchar(val: bool) -> c_uchar {
88    if val {
89        1 as c_uchar
90    } else {
91        0 as c_uchar
92    }
93}
94
95fn uchar_to_bool(val: c_uchar) -> bool {
96    if val == 0 {
97        false
98    } else {
99        true
100    }
101}
102
103/**
104 * This structure represents options that can be used when constructing a
105 * LevelDB instance.
106 */
107pub struct DBOptions {
108    opts: *mut cffi::leveldb_options_t,
109
110    // An (optional) comparator.  We hold on to a pointer to this to keep it
111    // alive for the lifetime of this options struct.
112    comparator: Option<DBComparator>,
113}
114
115impl DBOptions {
116    /**
117     * Create and return a new DBOptions instance.  Returns `None` if the
118     * underlying library call returns a null pointer.
119     */
120    pub fn new() -> Option<DBOptions> {
121        let opts = unsafe { cffi::leveldb_options_create() };
122        if opts.is_null() {
123            None
124        } else {
125            Some(DBOptions {
126                opts: opts,
127                comparator: None,
128            })
129        }
130    }
131
132    /**
133     * Set the comparator to use for this database.  By default, LevelDB uses
134     * a comparator does a lexicographic comparison.
135     * Note also that a comparator must be thread-safe.
136     */
137    pub fn set_comparator(&mut self, cmp: DBComparator) -> &mut DBOptions {
138        unsafe {
139            cffi::leveldb_options_set_comparator(self.opts, cmp.state.ptr);
140        }
141
142        // Hold on to this comparator so it gets dropped (and thus destroyed/
143        // freed) when we do.
144        self.comparator = Some(cmp);
145
146        self
147    }
148
149    /**
150     * Create the database if it's missing when we try to open it.
151     *
152     * Default: false
153     */
154    pub fn set_create_if_missing(&mut self, val: bool) -> &mut DBOptions {
155        unsafe {
156            cffi::leveldb_options_set_create_if_missing(self.opts, bool_to_uchar(val));
157        }
158
159        self
160    }
161
162    /**
163     * Return an error if the database already exists.
164     *
165     * Default: false
166     */
167    pub fn set_error_if_exists(&mut self, val: bool) -> &mut DBOptions {
168        unsafe {
169            cffi::leveldb_options_set_error_if_exists(self.opts, bool_to_uchar(val));
170        }
171
172        self
173    }
174
175    /**
176     * If set to true, the library will do aggressive checking of all data
177     * that it is processing and will stop early if it detects any errors.
178     *
179     * Default: false
180     */
181    pub fn set_paranoid_checks(&mut self, val: bool) -> &mut DBOptions {
182        unsafe {
183            cffi::leveldb_options_set_paranoid_checks(self.opts, bool_to_uchar(val));
184        }
185
186        self
187    }
188
189    /**
190     * Amount of data to build up in memory (backed by an unsorted log on-disk)
191     * before converting to a sorted on-disk file.
192     *
193     * Default: 4MiB
194     */
195    pub fn set_write_buffer_size(&mut self, val: usize) -> &mut DBOptions {
196        unsafe {
197            cffi::leveldb_options_set_write_buffer_size(self.opts, val as size_t);
198        }
199
200        self
201    }
202
203    /**
204     * Number of open files that can be used by the DB.  This value should be
205     * approximately one open file per 2MB of working set.
206     *
207     * Default: 1000
208     */
209    pub fn set_max_open_files(&mut self, val: isize) -> &mut DBOptions {
210        unsafe {
211            cffi::leveldb_options_set_max_open_files(self.opts, val as c_int);
212        }
213
214        self
215    }
216
217    /**
218     * Approximate size of user data packed per block.  Note that this
219     * corresponds to uncompressed data.
220     *
221     * Default: 4KB
222     */
223    pub fn set_block_size(&mut self, val: usize) -> &mut DBOptions {
224        unsafe {
225            cffi::leveldb_options_set_block_size(self.opts, val as size_t);
226        }
227
228        self
229    }
230
231    /**
232     * Number of keys between restart points for delta encoding of keys.  Most
233     * clients should not change this parameter.
234     *
235     * Default: 16
236     */
237    pub fn set_block_restart_interval(&mut self, val: isize) -> &mut DBOptions {
238        unsafe {
239            cffi::leveldb_options_set_block_restart_interval(self.opts, val as c_int);
240        }
241
242        self
243    }
244
245    /**
246     * Enable or disable compression.  Note that the default compression
247     * algorithm, Snappy, is significantly faster than most persistent storage.
248     * Thus, it's typically never worth switching this off.
249     *
250     * Default: true
251     */
252    #[cfg(feature = "snappy")]
253    pub fn set_compression(&mut self, val: bool) -> &mut DBOptions {
254        let val = if val {
255            cffi::Compression::Snappy
256        } else {
257            cffi::Compression::No
258        };
259
260        unsafe {
261            cffi::leveldb_options_set_compression(self.opts, val);
262        }
263
264        self
265    }
266
267    unsafe fn ptr(&self) -> *const cffi::leveldb_options_t {
268        self.opts as *const cffi::leveldb_options_t
269    }
270}
271
272impl Drop for DBOptions {
273    fn drop(&mut self) {
274        unsafe { cffi::leveldb_options_destroy(self.opts) };
275    }
276}
277
278/**
279 * An internal structure to represent the comparator state.  Note that, since
280 * the comparator struct is movable, we can't take the address of it and pass
281 * that to leveldb_comparator_create.  So, we keep the internal state in a Box,
282 * and can move the outer struct around freely.
283 */
284struct DBComparatorState {
285    name: &'static str,
286    cmp: Box<Fn(&[u8], &[u8]) -> Ordering + 'static>,
287    ptr: *mut cffi::leveldb_comparator_t,
288}
289
290impl Drop for DBComparatorState {
291    fn drop(&mut self) {
292        unsafe { cffi::leveldb_comparator_destroy(self.ptr) };
293    }
294}
295
296/**
297 * This structure represents a comparator for use in LevelDB.
298 */
299pub struct DBComparator {
300    state: Box<DBComparatorState>,
301}
302
303impl DBComparator {
304    /**
305     * Create a new comparator with the given name and comparison function.
306     */
307    pub fn new<F: 'static>(name: &'static str, cmp: F) -> DBComparator
308        where F: Fn(&[u8], &[u8]) -> Ordering
309    {
310        let mut state = Box::new(DBComparatorState {
311            name: name,
312            cmp: Box::new(cmp),
313            ptr: ptr::null_mut(),
314        });
315
316        let ptr = unsafe {
317            cffi::leveldb_comparator_create(
318                transmute(&*state),
319                comparator_destructor_callback,
320                comparator_compare_callback,
321                comparator_name_callback,
322            )
323        };
324
325        state.ptr = ptr;
326
327        DBComparator {
328            state: state,
329        }
330    }
331}
332
333#[allow(dead_code)]
334extern "C" fn comparator_destructor_callback(_state: *mut c_void) {
335    // Do nothing
336}
337
338#[allow(dead_code)]
339extern "C" fn comparator_compare_callback(state: *mut c_void, a: *const c_char, alen: size_t, b: *const c_char, blen: size_t) -> c_int {
340    unsafe {
341        // This is only safe since Box<T> is implemented as `struct Box(*mut T)`
342        let cmp: *const DBComparatorState = transmute(state);
343
344        let a_slice = slice::from_raw_parts::<u8>(a as *const u8, alen as usize);
345        let b_slice = slice::from_raw_parts::<u8>(b as *const u8, blen as usize);
346
347        // Comment from include/leveldb/comparator.h:
348        // Three-way comparison.  Returns value:
349        //   < 0 iff "a" < "b",
350        //   == 0 iff "a" == "b",
351        //   > 0 iff "a" > "b"
352        match ((*cmp).cmp)(a_slice, b_slice) {
353            Ordering::Less => -1,
354            Ordering::Equal => 0,
355            Ordering::Greater => 1,
356        }
357    }
358}
359
360#[allow(dead_code)]
361extern "C" fn comparator_name_callback(state: *mut c_void) -> *const c_char {
362    unsafe {
363        // This is only safe since Box<T> is implemented as `struct Box(*mut T)`
364        let cmp: *const DBComparatorState = transmute(state);
365
366        // This is safe to return, since the string has a static lifetime
367        (*cmp).name.as_ptr() as *const c_char
368    }
369}
370
371/**
372 * This structure represents options that can be used when reading from a
373 * LevelDB instance.
374 */
375pub struct DBReadOptions {
376    opts: *mut cffi::leveldb_readoptions_t,
377}
378
379impl DBReadOptions {
380    /**
381     * Create and return a new DBReadOptions instance.  Returns `None` if the
382     * underlying library call returns a null pointer.
383     */
384    pub fn new() -> Option<DBReadOptions> {
385        let opts = unsafe { cffi::leveldb_readoptions_create() };
386        if opts.is_null() {
387            None
388        } else {
389            Some(DBReadOptions {
390                opts: opts,
391            })
392        }
393    }
394
395    /**
396     * If set to 'true', all data read from the underlying storage will be
397     * verified against corresponding checksums.
398     *
399     * Defaults to 'false'.
400     */
401    pub fn set_verify_checksums(&mut self, val: bool) -> &mut DBReadOptions {
402        unsafe {
403            cffi::leveldb_readoptions_set_verify_checksums(self.opts, bool_to_uchar(val));
404        }
405
406        self
407    }
408
409    /**
410     * Set whether the data read for this iteration should be cached in memory.
411     *
412     * Defaults to 'true'.
413     */
414    pub fn set_fill_cache(&mut self, val: bool) -> &mut DBReadOptions {
415        unsafe {
416            cffi::leveldb_readoptions_set_fill_cache(self.opts, bool_to_uchar(val));
417        }
418
419        self
420    }
421
422    /**
423     * Set the snapshot to use when reading from the database.  If this is not
424     * set, then an implicit snapshot - of the state as of the beginning of the
425     * read operation - will be used.
426     *
427     * Note: currently private, since all access should be performed through
428     * DBSnapshot
429     */
430    fn set_snapshot(&mut self, snap: *const cffi::leveldb_snapshot_t) -> &mut DBReadOptions {
431        unsafe {
432            cffi::leveldb_readoptions_set_snapshot(self.opts, snap);
433        }
434
435        self
436    }
437
438    unsafe fn ptr(&self) -> *const cffi::leveldb_readoptions_t {
439        self.opts as *const cffi::leveldb_readoptions_t
440    }
441}
442
443impl Drop for DBReadOptions {
444    fn drop(&mut self) {
445        unsafe { cffi::leveldb_readoptions_destroy(self.opts) };
446    }
447}
448
449/**
450 * This structure represents options that can be used when writing to a LevelDB
451 * instance.
452 */
453pub struct DBWriteOptions {
454    opts: *mut cffi::leveldb_writeoptions_t,
455}
456
457impl DBWriteOptions {
458    /**
459     * Create and return a new DBWriteOptions instance.  Returns `None` if the
460     * underlying library call returns a null pointer.
461     */
462    pub fn new() -> Option<DBWriteOptions> {
463        let opts = unsafe { cffi::leveldb_writeoptions_create() };
464        if opts.is_null() {
465            None
466        } else {
467            Some(DBWriteOptions {
468                opts: opts,
469            })
470        }
471    }
472
473    /**
474     * Set whether the write will be flushed to disk before the write is
475     * considered "complete".  Essentially, if a write is performed without
476     * this value set, it has the same semantics as the `write()` syscall.  If
477     * sync is set, the semantics are the same as a `write()` followed by a
478     * `fsync()` call.
479     *
480     * The default value is false.
481     */
482    pub fn set_sync(&mut self, val: bool) -> &mut DBWriteOptions {
483        unsafe {
484            cffi::leveldb_writeoptions_set_sync(self.opts, bool_to_uchar(val));
485        }
486
487        self
488    }
489
490    unsafe fn ptr(&self) -> *const cffi::leveldb_writeoptions_t {
491        self.opts as *const cffi::leveldb_writeoptions_t
492    }
493}
494
495impl Drop for DBWriteOptions {
496    fn drop(&mut self) {
497        unsafe { cffi::leveldb_writeoptions_destroy(self.opts) };
498    }
499}
500
501/**
502 * A write batch holds a collection of updates to apply atomically to a
503 * database.  Updates are applied in the order in which they are added to the
504 * write batch.
505 */
506pub struct DBWriteBatch {
507    batch: *mut cffi::leveldb_writebatch_t,
508}
509
510impl DBWriteBatch {
511    /**
512     * Create a new, empty write batch.  Returns None if the underlying library
513     * call returns a null pointer.
514     */
515    pub fn new() -> Option<DBWriteBatch> {
516        let batch = unsafe { cffi::leveldb_writebatch_create() };
517        if batch.is_null() {
518            None
519        } else {
520            Some(DBWriteBatch {
521                batch: batch,
522            })
523        }
524    }
525
526    /**
527     * Set the database entry for "key" to "value".  See `put()` on `DB` for
528     * more information.
529     */
530    pub fn put(&mut self, key: &[u8], val: &[u8]) {
531        // TODO: does the API copy the underlying key/value, or do we need to
532        // ensure it lives long enough?
533        unsafe {
534            cffi::leveldb_writebatch_put(
535                self.batch,
536                key.as_ptr() as *const c_char,
537                key.len() as size_t,
538                val.as_ptr() as *const c_char,
539                val.len() as size_t
540            )
541        }
542    }
543
544    /**
545     * Clear all updates buffered in this write batch.
546     */
547    pub fn clear(&mut self) {
548        unsafe { cffi::leveldb_writebatch_clear(self.batch) };
549    }
550
551    /**
552     * If the database contains the given key, erase it.  Otherwise, do
553     * nothing.
554     */
555    pub fn delete(&mut self, key: &[u8]) {
556        unsafe {
557            cffi::leveldb_writebatch_delete(
558                self.batch,
559                key.as_ptr() as *const c_char,
560                key.len() as size_t
561            )
562        };
563    }
564
565    /**
566     * Iterate over the contents of the write batch by calling callbacks for
567     * each operation in the batch.
568     */
569    pub fn iterate<'a, F: 'a, G: 'a>(&'a self, put: F, delete: G)
570        where F: FnMut(&'a [u8], &'a [u8]) + 'a,
571              G: FnMut(&'a [u8]) + 'a,
572    {
573        let mut it = DBWriteBatchIter {
574            put:    Box::new(put),
575            delete: Box::new(delete),
576        };
577
578        unsafe {
579            cffi::leveldb_writebatch_iterate(
580                self.batch,
581                &mut it as *mut _ as *mut c_void,
582                writebatch_put_callback,
583                writebatch_delete_callback
584            );
585        };
586    }
587}
588
589struct DBWriteBatchIter<'a> {
590    pub put:    Box<FnMut(&'a [u8], &'a [u8]) + 'a>,
591    pub delete: Box<FnMut(&'a [u8]) + 'a>,
592}
593
594// Callback for DBWriteBatchIter
595extern "C" fn writebatch_put_callback(state: *mut c_void, key: *const c_char, klen: size_t, val: *const c_char, vlen: size_t) {
596    let it = state as *mut DBWriteBatchIter;
597
598    let key_slice = unsafe {
599        slice::from_raw_parts::<u8>(key as *const u8, klen as usize)
600    };
601    let val_slice = unsafe {
602        slice::from_raw_parts::<u8>(val as *const u8, vlen as usize)
603    };
604
605    unsafe { ((*it).put)(key_slice, val_slice) };
606}
607
608// Callback for DBWriteBatchIter
609extern "C" fn writebatch_delete_callback(state: *mut c_void, key: *const c_char, klen: size_t) {
610    let it = state as *mut DBWriteBatchIter;
611
612    let key_slice = unsafe {
613        slice::from_raw_parts::<u8>(key as *const u8, klen as usize)
614    };
615
616    unsafe { ((*it).delete)(key_slice) };
617}
618
619impl Drop for DBWriteBatch {
620    fn drop(&mut self) {
621        unsafe { cffi::leveldb_writebatch_destroy(self.batch) };
622    }
623}
624
625/**
626 * This structure represents an iterator over the database.  Note that since
627 * the next() function is bounded by a lifetime, it does not (quite) conform
628 * to the Iterator trait.  To get this, use the alloc() helper.
629 */
630pub struct DBIterator {
631    iter: *mut cffi::leveldb_iterator_t,
632}
633
634impl DBIterator {
635    // Note: deliberately not public
636    fn new(i: *mut cffi::leveldb_iterator_t) -> DBIterator {
637        unsafe { cffi::leveldb_iter_seek_to_first(i) };
638
639        DBIterator {
640            iter: i,
641        }
642    }
643
644    /**
645     * Return the next key/value pair from this iterator.
646     */
647    pub fn next<'a>(&'a mut self) -> Option<(&'a [u8], &'a [u8])> {
648        if !uchar_to_bool(unsafe { cffi::leveldb_iter_valid(self.ptr()) }) {
649            return None;
650        }
651
652        let key_slice = unsafe {
653            let mut keylen: size_t = 0;
654            let key = cffi::leveldb_iter_key(self.ptr(),
655                &mut keylen as *mut size_t);
656
657            slice::from_raw_parts::<u8>(key as *const u8, keylen as usize)
658        };
659
660        let val_slice = unsafe {
661            let mut vallen: size_t = 0;
662            let val = cffi::leveldb_iter_value(
663                self.ptr(), &mut vallen as *mut size_t);
664
665            slice::from_raw_parts::<u8>(val as *const u8, vallen as usize)
666        };
667
668        unsafe { cffi::leveldb_iter_next(self.iter) };
669
670        Some((key_slice, val_slice))
671    }
672
673    /**
674     * Return an instance of DBIteratorAlloc, an iterator that implements the
675     * Iterator trait, but allocates new Vec<u8>s for each item.  Note that
676     * this consumes the DBIterator instance, so it can't be used again.
677     */
678    pub fn alloc(self) -> DBIteratorAlloc {
679        DBIteratorAlloc::new(self)
680    }
681
682    /**
683     * Seek to the beginning of the database.
684     */
685    pub fn seek_to_first(&mut self) {
686        unsafe { cffi::leveldb_iter_seek_to_first(self.iter) };
687    }
688
689    /**
690     * Seek to the end of the database.
691     */
692    pub fn seek_to_last(&mut self) {
693        unsafe { cffi::leveldb_iter_seek_to_last(self.iter) };
694    }
695
696    /**
697     * Seek to the first key in the database that is at or past the given
698     * target key.
699     */
700    pub fn seek(&mut self, key: &[u8]) {
701        unsafe {
702            cffi::leveldb_iter_seek(
703                self.iter,
704                key.as_ptr() as *const c_char,
705                key.len() as size_t
706            );
707        }
708    }
709
710    /**
711     * Move to the previous item in the database.
712     */
713    pub fn prev(&mut self) {
714        unsafe { cffi::leveldb_iter_prev(self.iter) };
715    }
716
717    fn ptr(&self) -> *const cffi::leveldb_iterator_t {
718        self.iter as *const cffi::leveldb_iterator_t
719    }
720}
721
722impl Drop for DBIterator {
723    fn drop(&mut self) {
724        unsafe { cffi::leveldb_iter_destroy(self.iter) };
725    }
726}
727
728/**
729 * An iterator over a database that implements the standard library's Iterator
730 * trait.
731 */
732pub struct DBIteratorAlloc {
733    underlying: DBIterator,
734}
735
736impl DBIteratorAlloc {
737    // Note: deliberately not public
738    fn new(i: DBIterator) -> DBIteratorAlloc {
739        DBIteratorAlloc {
740            underlying: i,
741        }
742    }
743
744    /**
745     * Wraps the underlying `seek_to_first` call.
746     */
747    pub fn seek_to_first(&mut self) {
748        self.underlying.seek_to_first()
749    }
750
751    /**
752     * Wraps the underlying `seek_to_last` call.
753     */
754    pub fn seek_to_last(&mut self) {
755        self.underlying.seek_to_last()
756    }
757
758    /**
759     * Wrap the underlying `seek` call.
760     */
761    pub fn seek(&mut self, key: &[u8]) {
762        self.underlying.seek(key)
763    }
764}
765
766impl Iterator for DBIteratorAlloc {
767    type Item = (Vec<u8>, Vec<u8>);
768
769    fn next(&mut self) -> Option<(Vec<u8>, Vec<u8>)> {
770        match self.underlying.next() {
771            Some((key, val)) => {
772                Some((key.to_vec(), val.to_vec()))
773            },
774            None => None,
775        }
776    }
777}
778
779/**
780 * An immutable snapshot of the database at a point in time.
781 */
782pub struct DBSnapshot {
783    sn: *mut cffi::leveldb_snapshot_t,
784
785    // We can't save a pointer to the underlying DB itself, since that would
786    // prevent any further mutation (something that we want to allow).
787    db: DBImplPtr,
788}
789
790impl DBSnapshot {
791    // Note: deliberately not public
792    fn new_from(db: &DBImplPtr) -> DBSnapshot {
793        // Clone the underlying database to ensure that it doesn't go away.
794        let db = db.clone();
795
796        let sn = unsafe { cffi::leveldb_create_snapshot(db.db) };
797
798        DBSnapshot {
799            sn: sn,
800            db: db,
801        }
802    }
803
804    /**
805     * As `DB.get`, except operating on the state of this snapshot.
806     */
807    pub fn get(&self, key: &[u8]) -> LevelDBResult<Option<Vec<u8>>> {
808        // TODO: proper return code for OOM
809        let opts = match DBReadOptions::new() {
810            Some(o) => o,
811            None    => return Err(LevelDBError::OutOfMemoryError),
812        };
813
814        self.get_opts(key, opts)
815    }
816
817    /**
818     * As `DB.get_opts`, except operating on the state of this snapshot.
819     */
820    pub fn get_opts(&self, key: &[u8], opts: DBReadOptions) -> LevelDBResult<Option<Vec<u8>>> {
821        let mut opts = opts;
822
823        opts.set_snapshot(self.sn as *const cffi::leveldb_snapshot_t);
824        self.db.get(key, opts)
825    }
826
827    /**
828     * As `DB.iter`, except operating on the state of this snapshot.
829     */
830    pub fn iter(&self) -> LevelDBResult<DBIterator> {
831        // TODO: proper return code for OOM
832        let mut opts = match DBReadOptions::new() {
833            Some(o) => o,
834            None    => return Err(LevelDBError::OutOfMemoryError),
835        };
836
837        opts.set_snapshot(self.sn as *const cffi::leveldb_snapshot_t);
838        Ok(self.db.iter(opts))
839    }
840
841}
842
843impl Drop for DBSnapshot {
844    fn drop(&mut self) {
845        unsafe {
846            cffi::leveldb_release_snapshot(
847                self.db.db,
848                self.sn as *const cffi::leveldb_snapshot_t,
849            )
850        };
851    }
852}
853
854/*
855 * This internal structure keeps a reference to the underlying database, along
856 * with any other information that needs to be freed when the database goes out
857 * of scope (e.g. DB options).  It also provides the base interfaces for
858 * reading/writing to the database.
859 *
860 * WARNING: The methods on this take &self, since LevelDB itself is safe for
861 * concurrent access without any synchronization.  Note that this *does* mutate
862 * the database!  We enforce synchronization at the DB / DBSnapshot level, as
863 * opposed to this level.
864 */
865struct DBImpl {
866    // The DB handle
867    db: *mut cffi::leveldb_t,
868
869    // The options used to open the database.  We need to keep this alive for
870    // the lifetime of the database.
871    #[allow(dead_code)]
872    opts: DBOptions,
873}
874
875impl DBImpl {
876    fn open(path: &Path, opts: DBOptions) -> LevelDBResult<DBImplPtr> {
877        let res = with_errptr(|errptr| {
878            let c_string = CString::new(path.to_str().unwrap()).unwrap();
879            unsafe { cffi::leveldb_open(opts.ptr(), c_string.as_ptr(), errptr) }
880        });
881
882        let db = match res {
883            Ok(db) => db,
884            Err(v) => return Err(v),
885        };
886
887        Ok(Arc::new(DBImpl {
888            db: db,
889            opts: opts,
890        }))
891    }
892
893    fn put(&self, key: &[u8], val: &[u8], opts: DBWriteOptions) -> LevelDBResult<()> {
894        try!(with_errptr(|errptr| {
895            unsafe {
896                cffi::leveldb_put(
897                    self.db,
898                    opts.ptr(),
899                    key.as_ptr() as *const c_char,
900                    key.len() as size_t,
901                    val.as_ptr() as *const c_char,
902                    val.len() as size_t,
903                    errptr
904                )
905            }
906        }));
907
908        Ok(())
909    }
910
911    fn delete(&self, key: &[u8], opts: DBWriteOptions) -> LevelDBResult<()> {
912        try!(with_errptr(|errptr| {
913            unsafe {
914                cffi::leveldb_delete(
915                    self.db,
916                    opts.ptr(),
917                    key.as_ptr() as *const c_char,
918                    key.len() as size_t,
919                    errptr
920                )
921            }
922        }));
923
924        Ok(())
925    }
926
927    fn write(&self, batch: DBWriteBatch, opts: DBWriteOptions) -> LevelDBResult<()> {
928        try!(with_errptr(|errptr| {
929            unsafe {
930                cffi::leveldb_write(
931                    self.db,
932                    opts.ptr(),
933                    batch.batch,
934                    errptr
935                )
936            }
937        }));
938
939        Ok(())
940    }
941
942    fn get(&self, key: &[u8], opts: DBReadOptions) -> LevelDBResult<Option<Vec<u8>>> {
943        let mut size: size_t = 0;
944
945        let buff = try!(with_errptr(|errptr| {
946            unsafe {
947                cffi::leveldb_get(
948                    self.db,
949                    opts.ptr(),
950                    key.as_ptr() as *const c_char,
951                    key.len() as size_t,
952                    &mut size as *mut size_t,
953                    errptr
954                )
955            }
956        }));
957
958        if buff.is_null() {
959            return Ok(None)
960        }
961
962        let size = size as usize;
963
964        let vec: Vec<u8> = unsafe { slice::from_raw_parts(buff as *mut u8, size).to_vec() };
965
966        Ok(Some(vec))
967    }
968
969    fn iter(&self, opts: DBReadOptions) -> DBIterator {
970        let it = unsafe {
971            cffi::leveldb_create_iterator(
972                self.db,
973                opts.ptr()
974            )
975        };
976
977        DBIterator::new(it)
978    }
979}
980
981impl Drop for DBImpl {
982    fn drop(&mut self) {
983        unsafe {
984            cffi::leveldb_close(self.db)
985        }
986    }
987}
988
989// A reference-counted pointer to a database implementation.  We need to use
990// this, since snapshots can hold on to a reference to a DB.
991type DBImplPtr = Arc<DBImpl>;
992
993/**
994 * This struct represents an open instance of the database.
995*/
996#[derive(Clone)]
997pub struct DB {
998    db: DBImplPtr,
999}
1000
1001unsafe impl Send for DB {}
1002unsafe impl Sync for DB {}
1003
1004impl DB {
1005    /**
1006     * Open a database at the given path.  Returns a Result indicating whether
1007     * the database could be opened.  Note that this function will not create
1008     * the database at the given location if it does not exist.
1009     */
1010    pub fn open(path: &Path) -> LevelDBResult<DB> {
1011        // TODO: proper return code for OOM
1012        let opts = match DBOptions::new() {
1013            Some(o) => o,
1014            None    => return Err(LevelDBError::OutOfMemoryError),
1015        };
1016
1017        DB::open_with_opts(path, opts)
1018    }
1019
1020    /**
1021     * Create and returns a database at the given path.
1022     */
1023    pub fn create(path: &Path) -> LevelDBResult<DB> {
1024        // TODO: proper return code for OOM
1025        let mut opts = match DBOptions::new() {
1026            Some(o) => o,
1027            None    => return Err(LevelDBError::OutOfMemoryError),
1028        };
1029
1030        // TODO: can we remove a previously-existing database?
1031
1032        opts.set_create_if_missing(true);
1033        DB::open_with_opts(path, opts)
1034    }
1035
1036    /**
1037     * Open a database at the given path, using the provided options to control
1038     * the open behaviour.  Returns a Result indicating whether or not the
1039     * database could be opened.
1040     */
1041    pub fn open_with_opts(path: &Path, opts: DBOptions) -> LevelDBResult<DB> {
1042        match DBImpl::open(path, opts) {
1043            Ok(x)    => Ok(DB { db: x }),
1044            Err(why) => Err(why),
1045        }
1046    }
1047
1048    /**
1049     * Set the database entry for "key" to "value". Returns a result indicating
1050     * the success or failure of the operation.
1051     */
1052    pub fn put(&mut self, key: &[u8], val: &[u8]) -> LevelDBResult<()> {
1053        // TODO: proper return code for OOM
1054        let opts = match DBWriteOptions::new() {
1055            Some(o) => o,
1056            None    => return Err(LevelDBError::OutOfMemoryError),
1057        };
1058
1059        self.put_opts(key, val, opts)
1060    }
1061
1062    /**
1063     * Set the database entry for "key" to "value".  Allows specifying the
1064     * write options to use for this operaton.
1065     */
1066    pub fn put_opts(&mut self, key: &[u8], val: &[u8], opts: DBWriteOptions) -> LevelDBResult<()> {
1067        self.db.put(key, val, opts)
1068    }
1069
1070    /**
1071     * Remove the database entry (if any) for "key".  Returns a result
1072     * indicating the success of the operation.  It is not an error if "key"
1073     * did not exist in the database.
1074     */
1075    pub fn delete(&mut self, key: &[u8]) -> LevelDBResult<()> {
1076        // TODO: proper return code for OOM
1077        let opts = match DBWriteOptions::new() {
1078            Some(o) => o,
1079            None    => return Err(LevelDBError::OutOfMemoryError),
1080        };
1081
1082        self.delete_opts(key, opts)
1083    }
1084
1085    /**
1086     * Remove the database entry (if any) for "key".  As `delete()`, but allows
1087     * specifying the write options to use for this operation.
1088     */
1089    pub fn delete_opts(&mut self, key: &[u8], opts: DBWriteOptions) -> LevelDBResult<()> {
1090        self.db.delete(key, opts)
1091    }
1092
1093    /**
1094     * Apply the specified updates to the database, as given in the provided
1095     * DBWriteBatch.  Returns a result indicating the success of the operation.
1096     */
1097    pub fn write(&mut self, batch: DBWriteBatch) -> LevelDBResult<()> {
1098        // TODO: proper return code for OOM
1099        let opts = match DBWriteOptions::new() {
1100            Some(o) => o,
1101            None    => return Err(LevelDBError::OutOfMemoryError),
1102        };
1103
1104        self.write_opts(batch, opts)
1105    }
1106
1107    /**
1108     * Apply the given write batch.  As `write()`, but allows specifying the
1109     * write options to use for this operation.
1110     */
1111    pub fn write_opts(&mut self, batch: DBWriteBatch, opts: DBWriteOptions) -> LevelDBResult<()> {
1112        self.db.write(batch, opts)
1113    }
1114
1115    /**
1116     * If the database contains an entry for "key", return the associated value
1117     * - otherwise, return None.  This value is wrapped in a Result to indicate
1118     * if an error occurred.
1119     */
1120    pub fn get(&self, key: &[u8]) -> LevelDBResult<Option<Vec<u8>>> {
1121        // TODO: proper return code for OOM
1122        let opts = match DBReadOptions::new() {
1123            Some(o) => o,
1124            None    => return Err(LevelDBError::OutOfMemoryError),
1125        };
1126
1127        self.get_opts(key, opts)
1128    }
1129
1130    /**
1131     * Get the value for a given key.  As `get()`, but allows specifying the
1132     * options to use when reading.
1133     */
1134    pub fn get_opts(&self, key: &[u8], opts: DBReadOptions) -> LevelDBResult<Option<Vec<u8>>> {
1135        self.db.get(key, opts)
1136    }
1137
1138    /**
1139     * Return an iterator over the database.
1140     */
1141    pub fn iter(&mut self) -> LevelDBResult<DBIterator> {
1142        // TODO: proper return code for OOM
1143        let opts = match DBReadOptions::new() {
1144            Some(o) => o,
1145            None    => return Err(LevelDBError::OutOfMemoryError),
1146        };
1147
1148        Ok(self.db.iter(opts))
1149    }
1150
1151    /**
1152     * Return a snapshot of the database.
1153     */
1154    pub fn snapshot(&self) -> DBSnapshot {
1155        DBSnapshot::new_from(&self.db)
1156    }
1157
1158    // TODO:
1159    //  - static `destroy()` and `repair`
1160    //  - set caching
1161    //  - approximate size / compact range
1162    //  - property values
1163    //  - filter policy (what's it do?)
1164    //  - solve various memory leaks / lifetime issues
1165}
1166
1167#[cfg(test)]
1168mod tests {
1169    #![allow(unused_imports)]
1170
1171    extern crate tempdir;
1172
1173    use self::tempdir::TempDir;
1174    use leveldb_sys as ffi;
1175
1176    use super::{DB, DBComparator, DBOptions, DBReadOptions, DBWriteBatch};
1177
1178    fn new_temp_db(name: &str) -> DB {
1179        let tdir = match TempDir::new(name) {
1180            Ok(t)    => t,
1181            Err(why) => panic!("Error creating temp dir: {:?}", why),
1182        };
1183
1184        match DB::create(tdir.path()) {
1185            Ok(db)   => db,
1186            Err(why) => panic!("Error creating DB: {:?}", why),
1187        }
1188    }
1189
1190    #[test]
1191    fn test_can_get_version() {
1192        let major_ver = unsafe { ffi::leveldb_major_version() };
1193        let minor_ver = unsafe { ffi::leveldb_minor_version() };
1194
1195        assert!(major_ver >= 1);
1196        assert!(minor_ver >= 0);
1197    }
1198
1199    #[test]
1200    fn test_can_create() {
1201        let tdir = match TempDir::new("create") {
1202            Ok(t)    => t,
1203            Err(why) => panic!("Error creating temp dir: {:?}", why),
1204        };
1205
1206        let _db = match DB::create(tdir.path()) {
1207            Ok(db)   => db,
1208            Err(why) => panic!("Error creating DB: {:?}", why),
1209        };
1210    }
1211
1212    #[test]
1213    fn test_put() {
1214        let mut db = new_temp_db("put");
1215
1216        match db.put(b"foo", b"bar") {
1217            Ok(_)    => {},
1218            Err(why) => panic!("Error putting into DB: {:?}", why),
1219        };
1220    }
1221
1222    #[test]
1223    fn test_put_and_get() {
1224        let mut db = new_temp_db("put-and-get");
1225
1226        match db.put(b"foo", b"bar") {
1227            Ok(_)    => {},
1228            Err(why) => panic!("Error putting into DB: {:?}", why),
1229        };
1230
1231        match db.get(b"foo") {
1232            Ok(v)    => assert_eq!(v.expect("Value not found"), b"bar"),
1233            Err(why) => panic!("Error getting from DB: {:?}", why),
1234        };
1235    }
1236
1237    #[test]
1238    fn test_delete() {
1239        let mut db = new_temp_db("delete");
1240
1241        db.put(b"foo", b"bar").unwrap();
1242        db.put(b"abc", b"123").unwrap();
1243
1244        // Note: get --> unwrap Result --> expect Option --> convert Vec to slice
1245        assert_eq!(db.get(b"foo").unwrap().expect("Value not found"), b"bar");
1246        assert_eq!(db.get(b"abc").unwrap().expect("Value not found"), b"123");
1247
1248        match db.delete(b"foo") {
1249            Ok(_)    => {},
1250            Err(why) => panic!("Error deleting from DB: {:?}", why),
1251        }
1252
1253        assert_eq!(db.get(b"foo").unwrap(), None);
1254        assert_eq!(db.get(b"abc").unwrap().expect("Value not found"), b"123");
1255    }
1256
1257    #[test]
1258    fn test_write_batch() {
1259        let mut db = new_temp_db("write-batch");
1260
1261        db.put(b"foo", b"bar").unwrap();
1262        db.put(b"abc", b"123").unwrap();
1263
1264        // Test putting into a write batch
1265
1266        let mut batch = DBWriteBatch::new().expect("Error creating batch");
1267
1268        batch.put(b"def", b"456");
1269        batch.put(b"zzz", b"asdfgh");
1270        batch.delete(b"abc");
1271        batch.put(b"zzz", b"qwerty");
1272
1273        // Test iteration
1274
1275        let mut puts: Vec<(Vec<u8>, Vec<u8>)> = vec![];
1276        let mut deletes: Vec<Vec<u8>> = vec![];
1277
1278        batch.iterate(|k, v| {
1279            puts.push((k.to_vec(), v.to_vec()));
1280        }, |k| {
1281            deletes.push(k.to_vec());
1282        });
1283
1284        assert_eq!(puts.len(), 3);
1285        assert_eq!(deletes.len(), 1);
1286
1287        // Test writing
1288
1289        match db.write(batch) {
1290            Ok(_)    => {},
1291            Err(why) => panic!("Error writing to DB: {:?}", why),
1292        };
1293
1294        assert_eq!(db.get(b"foo").unwrap().expect("Value not found"), b"bar");
1295        assert_eq!(db.get(b"def").unwrap().expect("Value not found"), b"456");
1296        assert_eq!(db.get(b"zzz").unwrap().expect("Value not found"), b"qwerty");
1297    }
1298
1299    #[test]
1300    fn test_iteration() {
1301        let mut db = new_temp_db("iteration");
1302
1303        db.put(b"foo", b"bar").unwrap();
1304        db.put(b"abc", b"123").unwrap();
1305
1306        let mut it = db.iter().unwrap();
1307
1308        let t1 = match it.next() {
1309            Some((key, val)) => {
1310                (key.to_vec(), val.to_vec())
1311            },
1312            None => panic!("Expected item 1"),
1313        };
1314        let t2 = match it.next() {
1315            Some((key, val)) => {
1316                (key.to_vec(), val.to_vec())
1317            },
1318            None => panic!("Expected item 2"),
1319        };
1320        let t3 = it.next();
1321
1322        // Keys are stored ordered, despite the fact we inserted unordered.
1323        assert_eq!((&t1.0), b"abc");
1324        assert_eq!((&t1.1), b"123");
1325
1326        assert_eq!((&t2.0), b"foo");
1327        assert_eq!((&t2.1), b"bar");
1328
1329        assert!(t3.is_none());
1330    }
1331
1332    #[test]
1333    fn test_iteration_alloc() {
1334        let mut db = new_temp_db("iteration");
1335
1336        db.put(b"foo", b"bar").unwrap();
1337        db.put(b"abc", b"123").unwrap();
1338
1339        let items: Vec<(Vec<u8>, Vec<u8>)> = db.iter().unwrap().alloc().collect();
1340
1341        assert_eq!(items.len(), 2);
1342        assert_eq!((&items[0].0), b"abc");
1343        assert_eq!((&items[0].1), b"123");
1344        assert_eq!((&items[1].0), b"foo");
1345        assert_eq!((&items[1].1), b"bar");
1346    }
1347
1348    #[test]
1349    fn test_comparator_create() {
1350        let _c = DBComparator::new("comparator-create", |a, b| {
1351            a.cmp(b)
1352        });
1353    }
1354
1355    #[test]
1356    fn test_comparator() {
1357        let c = DBComparator::new("foo", |a, b| {
1358            // Compare inverse
1359            b.cmp(a)
1360        });
1361
1362        let mut opts = DBOptions::new().expect("error creating options");
1363        opts.set_comparator(c).set_create_if_missing(true);
1364
1365        let tdir = match TempDir::new("comparator") {
1366            Ok(t)    => t,
1367            Err(why) => panic!("Error creating temp dir: {:?}", why),
1368        };
1369
1370        let mut db = match DB::open_with_opts(tdir.path(), opts) {
1371            Ok(db)   => db,
1372            Err(why) => panic!("Error creating DB: {:?}", why),
1373        };
1374
1375        // Insert into the DB some values.
1376        db.put(b"aaaa", b"foo").unwrap();
1377        db.put(b"zzzz", b"bar").unwrap();
1378
1379        // Extract the values as an ordered vector.
1380        let items: Vec<(Vec<u8>, Vec<u8>)> = db.iter().unwrap().alloc().collect();
1381
1382        // Values should be in reverse order.
1383        assert_eq!(items.len(), 2);
1384        assert_eq!((&items[0].0), b"zzzz");
1385        assert_eq!((&items[0].1), b"bar");
1386        assert_eq!((&items[1].0), b"aaaa");
1387        assert_eq!((&items[1].1), b"foo");
1388    }
1389
1390    #[test]
1391    fn test_snapshot() {
1392        let mut db = new_temp_db("snapshot");
1393
1394        db.put(b"foo", b"bar").unwrap();
1395        db.put(b"abc", b"123").unwrap();
1396
1397        let snap = db.snapshot();
1398
1399        db.put(b"abc", b"456").unwrap();
1400
1401        let snap_val = match snap.get(b"abc") {
1402            Ok(val) => val.expect("Expected to find key 'abc'"),
1403            Err(why) => panic!("Error getting from DB: {:?}", why),
1404        };
1405        assert_eq!(snap_val, b"123");
1406
1407        let val = match db.get(b"abc") {
1408            Ok(val) => val.expect("Expected to find key 'abc'"),
1409            Err(why) => panic!("Error getting from DB: {:?}", why),
1410        };
1411        assert!(val == b"456");
1412
1413        let iter_items: Vec<(Vec<u8>, Vec<u8>)> = snap.iter().unwrap().alloc().collect();
1414        let db_items: Vec<(Vec<u8>, Vec<u8>)> = db.iter().unwrap().alloc().collect();
1415
1416        assert_eq!(iter_items.len(), 2);
1417        assert_eq!(db_items.len(), 2);
1418
1419        assert_eq!((&iter_items[0].0), b"abc");
1420        assert_eq!((&iter_items[0].1), b"123");
1421        assert_eq!((&iter_items[1].0), b"foo");
1422        assert_eq!((&iter_items[1].1), b"bar");
1423
1424        assert_eq!((&db_items[0].0), b"abc");
1425        assert_eq!((&db_items[0].1), b"456");
1426        assert_eq!((&db_items[1].0), b"foo");
1427        assert_eq!((&db_items[1].1), b"bar");
1428    }
1429}