Skip to content

Commit f2c5baf

Browse files
authored
Merge pull request #22 from G8XSU/paginated-store
Add interface for PaginatedKVStore.
2 parents f32a2ba + 4a08248 commit f2c5baf

3 files changed

Lines changed: 104 additions & 0 deletions

File tree

server/src/io/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub(crate) mod paginated_kv_store;
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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+
}

server/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod api;
2+
mod io;
23
mod service;
34
mod util;
45

0 commit comments

Comments
 (0)