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}