Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 24 additions & 16 deletions linera-views/src/backends/dynamo_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,10 @@ const VISIBLE_MAX_VALUE_SIZE: usize = RAW_MAX_VALUE_SIZE
- 1
- 1;

/// Fundamental constant in DynamoDB: The maximum size of a key is 1024 bytes
/// Fundamental constant in DynamoDB: The maximum size of a key is 1024 bytes.
/// We decrease by 1 because we append a [1] as prefix.
/// See https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html
const MAX_KEY_SIZE: usize = 1024;
const MAX_KEY_SIZE: usize = 1023;

/// Fundamental constants in DynamoDB: The maximum size of a [`TransactWriteItem`] is 4 MB.
/// See https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html
Expand Down Expand Up @@ -167,12 +168,17 @@ const MAX_BATCH_GET_ITEM_SIZE: usize = 40;
/// The second attribute is the actual key value, which is generated by concatenating the
/// context prefix. `The Vec<u8>` expression is obtained from `self.derive_key`.
fn build_key(start_key: &[u8], key: Vec<u8>) -> HashMap<String, AttributeValue> {
let mut prefixed_key = vec![1];
prefixed_key.extend(key);
[
(
PARTITION_ATTRIBUTE.to_owned(),
AttributeValue::B(Blob::new(start_key.to_vec())),
),
(KEY_ATTRIBUTE.to_owned(), AttributeValue::B(Blob::new(key))),
(
KEY_ATTRIBUTE.to_owned(),
AttributeValue::B(Blob::new(prefixed_key)),
),
]
.into()
}
Expand All @@ -183,12 +189,17 @@ fn build_key_value(
key: Vec<u8>,
value: Vec<u8>,
) -> HashMap<String, AttributeValue> {
let mut prefixed_key = vec![1];
prefixed_key.extend(key);
[
(
PARTITION_ATTRIBUTE.to_owned(),
AttributeValue::B(Blob::new(start_key.to_vec())),
),
(KEY_ATTRIBUTE.to_owned(), AttributeValue::B(Blob::new(key))),
(
KEY_ATTRIBUTE.to_owned(),
AttributeValue::B(Blob::new(prefixed_key)),
),
(
VALUE_ATTRIBUTE.to_owned(),
AttributeValue::B(Blob::new(value)),
Expand All @@ -199,7 +210,6 @@ fn build_key_value(

/// Checks that a key is of the correct size
fn check_key_size(key: &[u8]) -> Result<(), DynamoDbStoreInternalError> {
ensure!(!key.is_empty(), DynamoDbStoreInternalError::ZeroLengthKey);
ensure!(
key.len() <= MAX_KEY_SIZE,
DynamoDbStoreInternalError::KeyTooLong
Expand All @@ -216,7 +226,7 @@ fn extract_key(
.get(KEY_ATTRIBUTE)
.ok_or(DynamoDbStoreInternalError::MissingKey)?;
match key {
AttributeValue::B(blob) => Ok(&blob.as_ref()[prefix_len..]),
AttributeValue::B(blob) => Ok(&blob.as_ref()[1 + prefix_len..]),
key => Err(DynamoDbStoreInternalError::wrong_key_type(key)),
}
}
Expand Down Expand Up @@ -602,6 +612,8 @@ impl DynamoDbStoreInternal {
) -> Result<QueryOutput, DynamoDbStoreInternalError> {
let _guard = self.acquire().await;
let start_key = start_key.to_vec();
let mut prefixed_key_prefix = vec![1];
prefixed_key_prefix.extend(key_prefix);
let response = self
.client
.query()
Expand All @@ -611,7 +623,10 @@ impl DynamoDbStoreInternal {
"{PARTITION_ATTRIBUTE} = :partition and begins_with({KEY_ATTRIBUTE}, :prefix)"
))
.expression_attribute_values(":partition", AttributeValue::B(Blob::new(start_key)))
.expression_attribute_values(":prefix", AttributeValue::B(Blob::new(key_prefix)))
.expression_attribute_values(
":prefix",
AttributeValue::B(Blob::new(prefixed_key_prefix)),
)
.set_exclusive_start_key(start_key_map)
.send()
.boxed_sync()
Expand Down Expand Up @@ -746,7 +761,8 @@ impl DynamoDbStoreInternal {
.ok_or(DynamoDbStoreInternalError::MissingKey)?;

if let AttributeValue::B(blob) = key_attr {
let key = blob.as_ref();
let prefixed_key = blob.as_ref();
let key = &prefixed_key[1..]; // Remove the [1] prefix
if let Some(indices) = key_to_index.get(key) {
if let Some((&last, rest)) = indices.split_last() {
let value = extract_value_owned(&mut item)?;
Expand Down Expand Up @@ -966,10 +982,6 @@ pub enum DynamoDbStoreInternalError {
#[error("The transact must have length at most MAX_TRANSACT_WRITE_ITEM_SIZE")]
TransactUpperLimitSize,

/// Keys have to be of non-zero length.
#[error("The key must be of strictly positive length")]
ZeroLengthKey,

/// The key must have at most 1024 bytes
#[error("The key must have at most 1024 bytes")]
KeyTooLong,
Expand All @@ -978,10 +990,6 @@ pub enum DynamoDbStoreInternalError {
#[error("The key prefix must have at most 1024 bytes")]
KeyPrefixTooLong,

/// Key prefixes have to be of non-zero length.
#[error("The key_prefix must be of strictly positive length")]
ZeroLengthKeyPrefix,

/// The journal is not coherent
#[error(transparent)]
JournalConsistencyError(#[from] JournalConsistencyError),
Expand Down
2 changes: 1 addition & 1 deletion linera-views/src/test_utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ pub async fn run_reads<S: KeyValueStore>(store: S, key_values: Vec<(Vec<u8>, Vec
store.write_batch(batch).await.unwrap();
for key_prefix in keys
.iter()
.flat_map(|key| (0..key.len()).map(|u| &key[..=u]))
.flat_map(|key| (0..=key.len()).map(|u| &key[..u]))
{
// Getting the find_keys_by_prefix / find_key_values_by_prefix
let len_prefix = key_prefix.len();
Expand Down
Loading