commit e03588e29e0d6a8ab5371047c8e8bd8e99e7e1d1
parent 7365c20e5277431632d43f730ae48e79750373c4
Author: William Casarin <jb55@jb55.com>
Date: Thu, 28 Nov 2024 10:55:35 -0800
Merge Windows support
Diffstat:
12 files changed, 145 insertions(+), 83 deletions(-)
diff --git a/ccan/ccan/tal/str/str.c b/ccan/ccan/tal/str/str.c
@@ -1,14 +1,13 @@
/* Licensed under BSD-MIT - see LICENSE file for details */
-#include <unistd.h>
+//#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <limits.h>
#include <stdlib.h>
#include "str.h"
#include <sys/types.h>
-#include <regex.h>
+//#include <regex.h>
#include <stdarg.h>
-#include <unistd.h>
#include <stdio.h>
#include <ccan/str/str.h>
@@ -236,51 +235,3 @@ static size_t count_open_braces(const char *string)
#endif
}
-bool tal_strreg_(const tal_t *ctx, const char *string, const char *label,
- const char *regex, ...)
-{
- size_t nmatch = 1 + count_open_braces(regex);
- regmatch_t matches[nmatch];
- regex_t r;
- bool ret = false;
- unsigned int i;
- va_list ap;
-
- if (regcomp(&r, regex, REG_EXTENDED) != 0)
- goto fail_no_re;
-
- if (regexec(&r, string, nmatch, matches, 0) != 0)
- goto fail;
-
- ret = true;
- va_start(ap, regex);
- for (i = 1; i < nmatch; i++) {
- char **arg = va_arg(ap, char **);
- if (arg) {
- /* eg. ([a-z])? can give "no match". */
- if (matches[i].rm_so == -1)
- *arg = NULL;
- else {
- *arg = tal_strndup_(ctx,
- string + matches[i].rm_so,
- matches[i].rm_eo
- - matches[i].rm_so,
- label);
- /* FIXME: If we fail, we set some and leak! */
- if (!*arg) {
- ret = false;
- break;
- }
- }
- }
- }
- va_end(ap);
-fail:
- regfree(&r);
-fail_no_re:
- if (taken(regex))
- tal_free(regex);
- if (taken(string))
- tal_free(string);
- return ret;
-}
diff --git a/ccan/ccan/tal/tal.c b/ccan/ccan/tal/tal.c
@@ -952,9 +952,10 @@ static bool check_err(struct tal_hdr *t, const char *errorstr,
{
if (errorstr) {
/* Try not to malloc: it may be corrupted. */
- char msg[strlen(errorstr) + 20 + strlen(errmsg) + 1];
+ char *msg = malloc(strlen(errorstr) + 20 + strlen(errmsg) + 1);
sprintf(msg, "%s:%p %s", errorstr, from_tal_hdr(t), errmsg);
call_error(msg);
+ free(msg);
}
return false;
}
diff --git a/src/content_parser.c b/src/content_parser.c
@@ -3,8 +3,13 @@
#include "block.h"
#include "nostrdb.h"
#include "invoice.h"
+
+#ifndef _WIN32
#include "bolt11/bolt11.h"
+#endif
+
#include "bolt11/bech32.h"
+
#include <stdlib.h>
#include <string.h>
@@ -164,6 +169,11 @@ fail:
static int push_invoice_str(struct ndb_content_parser *p, struct ndb_str_block *str)
{
+#ifdef _WIN32
+ // we shouldn't be pushing invoices on windows until we fix
+ // bolt11 parser portability
+ return 0;
+#else
unsigned char *start;
struct bolt11 *bolt11;
char *fail;
@@ -186,6 +196,7 @@ static int push_invoice_str(struct ndb_content_parser *p, struct ndb_str_block *
tal_free(bolt11);
return 1;
+#endif
}
int push_block(struct ndb_content_parser *p, struct ndb_block *block);
@@ -455,6 +466,11 @@ static int parse_url(struct cursor *cur, struct ndb_block *block) {
static int parse_invoice(struct cursor *cur, struct ndb_block *block) {
unsigned char *start, *end;
+#ifdef _WIN32
+ // bolt11 stuff requires non-portable cc stuff, so ignore for now
+ return 0;
+#else
+
// optional
parse_str(cur, "lightning:");
@@ -478,6 +494,7 @@ static int parse_invoice(struct cursor *cur, struct ndb_block *block) {
cur->p = end;
return 1;
+#endif
}
diff --git a/src/nostr_bech32.c b/src/nostr_bech32.c
@@ -286,7 +286,7 @@ int parse_nostr_bech32(unsigned char *buf, int buflen,
unsigned char *start;
size_t parsed_len, u5_out_len, u8_out_len;
enum nostr_bech32_type type;
- static const int MAX_PREFIX = 8;
+#define MAX_PREFIX 8
struct cursor cur, bech32, u8;
make_cursor(buf, buf + buflen, &cur);
@@ -302,7 +302,7 @@ int parse_nostr_bech32(unsigned char *buf, int buflen,
if (parsed_len < 10 || parsed_len > 10000)
return 0;
- unsigned char u5[parsed_len];
+ unsigned char *u5 = malloc(parsed_len);
char prefix[MAX_PREFIX];
if (bech32_decode_len(prefix, u5, &u5_out_len, (const char*)start,
@@ -314,6 +314,8 @@ int parse_nostr_bech32(unsigned char *buf, int buflen,
if (!bech32_convert_bits(cur.p, &u8_out_len, 8, u5, u5_out_len, 5, 0))
return 0;
+ free(u5);
+
make_cursor(cur.p, cur.p + u8_out_len, &u8);
return parse_nostr_bech32_buffer(&u8, type, obj);
diff --git a/src/nostrdb.c b/src/nostrdb.c
@@ -12,6 +12,7 @@
#include "cpu.h"
#include "block.h"
#include "threadpool.h"
+#include "thread.h"
#include "protected_queue.h"
#include "memchr.h"
#include "print_util.h"
@@ -32,7 +33,7 @@
#define min(a,b) ((a) < (b) ? (a) : (b))
// the maximum number of things threads pop and push in bulk
-static const int THREAD_QUEUE_BATCH = 4096;
+#define THREAD_QUEUE_BATCH 4096
// maximum number of active subscriptions
#define MAX_SUBSCRIPTIONS 256
@@ -84,7 +85,6 @@ struct ndb_tag {
struct ndb_tags {
uint16_t padding;
uint16_t count;
- struct ndb_tag tag[0];
};
// v1
@@ -364,8 +364,8 @@ static int ndb_tag_key_compare(const MDB_val *a, const MDB_val *b)
if ((cmp = mdb_cmp_memn(&va, &vb)))
return cmp;
- ts_a = *(uint64_t*)(va.mv_data + va.mv_size);
- ts_b = *(uint64_t*)(vb.mv_data + vb.mv_size);
+ ts_a = *(uint64_t*)((unsigned char *)va.mv_data + va.mv_size);
+ ts_b = *(uint64_t*)((unsigned char *)vb.mv_data + vb.mv_size);
if (ts_a < ts_b)
return -1;
@@ -381,8 +381,8 @@ static int ndb_text_search_key_compare(const MDB_val *a, const MDB_val *b)
uint64_t sa, sb, nid_a, nid_b;
MDB_val a2, b2;
- make_cursor(a->mv_data, a->mv_data + a->mv_size, &ca);
- make_cursor(b->mv_data, b->mv_data + b->mv_size, &cb);
+ make_cursor(a->mv_data, (unsigned char *)a->mv_data + a->mv_size, &ca);
+ make_cursor(b->mv_data, (unsigned char *)b->mv_data + b->mv_size, &cb);
// note_id
if (unlikely(!cursor_pull_varint(&ca, &nid_a) || !cursor_pull_varint(&cb, &nid_b)))
@@ -3035,7 +3035,7 @@ static int ndb_query_plan_execute_tags(struct ndb_txn *txn,
if (taglen != k.mv_size - 9)
break;
- if (memcmp(k.mv_data+1, tag, k.mv_size-9))
+ if (memcmp((unsigned char *)k.mv_data+1, tag, k.mv_size-9))
break;
note_id = *(uint64_t*)v.mv_data;
@@ -3538,7 +3538,7 @@ static int ndb_text_search_next_word(MDB_cursor *cursor, MDB_cursor_op op,
int retries;
retries = -1;
- make_cursor(k->mv_data, k->mv_data + k->mv_size, &key_cursor);
+ make_cursor(k->mv_data, (unsigned char *)k->mv_data + k->mv_size, &key_cursor);
// When op is MDB_SET_RANGE, this initializes the search. Position
// the cursor at the next key greater than or equal to the specified
@@ -3567,7 +3567,7 @@ retry:
printf("\n");
*/
- make_cursor(k->mv_data, k->mv_data + k->mv_size, &key_cursor);
+ make_cursor(k->mv_data, (unsigned char *)k->mv_data + k->mv_size, &key_cursor);
if (unlikely(!ndb_unpack_text_search_key_noteid(&key_cursor, &result->key.note_id))) {
fprintf(stderr, "UNUSUAL: failed to unpack text search key note_id\n");
@@ -3980,6 +3980,7 @@ static void ndb_notify_subscriptions(struct ndb_monitor *monitor,
static void *ndb_writer_thread(void *data)
{
+ ndb_debug("started writer thread\n");
struct ndb_writer *writer = data;
struct ndb_writer_msg msgs[THREAD_QUEUE_BATCH], *msg;
struct written_note written_notes[THREAD_QUEUE_BATCH];
@@ -3999,6 +4000,7 @@ static void *ndb_writer_thread(void *data)
while (!done) {
txn.mdb_txn = NULL;
num_notes = 0;
+ ndb_debug("writer waiting for items\n");
popped = prot_queue_pop_all(&writer->inbox, msgs, THREAD_QUEUE_BATCH);
ndb_debug("writer popped %d items\n", popped);
@@ -4029,6 +4031,7 @@ static void *ndb_writer_thread(void *data)
switch (msg->type) {
case NDB_WRITER_QUIT:
// quits are handled before this
+ ndb_debug("writer thread got quit message\n");
done = 1;
continue;
case NDB_WRITER_PROFILE:
@@ -4098,7 +4101,7 @@ static void *ndb_writer_thread(void *data)
free(msg->note.note);
} else if (msg->type == NDB_WRITER_PROFILE) {
free(msg->profile.note.note);
- ndb_profile_record_builder_free(&msg->profile.record);
+ //ndb_profile_record_builder_free(&msg->profile.record);
} else if (msg->type == NDB_WRITER_BLOCKS) {
ndb_blocks_free(msg->blocks.blocks);
}
@@ -4199,7 +4202,7 @@ static int ndb_writer_init(struct ndb_writer *writer, struct ndb_lmdb *lmdb,
writer->queue_buflen, sizeof(struct ndb_writer_msg));
// spin up the writer thread
- if (pthread_create(&writer->thread_id, NULL, ndb_writer_thread, writer))
+ if (THREAD_CREATE(writer->thread_id, ndb_writer_thread, writer))
{
fprintf(stderr, "ndb writer thread failed to create\n");
return 0;
@@ -4242,14 +4245,18 @@ static int ndb_writer_destroy(struct ndb_writer *writer)
// kill thread
msg.type = NDB_WRITER_QUIT;
+ ndb_debug("writer: pushing quit message\n");
if (!prot_queue_push(&writer->inbox, &msg)) {
// queue is too full to push quit message. just kill it.
- pthread_exit(&writer->thread_id);
+ ndb_debug("writer: terminating thread\n");
+ THREAD_TERMINATE(writer->thread_id);
} else {
- pthread_join(writer->thread_id, NULL);
+ ndb_debug("writer: joining thread\n");
+ THREAD_FINISH(writer->thread_id);
}
// cleanup
+ ndb_debug("writer: cleaning up protected queue\n");
prot_queue_destroy(&writer->inbox);
free(writer->queue_buf);
@@ -4515,12 +4522,17 @@ void ndb_destroy(struct ndb *ndb)
return;
// ingester depends on writer and must be destroyed first
+ ndb_debug("destroying ingester\n");
ndb_ingester_destroy(&ndb->ingester);
+ ndb_debug("destroying writer\n");
ndb_writer_destroy(&ndb->writer);
+ ndb_debug("destroying monitor\n");
ndb_monitor_destroy(&ndb->monitor);
+ ndb_debug("closing env\n");
mdb_env_close(ndb->lmdb.env);
+ ndb_debug("ndb destroyed\n");
free(ndb);
}
@@ -4588,6 +4600,8 @@ int _ndb_process_events(struct ndb *ndb, const char *ldjson, size_t json_len, in
return 1;
}
+#ifndef _WIN32
+// TODO: windows
int ndb_process_events_stream(struct ndb *ndb, FILE* fp)
{
char *line = NULL;
@@ -4605,6 +4619,7 @@ int ndb_process_events_stream(struct ndb *ndb, FILE* fp)
return 1;
}
+#endif
int ndb_process_client_events(struct ndb *ndb, const char *ldjson, size_t json_len)
{
@@ -6126,7 +6141,7 @@ int ndb_stat(struct ndb *ndb, struct ndb_stat *stat)
/// Push an element to the current tag
///
/// Basic idea is to call ndb_builder_new_tag
-inline int ndb_builder_push_tag_str(struct ndb_builder *builder,
+int ndb_builder_push_tag_str(struct ndb_builder *builder,
const char *str, int len)
{
union ndb_packed_str pstr;
@@ -6338,12 +6353,17 @@ void ndb_tags_iterate_start(struct ndb_note *note, struct ndb_iterator *iter)
iter->index = -1;
}
+// Helper function to get a pointer to the nth tag
+static struct ndb_tag *ndb_tags_tag(struct ndb_tags *tags, size_t index) {
+ return (struct ndb_tag *)((uint8_t *)tags + sizeof(struct ndb_tags) + index * sizeof(struct ndb_tag));
+}
+
int ndb_tags_iterate_next(struct ndb_iterator *iter)
{
struct ndb_tags *tags;
if (iter->tag == NULL || iter->index == -1) {
- iter->tag = iter->note->tags.tag;
+ iter->tag = ndb_tags_tag(&iter->note->tags, 0);
iter->index = 0;
return iter->note->tags.count != 0;
}
diff --git a/src/nostrdb.h b/src/nostrdb.h
@@ -2,6 +2,7 @@
#define NOSTRDB_H
#include <inttypes.h>
+#include "win.h"
#include "cursor.h"
// maximum number of filters allowed in a filter group
@@ -455,7 +456,10 @@ int ndb_init(struct ndb **ndb, const char *dbdir, const struct ndb_config *);
int ndb_db_version(struct ndb *ndb);
int ndb_process_event(struct ndb *, const char *json, int len);
int ndb_process_events(struct ndb *, const char *ldjson, size_t len);
+#ifndef _WIN32
+// TODO: fix on windows
int ndb_process_events_stream(struct ndb *, FILE* fp);
+#endif
int ndb_process_client_event(struct ndb *, const char *json, int len);
int ndb_process_client_events(struct ndb *, const char *json, size_t len);
int ndb_begin_query(struct ndb *, struct ndb_txn *);
diff --git a/src/print_util.h b/src/print_util.h
@@ -22,12 +22,12 @@ static void print_tag_kv(struct ndb_txn *txn, MDB_val *k, MDB_val *v)
struct ndb_note *note;
uint64_t ts;
- ts = *(uint64_t*)(k->mv_data+(k->mv_size-8));
+ ts = *(uint64_t*)((uint8_t*)k->mv_data+(k->mv_size-8));
// TODO: p tags, etc
if (((const char*)k->mv_data)[0] == 'e' && k->mv_size == (1 + 32 + 8)) {
printf("note_tags 'e");
- print_hex(k->mv_data+1, 32);
+ print_hex((uint8_t*)k->mv_data+1, 32);
printf("' %" PRIu64, ts);
} else {
printf("note_tags '%.*s' %" PRIu64, (int)k->mv_size-8,
diff --git a/src/protected_queue.h b/src/protected_queue.h
@@ -12,12 +12,15 @@
#ifndef PROT_QUEUE_H
#define PROT_QUEUE_H
-#include <pthread.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "cursor.h"
#include "util.h"
+#include "thread.h"
+
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#define min(a,b) ((a) < (b) ? (a) : (b))
/*
* The prot_queue structure represents a thread-safe queue that can hold
diff --git a/src/thread.h b/src/thread.h
@@ -0,0 +1,63 @@
+#ifndef NDB_THREAD_H
+#define NDB_THREAD_H
+
+#ifdef _WIN32
+ #include <windows.h>
+
+ #define ErrCode() GetLastError()
+// Define POSIX-like thread types
+typedef HANDLE pthread_t;
+typedef CRITICAL_SECTION pthread_mutex_t;
+typedef CONDITION_VARIABLE pthread_cond_t;
+
+#define ErrCode() GetLastError()
+
+// Mutex functions
+#define pthread_mutex_init(mutex, attr) \
+ (InitializeCriticalSection(mutex), 0)
+
+#define pthread_mutex_destroy(mutex) \
+ (DeleteCriticalSection(mutex), 0)
+
+#define pthread_mutex_lock(mutex) \
+ (EnterCriticalSection(mutex), 0)
+
+#define pthread_mutex_unlock(mutex) \
+ (LeaveCriticalSection(mutex), 0)
+
+// Condition variable functions
+#define pthread_cond_init(cond, attr) \
+ (InitializeConditionVariable(cond), 0)
+
+#define pthread_cond_destroy(cond)
+
+#define pthread_cond_signal(cond) \
+ (WakeConditionVariable(cond), 0)
+
+#define pthread_cond_wait(cond, mutex) \
+ (SleepConditionVariableCS(cond, mutex, INFINITE) ? 0 : ErrCode())
+
+// Thread functions
+#define THREAD_CREATE(thr, start, arg) \
+ (((thr = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)start, arg, 0, NULL)) != NULL) ? 0 : ErrCode())
+
+#define THREAD_FINISH(thr) \
+ (WaitForSingleObject(thr, INFINITE), CloseHandle(thr), 0)
+
+#define THREAD_TERMINATE(thr) \
+ (TerminateThread(thr, 0) ? ErrCode() : 0)
+
+#else // _WIN32
+ #include <pthread.h>
+
+ //#define ErrCode() errno
+ #define THREAD_CREATE(thr,start,arg) pthread_create(&thr,NULL,start,arg)
+ #define THREAD_FINISH(thr) pthread_join(thr,NULL)
+ #define THREAD_TERMINATE(thr) pthread_exit(&thr)
+
+ #define LOCK_MUTEX(mutex) pthread_mutex_lock(mutex)
+ #define UNLOCK_MUTEX(mutex) pthread_mutex_unlock(mutex)
+
+#endif
+
+#endif // NDB_THREAD_H
diff --git a/src/threadpool.h b/src/threadpool.h
@@ -55,7 +55,7 @@ static int threadpool_init(struct threadpool *tp, int num_threads,
return 0;
}
- if (pthread_create(&t->thread_id, NULL, thread_fn, t) != 0) {
+ if (THREAD_CREATE(t->thread_id, thread_fn, t) != 0) {
fprintf(stderr, "threadpool_init: failed to create thread\n");
return 0;
}
@@ -90,9 +90,9 @@ static inline void threadpool_destroy(struct threadpool *tp)
for (int i = 0; i < tp->num_threads; i++) {
t = &tp->pool[i];
if (!prot_queue_push(&t->inbox, tp->quit_msg)) {
- pthread_exit(&t->thread_id);
+ THREAD_TERMINATE(t->thread_id);
} else {
- pthread_join(t->thread_id, NULL);
+ THREAD_FINISH(t->thread_id);
}
prot_queue_destroy(&t->inbox);
free(t->qmem);
diff --git a/src/util.h b/src/util.h
@@ -2,14 +2,6 @@
#ifndef NDB_UTIL_H
#define NDB_UTIL_H
-static inline int min(int a, int b) {
- return a < b ? a : b;
-}
-
-static inline int max(int a, int b) {
- return a > b ? a : b;
-}
-
static inline void* memdup(const void* src, size_t size) {
void* dest = malloc(size);
if (dest == NULL) {
diff --git a/src/win.h b/src/win.h
@@ -0,0 +1,9 @@
+#ifndef NOSTRDB_WIN_H
+#define NOSTRDB_WIN_H
+#ifdef _WIN32
+
+typedef ptrdiff_t ssize_t; // ssize_t is typically a signed version of size_t
+
+#endif
+#endif // NOSTRDB_WIN_H
+