commit 4c179987772f6d4d47b972b48391f1a99e1c9b5e
parent e90d933c6730b37bf420f1a57344a6cdc15ff03b
Author: William Casarin <jb55@jb55.com>
Date: Wed, 29 Oct 2025 16:21:44 -0700
migration: implement ndb_count_reactions
also verify it matches the online counting
Diffstat:
| M | src/nostrdb.c | | | 113 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------- |
| M | test.c | | | 12 | ++++++++++++ |
2 files changed, 95 insertions(+), 30 deletions(-)
diff --git a/src/nostrdb.c b/src/nostrdb.c
@@ -2002,14 +2002,94 @@ cleanup:
int ndb_cursor_start(MDB_cursor *cur, MDB_val *k, MDB_val *v);
+// find the last id tag in a note (e, p, etc)
+static unsigned char *ndb_note_last_id_tag(struct ndb_note *note, char type)
+{
+ unsigned char *last = NULL;
+ struct ndb_iterator iter;
+ struct ndb_str str;
+
+ // get the liked event id (last id)
+ ndb_tags_iterate_start(note, &iter);
+
+ while (ndb_tags_iterate_next(&iter)) {
+ if (iter.tag->count < 2)
+ continue;
+
+ str = ndb_tag_str(note, iter.tag, 0);
+
+ // assign liked to the last e tag
+ if (str.flag == NDB_PACKED_STR && str.str[0] == type) {
+ str = ndb_tag_str(note, iter.tag, 1);
+ if (str.flag == NDB_PACKED_ID)
+ last = str.id;
+ }
+ }
+
+ return last;
+}
+
+
static int ndb_count_replies(struct ndb_txn *txn, const unsigned char *note_id, uint16_t *direct_replies, uint32_t *thread_replies)
{
return 1;
}
/* count all of the reactions for a note */
-static int ndb_count_reactions(struct ndb_txn *txn, const unsigned char *note_id, uint32_t *count)
+int ndb_count_reactions(struct ndb_txn *txn, const unsigned char *note_id, uint32_t *count)
{
+ MDB_val k, v;
+ MDB_cursor *cur;
+ MDB_dbi db;
+
+ int rc;
+ uint64_t note_key;
+ size_t size;
+ struct ndb_note *note;
+ unsigned char *keybuf, *last_id;
+ char buffer[41]; /* 1 + 32 + 8 */
+ *count = 0;
+
+ db = txn->lmdb->dbs[NDB_DB_NOTE_TAGS];
+ if ((rc = mdb_cursor_open(txn->mdb_txn, db, &cur))) {
+ fprintf(stderr, "ndb_count_reactions: mdb_cursor_open failed, error %d\n", rc);
+ return 0;
+ }
+
+ buffer[0] = 'e';
+ memcpy(&buffer[1], note_id, 32);
+ memset(&buffer[33], 0x00, 8);
+
+ k.mv_data = buffer;
+ k.mv_size = sizeof(buffer);
+ v.mv_data = NULL;
+ v.mv_size = 0;
+
+ if (mdb_cursor_get(cur, &k, &v, MDB_SET_RANGE))
+ goto cleanup;
+
+ do {
+ keybuf = (unsigned char *)k.mv_data;
+ note_key = *((uint64_t*)v.mv_data);
+ if (k.mv_size < sizeof(buffer))
+ break;
+ if (keybuf[0] != 'e')
+ break;
+ if (memcmp(&keybuf[1], note_id, 32))
+ break;
+ if (!(note = ndb_get_note_by_key(txn, note_key, &size)))
+ continue;
+ if (ndb_note_kind(note) != 7)
+ continue;
+ if (!(last_id = ndb_note_last_id_tag(note, 'e')))
+ continue;
+ if (memcmp(last_id, note_id, 32))
+ continue;
+ (*count)++;
+ } while (mdb_cursor_get(cur, &k, &v, MDB_NEXT) == 0);
+
+cleanup:
+ mdb_cursor_close(cur);
return 1;
}
@@ -2108,7 +2188,7 @@ static void ndb_note_meta_builder_count_reactions(struct ndb_txn *txn, struct nd
//
/* switch from flatbuffer stats to custom v2 */
-static int ndb_migrate_reaction_stats(struct ndb_txn *txn)
+static int ndb_migrate_metadata(struct ndb_txn *txn)
{
MDB_val k, k2, v, v2;
MDB_cursor *cur;
@@ -2491,7 +2571,7 @@ static struct ndb_migration MIGRATIONS[] = {
{ .fn = ndb_migrate_lower_user_search_indices },
{ .fn = ndb_migrate_utf8_profile_names },
{ .fn = ndb_migrate_profile_indices },
- //{ .fn = ndb_migrate_reaction_stats },
+ //{ .fn = ndb_migrate_metadata },
};
@@ -3477,33 +3557,6 @@ static int ndb_write_profile(struct ndb_txn *txn,
return 1;
}
-// find the last id tag in a note (e, p, etc)
-static unsigned char *ndb_note_last_id_tag(struct ndb_note *note, char type)
-{
- unsigned char *last = NULL;
- struct ndb_iterator iter;
- struct ndb_str str;
-
- // get the liked event id (last id)
- ndb_tags_iterate_start(note, &iter);
-
- while (ndb_tags_iterate_next(&iter)) {
- if (iter.tag->count < 2)
- continue;
-
- str = ndb_tag_str(note, iter.tag, 0);
-
- // assign liked to the last e tag
- if (str.flag == NDB_PACKED_STR && str.str[0] == type) {
- str = ndb_tag_str(note, iter.tag, 1);
- if (str.flag == NDB_PACKED_ID)
- last = str.id;
- }
- }
-
- return last;
-}
-
int ndb_set_note_meta(struct ndb *ndb, const unsigned char *id, struct ndb_note_meta *meta)
{
struct ndb_writer_msg msg;
diff --git a/test.c b/test.c
@@ -30,6 +30,8 @@ static void delete_test_db() {
unlink(TEST_DIR "/data.lock");
}
+int ndb_count_reactions(struct ndb_txn *txn, const unsigned char *note_id, uint32_t *count);
+
static void db_load_events(struct ndb *ndb, const char *filename)
{
size_t filesize;
@@ -132,7 +134,17 @@ static void test_count_metadata()
assert(reactions > 0);
assert(total_reactions == reactions);
+
+ ndb_end_query(&txn);
+
+ ndb_begin_query(ndb, &txn);
+ /* this is used in the migration code,
+ * let's make sure it matches the online logic */
+ ndb_count_reactions(&txn, id, &reactions);
+ printf("\t# after-counted reactions %d\n", reactions);
+ assert(reactions == total_reactions);
ndb_end_query(&txn);
+
ndb_destroy(ndb);
delete_test_db();