1use crate::db::DBInner;
2use crate::ffi_util::raw_data_and_free;
3use crate::write_batch::get_ts_size_callback;
4use crate::{
5 AsColumnFamilyRef, Comparator, DBAccess, DBCommon, DBPinnableSlice,
6 DBRawIteratorWithThreadMode, Error, Options, ReadOptions, ThreadMode, ffi,
7};
8use libc::{c_char, c_uchar, c_void, size_t};
9use std::sync::Arc;
10
11pub struct WriteBatchWithIndex {
54 pub(crate) inner: *mut ffi::rocksdb_writebatch_wi_t,
55 _comparator: Option<Arc<Comparator>>,
58}
59
60pub struct WriteBatchWithIndexBuilder {
65 comparator: Option<Arc<Comparator>>,
66 reserved_bytes: usize,
67 overwrite_key: bool,
68 max_bytes: usize,
69 protection_bytes_per_key: usize,
70}
71
72impl WriteBatchWithIndexBuilder {
73 pub fn comparator(mut self, comparator: Arc<Comparator>) -> Self {
79 self.comparator = Some(comparator);
80 self
81 }
82
83 pub fn reserved_bytes(mut self, reserved_bytes: usize) -> Self {
85 self.reserved_bytes = reserved_bytes;
86 self
87 }
88
89 pub fn overwrite_key(mut self, overwrite_key: bool) -> Self {
96 self.overwrite_key = overwrite_key;
97 self
98 }
99
100 pub fn max_bytes(mut self, max_bytes: usize) -> Self {
103 self.max_bytes = max_bytes;
104 self
105 }
106
107 pub fn protection_bytes_per_key(mut self, protection_bytes_per_key: usize) -> Self {
112 self.protection_bytes_per_key = protection_bytes_per_key;
113 self
114 }
115
116 pub fn build(self) -> WriteBatchWithIndex {
118 let comparator_ptr = self
119 .comparator
120 .as_ref()
121 .map_or(std::ptr::null_mut(), |cmp| cmp.inner.as_ptr());
122 WriteBatchWithIndex {
123 inner: unsafe {
124 ffi::rocksdb_writebatch_wi_create_with_params(
125 comparator_ptr,
126 self.reserved_bytes,
127 c_uchar::from(self.overwrite_key),
128 self.max_bytes,
129 self.protection_bytes_per_key,
130 )
131 },
132 _comparator: self.comparator,
133 }
134 }
135}
136
137impl WriteBatchWithIndex {
138 pub fn new(reserved_bytes: usize, overwrite_key: bool) -> Self {
139 Self {
140 inner: unsafe {
141 ffi::rocksdb_writebatch_wi_create(
142 reserved_bytes as size_t,
143 c_uchar::from(overwrite_key),
144 )
145 },
146 _comparator: None,
147 }
148 }
149
150 pub fn builder() -> WriteBatchWithIndexBuilder {
165 WriteBatchWithIndexBuilder {
166 comparator: None,
167 reserved_bytes: 0,
168 overwrite_key: false,
169 max_bytes: 0,
170 protection_bytes_per_key: 0,
171 }
172 }
173
174 pub fn len(&self) -> usize {
175 unsafe { ffi::rocksdb_writebatch_wi_count(self.inner) as usize }
176 }
177
178 pub fn size_in_bytes(&self) -> usize {
180 unsafe {
181 let mut batch_size: size_t = 0;
182 ffi::rocksdb_writebatch_wi_data(self.inner, &raw mut batch_size);
183 batch_size
184 }
185 }
186
187 pub fn data(&self) -> &[u8] {
189 unsafe {
190 let mut batch_size: size_t = 0;
191 let batch_data = ffi::rocksdb_writebatch_wi_data(self.inner, &raw mut batch_size);
192 std::slice::from_raw_parts(batch_data as _, batch_size)
193 }
194 }
195
196 pub fn is_empty(&self) -> bool {
197 self.len() == 0
198 }
199
200 pub fn get_from_batch<K>(&self, key: K, options: &Options) -> Result<Option<Vec<u8>>, Error>
201 where
202 K: AsRef<[u8]>,
203 {
204 let key = key.as_ref();
205 unsafe {
206 let mut value_size: size_t = 0;
207 let value_data = ffi_try!(ffi::rocksdb_writebatch_wi_get_from_batch(
208 self.inner,
209 options.inner,
210 key.as_ptr() as *const c_char,
211 key.len() as size_t,
212 &raw mut value_size
213 ));
214
215 Ok(raw_data_and_free(value_data, value_size))
218 }
219 }
220
221 pub fn get_from_batch_cf<K>(
222 &self,
223 cf: &impl AsColumnFamilyRef,
224 key: K,
225 options: &Options,
226 ) -> Result<Option<Vec<u8>>, Error>
227 where
228 K: AsRef<[u8]>,
229 {
230 let key = key.as_ref();
231 unsafe {
232 let mut value_size: size_t = 0;
233 let value_data = ffi_try!(ffi::rocksdb_writebatch_wi_get_from_batch_cf(
234 self.inner,
235 options.inner,
236 cf.inner(),
237 key.as_ptr() as *const c_char,
238 key.len() as size_t,
239 &raw mut value_size
240 ));
241
242 Ok(raw_data_and_free(value_data, value_size))
245 }
246 }
247
248 pub fn get_from_batch_and_db<T, I, K>(
249 &self,
250 db: &DBCommon<T, I>,
251 key: K,
252 readopts: &ReadOptions,
253 ) -> Result<Option<Vec<u8>>, Error>
254 where
255 T: ThreadMode,
256 I: DBInner,
257 K: AsRef<[u8]>,
258 {
259 if readopts.inner.is_null() {
260 return Err(Error::new(
261 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
262 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
263 .to_owned(),
264 ));
265 }
266
267 let key = key.as_ref();
268 unsafe {
269 let mut value_size: size_t = 0;
270 let value_data = ffi_try!(ffi::rocksdb_writebatch_wi_get_from_batch_and_db(
271 self.inner,
272 db.inner.inner(),
273 readopts.inner,
274 key.as_ptr() as *const c_char,
275 key.len() as size_t,
276 &raw mut value_size
277 ));
278
279 Ok(raw_data_and_free(value_data, value_size))
282 }
283 }
284
285 pub fn get_pinned_from_batch_and_db<'db, T, I, K>(
290 &self,
291 db: &'db DBCommon<T, I>,
292 key: K,
293 readopts: &ReadOptions,
294 ) -> Result<Option<DBPinnableSlice<'db>>, Error>
295 where
296 T: ThreadMode,
297 I: DBInner,
298 K: AsRef<[u8]>,
299 {
300 if readopts.inner.is_null() {
301 return Err(Error::new(
302 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
303 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
304 .to_owned(),
305 ));
306 }
307
308 let key = key.as_ref();
309 unsafe {
310 let value_data = ffi_try!(ffi::rocksdb_writebatch_wi_get_pinned_from_batch_and_db(
311 self.inner,
312 db.inner.inner(),
313 readopts.inner,
314 key.as_ptr() as *const c_char,
315 key.len() as size_t,
316 ));
317
318 if value_data.is_null() {
319 Ok(None)
320 } else {
321 Ok(Some(DBPinnableSlice::from_c(value_data)))
322 }
323 }
324 }
325
326 pub fn get_from_batch_and_db_cf<T, I, K>(
327 &self,
328 db: &DBCommon<T, I>,
329 cf: &impl AsColumnFamilyRef,
330 key: K,
331 readopts: &ReadOptions,
332 ) -> Result<Option<Vec<u8>>, Error>
333 where
334 T: ThreadMode,
335 I: DBInner,
336 K: AsRef<[u8]>,
337 {
338 if readopts.inner.is_null() {
339 return Err(Error::new(
340 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
341 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
342 .to_owned(),
343 ));
344 }
345
346 let key = key.as_ref();
347 unsafe {
348 let mut value_size: size_t = 0;
349 let value_data = ffi_try!(ffi::rocksdb_writebatch_wi_get_from_batch_and_db_cf(
350 self.inner,
351 db.inner.inner(),
352 readopts.inner,
353 cf.inner(),
354 key.as_ptr() as *const c_char,
355 key.len() as size_t,
356 &raw mut value_size
357 ));
358
359 Ok(raw_data_and_free(value_data, value_size))
362 }
363 }
364
365 pub fn get_pinned_from_batch_and_db_cf<'db, T, I, K>(
369 &self,
370 db: &'db DBCommon<T, I>,
371 cf: &impl AsColumnFamilyRef,
372 key: K,
373 readopts: &ReadOptions,
374 ) -> Result<Option<DBPinnableSlice<'db>>, Error>
375 where
376 T: ThreadMode,
377 I: DBInner,
378 K: AsRef<[u8]>,
379 {
380 if readopts.inner.is_null() {
381 return Err(Error::new(
382 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
383 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
384 .to_owned(),
385 ));
386 }
387
388 let key = key.as_ref();
389 unsafe {
390 let value_data = ffi_try!(ffi::rocksdb_writebatch_wi_get_pinned_from_batch_and_db_cf(
391 self.inner,
392 db.inner.inner(),
393 readopts.inner,
394 cf.inner(),
395 key.as_ptr() as *const c_char,
396 key.len() as size_t,
397 ));
398
399 if value_data.is_null() {
400 Ok(None)
401 } else {
402 Ok(Some(DBPinnableSlice::from_c(value_data)))
403 }
404 }
405 }
406
407 pub fn put<K, V>(&mut self, key: K, value: V)
409 where
410 K: AsRef<[u8]>,
411 V: AsRef<[u8]>,
412 {
413 let key = key.as_ref();
414 let value = value.as_ref();
415
416 unsafe {
417 ffi::rocksdb_writebatch_wi_put(
418 self.inner,
419 key.as_ptr() as *const c_char,
420 key.len() as size_t,
421 value.as_ptr() as *const c_char,
422 value.len() as size_t,
423 );
424 }
425 }
426
427 pub fn put_cf<K, V>(&mut self, cf: &impl AsColumnFamilyRef, key: K, value: V)
428 where
429 K: AsRef<[u8]>,
430 V: AsRef<[u8]>,
431 {
432 let key = key.as_ref();
433 let value = value.as_ref();
434
435 unsafe {
436 ffi::rocksdb_writebatch_wi_put_cf(
437 self.inner,
438 cf.inner(),
439 key.as_ptr() as *const c_char,
440 key.len() as size_t,
441 value.as_ptr() as *const c_char,
442 value.len() as size_t,
443 );
444 }
445 }
446
447 pub fn merge<K, V>(&mut self, key: K, value: V)
448 where
449 K: AsRef<[u8]>,
450 V: AsRef<[u8]>,
451 {
452 let key = key.as_ref();
453 let value = value.as_ref();
454
455 unsafe {
456 ffi::rocksdb_writebatch_wi_merge(
457 self.inner,
458 key.as_ptr() as *const c_char,
459 key.len() as size_t,
460 value.as_ptr() as *const c_char,
461 value.len() as size_t,
462 );
463 }
464 }
465
466 pub fn merge_cf<K, V>(&mut self, cf: &impl AsColumnFamilyRef, key: K, value: V)
467 where
468 K: AsRef<[u8]>,
469 V: AsRef<[u8]>,
470 {
471 let key = key.as_ref();
472 let value = value.as_ref();
473
474 unsafe {
475 ffi::rocksdb_writebatch_wi_merge_cf(
476 self.inner,
477 cf.inner(),
478 key.as_ptr() as *const c_char,
479 key.len() as size_t,
480 value.as_ptr() as *const c_char,
481 value.len() as size_t,
482 );
483 }
484 }
485
486 pub fn delete<K: AsRef<[u8]>>(&mut self, key: K) {
488 let key = key.as_ref();
489
490 unsafe {
491 ffi::rocksdb_writebatch_wi_delete(
492 self.inner,
493 key.as_ptr() as *const c_char,
494 key.len() as size_t,
495 );
496 }
497 }
498
499 pub fn delete_cf<K: AsRef<[u8]>>(&mut self, cf: &impl AsColumnFamilyRef, key: K) {
500 let key = key.as_ref();
501
502 unsafe {
503 ffi::rocksdb_writebatch_wi_delete_cf(
504 self.inner,
505 cf.inner(),
506 key.as_ptr() as *const c_char,
507 key.len() as size_t,
508 );
509 }
510 }
511
512 pub fn single_delete<K: AsRef<[u8]>>(&mut self, key: K) {
520 let key = key.as_ref();
521
522 unsafe {
523 ffi::rocksdb_writebatch_wi_singledelete(
524 self.inner,
525 key.as_ptr() as *const c_char,
526 key.len() as size_t,
527 );
528 }
529 }
530
531 pub fn single_delete_cf<K: AsRef<[u8]>>(&mut self, cf: &impl AsColumnFamilyRef, key: K) {
535 let key = key.as_ref();
536
537 unsafe {
538 ffi::rocksdb_writebatch_wi_singledelete_cf(
539 self.inner,
540 cf.inner(),
541 key.as_ptr() as *const c_char,
542 key.len() as size_t,
543 );
544 }
545 }
546
547 pub fn delete_range<K: AsRef<[u8]>>(&mut self, from: K, to: K) {
555 let (start_key, end_key) = (from.as_ref(), to.as_ref());
556
557 unsafe {
558 ffi::rocksdb_writebatch_wi_delete_range(
559 self.inner,
560 start_key.as_ptr() as *const c_char,
561 start_key.len() as size_t,
562 end_key.as_ptr() as *const c_char,
563 end_key.len() as size_t,
564 );
565 }
566 }
567
568 pub fn delete_range_cf<K: AsRef<[u8]>>(&mut self, cf: &impl AsColumnFamilyRef, from: K, to: K) {
573 let (start_key, end_key) = (from.as_ref(), to.as_ref());
574
575 unsafe {
576 ffi::rocksdb_writebatch_wi_delete_range_cf(
577 self.inner,
578 cf.inner(),
579 start_key.as_ptr() as *const c_char,
580 start_key.len() as size_t,
581 end_key.as_ptr() as *const c_char,
582 end_key.len() as size_t,
583 );
584 }
585 }
586
587 pub fn put_log_data<V: AsRef<[u8]>>(&mut self, log_data: V) {
592 let log_data = log_data.as_ref();
593
594 unsafe {
595 ffi::rocksdb_writebatch_wi_put_log_data(
596 self.inner,
597 log_data.as_ptr() as *const c_char,
598 log_data.len() as size_t,
599 );
600 }
601 }
602
603 pub fn set_save_point(&mut self) {
608 unsafe {
609 ffi::rocksdb_writebatch_wi_set_save_point(self.inner);
610 }
611 }
612
613 pub fn rollback_to_save_point(&mut self) -> Result<(), Error> {
618 unsafe {
619 ffi_try!(ffi::rocksdb_writebatch_wi_rollback_to_save_point(
620 self.inner
621 ));
622 }
623 Ok(())
624 }
625
626 pub unsafe fn update_timestamps<S, F>(&mut self, ts: S, mut get_ts_size: F) -> Result<(), Error>
650 where
651 S: AsRef<[u8]>,
652 F: FnMut(u32) -> usize,
653 {
654 let ts = ts.as_ref();
655 let state = std::ptr::from_mut(&mut get_ts_size).cast::<c_void>();
656 unsafe {
657 ffi_try!(ffi::rocksdb_writebatch_wi_update_timestamps(
658 self.inner,
659 ts.as_ptr() as *const c_char,
660 ts.len() as size_t,
661 state,
662 Some(get_ts_size_callback::<F>),
663 ));
664 }
665 Ok(())
666 }
667
668 pub fn clear(&mut self) {
670 unsafe {
671 ffi::rocksdb_writebatch_wi_clear(self.inner);
672 }
673 }
674
675 pub fn iterator_with_base<'a, D>(
681 &'a self,
682 base_iterator: DBRawIteratorWithThreadMode<'a, D>,
683 ) -> DBRawIteratorWithThreadMode<'a, D>
684 where
685 D: DBAccess,
686 {
687 let (base_iterator_inner, readopts) = base_iterator.into_inner();
688
689 let iterator = unsafe {
690 ffi::rocksdb_writebatch_wi_create_iterator_with_base_readopts(
691 self.inner,
692 base_iterator_inner.as_ptr(),
693 readopts.as_ptr(),
694 )
695 };
696
697 DBRawIteratorWithThreadMode::from_inner(iterator, readopts)
701 }
702
703 pub fn iterator_with_base_cf<'a, D>(
706 &'a self,
707 base_iterator: DBRawIteratorWithThreadMode<'a, D>,
708 cf: &impl AsColumnFamilyRef,
709 ) -> DBRawIteratorWithThreadMode<'a, D>
710 where
711 D: DBAccess,
712 {
713 let (base_iterator_inner, readopts) = base_iterator.into_inner();
714
715 let iterator = unsafe {
716 ffi::rocksdb_writebatch_wi_create_iterator_with_base_cf_readopts(
717 self.inner,
718 base_iterator_inner.as_ptr(),
719 cf.inner(),
720 readopts.as_ptr(),
721 )
722 };
723
724 DBRawIteratorWithThreadMode::from_inner(iterator, readopts)
725 }
726}
727
728impl Drop for WriteBatchWithIndex {
729 fn drop(&mut self) {
730 unsafe {
731 ffi::rocksdb_writebatch_wi_destroy(self.inner);
732 }
733 }
734}
735
736unsafe impl Send for WriteBatchWithIndex {}