1use crate::db::DBInner;
2use crate::ffi_util::raw_data_and_free;
3use crate::{
4 AsColumnFamilyRef, DBAccess, DBCommon, DBPinnableSlice, DBRawIteratorWithThreadMode, Error,
5 Options, ReadOptions, ThreadMode, ffi,
6};
7use libc::{c_char, c_uchar, size_t};
8
9pub struct WriteBatchWithIndex {
44 pub(crate) inner: *mut ffi::rocksdb_writebatch_wi_t,
45}
46
47impl WriteBatchWithIndex {
48 pub fn new(reserved_bytes: usize, overwrite_key: bool) -> Self {
49 Self {
50 inner: unsafe {
51 ffi::rocksdb_writebatch_wi_create(
52 reserved_bytes as size_t,
53 c_uchar::from(overwrite_key),
54 )
55 },
56 }
57 }
58
59 pub fn len(&self) -> usize {
60 unsafe { ffi::rocksdb_writebatch_wi_count(self.inner) as usize }
61 }
62
63 pub fn size_in_bytes(&self) -> usize {
65 unsafe {
66 let mut batch_size: size_t = 0;
67 ffi::rocksdb_writebatch_wi_data(self.inner, &raw mut batch_size);
68 batch_size
69 }
70 }
71
72 pub fn data(&self) -> &[u8] {
74 unsafe {
75 let mut batch_size: size_t = 0;
76 let batch_data = ffi::rocksdb_writebatch_wi_data(self.inner, &raw mut batch_size);
77 std::slice::from_raw_parts(batch_data as _, batch_size)
78 }
79 }
80
81 pub fn is_empty(&self) -> bool {
82 self.len() == 0
83 }
84
85 pub fn get_from_batch<K>(&self, key: K, options: &Options) -> Result<Option<Vec<u8>>, Error>
86 where
87 K: AsRef<[u8]>,
88 {
89 let key = key.as_ref();
90 unsafe {
91 let mut value_size: size_t = 0;
92 let value_data = ffi_try!(ffi::rocksdb_writebatch_wi_get_from_batch(
93 self.inner,
94 options.inner,
95 key.as_ptr() as *const c_char,
96 key.len() as size_t,
97 &raw mut value_size
98 ));
99
100 Ok(raw_data_and_free(value_data, value_size))
103 }
104 }
105
106 pub fn get_from_batch_cf<K>(
107 &self,
108 cf: &impl AsColumnFamilyRef,
109 key: K,
110 options: &Options,
111 ) -> Result<Option<Vec<u8>>, Error>
112 where
113 K: AsRef<[u8]>,
114 {
115 let key = key.as_ref();
116 unsafe {
117 let mut value_size: size_t = 0;
118 let value_data = ffi_try!(ffi::rocksdb_writebatch_wi_get_from_batch_cf(
119 self.inner,
120 options.inner,
121 cf.inner(),
122 key.as_ptr() as *const c_char,
123 key.len() as size_t,
124 &raw mut value_size
125 ));
126
127 Ok(raw_data_and_free(value_data, value_size))
130 }
131 }
132
133 pub fn get_from_batch_and_db<T, I, K>(
134 &self,
135 db: &DBCommon<T, I>,
136 key: K,
137 readopts: &ReadOptions,
138 ) -> Result<Option<Vec<u8>>, Error>
139 where
140 T: ThreadMode,
141 I: DBInner,
142 K: AsRef<[u8]>,
143 {
144 if readopts.inner.is_null() {
145 return Err(Error::new(
146 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
147 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
148 .to_owned(),
149 ));
150 }
151
152 let key = key.as_ref();
153 unsafe {
154 let mut value_size: size_t = 0;
155 let value_data = ffi_try!(ffi::rocksdb_writebatch_wi_get_from_batch_and_db(
156 self.inner,
157 db.inner.inner(),
158 readopts.inner,
159 key.as_ptr() as *const c_char,
160 key.len() as size_t,
161 &raw mut value_size
162 ));
163
164 Ok(raw_data_and_free(value_data, value_size))
167 }
168 }
169
170 pub fn get_pinned_from_batch_and_db<'db, T, I, K>(
175 &self,
176 db: &'db DBCommon<T, I>,
177 key: K,
178 readopts: &ReadOptions,
179 ) -> Result<Option<DBPinnableSlice<'db>>, Error>
180 where
181 T: ThreadMode,
182 I: DBInner,
183 K: AsRef<[u8]>,
184 {
185 if readopts.inner.is_null() {
186 return Err(Error::new(
187 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
188 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
189 .to_owned(),
190 ));
191 }
192
193 let key = key.as_ref();
194 unsafe {
195 let value_data = ffi_try!(ffi::rocksdb_writebatch_wi_get_pinned_from_batch_and_db(
196 self.inner,
197 db.inner.inner(),
198 readopts.inner,
199 key.as_ptr() as *const c_char,
200 key.len() as size_t,
201 ));
202
203 if value_data.is_null() {
204 Ok(None)
205 } else {
206 Ok(Some(DBPinnableSlice::from_c(value_data)))
207 }
208 }
209 }
210
211 pub fn get_from_batch_and_db_cf<T, I, K>(
212 &self,
213 db: &DBCommon<T, I>,
214 cf: &impl AsColumnFamilyRef,
215 key: K,
216 readopts: &ReadOptions,
217 ) -> Result<Option<Vec<u8>>, Error>
218 where
219 T: ThreadMode,
220 I: DBInner,
221 K: AsRef<[u8]>,
222 {
223 if readopts.inner.is_null() {
224 return Err(Error::new(
225 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
226 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
227 .to_owned(),
228 ));
229 }
230
231 let key = key.as_ref();
232 unsafe {
233 let mut value_size: size_t = 0;
234 let value_data = ffi_try!(ffi::rocksdb_writebatch_wi_get_from_batch_and_db_cf(
235 self.inner,
236 db.inner.inner(),
237 readopts.inner,
238 cf.inner(),
239 key.as_ptr() as *const c_char,
240 key.len() as size_t,
241 &raw mut value_size
242 ));
243
244 Ok(raw_data_and_free(value_data, value_size))
247 }
248 }
249
250 pub fn get_pinned_from_batch_and_db_cf<'db, T, I, K>(
254 &self,
255 db: &'db DBCommon<T, I>,
256 cf: &impl AsColumnFamilyRef,
257 key: K,
258 readopts: &ReadOptions,
259 ) -> Result<Option<DBPinnableSlice<'db>>, Error>
260 where
261 T: ThreadMode,
262 I: DBInner,
263 K: AsRef<[u8]>,
264 {
265 if readopts.inner.is_null() {
266 return Err(Error::new(
267 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
268 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
269 .to_owned(),
270 ));
271 }
272
273 let key = key.as_ref();
274 unsafe {
275 let value_data = ffi_try!(ffi::rocksdb_writebatch_wi_get_pinned_from_batch_and_db_cf(
276 self.inner,
277 db.inner.inner(),
278 readopts.inner,
279 cf.inner(),
280 key.as_ptr() as *const c_char,
281 key.len() as size_t,
282 ));
283
284 if value_data.is_null() {
285 Ok(None)
286 } else {
287 Ok(Some(DBPinnableSlice::from_c(value_data)))
288 }
289 }
290 }
291
292 pub fn put<K, V>(&mut self, key: K, value: V)
294 where
295 K: AsRef<[u8]>,
296 V: AsRef<[u8]>,
297 {
298 let key = key.as_ref();
299 let value = value.as_ref();
300
301 unsafe {
302 ffi::rocksdb_writebatch_wi_put(
303 self.inner,
304 key.as_ptr() as *const c_char,
305 key.len() as size_t,
306 value.as_ptr() as *const c_char,
307 value.len() as size_t,
308 );
309 }
310 }
311
312 pub fn put_cf<K, V>(&mut self, cf: &impl AsColumnFamilyRef, key: K, value: V)
313 where
314 K: AsRef<[u8]>,
315 V: AsRef<[u8]>,
316 {
317 let key = key.as_ref();
318 let value = value.as_ref();
319
320 unsafe {
321 ffi::rocksdb_writebatch_wi_put_cf(
322 self.inner,
323 cf.inner(),
324 key.as_ptr() as *const c_char,
325 key.len() as size_t,
326 value.as_ptr() as *const c_char,
327 value.len() as size_t,
328 );
329 }
330 }
331
332 pub fn merge<K, V>(&mut self, key: K, value: V)
333 where
334 K: AsRef<[u8]>,
335 V: AsRef<[u8]>,
336 {
337 let key = key.as_ref();
338 let value = value.as_ref();
339
340 unsafe {
341 ffi::rocksdb_writebatch_wi_merge(
342 self.inner,
343 key.as_ptr() as *const c_char,
344 key.len() as size_t,
345 value.as_ptr() as *const c_char,
346 value.len() as size_t,
347 );
348 }
349 }
350
351 pub fn merge_cf<K, V>(&mut self, cf: &impl AsColumnFamilyRef, key: K, value: V)
352 where
353 K: AsRef<[u8]>,
354 V: AsRef<[u8]>,
355 {
356 let key = key.as_ref();
357 let value = value.as_ref();
358
359 unsafe {
360 ffi::rocksdb_writebatch_wi_merge_cf(
361 self.inner,
362 cf.inner(),
363 key.as_ptr() as *const c_char,
364 key.len() as size_t,
365 value.as_ptr() as *const c_char,
366 value.len() as size_t,
367 );
368 }
369 }
370
371 pub fn delete<K: AsRef<[u8]>>(&mut self, key: K) {
373 let key = key.as_ref();
374
375 unsafe {
376 ffi::rocksdb_writebatch_wi_delete(
377 self.inner,
378 key.as_ptr() as *const c_char,
379 key.len() as size_t,
380 );
381 }
382 }
383
384 pub fn delete_cf<K: AsRef<[u8]>>(&mut self, cf: &impl AsColumnFamilyRef, key: K) {
385 let key = key.as_ref();
386
387 unsafe {
388 ffi::rocksdb_writebatch_wi_delete_cf(
389 self.inner,
390 cf.inner(),
391 key.as_ptr() as *const c_char,
392 key.len() as size_t,
393 );
394 }
395 }
396
397 pub fn clear(&mut self) {
399 unsafe {
400 ffi::rocksdb_writebatch_wi_clear(self.inner);
401 }
402 }
403
404 pub fn iterator_with_base<'a, D>(
410 &'a self,
411 base_iterator: DBRawIteratorWithThreadMode<'a, D>,
412 ) -> DBRawIteratorWithThreadMode<'a, D>
413 where
414 D: DBAccess,
415 {
416 let (base_iterator_inner, readopts) = base_iterator.into_inner();
417
418 let iterator = unsafe {
419 ffi::rocksdb_writebatch_wi_create_iterator_with_base_readopts(
420 self.inner,
421 base_iterator_inner.as_ptr(),
422 readopts.as_ptr(),
423 )
424 };
425
426 DBRawIteratorWithThreadMode::from_inner(iterator, readopts)
430 }
431
432 pub fn iterator_with_base_cf<'a, D>(
435 &'a self,
436 base_iterator: DBRawIteratorWithThreadMode<'a, D>,
437 cf: &impl AsColumnFamilyRef,
438 ) -> DBRawIteratorWithThreadMode<'a, D>
439 where
440 D: DBAccess,
441 {
442 let (base_iterator_inner, readopts) = base_iterator.into_inner();
443
444 let iterator = unsafe {
445 ffi::rocksdb_writebatch_wi_create_iterator_with_base_cf_readopts(
446 self.inner,
447 base_iterator_inner.as_ptr(),
448 cf.inner(),
449 readopts.as_ptr(),
450 )
451 };
452
453 DBRawIteratorWithThreadMode::from_inner(iterator, readopts)
454 }
455}
456
457impl Drop for WriteBatchWithIndex {
458 fn drop(&mut self) {
459 unsafe {
460 ffi::rocksdb_writebatch_wi_destroy(self.inner);
461 }
462 }
463}
464
465unsafe impl Send for WriteBatchWithIndex {}