1 Interface differences between TDB and NTDB.
3 - ntdb shares 'struct TDB_DATA' with tdb, but TDB defines the TDB_DATA
4 typedef, whereas ntdb defines NTDB_DATA (ie. both are compatible).
5 If you include both ntdb.h and tdb.h, #include tdb.h first,
6 otherwise you'll get a compile error when tdb.h re-defined struct
13 - ntdb functions return NTDB_SUCCESS (ie 0) on success, and a negative
14 error on failure, whereas tdb functions returned 0 on success, and
15 -1 on failure. tdb then used tdb_error() to determine the error;
16 this API is nasty if we ever want to support threads, so is not supported.
22 void tdb_example(struct tdb_context *tdb, TDB_DATA key, TDB_DATA d)
24 if (tdb_store(tdb, key, d) == -1) {
25 printf("store failed: %s\n", tdb_errorstr(tdb));
29 void ntdb_example(struct ntdb_context *ntdb, NTDB_DATA key, NTDB_DATA d)
33 e = ntdb_store(ntdb, key, d);
35 printf("store failed: %s\n", ntdb_errorstr(e));
39 - ntdb's ntdb_fetch() returns an error, tdb's returned the data directly
40 (or tdb_null, and you were supposed to check tdb_error() to find out why).
46 void tdb_example(struct tdb_context *tdb, TDB_DATA key)
50 data = tdb_fetch(tdb, key);
52 printf("fetch failed: %s\n", tdb_errorstr(tdb));
56 void ntdb_example(struct ntdb_context *ntdb, NTDB_DATA key)
61 e = ntdb_fetch(ntdb, key, &data);
63 printf("fetch failed: %s\n", ntdb_errorstr(e));
67 - ntdb's ntdb_nextkey() frees the old key's dptr, in tdb you needed to do
74 void tdb_example(struct tdb_context *tdb)
76 TDB_DATA key, next, data;
78 for (key = tdb_firstkey(tdb); key.dptr; key = next) {
80 next = tdb_nextkey(tdb, key);
86 void ntdb_example(struct ntdb_context *ntdb)
91 for (e = ntdb_firstkey(ntdb,&k); !e; e = ntdb_nextkey(ntdb,&k))
95 - Unlike tdb_open/tdb_open_ex, ntdb_open does not allow NULL names,
96 even for NTDB_INTERNAL dbs, and thus ntdb_name() never returns NULL.
102 struct tdb_context *tdb_example(void)
104 return tdb_open(NULL, 0, TDB_INTERNAL, O_RDWR, 0);
107 struct ntdb_context *ntdb_example(void)
109 return ntdb_open("example", NTDB_INTERNAL, O_RDWR, 0);
112 - ntdb uses a linked list of attribute structures to implement logging and
113 alternate hashes. tdb used tdb_open_ex, which was not extensible.
119 /* Custom hash function */
120 static unsigned int my_tdb_hash_func(TDB_DATA *key)
125 struct tdb_context *tdb_example(void)
127 return tdb_open_ex("example.tdb", 0, TDB_DEFAULT,
128 O_CREAT|O_RDWR, 0600, NULL, my_hash_func);
131 /* Custom hash function */
132 static unsigned int my_ntdb_hash_func(const void *key, size_t len,
133 uint32_t seed, void *data)
138 struct ntdb_context *ntdb_example(void)
140 union ntdb_attribute hash;
142 hash.base.attr = NTDB_ATTRIBUTE_HASH;
143 hash.base.next = NULL;
144 hash.hash.fn = my_ntdb_hash_func;
145 return ntdb_open("example.ntdb", NTDB_DEFAULT,
146 O_CREAT|O_RDWR, 0600, &hash);
149 - tdb's tdb_open/tdb_open_ex took an explicit hash size, defaulting to
150 131. ntdb's uses an attribute for this, defaulting to 8192.
156 struct tdb_context *tdb_example(void)
158 return tdb_open("example.tdb", 10007, TDB_DEFAULT,
159 O_CREAT|O_RDWR, 0600);
162 struct ntdb_context *ntdb_example(void)
164 union ntdb_attribute hashsize;
166 hashsize.base.attr = NTDB_ATTRIBUTE_HASHSIZE;
167 hashsize.base.next = NULL;
168 hashsize.hashsize.size = 16384;
169 return ntdb_open("example.ntdb", NTDB_DEFAULT,
170 O_CREAT|O_RDWR, 0600, &hashsize);
173 - ntdb's log function is simpler than tdb's log function. The string
174 is already formatted, is not terminated by a '\n', and it takes an
175 enum ntdb_log_level not a tdb_debug_level, and which has only three
176 values: NTDB_LOG_ERROR, NTDB_LOG_USE_ERROR and NTDB_LOG_WARNING.
181 static void tdb_log(struct tdb_context *tdb,
182 enum tdb_debug_level level, const char *fmt, ...)
188 case TDB_DEBUG_FATAL:
189 fprintf(stderr, "FATAL: ");
191 case TDB_DEBUG_ERROR:
192 fprintf(stderr, "ERROR: ");
194 case TDB_DEBUG_WARNING:
195 fprintf(stderr, "WARNING: ");
197 case TDB_DEBUG_TRACE:
198 /* Don't print out tracing. */
202 name = tdb_name(tdb);
207 fprintf(stderr, "tdb(%s):", name);
210 vfprintf(stderr, fmt, ap);
214 struct tdb_context *tdb_example(void)
216 struct tdb_logging_context lctx;
218 lctx.log_fn = tdb_log;
219 return tdb_open_ex("example.tdb", 0, TDB_DEFAULT,
220 O_CREAT|O_RDWR, 0600, &lctx, NULL);
223 static void ntdb_log(struct ntdb_context *ntdb,
224 enum ntdb_log_level level,
225 enum NTDB_ERROR ecode,
231 fprintf(stderr, "ERROR: ");
233 case NTDB_LOG_USE_ERROR:
234 /* We made a mistake, so abort. */
237 case NTDB_LOG_WARNING:
238 fprintf(stderr, "WARNING: ");
242 fprintf(stderr, "ntdb(%s):%s:%s\n",
243 ntdb_name(ntdb), ntdb_errorstr(ecode), message);
246 struct ntdb_context *ntdb_example(void)
248 union ntdb_attribute log;
250 log.base.attr = NTDB_ATTRIBUTE_LOG;
251 log.base.next = NULL;
252 log.log.fn = ntdb_log;
253 return ntdb_open("example.ntdb", NTDB_DEFAULT,
254 O_CREAT|O_RDWR, 0600, &log);
257 - ntdb provides ntdb_deq() for comparing two NTDB_DATA, and ntdb_mkdata() for
258 creating an NTDB_DATA.
263 void tdb_example(struct tdb_context *tdb)
267 key.dsize = strlen("hello");
269 data = tdb_fetch(tdb, key);
270 if (data.dsize == key.dsize
271 && !memcmp(data.dptr, key.dptr, key.dsize))
272 printf("key is same as data\n");
277 void ntdb_example(struct ntdb_context *ntdb)
281 key = ntdb_mkdata("hello", strlen("hello"));
282 if (ntdb_fetch(ntdb, key, &data) == NTDB_SUCCESS) {
283 if (ntdb_deq(key, data)) {
284 printf("key is same as data\n");
290 - ntdb's ntdb_parse_record() takes a type-checked callback data
291 pointer, not a void * (though a void * pointer still works). The
292 callback function is allowed to do read operations on the database,
293 or write operations if you first call ntdb_lockall(). TDB's
294 tdb_parse_record() did not allow any database access within the
295 callback, could crash if you tried.
301 static int tdb_parser(TDB_DATA key, TDB_DATA data, void *private_data)
303 TDB_DATA *expect = private_data;
305 return data.dsize == expect->dsize
306 && !memcmp(data.dptr, expect->dptr, data.dsize);
309 void tdb_example(struct tdb_context *tdb, TDB_DATA key, NTDB_DATA d)
311 switch (tdb_parse_record(tdb, key, tdb_parser, &d)) {
313 printf("parse failed: %s\n", tdb_errorstr(tdb));
316 printf("data was different!\n");
319 printf("data was same!\n");
324 static int ntdb_parser(TDB_DATA key, TDB_DATA data, TDB_DATA *expect)
326 return ntdb_deq(data, *expect);
329 void ntdb_example(struct ntdb_context *ntdb, NTDB_DATA key, NTDB_DATA d)
333 e = tdb_parse_record(tdb, key, tdb_parser, &d);
336 printf("data was different!\n");
339 printf("data was same!\n");
342 printf("parse failed: %s\n", ntdb_errorstr(e));
347 - ntdb does locking on read-only databases (ie. O_RDONLY passed to ntdb_open).
348 tdb did not: use the NTDB_NOLOCK flag if you want to suppress locking.
354 struct tdb_context *tdb_example(void)
356 return tdb_open("example.tdb", 0, TDB_DEFAULT, O_RDONLY, 0);
359 struct ntdb_context *ntdb_example(void)
361 return ntdb_open("example.ntdb", NTDB_NOLOCK, O_RDONLY, NULL);
364 - Failure inside a transaction (such as a lock function failing) does
365 not implicitly cancel the transaction; you still need to call
366 ntdb_transaction_cancel().
371 void tdb_example(struct tdb_context *tdb, TDB_DATA key, TDB_DATA d)
373 if (tdb_transaction_start(tdb) == -1) {
374 printf("transaction failed: %s\n", tdb_errorstr(tdb));
378 if (tdb_store(tdb, key, d) == -1) {
379 printf("store failed: %s\n", tdb_errorstr(tdb));
382 if (tdb_transaction_commit(tdb) == -1) {
383 printf("commit failed: %s\n", tdb_errorstr(tdb));
387 void ntdb_example(struct ntdb_context *ntdb, NTDB_DATA key, NTDB_DATA d)
391 e = ntdb_transaction_start(ntdb);
393 printf("transaction failed: %s\n", ntdb_errorstr(e));
397 e = ntdb_store(ntdb, key, d);
399 printf("store failed: %s\n", ntdb_errorstr(e));
400 ntdb_transaction_cancel(ntdb);
403 e = ntdb_transaction_commit(ntdb);
405 printf("commit failed: %s\n", ntdb_errorstr(e));
409 - There is no NTDB_CLEAR_IF_FIRST flag; it has severe scalability and
410 API problems. If necessary, you can emulate this by using the open
411 hook and placing a 1-byte lock at offset 4. If your program forks
412 and exits, you will need to place this lock again in the child before
420 struct tdb_context *tdb_example(void)
422 return tdb_open("example.tdb", 0, TDB_CLEAR_IF_FIRST,
423 O_CREAT|O_RDWR, 0600);
426 static enum NTDB_ERROR clear_if_first(int fd, void *unused)
428 /* We hold a lock offset 4 always, so we can tell if
433 fl.l_whence = SEEK_SET;
434 fl.l_start = 4; /* ACTIVE_LOCK */
437 if (fcntl(fd, F_SETLK, &fl) == 0) {
438 /* We must be first ones to open it! Clear it. */
439 if (ftruncate(fd, 0) != 0) {
444 if (fcntl(fd, F_SETLKW, &fl) != 0) {
450 struct ntdb_context *ntdb_example(void)
452 union ntdb_attribute open_attr;
454 open_attr.openhook.base.attr = NTDB_ATTRIBUTE_OPENHOOK;
455 open_attr.openhook.base.next = NULL;
456 open_attr.openhook.fn = clear_if_first;
458 return ntdb_open("example.ntdb", NTDB_DEFAULT,
459 O_CREAT|O_RDWR, 0600, &open_attr);
462 - ntdb traversals are not reliable if the database is changed during
463 the traversal, ie your traversal may not cover all elements, or may
464 cover elements multiple times. As a special exception, deleting the
465 current record within ntdb_traverse() is reliable.
467 - There is no ntdb_traverse_read, since ntdb_traverse does not hold
468 a lock across the entire traversal anyway. If you want to make sure
469 that your traversal function does not write to the database, you can
470 set and clear the NTDB_RDONLY flag around the traversal.
472 - ntdb does not need tdb_reopen() or tdb_reopen_all(). If you call
473 fork() after during certain operations the child should close the
474 ntdb, or complete the operations before continuing to use the tdb:
476 ntdb_transaction_start(): child must ntdb_transaction_cancel()
477 ntdb_lockall(): child must call ntdb_unlockall()
478 ntdb_lockall_read(): child must call ntdb_unlockall_read()
479 ntdb_chainlock(): child must call ntdb_chainunlock()
480 ntdb_parse() callback: child must return from ntdb_parse()
482 - ntdb will not open a non-ntdb file, even if O_CREAT is specified. tdb
483 will overwrite an unknown file in that case.