Skip to main content

trine_kv/
point_value.rs

1use std::{ops::Range, sync::Arc};
2
3use crate::{
4    blob::{self, ValueRef},
5    error::{Error, Result},
6    internal_key::InternalKey,
7    stats::BlobReadMetrics,
8    storage::StorageReadBackend,
9    types::Value,
10};
11
12/// Value returned by `BucketReader::get`.
13///
14/// A `PointValue` may own its bytes or keep a shared reference to bytes inside
15/// a decoded table block. Use `as_bytes` when you only need to inspect the
16/// value, or `into_vec` when you need owned bytes.
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct PointValue {
19    inner: PointValueInner,
20}
21
22#[derive(Debug, Clone, PartialEq, Eq)]
23enum PointValueInner {
24    Owned(Value),
25    Shared {
26        bytes: Arc<[u8]>,
27        range: Range<usize>,
28    },
29}
30
31impl PointValue {
32    /// Returns the value bytes.
33    #[must_use]
34    pub fn as_bytes(&self) -> &[u8] {
35        match &self.inner {
36            PointValueInner::Owned(bytes) => bytes,
37            PointValueInner::Shared { bytes, range } => &bytes[range.start..range.end],
38        }
39    }
40
41    /// Returns owned value bytes.
42    ///
43    /// This is allocation-free when the value is already owned, and copies when
44    /// the value is backed by shared table-block bytes.
45    #[must_use]
46    pub fn into_vec(self) -> Vec<u8> {
47        match self.inner {
48            PointValueInner::Owned(bytes) => bytes,
49            PointValueInner::Shared { bytes, range } => bytes[range].to_vec(),
50        }
51    }
52
53    /// Returns an owned `Value`.
54    ///
55    /// This is equivalent to `into_vec`.
56    #[must_use]
57    pub fn into_value(self) -> Value {
58        self.into_vec()
59    }
60
61    #[must_use]
62    pub(crate) fn from_owned(bytes: Value) -> Self {
63        Self {
64            inner: PointValueInner::Owned(bytes),
65        }
66    }
67
68    pub(crate) fn from_shared(bytes: Arc<[u8]>, range: Range<usize>) -> Result<Self> {
69        if range.start > range.end || range.end > bytes.len() {
70            return Err(Error::Corruption {
71                message: "point value range outside data block".to_owned(),
72            });
73        }
74        Ok(Self {
75            inner: PointValueInner::Shared { bytes, range },
76        })
77    }
78}
79
80impl AsRef<[u8]> for PointValue {
81    fn as_ref(&self) -> &[u8] {
82        self.as_bytes()
83    }
84}
85
86#[derive(Debug, Clone)]
87pub(crate) enum PointValueSource {
88    Value(PointValue),
89    Blob(ValueRef),
90}
91
92impl PointValueSource {
93    pub(crate) fn from_value_ref(value: ValueRef) -> Self {
94        match value {
95            ValueRef::Inline(bytes) => Self::Value(PointValue::from_owned(bytes)),
96            ValueRef::BlobIndex(_) | ValueRef::Blob { .. } => Self::Blob(value),
97        }
98    }
99
100    pub(crate) fn from_shared(bytes: Arc<[u8]>, range: Range<usize>) -> Result<Self> {
101        PointValue::from_shared(bytes, range).map(Self::Value)
102    }
103
104    pub(crate) fn into_point_value(
105        self,
106        internal_key: &InternalKey,
107        db_path: Option<&std::path::Path>,
108        blob_reads: Option<&BlobReadMetrics>,
109    ) -> Result<PointValue> {
110        match self {
111            Self::Value(value) => Ok(value),
112            Self::Blob(value) => {
113                let db_path = db_path.ok_or_else(|| Error::Corruption {
114                    message: "in-memory database cannot read blob value references".to_owned(),
115                })?;
116                let bytes = blob::read_value_for_internal_key(db_path, &value, Some(internal_key))?;
117                if let Some(blob_reads) = blob_reads {
118                    blob_reads.record(bytes.len() as u64);
119                }
120                Ok(PointValue::from_owned(bytes))
121            }
122        }
123    }
124
125    pub(crate) async fn into_point_value_with_backend_async<B>(
126        self,
127        backend: &B,
128        internal_key: &InternalKey,
129        db_path: Option<&std::path::Path>,
130        blob_reads: Option<&BlobReadMetrics>,
131    ) -> Result<PointValue>
132    where
133        B: StorageReadBackend,
134    {
135        match self {
136            Self::Value(value) => Ok(value),
137            Self::Blob(value) => {
138                let db_path = db_path.ok_or_else(|| Error::Corruption {
139                    message: "in-memory database cannot read blob value references".to_owned(),
140                })?;
141                let bytes = blob::read_value_for_internal_key_with_backend_async(
142                    backend,
143                    db_path,
144                    &value,
145                    Some(internal_key),
146                )
147                .await?;
148                if let Some(blob_reads) = blob_reads {
149                    blob_reads.record(bytes.len() as u64);
150                }
151                Ok(PointValue::from_owned(bytes))
152            }
153        }
154    }
155}