nostrdb

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

commit aac9e1749b3a3f52251d4cd5ba88766c76beb4c1
parent 565e6895915d187fcbb9c05c90895dea4363b8f5
Author: William Casarin <jb55@jb55.com>
Date:   Thu, 20 Mar 2025 13:37:23 -0700

relay: add note relay iteration

This is a simple cursor that walks the NDB_DB_NOTE_RELAYS db

Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
Msrc/nostrdb.c | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/nostrdb.h | 12++++++++++++
Mtest.c | 32++++++++++++++++++++++++++------
3 files changed, 89 insertions(+), 6 deletions(-)

diff --git a/src/nostrdb.c b/src/nostrdb.c @@ -7328,6 +7328,57 @@ struct ndb_note * ndb_note_from_bytes(unsigned char *bytes) return note; } +int ndb_note_relay_iterate_start(struct ndb_txn *txn, + struct ndb_note_relay_iterator *iter, + uint64_t note_key) +{ + if (mdb_cursor_open(txn->mdb_txn, txn->lmdb->dbs[NDB_DB_NOTE_RELAYS], + (MDB_cursor**)&iter->mdb_cur)) { + return 0; + } + + iter->txn = txn; + iter->cursor_op = MDB_SET_KEY; + iter->note_key = note_key; + + return 1; +} + +const char *ndb_note_relay_iterate_next(struct ndb_note_relay_iterator *iter) +{ + int rc; + MDB_val k, v; + + if (iter->mdb_cur == NULL) + return NULL; + + k.mv_data = &iter->note_key; + k.mv_size = sizeof(iter->note_key); + + if ((rc = mdb_cursor_get((MDB_cursor *)iter->mdb_cur, &k, &v, + (MDB_cursor_op)iter->cursor_op))) + { + //fprintf(stderr, "autoclosing %d '%s'\n", iter->cursor_op, mdb_strerror(rc)); + // autoclose + ndb_note_relay_iterate_close(iter); + return NULL; + } + + iter->cursor_op = MDB_NEXT_DUP; + + return (const char*)v.mv_data; +} + +void ndb_note_relay_iterate_close(struct ndb_note_relay_iterator *iter) +{ + if (!iter || iter->mdb_cur == NULL) + return; + + mdb_cursor_close((MDB_cursor*)iter->mdb_cur); + + iter->mdb_cur = NULL; +} + void ndb_tags_iterate_start(struct ndb_note *note, struct ndb_iterator *iter) { iter->note = note; diff --git a/src/nostrdb.h b/src/nostrdb.h @@ -229,6 +229,13 @@ struct ndb_builder { struct ndb_tag *current_tag; }; +struct ndb_note_relay_iterator { + struct ndb_txn *txn; + uint64_t note_key; + int cursor_op; + void *mdb_cur; +}; + struct ndb_iterator { struct ndb_note *note; struct ndb_tag *tag; @@ -610,6 +617,11 @@ int ndb_tags_iterate_next(struct ndb_iterator *iter); struct ndb_str ndb_iter_tag_str(struct ndb_iterator *iter, int ind); struct ndb_str ndb_tag_str(struct ndb_note *note, struct ndb_tag *tag, int ind); +// RELAY ITER +int ndb_note_relay_iterate_start(struct ndb_txn *txn, struct ndb_note_relay_iterator *iter, uint64_t note_key); +const char *ndb_note_relay_iterate_next(struct ndb_note_relay_iterator *iter); +void ndb_note_relay_iterate_close(struct ndb_note_relay_iterator *iter); + // NAMES const char *ndb_db_name(enum ndb_dbs db); const char *ndb_kind_name(enum ndb_common_kind ck); diff --git a/test.c b/test.c @@ -1781,12 +1781,13 @@ static void test_filter_parse_search_json() { static void test_note_relay_index() { + const char *relay; struct ndb *ndb; struct ndb_txn txn; struct ndb_config config; struct ndb_note *note; struct ndb_filter filter, *f = &filter; - uint64_t note_id, subid; + uint64_t note_key, subid; struct ndb_ingest_meta meta; const char *json = "[\"EVENT\",{\"id\": \"0f20295584a62d983a4fa85f7e50b460cd0049f94d8cd250b864bb822a747114\",\"pubkey\": \"55c882cf4a255ac66fc8507e718a1d1283ba46eb7d678d0573184dada1a4f376\",\"created_at\": 1742498339,\"kind\": 1,\"tags\": [],\"content\": \"hi\",\"sig\": \"ae1218280f554ea0b04ae09921031493d60fb7831dfd2dbd7086efeace2719a46842ce80342ebc002da8943df02e98b8b4abb4629c7103ca2114e6c4425f97fe\"}]"; @@ -1809,11 +1810,11 @@ static void test_note_relay_index() ndb_ingest_meta_init(&meta, 1, "wss://relay.damus.io"); assert(ndb_process_event_with(ndb, json, strlen(json), &meta)); - assert(ndb_wait_for_notes(ndb, subid, &note_id, 1) == 1); - assert(note_id > 0); + assert(ndb_wait_for_notes(ndb, subid, &note_key, 1) == 1); + assert(note_key > 0); assert(ndb_begin_query(ndb, &txn)); - assert((note = ndb_get_note_by_key(&txn, note_id, NULL))); + assert((note = ndb_get_note_by_key(&txn, note_key, NULL))); ndb_end_query(&txn); @@ -1826,8 +1827,27 @@ static void test_note_relay_index() // 4) Check that we have both relays assert(ndb_begin_query(ndb, &txn)); - assert(ndb_note_seen_on_relay(&txn, note_id, "wss://relay.damus.io")); - assert(ndb_note_seen_on_relay(&txn, note_id, "wss://relay.mit.edu")); + assert(ndb_note_seen_on_relay(&txn, note_key, "wss://relay.damus.io")); + assert(ndb_note_seen_on_relay(&txn, note_key, "wss://relay.mit.edu")); + + // walk the relays + struct ndb_note_relay_iterator iter; + + assert(ndb_note_relay_iterate_start(&txn, &iter, note_key)); + + relay = ndb_note_relay_iterate_next(&iter); + assert(relay); + assert(!strcmp(relay, "wss://relay.damus.io")); + + relay = ndb_note_relay_iterate_next(&iter); + assert(relay); + assert(!strcmp(relay, "wss://relay.mit.edu")); + + assert(ndb_note_relay_iterate_next(&iter) == NULL); + ndb_note_relay_iterate_close(&iter); + assert(iter.mdb_cur == NULL); + + assert(ndb_end_query(&txn)); // Cleanup ndb_destroy(ndb);