int main(int argc, char *argv[]) { unsigned int i; bool found[NUM_TESTS]; struct ntdb_context *ntdb; int flags[] = { NTDB_DEFAULT, NTDB_NOMMAP, NTDB_CONVERT, NTDB_NOMMAP|NTDB_CONVERT }; plan_tests(sizeof(flags) / sizeof(flags[0]) * 6 + 1); for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) { ntdb = ntdb_open("run-93-repack.ntdb", flags[i]|MAYBE_NOSYNC, O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr); ok1(ntdb); if (!ntdb) break; ok1(store_all(ntdb)); ok1(ntdb_repack(ntdb) == NTDB_SUCCESS); memset(found, 0, sizeof(found)); ok1(ntdb_check(ntdb, NULL, NULL) == NTDB_SUCCESS); ok1(ntdb_traverse(ntdb, mark_entry, found) == NUM_TESTS); ok1(is_all_set(found, NUM_TESTS)); ntdb_close(ntdb); } ok1(tap_log_messages == 0); return exit_status(); }
static int dump_ntdb(const char *fname, const char *keyname) { struct ntdb_context *ntdb; NTDB_DATA key, value; ntdb = ntdb_open(fname, 0, O_RDONLY, 0, NULL); if (!ntdb) { printf("Failed to open %s\n", fname); return 1; } if (!keyname) { ntdb_traverse(ntdb, traverse_fn, NULL); } else { key = ntdb_mkdata(keyname, strlen(keyname)); if (ntdb_fetch(ntdb, key, &value) != 0) { return 1; } else { print_data(value); free(value.dptr); } } return 0; }
int main(int argc, char *argv[]) { unsigned int i; struct agent *agent; struct ntdb_context *ntdb; NTDB_DATA d = ntdb_mkdata("hello", 5); const char filename[] = "run-remap-in-read_traverse.ntdb"; plan_tests(4); agent = prepare_external_agent(); ntdb = ntdb_open(filename, MAYBE_NOSYNC, O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr); ok1(external_agent_operation(agent, OPEN, filename) == SUCCESS); i = add_records_to_grow(agent, ntdb->file->fd, ntdb->file->map_size); /* Do a traverse. */ ok1(ntdb_traverse(ntdb, NULL, NULL) == i); /* Now store something! */ ok1(ntdb_store(ntdb, d, d, NTDB_INSERT) == 0); ok1(tap_log_messages == 0); ntdb_close(ntdb); free_external_agent(agent); return exit_status(); }
_PUBLIC_ enum NTDB_ERROR ntdb_repack(struct ntdb_context *ntdb) { struct ntdb_context *tmp_db; struct traverse_state state; state.error = ntdb_transaction_start(ntdb); if (state.error != NTDB_SUCCESS) { return state.error; } tmp_db = ntdb_open("tmpdb", NTDB_INTERNAL, O_RDWR|O_CREAT, 0, NULL); if (tmp_db == NULL) { state.error = ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR, __location__ " Failed to create tmp_db"); ntdb_transaction_cancel(ntdb); return state.error; } state.dest_db = tmp_db; if (ntdb_traverse(ntdb, repack_traverse, &state) < 0) { goto fail; } state.error = ntdb_wipe_all(ntdb); if (state.error != NTDB_SUCCESS) { goto fail; } state.dest_db = ntdb; if (ntdb_traverse(tmp_db, repack_traverse, &state) < 0) { goto fail; } ntdb_close(tmp_db); return ntdb_transaction_commit(ntdb); fail: ntdb_transaction_cancel(ntdb); ntdb_close(tmp_db); return state.error; }
static int db_ntdb_traverse_read(struct db_context *db, int (*f)(struct db_record *rec, void *private_data), void *private_data) { struct db_ntdb_ctx *db_ctx = talloc_get_type_abort(db->private_data, struct db_ntdb_ctx); struct db_ntdb_traverse_ctx ctx; int64_t ret; ctx.db = db; ctx.f = f; ctx.private_data = private_data; /* This is a bit of paranoia to check that f() isn't altering * database. */ if (ntdb_get_flags(db_ctx->ntdb) & NTDB_RDONLY) { ret = ntdb_traverse(db_ctx->ntdb, db_ntdb_traverse_read_func, &ctx); } else { ntdb_add_flag(db_ctx->ntdb, NTDB_RDONLY); ret = ntdb_traverse(db_ctx->ntdb, db_ntdb_traverse_read_func, &ctx); ntdb_remove_flag(db_ctx->ntdb, NTDB_RDONLY); } if (ret < 0) { return -1; } /* Make sure we don't truncate! */ if ((int)ret != ret) { ret = INT_MAX; } return ret; }
static int db_ntdb_traverse(struct db_context *db, int (*f)(struct db_record *rec, void *private_data), void *private_data) { struct db_ntdb_ctx *db_ctx = talloc_get_type_abort(db->private_data, struct db_ntdb_ctx); struct db_ntdb_traverse_ctx ctx; int64_t ret; ctx.db = db; ctx.f = f; ctx.private_data = private_data; ret = ntdb_traverse(db_ctx->ntdb, db_ntdb_traverse_func, &ctx); if (ret < 0) { return -1; } /* Make sure we don't truncate! */ if ((int)ret != ret) { ret = INT_MAX; } return ret; }
int main(int argc, char *argv[]) { unsigned int i, j, num = 1000, stage = 0, stopat = -1; int flags = NTDB_DEFAULT; bool transaction = false, summary = false; NTDB_DATA key, data; struct ntdb_context *ntdb; struct timeval start, stop; union ntdb_attribute seed, log; bool do_stats = false; enum NTDB_ERROR ecode; /* Try to keep benchmarks even. */ seed.base.attr = NTDB_ATTRIBUTE_SEED; seed.base.next = NULL; seed.seed.seed = 0; log.base.attr = NTDB_ATTRIBUTE_LOG; log.base.next = &seed; log.log.fn = ntdb_log; if (argv[1] && strcmp(argv[1], "--internal") == 0) { flags = NTDB_INTERNAL; argc--; argv++; } if (argv[1] && strcmp(argv[1], "--transaction") == 0) { transaction = true; argc--; argv++; } if (argv[1] && strcmp(argv[1], "--no-sync") == 0) { flags |= NTDB_NOSYNC; argc--; argv++; } if (argv[1] && strcmp(argv[1], "--summary") == 0) { summary = true; argc--; argv++; } if (argv[1] && strcmp(argv[1], "--stats") == 0) { do_stats = true; argc--; argv++; } ntdb = ntdb_open("/tmp/speed.ntdb", flags, O_RDWR|O_CREAT|O_TRUNC, 0600, &log); if (!ntdb) err(1, "Opening /tmp/speed.ntdb"); key.dptr = (void *)&i; key.dsize = sizeof(i); data = key; if (argv[1]) { num = atoi(argv[1]); argv++; argc--; } if (argv[1]) { stopat = atoi(argv[1]); argv++; argc--; } /* Add 1000 records. */ printf("Adding %u records: ", num); fflush(stdout); if (transaction && (ecode = ntdb_transaction_start(ntdb))) errx(1, "starting transaction: %s", ntdb_errorstr(ecode)); gettimeofday(&start, NULL); for (i = 0; i < num; i++) if ((ecode = ntdb_store(ntdb, key, data, NTDB_INSERT)) != 0) errx(1, "Inserting key %u in ntdb: %s", i, ntdb_errorstr(ecode)); gettimeofday(&stop, NULL); if (transaction && (ecode = ntdb_transaction_commit(ntdb))) errx(1, "committing transaction: %s", ntdb_errorstr(ecode)); printf(" %zu ns (%zu bytes)\n", normalize(&start, &stop, num), file_size()); if (ntdb_check(ntdb, NULL, NULL)) errx(1, "ntdb_check failed!"); if (summary) { char *sumstr = NULL; ntdb_summary(ntdb, NTDB_SUMMARY_HISTOGRAMS, &sumstr); printf("%s\n", sumstr); free(sumstr); } if (do_stats) dump_and_clear_stats(&ntdb, flags, &log); if (++stage == stopat) exit(0); /* Finding 1000 records. */ printf("Finding %u records: ", num); fflush(stdout); if (transaction && (ecode = ntdb_transaction_start(ntdb))) errx(1, "starting transaction: %s", ntdb_errorstr(ecode)); gettimeofday(&start, NULL); for (i = 0; i < num; i++) { NTDB_DATA dbuf; if ((ecode = ntdb_fetch(ntdb, key, &dbuf)) != NTDB_SUCCESS || *(int *)dbuf.dptr != i) { errx(1, "Fetching key %u in ntdb gave %u", i, ecode ? ecode : *(int *)dbuf.dptr); } } gettimeofday(&stop, NULL); if (transaction && (ecode = ntdb_transaction_commit(ntdb))) errx(1, "committing transaction: %s", ntdb_errorstr(ecode)); printf(" %zu ns (%zu bytes)\n", normalize(&start, &stop, num), file_size()); if (ntdb_check(ntdb, NULL, NULL)) errx(1, "ntdb_check failed!"); if (summary) { char *sumstr = NULL; ntdb_summary(ntdb, NTDB_SUMMARY_HISTOGRAMS, &sumstr); printf("%s\n", sumstr); free(sumstr); } if (do_stats) dump_and_clear_stats(&ntdb, flags, &log); if (++stage == stopat) exit(0); /* Missing 1000 records. */ printf("Missing %u records: ", num); fflush(stdout); if (transaction && (ecode = ntdb_transaction_start(ntdb))) errx(1, "starting transaction: %s", ntdb_errorstr(ecode)); gettimeofday(&start, NULL); for (i = num; i < num*2; i++) { NTDB_DATA dbuf; ecode = ntdb_fetch(ntdb, key, &dbuf); if (ecode != NTDB_ERR_NOEXIST) errx(1, "Fetching key %u in ntdb gave %s", i, ntdb_errorstr(ecode)); } gettimeofday(&stop, NULL); if (transaction && (ecode = ntdb_transaction_commit(ntdb))) errx(1, "committing transaction: %s", ntdb_errorstr(ecode)); printf(" %zu ns (%zu bytes)\n", normalize(&start, &stop, num), file_size()); if (ntdb_check(ntdb, NULL, NULL)) errx(1, "ntdb_check failed!"); if (summary) { char *sumstr = NULL; ntdb_summary(ntdb, NTDB_SUMMARY_HISTOGRAMS, &sumstr); printf("%s\n", sumstr); free(sumstr); } if (do_stats) dump_and_clear_stats(&ntdb, flags, &log); if (++stage == stopat) exit(0); /* Traverse 1000 records. */ printf("Traversing %u records: ", num); fflush(stdout); if (transaction && (ecode = ntdb_transaction_start(ntdb))) errx(1, "starting transaction: %s", ntdb_errorstr(ecode)); i = 0; gettimeofday(&start, NULL); if (ntdb_traverse(ntdb, count_record, &i) != num) errx(1, "Traverse returned wrong number of records"); if (i != (num - 1) * (num / 2)) errx(1, "Traverse tallied to %u", i); gettimeofday(&stop, NULL); if (transaction && (ecode = ntdb_transaction_commit(ntdb))) errx(1, "committing transaction: %s", ntdb_errorstr(ecode)); printf(" %zu ns (%zu bytes)\n", normalize(&start, &stop, num), file_size()); if (ntdb_check(ntdb, NULL, NULL)) errx(1, "ntdb_check failed!"); if (summary) { char *sumstr = NULL; ntdb_summary(ntdb, NTDB_SUMMARY_HISTOGRAMS, &sumstr); printf("%s\n", sumstr); free(sumstr); } if (do_stats) dump_and_clear_stats(&ntdb, flags, &log); if (++stage == stopat) exit(0); /* Delete 1000 records (not in order). */ printf("Deleting %u records: ", num); fflush(stdout); if (transaction && (ecode = ntdb_transaction_start(ntdb))) errx(1, "starting transaction: %s", ntdb_errorstr(ecode)); gettimeofday(&start, NULL); for (j = 0; j < num; j++) { i = (j + 100003) % num; if ((ecode = ntdb_delete(ntdb, key)) != NTDB_SUCCESS) errx(1, "Deleting key %u in ntdb: %s", i, ntdb_errorstr(ecode)); } gettimeofday(&stop, NULL); if (transaction && (ecode = ntdb_transaction_commit(ntdb))) errx(1, "committing transaction: %s", ntdb_errorstr(ecode)); printf(" %zu ns (%zu bytes)\n", normalize(&start, &stop, num), file_size()); if (ntdb_check(ntdb, NULL, NULL)) errx(1, "ntdb_check failed!"); if (summary) { char *sumstr = NULL; ntdb_summary(ntdb, NTDB_SUMMARY_HISTOGRAMS, &sumstr); printf("%s\n", sumstr); free(sumstr); } if (do_stats) dump_and_clear_stats(&ntdb, flags, &log); if (++stage == stopat) exit(0); /* Re-add 1000 records (not in order). */ printf("Re-adding %u records: ", num); fflush(stdout); if (transaction && (ecode = ntdb_transaction_start(ntdb))) errx(1, "starting transaction: %s", ntdb_errorstr(ecode)); gettimeofday(&start, NULL); for (j = 0; j < num; j++) { i = (j + 100003) % num; if ((ecode = ntdb_store(ntdb, key, data, NTDB_INSERT)) != 0) errx(1, "Inserting key %u in ntdb: %s", i, ntdb_errorstr(ecode)); } gettimeofday(&stop, NULL); if (transaction && (ecode = ntdb_transaction_commit(ntdb))) errx(1, "committing transaction: %s", ntdb_errorstr(ecode)); printf(" %zu ns (%zu bytes)\n", normalize(&start, &stop, num), file_size()); if (ntdb_check(ntdb, NULL, NULL)) errx(1, "ntdb_check failed!"); if (summary) { char *sumstr = NULL; ntdb_summary(ntdb, NTDB_SUMMARY_HISTOGRAMS, &sumstr); printf("%s\n", sumstr); free(sumstr); } if (do_stats) dump_and_clear_stats(&ntdb, flags, &log); if (++stage == stopat) exit(0); /* Append 1000 records. */ if (transaction && (ecode = ntdb_transaction_start(ntdb))) errx(1, "starting transaction: %s", ntdb_errorstr(ecode)); printf("Appending %u records: ", num); fflush(stdout); gettimeofday(&start, NULL); for (i = 0; i < num; i++) if ((ecode = ntdb_append(ntdb, key, data)) != NTDB_SUCCESS) errx(1, "Appending key %u in ntdb: %s", i, ntdb_errorstr(ecode)); gettimeofday(&stop, NULL); if (transaction && (ecode = ntdb_transaction_commit(ntdb))) errx(1, "committing transaction: %s", ntdb_errorstr(ecode)); printf(" %zu ns (%zu bytes)\n", normalize(&start, &stop, num), file_size()); if (ntdb_check(ntdb, NULL, NULL)) errx(1, "ntdb_check failed!"); if (summary) { char *sumstr = NULL; ntdb_summary(ntdb, NTDB_SUMMARY_HISTOGRAMS, &sumstr); printf("%s\n", sumstr); free(sumstr); } if (++stage == stopat) exit(0); /* Churn 1000 records: not in order! */ if (transaction && (ecode = ntdb_transaction_start(ntdb))) errx(1, "starting transaction: %s", ntdb_errorstr(ecode)); printf("Churning %u records: ", num); fflush(stdout); gettimeofday(&start, NULL); for (j = 0; j < num; j++) { i = (j + 1000019) % num; if ((ecode = ntdb_delete(ntdb, key)) != NTDB_SUCCESS) errx(1, "Deleting key %u in ntdb: %s", i, ntdb_errorstr(ecode)); i += num; if ((ecode = ntdb_store(ntdb, key, data, NTDB_INSERT)) != 0) errx(1, "Inserting key %u in ntdb: %s", i, ntdb_errorstr(ecode)); } gettimeofday(&stop, NULL); if (transaction && (ecode = ntdb_transaction_commit(ntdb))) errx(1, "committing transaction: %s", ntdb_errorstr(ecode)); printf(" %zu ns (%zu bytes)\n", normalize(&start, &stop, num), file_size()); if (ntdb_check(ntdb, NULL, NULL)) errx(1, "ntdb_check failed!"); if (summary) { char *sumstr = NULL; ntdb_summary(ntdb, NTDB_SUMMARY_HISTOGRAMS, &sumstr); printf("%s\n", sumstr); free(sumstr); } if (do_stats) dump_and_clear_stats(&ntdb, flags, &log); if (++stage == stopat) exit(0); return 0; }
static int do_command(void) { COMMAND_TABLE *ctp = cmd_table; enum commands mycmd = CMD_HELP; int cmd_len; if (cmdname && strlen(cmdname) == 0) { mycmd = CMD_NEXT; } else { while (ctp->name) { cmd_len = strlen(ctp->name); if (strncmp(ctp->name,cmdname,cmd_len) == 0) { mycmd = ctp->cmd; break; } ctp++; } } switch (mycmd) { case CMD_CREATE_NTDB: bIterate = 0; create_ntdb(arg1); return 0; case CMD_OPEN_NTDB: bIterate = 0; open_ntdb(arg1); return 0; case CMD_SYSTEM: /* Shell command */ if (system(arg1) == -1) { terror(NTDB_SUCCESS, "system() call failed\n"); } return 0; case CMD_QUIT: return 1; default: /* all the rest require a open database */ if (!ntdb) { bIterate = 0; terror(NTDB_SUCCESS, "database not open"); help(); return 0; } switch (mycmd) { case CMD_TRANSACTION_START: bIterate = 0; ntdb_transaction_start(ntdb); return 0; case CMD_TRANSACTION_COMMIT: bIterate = 0; ntdb_transaction_commit(ntdb); return 0; case CMD_TRANSACTION_CANCEL: bIterate = 0; ntdb_transaction_cancel(ntdb); return 0; case CMD_ERASE: bIterate = 0; ntdb_traverse(ntdb, do_delete_fn, NULL); return 0; case CMD_DUMP: bIterate = 0; ntdb_traverse(ntdb, print_rec, NULL); return 0; case CMD_INSERT: bIterate = 0; insert_ntdb(arg1, arg1len,arg2,arg2len); return 0; case CMD_MOVE: bIterate = 0; move_rec(arg1,arg1len,arg2); return 0; case CMD_STORE: bIterate = 0; store_ntdb(arg1,arg1len,arg2,arg2len); return 0; case CMD_SHOW: bIterate = 0; show_ntdb(arg1, arg1len); return 0; case CMD_KEYS: ntdb_traverse(ntdb, print_key, NULL); return 0; case CMD_HEXKEYS: ntdb_traverse(ntdb, print_hexkey, NULL); return 0; case CMD_DELETE: bIterate = 0; delete_ntdb(arg1,arg1len); return 0; #if 0 case CMD_LIST_HASH_FREE: ntdb_dump_all(ntdb); return 0; case CMD_LIST_FREE: ntdb_printfreelist(ntdb); return 0; #endif case CMD_INFO: info_ntdb(); return 0; case CMD_SPEED: speed_ntdb(arg1); return 0; case CMD_MMAP: toggle_mmap(); return 0; case CMD_FIRST: bIterate = 1; first_record(ntdb, &iterate_kbuf); return 0; case CMD_NEXT: if (bIterate) next_record(ntdb, &iterate_kbuf); return 0; case CMD_CHECK: check_db(ntdb); return 0; case CMD_HELP: help(); return 0; case CMD_CREATE_NTDB: case CMD_OPEN_NTDB: case CMD_SYSTEM: case CMD_QUIT: /* * unhandled commands. cases included here to avoid compiler * warnings. */ return 0; } } return 0; }
static void speed_ntdb(const char *tlimit) { unsigned timelimit = tlimit?atoi(tlimit):0; double t; int ops; if (timelimit == 0) timelimit = 5; ops = 0; printf("Testing store speed for %u seconds\n", timelimit); _start_timer(); do { long int r = random(); NTDB_DATA key, dbuf; key = ntdb_mkdata("store test", strlen("store test")); dbuf.dptr = (unsigned char *)&r; dbuf.dsize = sizeof(r); ntdb_store(ntdb, key, dbuf, NTDB_REPLACE); t = _end_timer(); ops++; } while (t < timelimit); printf("%10.3f ops/sec\n", ops/t); ops = 0; printf("Testing fetch speed for %u seconds\n", timelimit); _start_timer(); do { long int r = random(); NTDB_DATA key, dbuf; key = ntdb_mkdata("store test", strlen("store test")); dbuf.dptr = (unsigned char *)&r; dbuf.dsize = sizeof(r); ntdb_fetch(ntdb, key, &dbuf); t = _end_timer(); ops++; } while (t < timelimit); printf("%10.3f ops/sec\n", ops/t); ops = 0; printf("Testing transaction speed for %u seconds\n", timelimit); _start_timer(); do { long int r = random(); NTDB_DATA key, dbuf; key = ntdb_mkdata("transaction test", strlen("transaction test")); dbuf.dptr = (unsigned char *)&r; dbuf.dsize = sizeof(r); ntdb_transaction_start(ntdb); ntdb_store(ntdb, key, dbuf, NTDB_REPLACE); ntdb_transaction_commit(ntdb); t = _end_timer(); ops++; } while (t < timelimit); printf("%10.3f ops/sec\n", ops/t); ops = 0; printf("Testing traverse speed for %u seconds\n", timelimit); _start_timer(); do { ntdb_traverse(ntdb, traverse_fn, NULL); t = _end_timer(); ops++; } while (t < timelimit); printf("%10.3f ops/sec\n", ops/t); }
int main(int argc, char *argv[]) { unsigned int i, j; int num; struct trav_data td; NTDB_DATA k; struct ntdb_context *ntdb; union ntdb_attribute seed_attr; enum NTDB_ERROR ecode; int flags[] = { NTDB_INTERNAL, NTDB_DEFAULT, NTDB_NOMMAP, NTDB_INTERNAL|NTDB_CONVERT, NTDB_CONVERT, NTDB_NOMMAP|NTDB_CONVERT }; seed_attr.base.attr = NTDB_ATTRIBUTE_SEED; seed_attr.base.next = &tap_log_attr; seed_attr.seed.seed = 6334326220117065685ULL; plan_tests(sizeof(flags) / sizeof(flags[0]) * (NUM_RECORDS*6 + (NUM_RECORDS-1)*3 + 22) + 1); for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) { ntdb = ntdb_open("api-firstkey-nextkey.ntdb", flags[i]|MAYBE_NOSYNC, O_RDWR|O_CREAT|O_TRUNC, 0600, &seed_attr); ok1(ntdb); if (!ntdb) continue; ok1(ntdb_firstkey(ntdb, &k) == NTDB_ERR_NOEXIST); /* One entry... */ k.dptr = (unsigned char *)# k.dsize = sizeof(num); num = 0; ok1(ntdb_store(ntdb, k, k, NTDB_INSERT) == 0); ok1(ntdb_firstkey(ntdb, &k) == NTDB_SUCCESS); ok1(k.dsize == sizeof(num)); ok1(memcmp(k.dptr, &num, sizeof(num)) == 0); ok1(ntdb_nextkey(ntdb, &k) == NTDB_ERR_NOEXIST); /* Two entries. */ k.dptr = (unsigned char *)# k.dsize = sizeof(num); num = 1; ok1(ntdb_store(ntdb, k, k, NTDB_INSERT) == 0); ok1(ntdb_firstkey(ntdb, &k) == NTDB_SUCCESS); ok1(k.dsize == sizeof(num)); memcpy(&num, k.dptr, sizeof(num)); ok1(num == 0 || num == 1); ok1(ntdb_nextkey(ntdb, &k) == NTDB_SUCCESS); ok1(k.dsize == sizeof(j)); memcpy(&j, k.dptr, sizeof(j)); ok1(j == 0 || j == 1); ok1(j != num); ok1(ntdb_nextkey(ntdb, &k) == NTDB_ERR_NOEXIST); /* Clean up. */ k.dptr = (unsigned char *)# k.dsize = sizeof(num); num = 0; ok1(ntdb_delete(ntdb, k) == 0); num = 1; ok1(ntdb_delete(ntdb, k) == 0); /* Now lots of records. */ ok1(store_records(ntdb)); td.calls = 0; num = ntdb_traverse(ntdb, trav, &td); ok1(num == NUM_RECORDS); ok1(td.calls == NUM_RECORDS); /* Simple loop should match ntdb_traverse */ for (j = 0, ecode = ntdb_firstkey(ntdb, &k); j < td.calls; j++) { int val; ok1(ecode == NTDB_SUCCESS); ok1(k.dsize == sizeof(val)); memcpy(&val, k.dptr, k.dsize); ok1(td.records[j] == val); ecode = ntdb_nextkey(ntdb, &k); } /* But arbitrary orderings should work too. */ for (j = td.calls-1; j > 0; j--) { k.dptr = (unsigned char *)&td.records[j-1]; k.dsize = sizeof(td.records[j-1]); k = dup_key(k); ok1(ntdb_nextkey(ntdb, &k) == NTDB_SUCCESS); ok1(k.dsize == sizeof(td.records[j])); ok1(memcmp(k.dptr, &td.records[j], k.dsize) == 0); free(k.dptr); } /* Even delete should work. */ for (j = 0, ecode = ntdb_firstkey(ntdb, &k); ecode != NTDB_ERR_NOEXIST; j++) { ok1(ecode == NTDB_SUCCESS); ok1(k.dsize == 4); ok1(ntdb_delete(ntdb, k) == 0); ecode = ntdb_nextkey(ntdb, &k); } diag("delete using first/nextkey gave %u of %u records", j, NUM_RECORDS); ok1(j == NUM_RECORDS); ntdb_close(ntdb); } ok1(tap_log_messages == 0); return exit_status(); }