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