Skip to content

Add SqliteStore backend #100

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 5, 2023
Merged

Conversation

tnull
Copy link
Collaborator

@tnull tnull commented May 18, 2023

Based on #101.

Finally, we add an SQLite-based KVStore implementation which becomes the new default
default for Node::build. The FilesystemStore is still configurable via Node::build_with_fs_store

@tnull tnull requested review from jkczyz and G8XSU May 18, 2023 15:47
@tnull tnull mentioned this pull request May 18, 2023
47 tasks
@tnull tnull force-pushed the 2023-05-add-sqlite-store branch from 603a52f to 5cf438d Compare May 18, 2023 15:55
@G8XSU
Copy link
Contributor

G8XSU commented May 18, 2023

Can we move the last commit of SQLite impl in separate PR, would like to review it separately. :)

@tnull
Copy link
Collaborator Author

tnull commented May 19, 2023

Can we move the last commit of SQLite impl in separate PR, would like to review it separately. :)

Mh, I'd actually rather not have yet another PR to maintain and rebase. But whatever. Now moved the first 3 commits to #101 upon which this PR is now based.

@tnull tnull changed the title Make KVStore configurable and add SqliteStore backend Add SqliteStore backend May 19, 2023
@tnull tnull force-pushed the 2023-05-add-sqlite-store branch 2 times, most recently from 309881f to ce7819a Compare May 24, 2023 20:33
@tnull
Copy link
Collaborator Author

tnull commented May 24, 2023

Rebased on current #101 and added a corresponding fixup that avoids allocating msg strings unnecessarily.


impl KVStorePersister for SqliteStore {
fn persist<W: Writeable>(&self, prefixed_key: &str, object: &W) -> lightning::io::Result<()> {
let msg = format!("Could not persist file for key {}.", prefixed_key);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since this is not a filesystem store, we don't need or shouldn't use parent dir as namespace,
instead we could use a static string as namespace like "ldk_core_store"?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since this is not a filesystem store, we don't need or shouldn't use parent dir as namespace, instead we could use a static string as namespace like "ldk_core_store"?

Yes we should, as unfortunately LDK persistence makes strong assumptions about the structure of the keys and for example gives us channel monitors as keys monitors/[txid][index]. Plus, having the different backends decide to rename namespaces is a bad idea when it comes to migration between backends. I now DRYed up the key splitting however.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"having the different backends decide to rename namespaces is a bad idea". yes exactly
that is why we should not be using anything to do with parent directories and key parsing from ldk-key as namespace keys. (for all kvstores including filesystem)

afaiu, ldk doesn't enforce anything by having keys like "monitors/[txid][index]", ldk is just providing a prefix.
we could have something like "ldk_core" as namespace and "monitors/[txid][index]" as full key.

otherwise we are letting ldk-core create namespaces dynamically instead of ldk-node having fixed set of namespaces.(even though we own ldk-core, this is not ideal from ldk-node user perspective)

otherwise, in future, if ldk decides to store something new as "xyzMeta/" we would end up creating a namespace out of it and migration code will need to change.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"having the different backends decide to rename namespaces is a bad idea". yes exactly that is why we should not be using anything to do with parent directories and key parsing from ldk-key as namespace keys. (for all kvstores including filesystem)

afaiu, ldk doesn't enforce anything by having keys like "monitors/[txid][index]", ldk is just providing a prefix. we could have something like "ldk_core" as namespace and "monitors/[txid][index]" as full key.

No, it's clearly not just a prefix but an implied namespace, actually even an implied path as all assumptions are made around FilesystemPersister. We should def. not buy into the hardcoded prefixes but rather extract them and use them in a sane way. This is exactly why I added the namespaces to the KVStore interface in the first place, and I'll be looking into upstreaming them, as the hardcoded strings cluttered over different places in the code is just a mess. I'll def. won't throw "everything LDK" into a single namespace.

otherwise we are letting ldk-core create namespaces dynamically instead of ldk-node having fixed set of namespaces.(even though we own ldk-core, this is not ideal from ldk-node user perspective)

We have a pretty good grasp on what's going on in the upstream codebase and we don't make any promises about what namespaces exactly the user needs to handle: the interface takes a namespace: &str instead of an enum for a reason. So yes, any implementation of the KVStore should be able to handle new namespaces without issue.

otherwise, in future, if ldk decides to store something new as "xyzMeta/" we would end up creating a namespace out of it and migration code will need to change.

Yes, this was why I thought about adding a list_namespaces method to the interface to make all data explorable by way of the interface. However, I still think we made the right decision to keep migration out-of-bound.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's clearly not just a prefix but an implied namespace, actually even an implied path as all assumptions are made around FilesystemPersister

there is no enforced implied namespace, cash-lit doesn't care about it, ldk doesn't care about it. We are making that assumption right now in this PR, as we split the key into a file-path for a non-filesystem-directory datastore. We shouldn't be thinking of this having any relation to file-path or filesystem-directory/subdirectory.

Copy link
Collaborator Author

@tnull tnull May 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no enforced implied namespace, cash-lit doesn't care about it, ldk doesn't care about it. We are making that assumption right now in this PR, as we split the key into a file-path for a non-filesystem-directory datastore. We shouldn't be thinking of this having any relation to file-path or filesystem-directory/subdirectory.

Alright, I assume you'd then argue to do the same in FilesystemStore, i.e., save all LDK objects in a single directory? The prefix is exactly why I added namespaces in the first place, and I'll be using them in this PR for this KVStore unless there is a convincing technical argument not to. Even though I don't think it matters all too much, please note it would also be less performant to always retrieve all rows from the entire LDK namespace and filter them down to the keys we want, e.g., in read_channelmonitors.

I'm sorry but this simply doesn't make sense. If VSS doesn't support namespaces that's fine, then you should find a workaround in the respectiveKVStore impl and that may be to keep the keys prefixed, but maybe there is a better way to do it also.

@tnull tnull force-pushed the 2023-05-add-sqlite-store branch from 9521a41 to 5bf9d57 Compare May 25, 2023 09:34
@tnull
Copy link
Collaborator Author

tnull commented May 25, 2023

Rebased on main after merging #101 and addressed the feedback so far.

@tnull tnull force-pushed the 2023-05-add-sqlite-store branch 2 times, most recently from 22b8760 to 121b96c Compare May 25, 2023 10:07
@tnull tnull added this to the 0.1 milestone May 25, 2023
@tnull tnull force-pushed the 2023-05-add-sqlite-store branch from 52856b7 to 6eb6375 Compare May 27, 2023 06:39
@tnull
Copy link
Collaborator Author

tnull commented May 27, 2023

Rebased on main after #88 landed.

@tnull
Copy link
Collaborator Author

tnull commented Jun 1, 2023

@G8XSU @jkczyz Can I squash the fixups here?

@jkczyz
Copy link
Contributor

jkczyz commented Jun 1, 2023

@G8XSU @jkczyz Can I squash the fixups here?

SGTM

@tnull tnull force-pushed the 2023-05-add-sqlite-store branch from 6eb6375 to d66bb1a Compare June 1, 2023 13:38
@tnull
Copy link
Collaborator Author

tnull commented Jun 1, 2023

SGTM

Squashed without further changes.

G8XSU
G8XSU previously approved these changes Jun 1, 2023
Copy link
Contributor

@G8XSU G8XSU left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall LGTM

@tnull tnull force-pushed the 2023-05-add-sqlite-store branch from d66bb1a to a53f74a Compare June 1, 2023 19:00
@tnull
Copy link
Collaborator Author

tnull commented Jun 1, 2023

Amended last commit to include the following change:

diff --git a/src/io/sqlite_store.rs b/src/io/sqlite_store.rs
index 6d7e166..ee38f5d 100644
--- a/src/io/sqlite_store.rs
+++ b/src/io/sqlite_store.rs
@@ -118,9 +118,8 @@ impl KVStore for SqliteStore {

        fn remove(&self, namespace: &str, key: &str) -> std::io::Result<bool> {
+               let locked_conn = self.connection.lock().unwrap();
+
                let sql = format!("DELETE FROM {} WHERE namespace=:namespace AND key=:key;", KV_TABLE_NAME);
-               let changes = self
-                       .connection
-                       .lock()
-                       .unwrap()
+               let changes = locked_conn
                        .execute(
                                &sql,

tnull added 2 commits June 1, 2023 21:49
We here add an `KVStore` implementation on SQLite, which becomes the new
default for `Node::build`. The `FilesystemStore` is still configurable
via `Node::build_with_fs_store`
@tnull tnull force-pushed the 2023-05-add-sqlite-store branch from a53f74a to 4653e5c Compare June 1, 2023 19:50
@tnull
Copy link
Collaborator Author

tnull commented Jun 1, 2023

Rebased on main after #108 was merged.

@tnull tnull merged commit 8f9f234 into lightningdevkit:main Jun 5, 2023
@imaginator
Copy link

What's the reasoning behind having KV storage instead of a full SQL schema?

@tnull
Copy link
Collaborator Author

tnull commented Jun 23, 2023

What's the reasoning behind having KV storage instead of a full SQL schema?

Well, for one LDK's 'native' serialization format is TLV-encoded blobs that are persisted under particular keys. BDK will follow a similar approach with the upcoming changes in 1.0. So it didn't really make sense to follow an entirely different model for LDK Node's own objects. Additionally, I'm not sure a 'real' SQL schema would have much benefits over the key value approach and the latter also allows a much simpler KVStore abstraction that can be easier implemented against a variety of backends.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants