ckb_rocksdb/
write_batch.rs

1// Copyright 2019 Tyler Neely
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15
16use crate::ffi;
17
18use crate::{ColumnFamily, Error, handle::Handle};
19
20use libc::{c_char, size_t};
21
22/// An atomic batch of write operations.
23///
24/// Making an atomic commit of several writes:
25///
26/// ```
27/// use ckb_rocksdb::{prelude::*, WriteBatch};
28/// # use ckb_rocksdb::TemporaryDBPath;
29///
30/// let path = "_path_for_rocksdb_storage1";
31/// # let path = TemporaryDBPath::new();
32/// # {
33///
34/// let db = DB::open_default(&path).unwrap();
35///
36/// let mut batch = WriteBatch::default();
37/// batch.put(b"my key", b"my value");
38/// batch.put(b"key2", b"value2");
39/// batch.put(b"key3", b"value3");
40///
41/// db.write(&batch); // Atomically commits the batch
42/// # }
43/// ```
44pub struct WriteBatch {
45    inner: *mut ffi::rocksdb_writebatch_t,
46}
47
48impl WriteBatch {
49    pub fn len(&self) -> usize {
50        unsafe { ffi::rocksdb_writebatch_count(self.inner) as usize }
51    }
52
53    /// Return WriteBatch serialized size (in bytes).
54    pub fn size_in_bytes(&self) -> usize {
55        unsafe {
56            let mut batch_size: size_t = 0;
57            ffi::rocksdb_writebatch_data(self.inner, &mut batch_size);
58            batch_size
59        }
60    }
61
62    pub fn is_empty(&self) -> bool {
63        self.len() == 0
64    }
65
66    /// Insert a value into the database under the given key.
67    pub fn put<K, V>(&mut self, key: K, value: V) -> Result<(), Error>
68    where
69        K: AsRef<[u8]>,
70        V: AsRef<[u8]>,
71    {
72        let key = key.as_ref();
73        let value = value.as_ref();
74
75        unsafe {
76            ffi::rocksdb_writebatch_put(
77                self.handle(),
78                key.as_ptr() as *const c_char,
79                key.len() as size_t,
80                value.as_ptr() as *const c_char,
81                value.len() as size_t,
82            );
83            Ok(())
84        }
85    }
86
87    pub fn put_cf<K, V>(&mut self, cf: &ColumnFamily, key: K, value: V) -> Result<(), Error>
88    where
89        K: AsRef<[u8]>,
90        V: AsRef<[u8]>,
91    {
92        let key = key.as_ref();
93        let value = value.as_ref();
94
95        unsafe {
96            ffi::rocksdb_writebatch_put_cf(
97                self.handle(),
98                cf.handle(),
99                key.as_ptr() as *const c_char,
100                key.len() as size_t,
101                value.as_ptr() as *const c_char,
102                value.len() as size_t,
103            );
104            Ok(())
105        }
106    }
107
108    pub fn merge<K, V>(&mut self, key: K, value: V) -> Result<(), Error>
109    where
110        K: AsRef<[u8]>,
111        V: AsRef<[u8]>,
112    {
113        let key = key.as_ref();
114        let value = value.as_ref();
115
116        unsafe {
117            ffi::rocksdb_writebatch_merge(
118                self.handle(),
119                key.as_ptr() as *const c_char,
120                key.len() as size_t,
121                value.as_ptr() as *const c_char,
122                value.len() as size_t,
123            );
124            Ok(())
125        }
126    }
127
128    pub fn merge_cf<K, V>(&mut self, cf: &ColumnFamily, key: K, value: V) -> Result<(), Error>
129    where
130        K: AsRef<[u8]>,
131        V: AsRef<[u8]>,
132    {
133        let key = key.as_ref();
134        let value = value.as_ref();
135
136        unsafe {
137            ffi::rocksdb_writebatch_merge_cf(
138                self.handle(),
139                cf.handle(),
140                key.as_ptr() as *const c_char,
141                key.len() as size_t,
142                value.as_ptr() as *const c_char,
143                value.len() as size_t,
144            );
145            Ok(())
146        }
147    }
148
149    /// Remove the database entry for key.
150    ///
151    /// Returns an error if the key was not found.
152    pub fn delete<K: AsRef<[u8]>>(&mut self, key: K) -> Result<(), Error> {
153        let key = key.as_ref();
154
155        unsafe {
156            ffi::rocksdb_writebatch_delete(
157                self.handle(),
158                key.as_ptr() as *const c_char,
159                key.len() as size_t,
160            );
161            Ok(())
162        }
163    }
164
165    pub fn delete_cf<K: AsRef<[u8]>>(&mut self, cf: &ColumnFamily, key: K) -> Result<(), Error> {
166        let key = key.as_ref();
167
168        unsafe {
169            ffi::rocksdb_writebatch_delete_cf(
170                self.handle(),
171                cf.handle(),
172                key.as_ptr() as *const c_char,
173                key.len() as size_t,
174            );
175            Ok(())
176        }
177    }
178
179    /// Remove database entries from start key to end key.
180    ///
181    /// Removes the database entries in the range ["begin_key", "end_key"), i.e.,
182    /// including "begin_key" and excluding "end_key". It is not an error if no
183    /// keys exist in the range ["begin_key", "end_key").
184    pub fn delete_range<K: AsRef<[u8]>>(&mut self, from: K, to: K) -> Result<(), Error> {
185        let (start_key, end_key) = (from.as_ref(), to.as_ref());
186
187        unsafe {
188            ffi::rocksdb_writebatch_delete_range(
189                self.handle(),
190                start_key.as_ptr() as *const c_char,
191                start_key.len() as size_t,
192                end_key.as_ptr() as *const c_char,
193                end_key.len() as size_t,
194            );
195            Ok(())
196        }
197    }
198
199    /// Remove database entries in column family from start key to end key.
200    ///
201    /// Removes the database entries in the range ["begin_key", "end_key"), i.e.,
202    /// including "begin_key" and excluding "end_key". It is not an error if no
203    /// keys exist in the range ["begin_key", "end_key").
204    pub fn delete_range_cf<K: AsRef<[u8]>>(
205        &mut self,
206        cf: &ColumnFamily,
207        from: K,
208        to: K,
209    ) -> Result<(), Error> {
210        let (start_key, end_key) = (from.as_ref(), to.as_ref());
211
212        unsafe {
213            ffi::rocksdb_writebatch_delete_range_cf(
214                self.handle(),
215                cf.handle(),
216                start_key.as_ptr() as *const c_char,
217                start_key.len() as size_t,
218                end_key.as_ptr() as *const c_char,
219                end_key.len() as size_t,
220            );
221            Ok(())
222        }
223    }
224
225    /// Clear all updates buffered in this batch.
226    pub fn clear(&mut self) -> Result<(), Error> {
227        unsafe {
228            ffi::rocksdb_writebatch_clear(self.inner);
229        }
230        Ok(())
231    }
232}
233
234impl Default for WriteBatch {
235    fn default() -> WriteBatch {
236        WriteBatch {
237            inner: unsafe { ffi::rocksdb_writebatch_create() },
238        }
239    }
240}
241
242impl Drop for WriteBatch {
243    fn drop(&mut self) {
244        unsafe { ffi::rocksdb_writebatch_destroy(self.inner) }
245    }
246}
247
248impl Handle<ffi::rocksdb_writebatch_t> for WriteBatch {
249    fn handle(&self) -> *mut ffi::rocksdb_writebatch_t {
250        self.inner
251    }
252}