nostrdb

an unfairly fast embedded nostr database backed by lmdb
git clone git://jb55.com/nostrdb
Log | Files | Refs | Submodules | README | LICENSE

commit 48d62971a6c396f1e0dc0e03c58d64932403beb7
parent e85222188d19f1d94ad88fb2120a9a3dfb9375bd
Author: William Casarin <jb55@jb55.com>
Date:   Wed, 30 Aug 2023 13:57:51 -0700

add transactions

this will allow reads to survive for longer

Diffstat:
Mnostrdb.c | 56+++++++++++++++++++++++++++-----------------------------
Mnostrdb.h | 15++++++++++++---
Mtest.c | 14++++++++++----
3 files changed, 49 insertions(+), 36 deletions(-)

diff --git a/nostrdb.c b/nostrdb.c @@ -207,6 +207,18 @@ struct ndb_writer_msg { }; }; +int ndb_begin_query(struct ndb *ndb, struct ndb_txn *txn) +{ + txn->ndb = ndb; + MDB_txn **mdb_txn = (MDB_txn **)&txn->mdb_txn; + return mdb_txn_begin(ndb->lmdb.env, NULL, 0, mdb_txn) == 0; +} + +void ndb_end_query(struct ndb_txn *txn) +{ + mdb_txn_abort(txn->mdb_txn); +} + int ndb_note_verify(void *ctx, unsigned char pubkey[32], unsigned char id[32], unsigned char sig[64]) { @@ -249,8 +261,8 @@ int ndb_get_tsid(MDB_txn *txn, struct ndb_lmdb *lmdb, enum ndb_dbs db, { MDB_val k, v; MDB_cursor *cur; - struct ndb_tsid tsid; int success = 0; + struct ndb_tsid tsid; ndb_tsid_high(&tsid, id); k.mv_data = &tsid; @@ -280,23 +292,17 @@ cleanup: return success; } -static void *ndb_lookup_by_key(struct ndb *ndb, uint64_t key, +static void *ndb_lookup_by_key(struct ndb_txn *txn, uint64_t key, enum ndb_dbs store, size_t *len) { MDB_val k, v; - MDB_txn *txn; k.mv_data = &key; k.mv_size = sizeof(key); - if (mdb_txn_begin(ndb->lmdb.env, 0, 0, &txn)) { - ndb_debug("ndb_get_note_by_id: mdb_txn_begin failed\n"); - return NULL; - } - - if (mdb_get(txn, ndb->lmdb.dbs[store], &k, &v)) { + if (mdb_get(txn->mdb_txn, txn->ndb->lmdb.dbs[store], &k, &v)) { ndb_debug("ndb_get_profile_by_pubkey: mdb_get note failed\n"); - mdb_txn_abort(txn); + mdb_txn_abort(txn->mdb_txn); return NULL; } @@ -306,53 +312,45 @@ static void *ndb_lookup_by_key(struct ndb *ndb, uint64_t key, return v.mv_data; } -static void *ndb_lookup_tsid(struct ndb *ndb, enum ndb_dbs ind, +static void *ndb_lookup_tsid(struct ndb_txn *txn, enum ndb_dbs ind, enum ndb_dbs store, const unsigned char *pk, size_t *len) { MDB_val k, v; - MDB_txn *txn; void *res = NULL; if (len) *len = 0; - if (mdb_txn_begin(ndb->lmdb.env, 0, 0, &txn)) { - ndb_debug("ndb_get_note_by_id: mdb_txn_begin failed\n"); - return NULL; - } - - if (!ndb_get_tsid(txn, &ndb->lmdb, ind, pk, &k)) { + if (!ndb_get_tsid(txn->mdb_txn, &txn->ndb->lmdb, ind, pk, &k)) { //ndb_debug("ndb_get_profile_by_pubkey: ndb_get_tsid failed\n"); - goto cleanup; + return 0; } - if (mdb_get(txn, ndb->lmdb.dbs[store], &k, &v)) { + if (mdb_get(txn->mdb_txn, txn->ndb->lmdb.dbs[store], &k, &v)) { ndb_debug("ndb_get_profile_by_pubkey: mdb_get note failed\n"); - goto cleanup; + return 0; } res = v.mv_data; assert(((uint64_t)res % 4) == 0); if (len) *len = v.mv_size; -cleanup: - mdb_txn_abort(txn); return res; } -void *ndb_get_profile_by_pubkey(struct ndb *ndb, const unsigned char *pk, size_t *len) +void *ndb_get_profile_by_pubkey(struct ndb_txn *txn, const unsigned char *pk, size_t *len) { - return ndb_lookup_tsid(ndb, NDB_DB_PROFILE_PK, NDB_DB_PROFILE, pk, len); + return ndb_lookup_tsid(txn, NDB_DB_PROFILE_PK, NDB_DB_PROFILE, pk, len); } -struct ndb_note *ndb_get_note_by_id(struct ndb *ndb, const unsigned char *id, size_t *len) +struct ndb_note *ndb_get_note_by_id(struct ndb_txn *txn, const unsigned char *id, size_t *len) { - return ndb_lookup_tsid(ndb, NDB_DB_NOTE_ID, NDB_DB_NOTE, id, len); + return ndb_lookup_tsid(txn, NDB_DB_NOTE_ID, NDB_DB_NOTE, id, len); } -struct ndb_note *ndb_get_note_by_key(struct ndb *ndb, uint64_t key, size_t *len) +struct ndb_note *ndb_get_note_by_key(struct ndb_txn *txn, uint64_t key, size_t *len) { - return ndb_lookup_by_key(ndb, key, NDB_DB_NOTE, len); + return ndb_lookup_by_key(txn, key, NDB_DB_NOTE, len); } static int ndb_has_note(MDB_txn *txn, struct ndb_lmdb *lmdb, const unsigned char *id) diff --git a/nostrdb.h b/nostrdb.h @@ -18,10 +18,17 @@ struct ndb_json_parser; struct ndb; +// sorry, swift needs help with forward declared pointers like this struct ndb_t { struct ndb *ndb; }; +// required to keep a read +struct ndb_txn { + struct ndb *ndb; + void *mdb_txn; +}; + // To-client event types enum tce_type { NDB_TCE_EVENT = 0x1, @@ -154,9 +161,11 @@ int ndb_note_verify(void *secp_ctx, unsigned char pubkey[32], unsigned char id[3 int ndb_init(struct ndb **ndb, const char *dbdir, size_t mapsize, int ingester_threads); int ndb_process_event(struct ndb *, const char *json, int len); int ndb_process_events(struct ndb *, const char *ldjson, size_t len); -void *ndb_get_profile_by_pubkey(struct ndb *, const unsigned char *pubkey, size_t *len); -struct ndb_note *ndb_get_note_by_id(struct ndb *, const unsigned char *id, size_t *len); -struct ndb_note *ndb_get_note_by_key(struct ndb *, uint64_t key, size_t *len); +int ndb_begin_query(struct ndb *, struct ndb_txn *); +void ndb_end_query(struct ndb_txn *); +void *ndb_get_profile_by_pubkey(struct ndb_txn *txn, const unsigned char *pubkey, size_t *len); +struct ndb_note *ndb_get_note_by_id(struct ndb_txn *txn, const unsigned char *id, size_t *len); +struct ndb_note *ndb_get_note_by_key(struct ndb_txn *txn, uint64_t key, size_t *len); void ndb_destroy(struct ndb *); // BUILDER diff --git a/test.c b/test.c @@ -41,9 +41,12 @@ static void test_load_profiles() 0xd2, 0xb4, 0xd1, 0x3a, 0x55, 0x43, 0x09, 0x07 }; const char *expected_content = "{\"website\":\"selenejin.com\",\"lud06\":\"\",\"nip05\":\"selenejin@BitcoinNostr.com\",\"picture\":\"https://nostr.build/i/3549697beda0fe1f4ae621f359c639373d92b7c8d5c62582b656c5843138c9ed.jpg\",\"display_name\":\"Selene Jin\",\"about\":\"INTJ | Founding Designer @Blockstream\",\"name\":\"SeleneJin\"}"; - struct ndb_note *note = ndb_get_note_by_id(ndb, id, NULL); + struct ndb_txn txn; + assert(ndb_begin_query(ndb, &txn)); + struct ndb_note *note = ndb_get_note_by_id(&txn, id, NULL); assert(note != NULL); assert(!strcmp(ndb_note_content(note), expected_content)); + ndb_end_query(&txn); ndb_destroy(ndb); @@ -268,7 +271,9 @@ static void test_fetch_last_noteid() unsigned char id[32] = { 0xdc, 0x96, 0x4f, 0x4c, 0x89, 0x83, 0x64, 0x13, 0x8e, 0x81, 0x96, 0xf0, 0xc7, 0x33, 0x38, 0xc8, 0xcc, 0x3e, 0xbf, 0xa3, 0xaf, 0xdd, 0xbc, 0x7d, 0xd1, 0x58, 0xb4, 0x84, 0x7c, 0x1e, 0xbf, 0xa0 }; - struct ndb_note *note = ndb_get_note_by_id(ndb, id, &len); + struct ndb_txn txn; + assert(ndb_begin_query(ndb, &txn)); + struct ndb_note *note = ndb_get_note_by_id(&txn, id, &len); assert(note != NULL); assert(note->created_at == 1650054135); @@ -278,7 +283,7 @@ static void test_fetch_last_noteid() 0xd1, 0x2c, 0x17, 0xbd, 0xe3, 0x09, 0x4a, 0xd3, 0x2f, 0x4a, 0xb8, 0x62, 0xa6, 0xcc, 0x6f, 0x5c, 0x28, 0x9c, 0xfe, 0x7d, 0x58, 0x02, 0x27, 0x0b, 0xdf, 0x34, 0x90, 0x4d, 0xf5, 0x85, 0xf3, 0x49 }; - void *root = ndb_get_profile_by_pubkey(ndb, pk, &len); + void *root = ndb_get_profile_by_pubkey(&txn, pk, &len); assert(root); int res = NdbProfileRecord_verify_as_root(root, len); @@ -297,7 +302,8 @@ static void test_fetch_last_noteid() printf("note_key %" PRIu64 "\n", key); - struct ndb_note *n = ndb_get_note_by_key(ndb, key, NULL); + struct ndb_note *n = ndb_get_note_by_key(&txn, key, NULL); + ndb_end_query(&txn); assert(memcmp(profile_note_id, n->id, 32) == 0); //fwrite(profile, len, 1, stdout);