leveldb/database/
batch.rs

1use super::db::Database;
2use super::error::Error;
3use super::key::IntoLevelDBKey;
4use super::options::{c_writeoptions, WriteOptions};
5use cruzbit_leveldb_sys::*;
6use libc::{c_char, c_void, size_t};
7use std::{ptr, slice};
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.is_null() {
45                Ok(())
46            } else {
47                Err(Error::new_from_char(error))
48            }
49        }
50    }
51}
52
53impl Default for WriteBatch {
54    fn default() -> Self {
55        Self::new()
56    }
57}
58
59impl WriteBatch {
60    pub fn new() -> WriteBatch {
61        let ptr = unsafe { leveldb_writebatch_create() };
62        let raw = RawWriteBatch { ptr };
63
64        WriteBatch { write_batch: raw }
65    }
66
67    /// Clear the writebatch
68    pub fn clear(&self) {
69        unsafe { leveldb_writebatch_clear(self.write_batch.ptr) };
70    }
71
72    /// Batch a put operation
73    pub fn put(&self, key: &dyn IntoLevelDBKey, value: &[u8]) {
74        let _ = key.as_u8_slice_for_write(&|k| {
75            self.put_u8(k, value);
76
77            Ok(())
78        });
79    }
80
81    pub fn put_u8(&self, key: &[u8], value: &[u8]) {
82        unsafe {
83            leveldb_writebatch_put(
84                self.write_batch.ptr,
85                key.as_ptr() as *mut c_char,
86                key.len() as size_t,
87                value.as_ptr() as *mut c_char,
88                value.len() as size_t,
89            );
90        }
91    }
92
93    /// Batch a delete operation
94    pub fn delete(&self, key: &dyn IntoLevelDBKey) {
95        let _ = key.as_u8_slice_for_write(&|k| {
96            self.delete_u8(k);
97
98            Ok(())
99        });
100    }
101
102    pub fn delete_u8(&self, key: &[u8]) {
103        unsafe {
104            leveldb_writebatch_delete(
105                self.write_batch.ptr,
106                key.as_ptr() as *mut c_char,
107                key.len() as size_t,
108            );
109        }
110    }
111
112    /// Iterate over the writeBatch, returning the resulting iterator
113    pub fn iterate<T: WriteBatchIterator>(&mut self, iterator: Box<T>) -> Box<T> {
114        unsafe {
115            let iter = Box::into_raw(iterator);
116            leveldb_writebatch_iterate(
117                self.write_batch.ptr,
118                iter as *mut c_void,
119                put_callback::<T>,
120                deleted_callback::<T>,
121            );
122            Box::from_raw(iter)
123        }
124    }
125}
126
127/// A trait for iterators to iterate over written batches and check their validity.
128pub trait WriteBatchIterator {
129    /// Callback for put items
130    fn put_u8(&mut self, key: &[u8], value: &[u8]);
131
132    /// Callback for deleted items
133    fn deleted_u8(&mut self, key: &[u8]);
134}
135
136extern "C" fn put_callback<T: WriteBatchIterator>(
137    state: *mut c_void,
138    key: *const c_char,
139    key_len: size_t,
140    val: *const c_char,
141    val_len: size_t,
142) {
143    unsafe {
144        let iter: &mut T = &mut *(state as *mut T);
145        let key_slice = slice::from_raw_parts::<u8>(key as *const u8, key_len);
146        let val_slice = slice::from_raw_parts::<u8>(val as *const u8, val_len);
147
148        iter.put_u8(key_slice, val_slice);
149    }
150}
151
152extern "C" fn deleted_callback<T: WriteBatchIterator>(
153    state: *mut c_void,
154    key: *const c_char,
155    key_len: size_t,
156) {
157    unsafe {
158        let iter: &mut T = &mut *(state as *mut T);
159        let key_slice = slice::from_raw_parts::<u8>(key as *const u8, key_len);
160
161        iter.deleted_u8(key_slice);
162    }
163}