ndb.c (9636B)
1 2 3 #include "nostrdb.h" 4 #include "lmdb.h" 5 #include "print_util.h" 6 #include "hex.h" 7 #include <time.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <sys/stat.h> 11 #include <sys/mman.h> 12 #include <unistd.h> 13 #include <fcntl.h> 14 15 static int usage() 16 { 17 printf("usage: ndb [--skip-verification] [-d db_dir] <command>\n\n"); 18 printf("commands\n\n"); 19 printf(" stat\n"); 20 printf(" search [--oldest-first] [--limit 42] <fulltext query>\n"); 21 printf(" query [-k 42] [-k 1337] [-l 42] [-e abcdef...] [-a abcdef... -a bcdef...]\n"); 22 printf(" profile <pubkey>\n"); 23 printf(" print-search-keys\n"); 24 printf(" print-kind-keys\n"); 25 printf(" print-tag-keys\n"); 26 printf(" import <line-delimited json file>\n\n"); 27 printf("settings\n\n"); 28 printf(" --skip-verification skip signature validation\n"); 29 printf(" -d <db_dir> set database directory\n"); 30 return 1; 31 } 32 33 34 static int map_file(const char *filename, unsigned char **p, size_t *flen) 35 { 36 struct stat st; 37 int des; 38 stat(filename, &st); 39 *flen = st.st_size; 40 41 des = open(filename, O_RDONLY); 42 43 *p = mmap(NULL, *flen, PROT_READ, MAP_PRIVATE, des, 0); 44 close(des); 45 46 return *p != MAP_FAILED; 47 } 48 49 static inline void print_stat_counts(struct ndb_stat_counts *counts) 50 { 51 printf("%zu\t%zu\t%zu\t%zu\n", 52 counts->count, 53 counts->key_size, 54 counts->value_size, 55 counts->key_size + counts->value_size); 56 } 57 58 static void print_stats(struct ndb_stat *stat) 59 { 60 int i; 61 const char *name; 62 struct ndb_stat_counts *c; 63 64 struct ndb_stat_counts total; 65 ndb_stat_counts_init(&total); 66 67 printf("name\tcount\tkey_bytes\tvalue_bytes\ttotal_bytes\n"); 68 printf("---\ndbs\n---\n"); 69 for (i = 0; i < NDB_DBS; i++) { 70 name = ndb_db_name(i); 71 72 total.count += stat->dbs[i].count; 73 total.key_size += stat->dbs[i].key_size; 74 total.value_size += stat->dbs[i].value_size; 75 76 printf("%s\t", name); 77 print_stat_counts(&stat->dbs[i]); 78 } 79 80 printf("total\t"); 81 print_stat_counts(&total); 82 83 printf("-----\nkinds\n-----\n"); 84 for (i = 0; i < NDB_CKIND_COUNT; i++) { 85 c = &stat->common_kinds[i]; 86 if (c->count == 0) 87 continue; 88 89 printf("%s\t", ndb_kind_name(i)); 90 print_stat_counts(c); 91 } 92 93 if (stat->other_kinds.count != 0) { 94 printf("other\t"); 95 print_stat_counts(&stat->other_kinds); 96 } 97 } 98 99 int ndb_print_search_keys(struct ndb_txn *txn); 100 int ndb_print_kind_keys(struct ndb_txn *txn); 101 int ndb_print_tag_index(struct ndb_txn *txn); 102 103 static void print_note(struct ndb_note *note) 104 { 105 static char buf[5000000]; 106 if (!ndb_note_json(note, buf, sizeof(buf))) { 107 print_hex_stream(stderr, ndb_note_id(note), 32); 108 fprintf(stderr, " is too big to print! >5mb"); 109 return; 110 } 111 puts(buf); 112 } 113 114 static void ndb_print_text_search_result(struct ndb_txn *txn, 115 struct ndb_text_search_result *r) 116 { 117 size_t len; 118 struct ndb_note *note; 119 120 //ndb_print_text_search_key(&r->key); 121 122 if (!(note = ndb_get_note_by_key(txn, r->key.note_id, &len))) { 123 fprintf(stderr,": note not found"); 124 return; 125 } 126 127 //fprintf(stderr,"\n"); 128 print_note(note); 129 } 130 131 132 int main(int argc, char *argv[]) 133 { 134 struct ndb *ndb; 135 int i, flags, limit, count, current_field, len, res; 136 long nanos; 137 struct ndb_stat stat; 138 struct ndb_txn txn; 139 struct ndb_text_search_results results; 140 struct ndb_text_search_result *result; 141 const char *dir; 142 unsigned char *data; 143 size_t data_len; 144 struct ndb_config config; 145 struct timespec t1, t2; 146 struct ndb_text_search_config search_config; 147 unsigned char tmp_id[32]; 148 149 // profiles 150 const char *pk_str; 151 void *ptr; 152 size_t profile_len; 153 uint64_t key; 154 155 res = 0; 156 ndb_default_config(&config); 157 ndb_default_text_search_config(&search_config); 158 ndb_config_set_mapsize(&config, 1024ULL * 1024ULL * 1024ULL * 1024ULL /* 1 TiB */); 159 160 if (argc < 2) { 161 return usage(); 162 } 163 164 dir = "."; 165 flags = 0; 166 for (i = 0; i < 2; i++) 167 { 168 if (!strcmp(argv[1], "-d") && argv[2]) { 169 dir = argv[2]; 170 argv += 2; 171 argc -= 2; 172 } else if (!strcmp(argv[1], "--skip-verification")) { 173 flags = NDB_FLAG_SKIP_NOTE_VERIFY; 174 argv += 1; 175 argc -= 1; 176 } 177 } 178 179 ndb_config_set_flags(&config, flags); 180 181 fprintf(stderr, "using db '%s'\n", dir); 182 183 if (!ndb_init(&ndb, dir, &config)) { 184 return 2; 185 } 186 187 if (argc >= 3 && !strcmp(argv[1], "search")) { 188 for (i = 0; i < 2; i++) { 189 if (!strcmp(argv[2], "--oldest-first")) { 190 ndb_text_search_config_set_order(&search_config, NDB_ORDER_ASCENDING); 191 argv++; 192 argc--; 193 } else if (!strcmp(argv[2], "--limit") || !strcmp(argv[2], "-l")) { 194 limit = atoi(argv[3]); 195 ndb_text_search_config_set_limit(&search_config, limit); 196 argv += 2; 197 argc -= 2; 198 } 199 } 200 201 ndb_begin_query(ndb, &txn); 202 clock_gettime(CLOCK_MONOTONIC, &t1); 203 ndb_text_search(&txn, argv[2], &results, &search_config); 204 clock_gettime(CLOCK_MONOTONIC, &t2); 205 206 nanos = (t2.tv_sec - t1.tv_sec) * (long)1e9 + (t2.tv_nsec - t1.tv_nsec); 207 208 fprintf(stderr, "%d results in %f ms\n", results.num_results, nanos/1000000.0); 209 210 // print results for now 211 for (i = 0; i < results.num_results; i++) { 212 result = &results.results[i]; 213 //fprintf(stderr, "[%02d] ", i+1); 214 ndb_print_text_search_result(&txn, result); 215 } 216 217 ndb_end_query(&txn); 218 } else if (argc == 2 && !strcmp(argv[1], "stat")) { 219 if (!ndb_stat(ndb, &stat)) { 220 res = 3; 221 goto cleanup; 222 } 223 224 print_stats(&stat); 225 } else if (argc >= 3 && !strcmp(argv[1], "query")) { 226 struct ndb_filter filter, *f = &filter; 227 ndb_filter_init(f); 228 229 argv += 2; 230 argc -= 2; 231 current_field = 0; 232 233 for (i = 0; argc && i < 1000; i++) { 234 if (!strcmp(argv[0], "-k")) { 235 if (current_field != NDB_FILTER_KINDS) { 236 ndb_filter_end_field(f); 237 ndb_filter_start_field(f, NDB_FILTER_KINDS); 238 } 239 current_field = NDB_FILTER_KINDS; 240 ndb_filter_add_int_element(f, atoll(argv[1])); 241 argv += 2; 242 argc -= 2; 243 } else if (!strcmp(argv[0], "-l")) { 244 limit = atol(argv[1]); 245 if (current_field) { 246 ndb_filter_end_field(f); 247 current_field = 0; 248 } 249 ndb_filter_start_field(f, NDB_FILTER_LIMIT); 250 current_field = NDB_FILTER_LIMIT; 251 ndb_filter_add_int_element(f, limit); 252 ndb_filter_end_field(f); 253 argv += 2; 254 argc -= 2; 255 } else if (!strcmp(argv[0], "-u")) { 256 if (current_field) { 257 ndb_filter_end_field(f); 258 current_field = 0; 259 } 260 ndb_filter_start_field(f, NDB_FILTER_UNTIL); 261 ndb_filter_add_int_element(f, atoll(argv[1])); 262 ndb_filter_end_field(f); 263 argv += 2; 264 argc -= 2; 265 } else if (!strcmp(argv[0], "-t")) { 266 if (current_field) { 267 ndb_filter_end_field(f); 268 current_field = 0; 269 } 270 ndb_filter_start_tag_field(f, 't'); 271 ndb_filter_add_str_element(f, argv[1]); 272 ndb_filter_end_field(f); 273 argv += 2; 274 argc -= 2; 275 } else if (!strcmp(argv[0], "-e")) { 276 if (current_field != 'e') { 277 if (!ndb_filter_start_tag_field(f, 'e')) { 278 fprintf(stderr, "field already started\n"); 279 res = 44; 280 goto cleanup; 281 } 282 } 283 current_field = 'e'; 284 285 if (len != 64 || !hex_decode(argv[1], 64, tmp_id, sizeof(tmp_id))) { 286 fprintf(stderr, "invalid hex id\n"); 287 res = 42; 288 goto cleanup; 289 } 290 291 if (!ndb_filter_add_id_element(f, tmp_id)) { 292 fprintf(stderr, "too many event ids\n"); 293 res = 43; 294 goto cleanup; 295 } 296 297 argv += 2; 298 argc -= 2; 299 } else if (!strcmp(argv[0], "-a")) { 300 if (current_field != NDB_FILTER_AUTHORS) 301 ndb_filter_start_field(f, NDB_FILTER_AUTHORS); 302 current_field = NDB_FILTER_AUTHORS; 303 304 len = strlen(argv[1]); 305 if (len != 64 || !hex_decode(argv[1], 64, tmp_id, sizeof(tmp_id))) { 306 fprintf(stderr, "invalid hex pubkey\n"); 307 res = 42; 308 goto cleanup; 309 } 310 311 if (!ndb_filter_add_id_element(f, tmp_id)) { 312 fprintf(stderr, "too many author pubkeys\n"); 313 res = 43; 314 goto cleanup; 315 } 316 317 argv += 2; 318 argc -= 2; 319 } 320 } 321 322 if (current_field) { 323 ndb_filter_end_field(f); 324 current_field = 0; 325 } 326 327 struct ndb_query_result results[10000]; 328 ndb_begin_query(ndb, &txn); 329 330 clock_gettime(CLOCK_MONOTONIC, &t1); 331 if (!ndb_query(&txn, f, 1, results, 10000, &count)) { 332 fprintf(stderr, "query error\n"); 333 } 334 clock_gettime(CLOCK_MONOTONIC, &t2); 335 336 nanos = (t2.tv_sec - t1.tv_sec) * (long)1e9 + (t2.tv_nsec - t1.tv_nsec); 337 338 fprintf(stderr, "%d results in %f ms\n", count, nanos/1000000.0); 339 for (i = 0; i < count; i++) { 340 print_note(results[i].note); 341 } 342 343 ndb_end_query(&txn); 344 345 } else if (argc == 3 && !strcmp(argv[1], "import")) { 346 if (!strcmp(argv[2], "-")) { 347 ndb_process_events_stream(ndb, stdin); 348 } else { 349 map_file(argv[2], &data, &data_len); 350 ndb_process_events(ndb, (const char *)data, data_len); 351 ndb_process_client_events(ndb, (const char *)data, data_len); 352 } 353 } else if (argc == 2 && !strcmp(argv[1], "print-search-keys")) { 354 ndb_begin_query(ndb, &txn); 355 ndb_print_search_keys(&txn); 356 ndb_end_query(&txn); 357 } else if (argc == 2 && !strcmp(argv[1], "print-kind-keys")) { 358 ndb_begin_query(ndb, &txn); 359 ndb_print_kind_keys(&txn); 360 ndb_end_query(&txn); 361 } else if (argc == 2 && !strcmp(argv[1], "print-tag-keys")) { 362 ndb_begin_query(ndb, &txn); 363 ndb_print_tag_index(&txn); 364 ndb_end_query(&txn); 365 } else if (argc == 3 && !strcmp(argv[1], "profile")) { 366 pk_str = argv[2]; 367 if (!hex_decode(pk_str, strlen(pk_str), tmp_id, sizeof(tmp_id))) { 368 fprintf(stderr, "failed to decode hex pubkey '%s'\n", pk_str); 369 res = 88; 370 goto cleanup; 371 } 372 ndb_begin_query(ndb, &txn); 373 if (!(ptr = ndb_get_profile_by_pubkey(&txn, tmp_id, &profile_len, &key))) { 374 ndb_end_query(&txn); 375 fprintf(stderr, "profile not found\n"); 376 res = 89; 377 goto cleanup; 378 } 379 ndb_end_query(&txn); 380 print_hex(ptr, profile_len); 381 printf("\n"); 382 } else { 383 ndb_destroy(ndb); 384 return usage(); 385 } 386 387 cleanup: 388 ndb_destroy(ndb); 389 return res; 390 }