nostrdb

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

commit 750346cce36d7e533ec6e88fbd3011d9a753b91d
parent 8636e48ffa2852a922609d070f2e2af347236a45
Author: William Casarin <jb55@jb55.com>
Date:   Fri, 11 Aug 2023 20:27:21 -0700

ndb: add note querying by id, add tests

Diffstat:
Mnostrdb.c | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Mnostrdb.h | 2++
Mtest.c | 13+++++++++++++
3 files changed, 73 insertions(+), 16 deletions(-)

diff --git a/nostrdb.c b/nostrdb.c @@ -238,35 +238,76 @@ static int ndb_writer_queue_note(struct ndb_writer *writer, return prot_queue_push(&writer->inbox, &msg); } -static uint64_t ndb_get_note_by_id(MDB_txn *txn, struct ndb_lmdb *lmdb, - unsigned char *id) +// get some value based on a clustered id key +int ndb_get_tsid(MDB_txn *txn, struct ndb_lmdb *lmdb, enum ndb_dbs db, + unsigned char *id, MDB_val *val) { - MDB_val key, data; + MDB_val k, v; MDB_cursor *cur; struct ndb_tsid tsid; + int success = 0; ndb_tsid_high(&tsid, id); - key.mv_data = &tsid; - key.mv_size = sizeof(tsid); + k.mv_data = &tsid; + k.mv_size = sizeof(tsid); - mdb_cursor_open(txn, lmdb->dbs[NDB_DB_NOTE_ID], &cur); + mdb_cursor_open(txn, lmdb->dbs[db], &cur); // Position cursor at the next key greater than or equal to the specified key - if (mdb_cursor_get(cur, &key, &data, MDB_SET_RANGE)) { - mdb_cursor_close(cur); - return 0; + if (mdb_cursor_get(cur, &k, &v, MDB_SET_RANGE)) { + // Failed :(. It could be the last element? + if (mdb_cursor_get(cur, &k, &v, MDB_LAST)) + goto cleanup; + } else { + // if set range worked and our key exists, it should be + // the one right before this one + if (mdb_cursor_get(cur, &k, &v, MDB_PREV)) + goto cleanup; } - if (mdb_cursor_get(cur, &key, &data, MDB_PREV)) { - mdb_cursor_close(cur); - return 0; + if (memcmp(k.mv_data, id, 32) == 0) { + *val = v; + success = 1; } +cleanup: mdb_cursor_close(cur); - if (memcmp(key.mv_data, id, 32) == 0) - return *((uint64_t*)data.mv_data); + return success; +} - return 0; +struct ndb_note *ndb_get_note_by_id(struct ndb *ndb, unsigned char *id) +{ + MDB_val k, v; + MDB_txn *txn; + + 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, NDB_DB_NOTE_ID, id, &k)) { + ndb_debug("ndb_get_note_by_id: ndb_get_tsid failed\n"); + return NULL; + } + + if (mdb_get(txn, ndb->lmdb.dbs[NDB_DB_NOTE], &k, &v)) { + ndb_debug("ndb_get_note_by_id: mdb_get note failed\n"); + return NULL; + } + + mdb_txn_abort(txn); + + return (struct ndb_note *)v.mv_data; +} + +static int ndb_has_note(MDB_txn *txn, struct ndb_lmdb *lmdb, unsigned char *id) +{ + MDB_val val; + + if (!ndb_get_tsid(txn, lmdb, NDB_DB_NOTE_ID, id, &val)) + return 0; + + return 1; } static enum ndb_idres ndb_ingester_json_controller(void *data, const char *hexid) @@ -282,7 +323,7 @@ static enum ndb_idres ndb_ingester_json_controller(void *data, const char *hexid key.mv_size = 32; key.mv_data = id; - if (!ndb_get_note_by_id(c->read_txn, c->lmdb, id)) + if (!ndb_has_note(c->read_txn, c->lmdb, id)) return NDB_IDRES_CONT; return NDB_IDRES_STOP; @@ -315,6 +356,7 @@ static int ndb_process_profile_note(struct ndb_note *note, void **profile, return 1; } + static int ndb_ingester_process_event(secp256k1_context *ctx, struct ndb_ingester *ingester, struct ndb_ingester_event *ev, diff --git a/nostrdb.h b/nostrdb.h @@ -151,6 +151,8 @@ int ndb_note_verify(void *secp_ctx, unsigned char pubkey[32], unsigned char id[3 int ndb_init(struct ndb **ndb, 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, int len); +int ndb_get_profile(struct ndb *, unsigned char pubkey[32], void **out); +struct ndb_note *ndb_get_note_by_id(struct ndb *, unsigned char *id); void ndb_destroy(struct ndb *); // BUILDER diff --git a/test.c b/test.c @@ -30,6 +30,19 @@ static void test_load_profiles() ndb_destroy(ndb); + assert(ndb_init(&ndb, mapsize, ingester_threads)); + unsigned char id[32] = { + 0x22, 0x05, 0x0b, 0x6d, 0x97, 0xbb, 0x9d, 0xa0, 0x9e, 0x90, 0xed, 0x0c, + 0x6d, 0xd9, 0x5e, 0xed, 0x1d, 0x42, 0x3e, 0x27, 0xd5, 0xcb, 0xa5, 0x94, + 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); + assert(note != NULL); + assert(!strcmp(ndb_note_content(note), expected_content)); + + ndb_destroy(ndb); + free(json); free(buf); }