Skip to main content

leveldb/database/
batch.rs

1use leveldb_sys::*;
2use libc::{c_char, size_t, c_void};
3use std::{slice, ptr};
4use super::options::{WriteOptions, c_writeoptions};
5use super::error::Error;
6use super::db::Database;
7use super::key::IntoLevelDBKey;
8
9pub(crate) struct RawWriteBatch {
10    pub(crate) ptr: *mut leveldb_writebatch_t,
11}
12
13impl Drop for RawWriteBatch {
14    fn drop(&mut self) {
15        unsafe {
16            leveldb_writebatch_destroy(self.ptr);
17        }
18    }
19}
20
21pub struct WriteBatch {
22    pub(crate) write_batch: RawWriteBatch,
23}
24
25/// Batch access to the database
26pub trait Batch {
27    /// Write a batch to the database, ensuring success for all items or an error
28    fn write(&self, options: &WriteOptions, batch: &WriteBatch) -> Result<(), Error>;
29}
30
31impl Batch for Database {
32    fn write(&self, options: &WriteOptions, batch: &WriteBatch) -> Result<(), Error> {
33        unsafe {
34            let mut error = ptr::null_mut();
35            let c_write_options = c_writeoptions(options);
36
37            leveldb_write(
38                self.database.ptr,
39                c_write_options,
40                batch.write_batch.ptr,
41                &mut error
42            );
43
44            if error == ptr::null_mut() {
45                Ok(())
46            } else {
47                Err(Error::new_from_char(error))
48            }
49        }
50    }
51}
52
53impl WriteBatch {
54    pub fn new() -> WriteBatch {
55        let ptr = unsafe { leveldb_writebatch_create() };
56        let raw = RawWriteBatch { ptr };
57
58        WriteBatch {
59            write_batch: raw,
60        }
61    }
62
63    /// Clear the writebatch
64    pub fn clear(&self) {
65        unsafe { leveldb_writebatch_clear(self.write_batch.ptr) };
66    }
67
68    /// Batch a put operation
69    pub fn put(&self, key: &dyn IntoLevelDBKey, value: &[u8]) {
70        let _ = key.as_u8_slice_for_write(&|k| {
71            self.put_u8(k, value);
72
73            Ok(())
74        });
75    }
76
77
78    pub fn put_u8(&self, key: &[u8], value: &[u8]) {
79        unsafe {
80            leveldb_writebatch_put(self.write_batch.ptr,
81                                   key.as_ptr() as *mut c_char,
82                                   key.len() as size_t,
83                                   value.as_ptr() as *mut c_char,
84                                   value.len() as size_t);
85        }
86    }
87
88    /// Batch a delete operation
89    pub fn delete(&self, key: &dyn IntoLevelDBKey) {
90        let _ = key.as_u8_slice_for_write(&|k| {
91            self.delete_u8(k);
92
93            Ok(())
94        });
95    }
96
97    pub fn delete_u8(&self, key: &[u8]) {
98        unsafe {
99            leveldb_writebatch_delete(self.write_batch.ptr,
100                                      key.as_ptr() as *mut c_char,
101                                      key.len() as size_t);
102        }
103    }
104
105    /// Iterate over the writeBatch, returning the resulting iterator
106    pub fn iterate<T: WriteBatchIterator>(&mut self, iterator: Box<T>) -> Box<T> {
107        unsafe {
108            let iter = Box::into_raw(iterator);
109            leveldb_writebatch_iterate(self.write_batch.ptr,
110                                       iter as *mut c_void,
111                                       put_callback::<T>,
112                                       deleted_callback::<T>);
113            Box::from_raw(iter)
114        }
115    }
116}
117
118/// A trait for iterators to iterate over written batches and check their validity.
119pub trait WriteBatchIterator {
120    /// Callback for put items
121    fn put_u8(&mut self, key: &[u8], value: &[u8]);
122
123    /// Callback for deleted items
124    fn deleted_u8(&mut self, key: &[u8]);
125}
126
127extern "C" fn put_callback<T: WriteBatchIterator>(
128    state: *mut c_void,
129    key: *const c_char,
130    key_len: size_t,
131    val: *const c_char,
132    val_len: size_t) {
133
134    unsafe {
135        let iter: &mut T = &mut *(state as *mut T);
136        let key_slice = slice::from_raw_parts::<u8>(key as *const u8, key_len as usize);
137        let val_slice = slice::from_raw_parts::<u8>(val as *const u8, val_len as usize);
138
139        iter.put_u8(key_slice, val_slice);
140    }
141}
142
143extern "C" fn deleted_callback<T: WriteBatchIterator>(
144    state: *mut c_void,
145    key: *const c_char,
146    key_len: size_t
147) {
148    unsafe {
149        let iter: &mut T = &mut *(state as *mut T);
150        let key_slice = slice::from_raw_parts::<u8>(key as *const u8, key_len as usize);
151
152        iter.deleted_u8(key_slice);
153    }
154}