|
| 1 | +use std::io; |
| 2 | + |
| 3 | +/// Provides an interface that allows storage and retrieval of persisted values that are associated |
| 4 | +/// with given keys, with support for pagination with time-based ordering. |
| 5 | +/// |
| 6 | +/// In order to avoid collisions, the key space is segmented based on the given `primary_namespace`s |
| 7 | +/// and `secondary_namespace`s. Implementations of this trait are free to handle them in different |
| 8 | +/// ways, as long as per-namespace key uniqueness is asserted. |
| 9 | +/// |
| 10 | +/// Keys and namespaces are required to be valid ASCII strings in the range of |
| 11 | +/// [`KVSTORE_NAMESPACE_KEY_ALPHABET`] and no longer than [`KVSTORE_NAMESPACE_KEY_MAX_LEN`]. Empty |
| 12 | +/// primary namespaces and secondary namespaces (`""`) are considered valid; however, if |
| 13 | +/// `primary_namespace` is empty, `secondary_namespace` must also be empty. This means that concerns |
| 14 | +/// should always be separated by primary namespace first, before secondary namespaces are used. |
| 15 | +/// While the number of primary namespaces will be relatively small and determined at compile time, |
| 16 | +/// there may be many secondary namespaces per primary namespace. Note that per-namespace uniqueness |
| 17 | +/// needs to also hold for keys *and* namespaces in any given namespace, i.e., conflicts between keys |
| 18 | +/// and equally named primary or secondary namespaces must be avoided. |
| 19 | +/// |
| 20 | +/// **Note:** This trait extends the functionality of [`KVStore`] by adding support for |
| 21 | +/// paginated listing of keys based on a monotonic counter or logical timestamp. This is useful |
| 22 | +/// when dealing with a large number of keys that cannot be efficiently retrieved all at once. |
| 23 | +/// |
| 24 | +/// See also [`KVStore`]. |
| 25 | +/// |
| 26 | +/// [`KVStore`]: ldk_node::lightning::util::persist::KVStore |
| 27 | +/// [`KVSTORE_NAMESPACE_KEY_ALPHABET`]: ldk_node::lightning::util::persist::KVSTORE_NAMESPACE_KEY_ALPHABET |
| 28 | +/// [`KVSTORE_NAMESPACE_KEY_MAX_LEN`]: ldk_node::lightning::util::persist::KVSTORE_NAMESPACE_KEY_MAX_LEN |
| 29 | +pub trait PaginatedKVStore { |
| 30 | + /// Returns the data stored for the given `primary_namespace`, `secondary_namespace`, and `key`. |
| 31 | + /// |
| 32 | + /// Returns an [`ErrorKind::NotFound`] if the given `key` could not be found in the given |
| 33 | + /// `primary_namespace` and `secondary_namespace`. |
| 34 | + /// |
| 35 | + /// [`ErrorKind::NotFound`]: io::ErrorKind::NotFound |
| 36 | + fn read( |
| 37 | + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, |
| 38 | + ) -> Result<Vec<u8>, io::Error>; |
| 39 | + |
| 40 | + /// Persists the given data under the given `key` with an associated `time`. |
| 41 | + /// |
| 42 | + /// The `time` parameter is a `i64` representing a monotonic counter or logical timestamp. |
| 43 | + /// It is used to track the order of keys for list operations. Implementations should store the |
| 44 | + /// `time` value and use it for ordering in the `list` method. |
| 45 | + /// |
| 46 | + /// Will create the given `primary_namespace` and `secondary_namespace` if not already present |
| 47 | + /// in the store. |
| 48 | + fn write( |
| 49 | + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, time: i64, buf: &[u8], |
| 50 | + ) -> Result<(), io::Error>; |
| 51 | + |
| 52 | + /// Removes any data that had previously been persisted under the given `key`. |
| 53 | + /// |
| 54 | + /// If the `lazy` flag is set to `true`, the backend implementation might choose to lazily |
| 55 | + /// remove the given `key` at some point in time after the method returns, e.g., as part of an |
| 56 | + /// eventual batch deletion of multiple keys. As a consequence, subsequent calls to |
| 57 | + /// [`PaginatedKVStore::list`] might include the removed key until the changes are actually persisted. |
| 58 | + /// |
| 59 | + /// Note that while setting the `lazy` flag reduces the I/O burden of multiple subsequent |
| 60 | + /// `remove` calls, it also influences the atomicity guarantees as lazy `remove`s could |
| 61 | + /// potentially get lost on crash after the method returns. Therefore, this flag should only be |
| 62 | + /// set for `remove` operations that can be safely replayed at a later time. |
| 63 | + /// |
| 64 | + /// Returns successfully if no data will be stored for the given `primary_namespace`, |
| 65 | + /// `secondary_namespace`, and `key`, independently of whether it was present before its |
| 66 | + /// invocation or not. |
| 67 | + fn remove( |
| 68 | + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, lazy: bool, |
| 69 | + ) -> Result<(), io::Error>; |
| 70 | + |
| 71 | + /// Returns a paginated list of keys that are stored under the given `secondary_namespace` in |
| 72 | + /// `primary_namespace`, ordered in descending order of `time`. |
| 73 | + /// |
| 74 | + /// The `list` method returns the latest records first, based on the `time` associated with each key. |
| 75 | + /// Pagination is controlled by the `next_page_token`, which is an `Option<String>` |
| 76 | + /// used to determine the starting point for the next page of results. If `next_page_token` is `None`, |
| 77 | + /// the listing starts from the most recent entry. The `next_page_token` in the returned |
| 78 | + /// [`ListResponse`] can be used to fetch the next page of results. |
| 79 | + /// |
| 80 | + /// Implementations should ensure that keys are returned in descending order of `time` and that |
| 81 | + /// pagination tokens are correctly managed. |
| 82 | + /// |
| 83 | + /// Returns an empty list if `primary_namespace` or `secondary_namespace` is unknown or if |
| 84 | + /// there are no more keys to return. |
| 85 | + /// |
| 86 | + /// [`ListResponse`]: struct.ListResponse.html |
| 87 | + fn list( |
| 88 | + &self, primary_namespace: &str, secondary_namespace: &str, next_page_token: Option<String>, |
| 89 | + ) -> Result<ListResponse, io::Error>; |
| 90 | +} |
| 91 | + |
| 92 | +/// Represents the response from a paginated `list` operation. |
| 93 | +/// |
| 94 | +/// Contains the list of keys and an optional `next_page_token` that can be used to retrieve the |
| 95 | +/// next set of keys. |
| 96 | +pub struct ListResponse { |
| 97 | + /// A vector of keys, ordered in descending order of `time`. |
| 98 | + pub keys: Vec<String>, |
| 99 | + |
| 100 | + /// A token that can be used to retrieve the next set of keys. |
| 101 | + pub next_page_token: Option<String>, |
| 102 | +} |
0 commit comments