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:
| M | nostrdb.c | | | 56 | +++++++++++++++++++++++++++----------------------------- | 
| M | nostrdb.h | | | 15 | ++++++++++++--- | 
| M | test.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);