diff --git a/services/backup/src/constants.rs b/services/backup/src/constants.rs --- a/services/backup/src/constants.rs +++ b/services/backup/src/constants.rs @@ -4,6 +4,11 @@ pub const MPSC_CHANNEL_BUFFER_CAPACITY: usize = 1; pub const ID_SEPARATOR: &str = ":"; +// 400KiB limit (in docs there is KB but they mean KiB) - +// https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ServiceQuotas.html +// This includes both attribute names' and values' lengths +pub const LOG_DATA_SIZE_DATABASE_LIMIT: usize = 1024 * 400; + // Configuration defaults pub const DEFAULT_GRPC_SERVER_PORT: u64 = 50051; diff --git a/services/backup/src/database.rs b/services/backup/src/database.rs --- a/services/backup/src/database.rs +++ b/services/backup/src/database.rs @@ -50,6 +50,17 @@ } } +static LOG_ITEM_HEADERS_SIZE: usize = { + let mut size: usize = 0; + size += LOG_TABLE_FIELD_BACKUP_ID.as_bytes().len(); + size += LOG_TABLE_FIELD_LOG_ID.as_bytes().len(); + size += LOG_TABLE_FIELD_PERSISTED_IN_BLOB.as_bytes().len(); + size += LOG_TABLE_FIELD_VALUE.as_bytes().len(); + size += LOG_TABLE_FIELD_ATTACHMENT_HOLDERS.as_bytes().len(); + size += LOG_TABLE_FIELD_DATA_HASH.as_bytes().len(); + size +}; + #[derive(Clone, Debug)] pub struct LogItem { pub backup_id: String, @@ -60,6 +71,43 @@ pub data_hash: String, } +impl LogItem { + /// Calculates size based on raw log item components, + /// without allocating a new item + pub fn size_from_components( + backup_id: &str, + log_id: &str, + log_hash: &str, + data: &[u8], + ) -> usize { + let mut size: usize = LOG_ITEM_HEADERS_SIZE; + size += backup_id.as_bytes().len(); + size += log_id.as_bytes().len(); + size += data.len(); + size += log_hash.as_bytes().len(); + + // persistent in blob, attachment holders, use defaults here + size += false.to_string().as_bytes().len(); + size += "".as_bytes().len(); + + size + } + + /// Total size of this item in the DynamoDB table. This value must be + /// smaller than [`crate::constants::LOG_DATA_SIZE_DATABASE_LIMIT`] + /// in order to successfully put this item into a DynamoDB database. + pub fn total_size(&self) -> usize { + let mut size: usize = LOG_ITEM_HEADERS_SIZE; + size += self.backup_id.as_bytes().len(); + size += self.log_id.as_bytes().len(); + size += self.persisted_in_blob.to_string().as_bytes().len(); + size += self.value.as_bytes().len(); + size += self.attachment_holders.as_bytes().len(); + size += self.data_hash.as_bytes().len(); + size + } +} + #[derive(Clone)] pub struct DatabaseClient { client: Arc,