wafsamba: use additional xml catalog file (bug #9512)
[Samba/gebeck_regimport.git] / lib / ntdb / doc / TDB_porting.txt
blob5daf94b74b9234caa6faa0586047338b6837ce1e
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
7   TDB_DATA.
9   Example:
10         #include <tdb.h>
11         #include <ntdb.h>
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.
18   Example:
19         #include <tdb.h>
20         #include <ntdb.h>
22         void tdb_example(struct tdb_context *tdb, TDB_DATA key, TDB_DATA d)
23         {
24                 if (tdb_store(tdb, key, d) == -1) {
25                         printf("store failed: %s\n", tdb_errorstr(tdb));
26                 }
27         }
29         void ntdb_example(struct ntdb_context *ntdb, NTDB_DATA key, NTDB_DATA d)
30         {
31                 enum NTDB_ERROR e;
33                 e = ntdb_store(ntdb, key, d);
34                 if (e) {
35                         printf("store failed: %s\n", ntdb_errorstr(e));
36                 }
37         }
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).
42   Example:
43         #include <tdb.h>
44         #include <ntdb.h>
46         void tdb_example(struct tdb_context *tdb, TDB_DATA key)
47         {
48                 TDB_DATA data;
50                 data = tdb_fetch(tdb, key);
51                 if (!data.dptr) {
52                         printf("fetch failed: %s\n", tdb_errorstr(tdb));
53                 }
54         }
56         void ntdb_example(struct ntdb_context *ntdb, NTDB_DATA key)
57         {
58                 NTDB_DATA data;
59                 enum NTDB_ERROR e;
61                 e = ntdb_fetch(ntdb, key, &data);
62                 if (e) {
63                         printf("fetch failed: %s\n", ntdb_errorstr(e));
64                 }
65         }
67 - ntdb's ntdb_nextkey() frees the old key's dptr, in tdb you needed to do
68   this manually.
70   Example:
71         #include <tdb.h>
72         #include <ntdb.h>
74         void tdb_example(struct tdb_context *tdb)
75         {
76                 TDB_DATA key, next, data;
78                 for (key = tdb_firstkey(tdb); key.dptr; key = next) {
79                         printf("Got key!\n");
80                         next = tdb_nextkey(tdb, key);
81                         free(key.dptr);
82                 }
83         }
86         void ntdb_example(struct ntdb_context *ntdb)
87         {
88                 NTDB_DATA k, data;
89                 enum NTDB_ERROR e;
91                 for (e = ntdb_firstkey(ntdb,&k); !e; e = ntdb_nextkey(ntdb,&k))
92                         printf("Got key!\n");
93         }
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.
98   Example:
99         #include <tdb.h>
100         #include <ntdb.h>
102         struct tdb_context *tdb_example(void)
103         {
104                 return tdb_open(NULL, 0, TDB_INTERNAL, O_RDWR, 0);
105         }
107         struct ntdb_context *ntdb_example(void)
108         {
109                 return ntdb_open("example", NTDB_INTERNAL, O_RDWR, 0);
110         }
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.
115   Example:
116         #include <tdb.h>
117         #include <ntdb.h>
119         /* Custom hash function */
120         static unsigned int my_tdb_hash_func(TDB_DATA *key)
121         {
122                 return key->dsize;
123         }
125         struct tdb_context *tdb_example(void)
126         {
127                 return tdb_open_ex("example.tdb", 0, TDB_DEFAULT,
128                                    O_CREAT|O_RDWR, 0600, NULL, my_hash_func);
129         }
131         /* Custom hash function */
132         static unsigned int my_ntdb_hash_func(const void *key, size_t len,
133                                               uint32_t seed, void *data)
134         {
135                 return len;
136         }
138         struct ntdb_context *ntdb_example(void)
139         {
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);
147         }
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.
152   Example:
153         #include <tdb.h>
154         #include <ntdb.h>
156         struct tdb_context *tdb_example(void)
157         {
158                 return tdb_open("example.tdb", 10007, TDB_DEFAULT,
159                                 O_CREAT|O_RDWR, 0600);
160         }
162         struct ntdb_context *ntdb_example(void)
163         {
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);
171         }
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.
178         #include <tdb.h>
179         #include <ntdb.h>
181         static void tdb_log(struct tdb_context *tdb,
182                             enum tdb_debug_level level, const char *fmt, ...)
183         {
184                 va_list ap;
185                 const char *name;
187                 switch (level) {
188                 case TDB_DEBUG_FATAL:
189                         fprintf(stderr, "FATAL: ");
190                         break;
191                 case TDB_DEBUG_ERROR:
192                         fprintf(stderr, "ERROR: ");
193                         break;
194                 case TDB_DEBUG_WARNING:
195                         fprintf(stderr, "WARNING: ");
196                         break;
197                 case TDB_DEBUG_TRACE:
198                         /* Don't print out tracing. */
199                         return;
200                 }
202                 name = tdb_name(tdb);
203                 if (!name) {
204                         name = "unnamed";
205                 }
207                 fprintf(stderr, "tdb(%s):", name);
209                 va_start(ap, fmt);
210                 vfprintf(stderr, fmt, ap);
211                 va_end(ap);
212         }
214         struct tdb_context *tdb_example(void)
215         {
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);
221         }
223         static void ntdb_log(struct ntdb_context *ntdb,
224                              enum ntdb_log_level level,
225                              enum NTDB_ERROR ecode,
226                              const char *message,
227                              void *data)
228         {
229                 switch (level) {
230                 case NTDB_LOG_ERROR:
231                         fprintf(stderr, "ERROR: ");
232                         break;
233                 case NTDB_LOG_USE_ERROR:
234                         /* We made a mistake, so abort. */
235                         abort();
236                         break;
237                 case NTDB_LOG_WARNING:
238                         fprintf(stderr, "WARNING: ");
239                         break;
240                 }
242                 fprintf(stderr, "ntdb(%s):%s:%s\n",
243                         ntdb_name(ntdb), ntdb_errorstr(ecode), message);
244         }
246         struct ntdb_context *ntdb_example(void)
247         {
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);
255         }
257 - ntdb provides ntdb_deq() for comparing two NTDB_DATA, and ntdb_mkdata() for
258   creating an NTDB_DATA.
260         #include <tdb.h>
261         #include <ntdb.h>
263         void tdb_example(struct tdb_context *tdb)
264         {
265                 TDB_DATA data, key;
267                 key.dsize = strlen("hello");
268                 key.dptr = "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");
273                 }
274                 free(data.dptr);
275         }
277         void ntdb_example(struct ntdb_context *ntdb)
278         {
279                 NTDB_DATA data, key;
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");
285                         }
286                         free(data.dptr);
287                 }
288         }
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.
297   Example:
298         #include <tdb.h>
299         #include <ntdb.h>
301         static int tdb_parser(TDB_DATA key, TDB_DATA data, void *private_data)
302         {
303                 TDB_DATA *expect = private_data;
305                 return data.dsize == expect->dsize
306                         && !memcmp(data.dptr, expect->dptr, data.dsize);
307         }
309         void tdb_example(struct tdb_context *tdb, TDB_DATA key, NTDB_DATA d)
310         {
311                 switch (tdb_parse_record(tdb, key, tdb_parser, &d)) {
312                 case -1:
313                         printf("parse failed: %s\n", tdb_errorstr(tdb));
314                         break;
315                 case 0:
316                         printf("data was different!\n");
317                         break;
318                 case 1:
319                         printf("data was same!\n");
320                         break;
321                 }
322         }
324         static int ntdb_parser(TDB_DATA key, TDB_DATA data, TDB_DATA *expect)
325         {
326                 return ntdb_deq(data, *expect);
327         }
329         void ntdb_example(struct ntdb_context *ntdb, NTDB_DATA key, NTDB_DATA d)
330         {
331                 enum NTDB_ERROR e;
333                 e = tdb_parse_record(tdb, key, tdb_parser, &d);
334                 switch (e) {
335                 case 0:
336                         printf("data was different!\n");
337                         break;
338                 case 1:
339                         printf("data was same!\n");
340                         break;
341                 default:
342                         printf("parse failed: %s\n", ntdb_errorstr(e));
343                         break;
344                 }
345         }
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.
350   Example:
351         #include <tdb.h>
352         #include <ntdb.h>
354         struct tdb_context *tdb_example(void)
355         {
356                 return tdb_open("example.tdb", 0, TDB_DEFAULT, O_RDONLY, 0);
357         }
359         struct ntdb_context *ntdb_example(void)
360         {
361                 return ntdb_open("example.ntdb", NTDB_NOLOCK, O_RDONLY, NULL);
362         }
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().
368         #include <tdb.h>
369         #include <ntdb.h>
371         void tdb_example(struct tdb_context *tdb, TDB_DATA key, TDB_DATA d)
372         {
373                 if (tdb_transaction_start(tdb) == -1) {
374                         printf("transaction failed: %s\n", tdb_errorstr(tdb));
375                         return;
376                 }
378                 if (tdb_store(tdb, key, d) == -1) {
379                         printf("store failed: %s\n", tdb_errorstr(tdb));
380                         return;
381                 }
382                 if (tdb_transaction_commit(tdb) == -1) {
383                         printf("commit failed: %s\n", tdb_errorstr(tdb));
384                 }
385         }
387         void ntdb_example(struct ntdb_context *ntdb, NTDB_DATA key, NTDB_DATA d)
388         {
389                 enum NTDB_ERROR e;
391                 e = ntdb_transaction_start(ntdb);
392                 if (e) {
393                         printf("transaction failed: %s\n", ntdb_errorstr(e));
394                         return;
395                 }
397                 e = ntdb_store(ntdb, key, d);
398                 if (e) {
399                         printf("store failed: %s\n", ntdb_errorstr(e));
400                         ntdb_transaction_cancel(ntdb);
401                 }
403                 e = ntdb_transaction_commit(ntdb);
404                 if (e) {
405                         printf("commit failed: %s\n", ntdb_errorstr(e));
406                 }
407         }
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
413   the parent exits.
415   Example:
417         #include <tdb.h>
418         #include <ntdb.h>
420         struct tdb_context *tdb_example(void)
421         {
422                 return tdb_open("example.tdb", 0, TDB_CLEAR_IF_FIRST,
423                                    O_CREAT|O_RDWR, 0600);
424         }
426         static enum NTDB_ERROR clear_if_first(int fd, void *unused)
427         {
428                 /* We hold a lock offset 4 always, so we can tell if
429                  * anyone else is. */
430                 struct flock fl;
432                 fl.l_type = F_WRLCK;
433                 fl.l_whence = SEEK_SET;
434                 fl.l_start = 4; /* ACTIVE_LOCK */
435                 fl.l_len = 1;
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) {
440                                 return NTDB_ERR_IO;
441                         }
442                 }
443                 fl.l_type = F_RDLCK;
444                 if (fcntl(fd, F_SETLKW, &fl) != 0) {
445                         return NTDB_ERR_IO;
446                 }
447                 return NTDB_SUCCESS;
448         }
450         struct ntdb_context *ntdb_example(void)
451         {
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);
460         }
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.