Import upstream v0.16.22, stripped
Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f Enterprise-only files removed or emptied: 63 Enterprise-only snippets removed: 117 in 50 files Dangling module declarations removed: 5 Cargo edits turning enterprise off: 14 Verification: clean Enterprise feature gates left for rebuilt features: 19 in 18 files Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use super::{FdbStore, MAX_VALUE_SIZE};
|
||||
use crate::{
|
||||
IterateParams, SUBSPACE_BLOBS,
|
||||
backend::foundationdb::into_error,
|
||||
write::{AnyKey, key::KeySerializer},
|
||||
};
|
||||
use std::ops::Range;
|
||||
use trc::AddContext;
|
||||
use types::blob_hash::BLOB_HASH_LEN;
|
||||
|
||||
impl FdbStore {
|
||||
pub(crate) async fn get_blob(
|
||||
&self,
|
||||
key: &[u8],
|
||||
range: Range<usize>,
|
||||
) -> trc::Result<Option<Vec<u8>>> {
|
||||
let block_start = range.start / MAX_VALUE_SIZE;
|
||||
let bytes_start = range.start % MAX_VALUE_SIZE;
|
||||
let block_end = (range.end / MAX_VALUE_SIZE) + 1;
|
||||
|
||||
let begin = KeySerializer::new(key.len() + 2)
|
||||
.write(key)
|
||||
.write(block_start as u16)
|
||||
.finalize();
|
||||
let end = KeySerializer::new(key.len() + 2)
|
||||
.write(key)
|
||||
.write(block_end as u16)
|
||||
.finalize();
|
||||
let key_len = begin.len();
|
||||
|
||||
let mut blob_data: Option<Vec<u8>> = None;
|
||||
let blob_range = range.end - range.start;
|
||||
|
||||
self.iterate(
|
||||
IterateParams::new(
|
||||
AnyKey {
|
||||
subspace: SUBSPACE_BLOBS,
|
||||
key: begin,
|
||||
},
|
||||
AnyKey {
|
||||
subspace: SUBSPACE_BLOBS,
|
||||
key: end,
|
||||
},
|
||||
),
|
||||
|key, value| {
|
||||
if key.len() == key_len {
|
||||
if let Some(blob_data) = &mut blob_data {
|
||||
blob_data.extend_from_slice(
|
||||
value
|
||||
.get(
|
||||
..std::cmp::min(
|
||||
blob_range.saturating_sub(blob_data.len()),
|
||||
value.len(),
|
||||
),
|
||||
)
|
||||
.unwrap_or(&[]),
|
||||
);
|
||||
if blob_data.len() == blob_range {
|
||||
return Ok(false);
|
||||
}
|
||||
} else {
|
||||
let blob_size = if blob_range <= (5 * (1 << 20)) {
|
||||
blob_range
|
||||
} else if value.len() == MAX_VALUE_SIZE {
|
||||
MAX_VALUE_SIZE * 2
|
||||
} else {
|
||||
value.len()
|
||||
};
|
||||
let mut blob_data_ = Vec::with_capacity(blob_size);
|
||||
blob_data_.extend_from_slice(
|
||||
value
|
||||
.get(
|
||||
bytes_start
|
||||
..std::cmp::min(bytes_start + blob_range, value.len()),
|
||||
)
|
||||
.unwrap_or(&[]),
|
||||
);
|
||||
let is_done = blob_data_.len() == blob_range;
|
||||
blob_data = blob_data_.into();
|
||||
if is_done {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(true)
|
||||
},
|
||||
)
|
||||
.await
|
||||
.caused_by(trc::location!())?;
|
||||
|
||||
Ok(blob_data)
|
||||
}
|
||||
|
||||
pub(crate) async fn put_blob(&self, key: &[u8], data: &[u8]) -> trc::Result<()> {
|
||||
const N_CHUNKS: usize = (1 << 5) - 1;
|
||||
let last_chunk = std::cmp::max(
|
||||
(data.len() / MAX_VALUE_SIZE)
|
||||
+ if !data.len().is_multiple_of(MAX_VALUE_SIZE) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
},
|
||||
1,
|
||||
) - 1;
|
||||
let mut trx = self.db.create_trx().map_err(into_error)?;
|
||||
|
||||
for (chunk_pos, chunk_bytes) in data.chunks(MAX_VALUE_SIZE).enumerate() {
|
||||
trx.set(
|
||||
&KeySerializer::new(key.len() + 3)
|
||||
.write(SUBSPACE_BLOBS)
|
||||
.write(key)
|
||||
.write(chunk_pos as u16)
|
||||
.finalize(),
|
||||
chunk_bytes,
|
||||
);
|
||||
if chunk_pos == last_chunk || (chunk_pos > 0 && chunk_pos % N_CHUNKS == 0) {
|
||||
self.commit(trx, false).await?;
|
||||
if chunk_pos < last_chunk {
|
||||
trx = self.db.create_trx().map_err(into_error)?;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn delete_blob(&self, key: &[u8]) -> trc::Result<bool> {
|
||||
if key.len() < BLOB_HASH_LEN {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let trx = self.db.create_trx().map_err(into_error)?;
|
||||
trx.clear_range(
|
||||
&KeySerializer::new(key.len() + 3)
|
||||
.write(SUBSPACE_BLOBS)
|
||||
.write(key)
|
||||
.write(0u16)
|
||||
.finalize(),
|
||||
&KeySerializer::new(key.len() + 3)
|
||||
.write(SUBSPACE_BLOBS)
|
||||
.write(key)
|
||||
.write(u16::MAX)
|
||||
.finalize(),
|
||||
);
|
||||
|
||||
self.commit(trx, false).await
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user