message_storage.rs
Overview
This file implements the DurableStorageRead trait for the MessageDurableStorage struct, providing methods to load and iterate over stored messages identified by MessageIdentifier. The main responsibility of this module is to facilitate reading message data from durable storage, handling error conditions, and providing navigation between messages in message queues. It abstracts the underlying storage mechanism and exposes a read-only API to access messages wrapped in Arc<WrappedMessage> for thread-safe shared ownership.
The constant BATCH_SIZE is used to limit the number of messages fetched in batch operations to optimize performance and resource usage during iteration.
Implemented Trait: DurableStorageRead<MessageIdentifier, Arc>
The trait DurableStorageRead defines functionality for loading individual messages and iterating over them. This file provides three key methods:
1. load_message
fn load_message(
&self,
key: &MessageIdentifier,
) -> Result<Arc<WrappedMessage>, Self::LoadError>
Purpose: Load a single message from storage based on the provided
MessageIdentifier.Parameters:
key: Reference to aMessageIdentifierthat uniquely identifies the message.
Returns:
Ok(Arc<WrappedMessage>)on success, wrapping the retrieved message.Err(LoadErr)if the message cannot be found or an error occurs during retrieval.
Implementation Details:
Extracts the message hash from the key.
Calls
read_messageto fetch the message from storage.Converts errors into
LoadErr::NoState.Wraps the message in an
Arcfor shared ownership.
Usage Example:
let message = message_storage.load_message(&message_identifier)?;
println!("Loaded message: {:?}", message);
2. next
fn next(&self, key: &MessageIdentifier) -> Result<Option<MessageIdentifier>, Self::LoadError>
Purpose: Retrieve the identifier of the next message following the given message.
Parameters:
key: Reference to the current message'sMessageIdentifier.
Returns:
Ok(Some(MessageIdentifier))with the next message's identifier if available.Ok(None)if there is no next message.Err(LoadErr)if the next message cannot be loaded or deserialized.
Implementation Details:
Reads the current message to get its row ID and stored data.
Extracts the destination account ID from the message to determine the queue.
Uses
next_simpleto fetch the next message in the queue.Handles deserialization errors and maps them to
LoadErr::DeserializationError.Constructs a new
MessageIdentifierfor the next message usingOutMsgQueueKey.
Usage Example:
if let Some(next_id) = message_storage.next(¤t_message_id)? {
println!("Next message ID: {:?}", next_id);
} else {
println!("No next message found.");
}
3. remaining_messages
fn remaining_messages(
&self,
starting_key: &MessageIdentifier,
limit: usize,
) -> Result<Vec<Arc<WrappedMessage>>, Self::LoadError>
Purpose: Retrieve up to
limitmessages starting from the message identified bystarting_key.Parameters:
starting_key: Reference toMessageIdentifierwhere retrieval begins.limit: The maximum number of messages to return.
Returns:
Ok(Vec<Arc<WrappedMessage>>)containing the loaded messages.Err(LoadErr)if any error occurs during retrieval.
Implementation Details:
Starts by loading the message for
starting_key.Extracts destination account ID to identify the message queue.
Adds the initial message to the result vector.
Iteratively fetches subsequent messages in batches of size up to
BATCH_SIZEor the remaining limit vianext_simple.Stops when fewer messages than requested are returned, indicating the end of the queue.
Usage Example:
let messages = message_storage.remaining_messages(&start_message_id, 100)?;
for msg in messages {
println!("Message: {:?}", msg);
}
Important Implementation Details
Error Handling: Uses a custom
LoadErrenum to represent loading errors such as missing state (NoState) or deserialization issues.Message Hashing: Message identification relies on hexadecimal string representation of message hashes.
Batch Processing: Uses a fixed batch size (
BATCH_SIZE = 50) for efficient retrieval of multiple messages.Concurrency: Returns
Arc<WrappedMessage>to allow safe sharing of message data across threads.Dependency Calls:
read_message: Reads a single message from storage by hash.next_simple: Retrieves the next set of messages after a given row ID for a destination account.
Tracing: Errors during message loading and iteration are logged using the
tracingcrate for observability.
Interactions with Other Components
MessageIdentifier: Acts as a unique key for messages; this file converts between
MessageIdentifierand the internal message hash representation.WrappedMessage: Represents the stored message object wrapped for safe shared access.
MessageDurableStorage: The underlying storage abstraction that provides
read_messageandnext_simpleto fetch messages.OutMsgQueueKey: Used to construct the
MessageIdentifierfor the next message in the queue using workchain and prefix information.Error Types: Utilizes
LoadErrto propagate errors encountered during data retrieval and deserialization.This file is part of a message queue system responsible for managing outgoing messages, likely integrated with other modules handling message creation, dispatch, and storage management.
Diagram: Class and Trait Implementation Structure
classDiagram
class MessageDurableStorage {
+read_message()
+next_simple()
}
class DurableStorageRead~K,V~ {
<<trait>>
+load_message(key: &K) -> Result<V, LoadErr>
+next(key: &K) -> Result<Option<K>, LoadErr>
+remaining_messages(starting_key: &K, limit: usize) -> Result<Vec<V>, LoadErr>
}
class MessageIdentifier {
+inner()
}
class WrappedMessage
MessageDurableStorage ..|> DurableStorageRead~MessageIdentifier, Arc<WrappedMessage>~
DurableStorageRead~MessageIdentifier, Arc<WrappedMessage>~ : implements >
MessageDurableStorage --> MessageIdentifier : uses
MessageDurableStorage --> WrappedMessage : loads returns
This diagram models the relationship between MessageDurableStorage, the DurableStorageRead trait it implements, and the key and value types involved (MessageIdentifier and WrappedMessage).
For more information on message identifiers, storage abstractions, and error handling, see the topics related to Message Identification, Durable Storage, and Error Handling.