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#[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 #[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 #[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 #[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}