ckb_rocksdb/db_pinnable_slice.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 libc::size_t;
17
18use crate::ffi;
19use std::fmt;
20use std::marker::PhantomData;
21use std::ops::Deref;
22use std::slice;
23
24use crate::DB;
25
26/// Wrapper around RocksDB PinnableSlice struct.
27///
28/// With a pinnable slice, we can directly leverage in-memory data within
29/// RocksDB toa void unnecessary memory copies. The struct here wraps the
30/// returned raw pointer and ensures proper finalization work.
31pub struct DBPinnableSlice<'a> {
32 ptr: *mut ffi::rocksdb_pinnableslice_t,
33 db: PhantomData<&'a DB>,
34}
35
36// Safety note: auto-implementing Send on most db-related types is prevented by the inner FFI
37// pointer. In most cases, however, this pointer is Send-safe because it is never aliased and
38// rocksdb internally does not rely on thread-local information for its user-exposed types.
39unsafe impl Send for DBPinnableSlice<'_> {}
40
41// Sync is similarly safe for many types because they do not expose interior mutability, and their
42// use within the rocksdb library is generally behind a const reference
43unsafe impl Sync for DBPinnableSlice<'_> {}
44
45impl AsRef<[u8]> for DBPinnableSlice<'_> {
46 fn as_ref(&self) -> &[u8] {
47 // Implement this via Deref so as not to repeat ourselves
48 self
49 }
50}
51
52impl Deref for DBPinnableSlice<'_> {
53 type Target = [u8];
54
55 fn deref(&self) -> &[u8] {
56 unsafe {
57 let mut val_len: size_t = 0;
58 let val = ffi::rocksdb_pinnableslice_value(self.ptr, &mut val_len) as *mut u8;
59 slice::from_raw_parts(val, val_len)
60 }
61 }
62}
63
64impl Drop for DBPinnableSlice<'_> {
65 fn drop(&mut self) {
66 unsafe {
67 ffi::rocksdb_pinnableslice_destroy(self.ptr);
68 }
69 }
70}
71
72impl<'a> DBPinnableSlice<'a> {
73 /// Used to wrap a PinnableSlice from rocksdb to avoid unnecessary memcpy
74 ///
75 /// # Unsafe
76 /// Requires that the pointer must be generated by rocksdb_get_pinned
77 pub unsafe fn from_c(ptr: *mut ffi::rocksdb_pinnableslice_t) -> DBPinnableSlice<'a> {
78 DBPinnableSlice {
79 ptr,
80 db: PhantomData,
81 }
82 }
83}
84
85impl fmt::Debug for DBPinnableSlice<'_> {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 write!(f, "{:?}", self.deref())
88 }
89}