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::{handle::Handle, ColumnFamily, Error};
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/// # }
44/// ```
45pub struct WriteBatch {
46    inner: *mut ffi::rocksdb_writebatch_t,
47}
48
49impl WriteBatch {
50    pub fn len(&self) -> usize {
51        unsafe { ffi::rocksdb_writebatch_count(self.inner) as usize }
52    }
53
54    /// Return WriteBatch serialized size (in bytes).
55    pub fn size_in_bytes(&self) -> usize {
56        unsafe {
57            let mut batch_size: size_t = 0;
58            ffi::rocksdb_writebatch_data(self.inner, &mut batch_size);
59            batch_size
60        }
61    }
62
63    pub fn is_empty(&self) -> bool {
64        self.len() == 0
65    }
66
67    /// Insert a value into the database under the given key.
68    pub fn put<K, V>(&mut self, key: K, value: V) -> Result<(), Error>
69    where
70        K: AsRef<[u8]>,
71        V: AsRef<[u8]>,
72    {
73        let key = key.as_ref();
74        let value = value.as_ref();
75
76        unsafe {
77            ffi::rocksdb_writebatch_put(
78                self.handle(),
79                key.as_ptr() as *const c_char,
80                key.len() as size_t,
81                value.as_ptr() as *const c_char,
82                value.len() as size_t,
83            );
84            Ok(())
85        }
86    }
87
88    pub fn put_cf<K, V>(&mut self, cf: &ColumnFamily, key: K, value: V) -> Result<(), Error>
89    where
90        K: AsRef<[u8]>,
91        V: AsRef<[u8]>,
92    {
93        let key = key.as_ref();
94        let value = value.as_ref();
95
96        unsafe {
97            ffi::rocksdb_writebatch_put_cf(
98                self.handle(),
99                cf.handle(),
100                key.as_ptr() as *const c_char,
101                key.len() as size_t,
102                value.as_ptr() as *const c_char,
103                value.len() as size_t,
104            );
105            Ok(())
106        }
107    }
108
109    pub fn merge<K, V>(&mut self, key: K, value: V) -> Result<(), Error>
110    where
111        K: AsRef<[u8]>,
112        V: AsRef<[u8]>,
113    {
114        let key = key.as_ref();
115        let value = value.as_ref();
116
117        unsafe {
118            ffi::rocksdb_writebatch_merge(
119                self.handle(),
120                key.as_ptr() as *const c_char,
121                key.len() as size_t,
122                value.as_ptr() as *const c_char,
123                value.len() as size_t,
124            );
125            Ok(())
126        }
127    }
128
129    pub fn merge_cf<K, V>(&mut self, cf: &ColumnFamily, key: K, value: V) -> Result<(), Error>
130    where
131        K: AsRef<[u8]>,
132        V: AsRef<[u8]>,
133    {
134        let key = key.as_ref();
135        let value = value.as_ref();
136
137        unsafe {
138            ffi::rocksdb_writebatch_merge_cf(
139                self.handle(),
140                cf.handle(),
141                key.as_ptr() as *const c_char,
142                key.len() as size_t,
143                value.as_ptr() as *const c_char,
144                value.len() as size_t,
145            );
146            Ok(())
147        }
148    }
149
150    /// Remove the database entry for key.
151    ///
152    /// Returns an error if the key was not found.
153    pub fn delete<K: AsRef<[u8]>>(&mut self, key: K) -> Result<(), Error> {
154        let key = key.as_ref();
155
156        unsafe {
157            ffi::rocksdb_writebatch_delete(
158                self.handle(),
159                key.as_ptr() as *const c_char,
160                key.len() as size_t,
161            );
162            Ok(())
163        }
164    }
165
166    pub fn delete_cf<K: AsRef<[u8]>>(&mut self, cf: &ColumnFamily, key: K) -> Result<(), Error> {
167        let key = key.as_ref();
168
169        unsafe {
170            ffi::rocksdb_writebatch_delete_cf(
171                self.handle(),
172                cf.handle(),
173                key.as_ptr() as *const c_char,
174                key.len() as size_t,
175            );
176            Ok(())
177        }
178    }
179
180    /// Remove database entries from start key to end key.
181    ///
182    /// Removes the database entries in the range ["begin_key", "end_key"), i.e.,
183    /// including "begin_key" and excluding "end_key". It is not an error if no
184    /// keys exist in the range ["begin_key", "end_key").
185    pub fn delete_range<K: AsRef<[u8]>>(&mut self, from: K, to: K) -> Result<(), Error> {
186        let (start_key, end_key) = (from.as_ref(), to.as_ref());
187
188        unsafe {
189            ffi::rocksdb_writebatch_delete_range(
190                self.handle(),
191                start_key.as_ptr() as *const c_char,
192                start_key.len() as size_t,
193                end_key.as_ptr() as *const c_char,
194                end_key.len() as size_t,
195            );
196            Ok(())
197        }
198    }
199
200    /// Remove database entries in column family from start key to end key.
201    ///
202    /// Removes the database entries in the range ["begin_key", "end_key"), i.e.,
203    /// including "begin_key" and excluding "end_key". It is not an error if no
204    /// keys exist in the range ["begin_key", "end_key").
205    pub fn delete_range_cf<K: AsRef<[u8]>>(
206        &mut self,
207        cf: &ColumnFamily,
208        from: K,
209        to: K,
210    ) -> Result<(), Error> {
211        let (start_key, end_key) = (from.as_ref(), to.as_ref());
212
213        unsafe {
214            ffi::rocksdb_writebatch_delete_range_cf(
215                self.handle(),
216                cf.handle(),
217                start_key.as_ptr() as *const c_char,
218                start_key.len() as size_t,
219                end_key.as_ptr() as *const c_char,
220                end_key.len() as size_t,
221            );
222            Ok(())
223        }
224    }
225
226    /// Clear all updates buffered in this batch.
227    pub fn clear(&mut self) -> Result<(), Error> {
228        unsafe {
229            ffi::rocksdb_writebatch_clear(self.inner);
230        }
231        Ok(())
232    }
233}
234
235impl Default for WriteBatch {
236    fn default() -> WriteBatch {
237        WriteBatch {
238            inner: unsafe { ffi::rocksdb_writebatch_create() },
239        }
240    }
241}
242
243impl Drop for WriteBatch {
244    fn drop(&mut self) {
245        unsafe { ffi::rocksdb_writebatch_destroy(self.inner) }
246    }
247}
248
249impl Handle<ffi::rocksdb_writebatch_t> for WriteBatch {
250    fn handle(&self) -> *mut ffi::rocksdb_writebatch_t {
251        self.inner
252    }
253}