3 # See the file LICENSE for redistribution information.
5 # Copyright (c) 1996-2009 Oracle. All rights reserved.
10 # This awk script generates all the log, print, and read routines for the DB
11 # logging. It also generates a template for the recovery functions (these
12 # functions must still be edited, but are highly stylized and the initial
13 # template gets you a fair way along the path).
15 # For a given file prefix.src, we generate a file prefix_auto.c, and a file
16 # prefix_auto.h that contains:
18 # external declarations for the file's functions
19 # defines for the physical record types
20 # (logical types are defined in each subsystem manually)
21 # structures to contain the data unmarshalled from the log.
23 # This awk script requires that four variables be set when it is called:
25 # source_file -- the C source file being created
26 # header_file -- the C #include file being created
27 # template_file -- the template file being created
29 # And stdin must be the input file that defines the recovery setup.
31 # Within each file prefix.src, we use a number of public keywords (documented
32 # in the reference guide) as well as the following ones which are private to
34 # DBPRIVATE Indicates that a file will be built as part of DB,
35 # rather than compiled independently, and so can use
36 # DB-private interfaces (such as DB_LOG_NOCOPY).
37 # DB A DB handle. Logs the dbreg fileid for that handle,
38 # and makes the *_log interface take a DB * instead of a
40 # PGDBT Just like DBT, only we know it stores a page or page
41 # header, so we can byte-swap it (once we write the
42 # byte-swapping code, which doesn't exist yet).
43 # LOCKS Just like DBT, but uses a print function for locks.
46 if (source_file == "" ||
47 header_file == "" || template_file == "") {
48 print "Usage: gen_rec.awk requires three variables to be set:"
49 print "\theader_file\t-- the recover #include file being created"
50 print "\tprint_file\t-- the print source file being created"
51 print "\tsource_file\t-- the recover source file being created"
52 print "\ttemplate_file\t-- the template file being created"
61 # These are the variables we use to create code that calls into
62 # db routines and/or uses an environment.
66 log_call = "dbenv->log_put"
73 log_call = "__log_put"
80 printf("/* Do not edit: automatically built by gen_rec.awk. */\n\n")\
82 printf("#include \"db_config.h\"\n") >> CFILE
84 printf("#include <errno.h>\n") >> CFILE
85 printf("#include <stdlib.h>\n") >> CFILE
86 printf("#include <string.h>\n") >> CFILE
87 printf("#include \"db.h\"\n") >> CFILE
88 printf("#include \"db_int.h\"\n") >> CFILE
89 printf("#include \"dbinc/db_swap.h\"\n") >> CFILE
92 printf("/* Do not edit: automatically built by gen_rec.awk. */\n\n")\
94 printf("#include \"db_config.h\"\n\n") >> PFILE
96 printf("#include <ctype.h>\n") >> PFILE
97 printf("#include <stdio.h>\n") >> PFILE
98 printf("#include <stdlib.h>\n") >> PFILE
99 printf("#include \"db.h\"\n") >> PFILE
102 if (prefix == "__ham")
103 printf("#ifdef HAVE_HASH\n") >> PFILE
104 if (prefix == "__qam")
105 printf("#ifdef HAVE_QUEUE\n") >> PFILE
107 # Start .h file, make the entire file conditional.
108 printf("/* Do not edit: automatically built by gen_rec.awk. */\n\n")\
110 printf("#ifndef\t%s_AUTO_H\n#define\t%s_AUTO_H\n", prefix, prefix)\
113 # Write recovery template file headers
115 # This assumes we're doing DB recovery.
116 printf("#include \"db_config.h\"\n\n") > TFILE
117 printf("#include \"db_int.h\"\n") >> TFILE
118 printf("#include \"dbinc/db_page.h\"\n") >> TFILE
119 printf("#include \"dbinc/%s.h\"\n", prefix) >> TFILE
120 printf("#include \"dbinc/log.h\"\n\n") >> TFILE
122 printf("#include \"db.h\"\n\n") > TFILE
126 for (i = 2; i < NF; i++)
127 printf("%s ", $i) >> CFILE
128 printf("%s\n", $i) >> CFILE
129 for (i = 2; i < NF; i++)
130 printf("%s ", $i) >> PFILE
131 printf("%s\n", $i) >> PFILE
133 /^[ ]*(BEGIN|BEGIN_COMPAT)/ {
135 print "Invalid format: missing END statement"
146 # BEGIN_COMPAT does not need logging function or rec table entry.
148 need_log_function = ($1 == "BEGIN");
149 is_compat = ($1 == "BEGIN_COMPAT");
158 make_name(thisfunc, thisfunc, version);
160 /^[ ]*(DB|ARG|DBT|LOCKS|PGDBT|PGDDBT|POINTER|TIME)/ {
164 formats[nvars] = $NF;
165 for (i = 4; i < NF; i++)
166 types[nvars] = sprintf("%s %s", types[nvars], $i);
172 if ($1 == "DB" || $1 == "ARG" || $1 == "TIME") {
173 sizes[nvars] = sprintf("sizeof(u_int32_t)");
174 if ($3 != "u_int32_t")
176 } else if ($1 == "POINTER")
177 sizes[nvars] = sprintf("sizeof(*%s)", $2);
178 else { # DBT, PGDBT, PGDDBT
180 sprintf("sizeof(u_int32_t) + (%s == NULL ? 0 : %s->size)",\
184 hdrdbt = vars[nvars];
185 else if ($1 == "PGDDBT")
193 old_logfunc = logfunc;
194 old_funcname = funcname;
195 make_name($2, funcname, $3);
196 internal_name = sprintf("%s_%s_int", prefix, thisfunc);
197 dup_logfunc = logfunc;
198 dup_funcname = funcname;
200 logfunc = old_logfunc;
201 funcname = old_funcname;
205 print "Invalid format: missing BEGIN statement"
209 # Declare the record type.
210 printf("#define\tDB_%s\t%d\n", funcname, rectype) >> HFILE
212 printf("#define\tDB_%s\t%d\n",\
213 dup_funcname, dup_rectype) >> HFILE
215 # Structure declaration.
216 printf("typedef struct _%s_args {\n", funcname) >> HFILE
218 # Here are the required fields for every structure
219 printf("\tu_int32_t type;\n\tDB_TXN *txnp;\n") >> HFILE
220 printf("\tDB_LSN prev_lsn;\n") >>HFILE
222 # Here are the specified fields.
223 for (i = 0; i < nvars; i++) {
225 if (modes[i] == "POINTER") {
227 t = substr(types[i], 1, ndx - 2);
229 printf("\t%s\t%s;\n", t, vars[i]) >> HFILE
231 printf("} %s_args;\n\n", funcname) >> HFILE
233 # Output the read, log, and print functions (note that we must
234 # generate the required read function first, because we use its
235 # prototype in the print function).
239 if (need_log_function) {
246 f = "template/rec_ctemp"
248 f = "template/rec_utemp"
251 "sed -e s/PREF/%s/ -e s/FUNC/%s/ -e s/DUP/%s/ < template/rec_%s >> %s",
252 prefix, thisfunc, dup_thisfunc,
253 dbprivate ? "ctemp" : "utemp", TFILE)
256 # Done writing stuff, reset and continue.
261 # End the conditional for the HFILE
262 printf("#endif\n") >> HFILE
264 # Print initialization routine; function prototype
265 p[1] = sprintf("int %s_init_print %s%s%s", prefix,
266 "__P((", env_type, " *, DB_DISTAB *));");
268 proto_format(p, PFILE);
270 # Create the routine to call __db_add_recovery(print_fn, id)
271 printf("int\n%s_init_print(%s, dtabp)\n",\
272 prefix, env_var) >> PFILE
273 printf("\t%s *%s;\n", env_type, env_var) >> PFILE
274 printf("\tDB_DISTAB *dtabp;\n{\n") >> PFILE
275 # If application-specific, the user will need a prototype for
276 # __db_add_recovery, since they won't have DB's.
279 "\tint __db_add_recovery __P((%s *, DB_DISTAB *,\n",\
282 "\t int (*)(%s *, DBT *, DB_LSN *, db_recops), u_int32_t));\n",\
286 printf("\tint ret;\n\n") >> PFILE
287 for (i = 0; i < num_funcs; i++) {
288 if (functable[i] == 1)
290 printf("\tif ((ret = __db_add_recovery%s(%s, ",\
291 dbprivate ? "_int" : "", env_var) >> PFILE
292 printf("dtabp,\n") >> PFILE
293 printf("\t %s_print, DB_%s)) != 0)\n",\
294 dupfuncs[i], funcs[i]) >> PFILE
295 printf("\t\treturn (ret);\n") >> PFILE
297 printf("\treturn (0);\n}\n") >> PFILE
298 if (prefix == "__ham")
299 printf("#endif /* HAVE_HASH */\n") >> PFILE
300 if (prefix == "__qam")
301 printf("#endif /* HAVE_QUEUE */\n") >> PFILE
303 # We only want to generate *_init_recover functions if this is a
304 # DB-private, rather than application-specific, set of recovery
305 # functions. Application-specific recovery functions should be
306 # dispatched using the DB_ENV->set_app_dispatch callback rather than
307 # a DB dispatch table ("dtab").
310 # Everything below here is dbprivate, so it uses ENV instead of DB_ENV
311 # Recover initialization routine
312 p[1] = sprintf("int %s_init_recover %s", prefix,\
313 "__P((ENV *, DB_DISTAB *));");
315 proto_format(p, CFILE);
317 # Create the routine to call db_add_recovery(func, id)
318 printf("int\n%s_init_recover(env, dtabp)\n", prefix) >> CFILE
319 printf("\tENV *env;\n") >> CFILE
320 printf("\tDB_DISTAB *dtabp;\n{\n") >> CFILE
321 printf("\tint ret;\n\n") >> CFILE
322 for (i = 0; i < num_funcs; i++) {
323 if (functable[i] == 1)
325 printf("\tif ((ret = __db_add_recovery_int(env, ") >> CFILE
326 printf("dtabp,\n") >> CFILE
327 printf("\t %s_recover, DB_%s)) != 0)\n",\
328 funcs[i], funcs[i]) >> CFILE
329 printf("\t\treturn (ret);\n") >> CFILE
331 printf("\treturn (0);\n}\n") >> CFILE
334 function log_function()
336 log_prototype(logfunc, 0);
338 log_prototype(dup_logfunc, 0);
339 log_prototype(internal_name, 1);
342 # Function declaration
343 log_funcdecl(logfunc, 0);
345 log_callint(funcname);
346 log_funcdecl(dup_logfunc, 0);
347 log_callint(dup_funcname);
348 log_funcdecl(internal_name, 1);
351 # Function body and local decls
352 printf("{\n") >> CFILE
353 printf("\tDBT logrec;\n") >> CFILE
354 printf("\tDB_LSN *lsnp, null_lsn, *rlsnp;\n") >> CFILE
356 printf("\tDB_TXNLOGREC *lr;\n") >> CFILE
358 printf("\t%s *%s;\n",
359 env_type, env_var) >> CFILE
361 printf("\tENV *env;\n") >> CFILE
363 printf("\tu_int32_t ") >> CFILE
365 printf("zero, ") >> CFILE
367 printf("uinttmp, ") >> CFILE
368 printf("rectype, txn_num;\n") >> CFILE
369 printf("\tu_int npad;\n") >> CFILE
370 printf("\tu_int8_t *bp;\n") >> CFILE
371 printf("\tint ") >> CFILE
373 printf("is_durable, ") >> CFILE
375 printf("ret;\n\n") >> CFILE
379 printf("\tCOMPQUIET(lr, NULL);\n\n") >> CFILE
382 printf("\t%s = dbp->%s;\n", env_var, env_var) >> CFILE
384 printf("\tenv = dbenv->env;\n") >> CFILE
385 printf("\trlsnp = ret_lsnp;\n") >> CFILE
387 printf("\trectype = type;\n") >> CFILE
389 printf("\trectype = DB_%s;\n", funcname) >> CFILE
390 printf("\tnpad = 0;\n") >> CFILE
391 printf("\tret = 0;\n\n") >> CFILE
394 printf("\tif (LF_ISSET(DB_LOG_NOT_DURABLE)") >> CFILE
396 printf(" ||\n\t ") >> CFILE
397 printf("F_ISSET(dbp, DB_AM_NOT_DURABLE)) {\n") >> CFILE
399 printf(") {\n") >> CFILE
401 printf("\t\tif (txnp == NULL)\n") >> CFILE
402 printf("\t\t\treturn (0);\n") >> CFILE
403 printf("\t\tis_durable = 0;\n") >> CFILE
404 printf("\t} else\n") >> CFILE
405 printf("\t\tis_durable = 1;\n\n") >> CFILE
407 printf("\tif (txnp == NULL) {\n") >> CFILE
408 printf("\t\ttxn_num = 0;\n") >> CFILE
409 printf("\t\tlsnp = &null_lsn;\n") >> CFILE
410 printf("\t\tnull_lsn.file = null_lsn.offset = 0;\n") >> CFILE
411 printf("\t} else {\n") >> CFILE
412 if (dbprivate && logfunc != "__db_debug") {
414 "\t\tif (TAILQ_FIRST(&txnp->kids) != NULL &&\n") >> CFILE
415 printf("\t\t (ret = __txn_activekids(") >> CFILE
416 printf("env, rectype, txnp)) != 0)\n") >> CFILE
417 printf("\t\t\treturn (ret);\n") >> CFILE
419 printf("\t\t/*\n\t\t * We need to assign begin_lsn while ") >> CFILE
420 printf("holding region mutex.\n") >> CFILE
421 printf("\t\t * That assignment is done inside the ") >> CFILE
422 printf("DbEnv->log_put call,\n\t\t * ") >> CFILE
423 printf("so pass in the appropriate memory location to be ") >> CFILE
424 printf("filled\n\t\t * in by the log_put code.\n\t\t */\n") >> CFILE
425 printf("\t\tDB_SET_TXN_LSNP(txnp, &rlsnp, &lsnp);\n") >> CFILE
426 printf("\t\ttxn_num = txnp->txnid;\n") >> CFILE
427 printf("\t}\n\n") >> CFILE
429 # If we're logging a DB handle, make sure we have a log
431 db_handle_id_function(modes, nvars);
434 printf("\tlogrec.size = ") >> CFILE
435 printf("sizeof(rectype) + ") >> CFILE
436 printf("sizeof(txn_num) + sizeof(DB_LSN)") >> CFILE
437 for (i = 0; i < nvars; i++)
438 printf("\n\t + %s", sizes[i]) >> CFILE
439 printf(";\n") >> CFILE
441 printf("\tif (CRYPTO_ON(env)) {\n") >> CFILE
443 "\t\tnpad = env->crypto_handle->adj_size(logrec.size);\n") >> CFILE
444 printf("\t\tlogrec.size += npad;\n\t}\n\n") >> CFILE
446 printf("\tif (is_durable || txnp == NULL) {\n") >> CFILE
447 printf("\t\tif ((ret =\n\t\t __os_malloc(env, ") >> CFILE
448 printf("logrec.size, &logrec.data)) != 0)\n") >> CFILE
449 printf("\t\t\treturn (ret);\n") >> CFILE
450 printf("\t} else {\n") >> CFILE
452 "lr", "logrec.size + sizeof(DB_TXNLOGREC)", CFILE)
453 printf("#ifdef DIAGNOSTIC\n") >> CFILE
454 printf("\t\tif ((ret =\n\t\t __os_malloc(env, ") >> CFILE
455 printf("logrec.size, &logrec.data)) != 0) {\n") >> CFILE
456 printf("\t\t\t__os_free(env, lr);\n") >> CFILE
457 printf("\t\t\treturn (ret);\n") >> CFILE
458 printf("\t\t}\n") >> CFILE
459 printf("#else\n") >> CFILE
460 printf("\t\tlogrec.data = lr->data;\n") >> CFILE
461 printf("#endif\n") >> CFILE
462 printf("\t}\n") >> CFILE
464 write_malloc("\t", "logrec.data", "logrec.size", CFILE)
465 printf("\tbp = logrec.data;\n\n") >> CFILE
467 printf("\tif (npad > 0)\n") >> CFILE
468 printf("\t\tmemset((u_int8_t *)logrec.data + logrec.size ") >> CFILE
469 printf("- npad, 0, npad);\n\n") >> CFILE
470 printf("\tbp = logrec.data;\n\n") >> CFILE
472 # Copy args into buffer
473 printf("\tLOGCOPY_32(env, bp, &rectype);\n") >> CFILE
474 printf("\tbp += sizeof(rectype);\n\n") >> CFILE
475 printf("\tLOGCOPY_32(env, bp, &txn_num);\n") >> CFILE
476 printf("\tbp += sizeof(txn_num);\n\n") >> CFILE
477 printf("\tLOGCOPY_FROMLSN(env, bp, lsnp);\n") >> CFILE
478 printf("\tbp += sizeof(DB_LSN);\n\n") >> CFILE
480 for (i = 0; i < nvars; i++) {
481 if (modes[i] == "ARG" || modes[i] == "TIME") {
482 if (types[i] == "u_int32_t") {
483 printf("\tLOGCOPY_32(env, bp, &%s);\n",
485 printf("\tbp += sizeof(%s);\n\n",
488 printf("\tuinttmp = (u_int32_t)%s;\n",
490 printf("\tLOGCOPY_32(env,") >> CFILE
491 printf("bp, &uinttmp);\n") >> CFILE
492 printf("\tbp += sizeof(uinttmp);\n\n") >> CFILE
494 } else if (modes[i] == "DBT" || modes[i] == "LOCKS" ||\
495 modes[i] == "PGDBT" || modes[i] == "PGDDBT") {
496 printf("\tif (%s == NULL) {\n", vars[i]) >> CFILE
497 printf("\t\tzero = 0;\n") >> CFILE
498 printf("\t\tLOGCOPY_32(env, bp, &zero);\n") >> CFILE
499 printf("\t\tbp += sizeof(u_int32_t);\n") >> CFILE
500 printf("\t} else {\n") >> CFILE
501 printf("\t\tLOGCOPY_32(env, bp, &%s->size);\n",
503 printf("\t\tbp += sizeof(%s->size);\n", vars[i])\
505 printf("\t\tmemcpy(bp, %s->data, %s->size);\n",\
506 vars[i], vars[i]) >> CFILE
507 if (modes[i] == "PGDBT" && !is_compat) {
508 printf("\t\tif (LOG_SWAPPED(env))\n") >> CFILE
510 "\t\t\tif ((ret = __db_pageswap(dbp,\n") >> CFILE
512 "\t\t\t (PAGE *)bp, (size_t)%s->size, (DBT *)%s, 0)) != 0)\n",
513 vars[i], ddbt) >> CFILE
514 printf("\t\t\t\treturn (ret);\n") >> CFILE
515 } else if (modes[i] == "PGDDBT") {
516 printf("\t\tif (LOG_SWAPPED(env) && ") >> CFILE
517 printf("F_ISSET(%s, DB_DBT_APPMALLOC))\n",
519 printf("\t\t\t__os_free(env, %s->data);\n",
522 printf("\t\tbp += %s->size;\n", vars[i]) >> CFILE
523 printf("\t}\n\n") >> CFILE
524 } else if (modes[i] == "DB") {
526 "\tuinttmp = (u_int32_t)dbp->log_filename->id;\n")\
528 printf("\tLOGCOPY_32(env, bp, &uinttmp);\n") >> CFILE
529 printf("\tbp += sizeof(uinttmp);\n\n") >> CFILE
531 printf("\tif (%s != NULL)", vars[i]) >> CFILE
532 if (has_dbp && types[i] == "DB_LSN *") {
533 printf(" {\n\t\tif (txnp != NULL) {\n")\
536 "\t\t\tLOG *lp = env->lg_handle->reginfo.primary;\n") >> CFILE
538 "\t\t\tif (LOG_COMPARE(%s, &lp->lsn) >= 0 && (ret =\n", vars[i])\
541 "\t\t\t __log_check_page_lsn(env, dbp, %s)) != 0)\n", vars[i])\
543 printf("\t\t\t\treturn (ret);\n") >> CFILE
544 printf("\t\t}") >> CFILE
546 printf("\n\t\tLOGCOPY_FROMLSN(env, bp, %s);\n",
548 if (has_dbp && types[i] == "DB_LSN *")
549 printf("\t} else\n") >> CFILE
551 printf("\telse\n") >> CFILE
552 printf("\t\tmemset(bp, 0, %s);\n", sizes[i]) >> CFILE
553 printf("\tbp += %s;\n\n", sizes[i]) >> CFILE
557 # Error checking. User code won't have DB_ASSERT available, but
558 # this is a pretty unlikely assertion anyway, so we just leave it out
559 # rather than requiring assert.h.
561 printf("\tDB_ASSERT(env,\n") >> CFILE
562 printf("\t (u_int32_t)(bp - (u_int8_t *)") >> CFILE
563 printf("logrec.data) <= logrec.size);\n\n") >> CFILE
564 # Save the log record off in the txn's linked list,
566 # We didn't call the crypto alignment function when
567 # we created this log record (because we don't have
568 # the right header files to find the function), so
569 # we have to copy the log record to make sure the
570 # alignment is correct.
571 printf("\tif (is_durable || txnp == NULL) {\n") >> CFILE
572 # Output the log record and update the return LSN.
573 printf("\t\tif ((ret = __log_put(env, rlsnp,") >> CFILE
574 printf("(DBT *)&logrec,\n") >> CFILE
575 printf("\t\t flags | DB_LOG_NOCOPY)) == 0") >> CFILE
576 printf(" && txnp != NULL) {\n") >> CFILE
577 printf("\t\t\t*lsnp = *rlsnp;\n") >> CFILE
579 printf("\t\t\tif (rlsnp != ret_lsnp)\n") >> CFILE
580 printf("\t\t\t\t *ret_lsnp = *rlsnp;\n") >> CFILE
581 printf("\t\t}\n\t} else {\n") >> CFILE
582 printf("\t\tret = 0;\n") >> CFILE
583 printf("#ifdef DIAGNOSTIC\n") >> CFILE
585 # Add the debug bit if we are logging a ND record.
586 printf("\t\t/*\n") >> CFILE
587 printf("\t\t * Set the debug bit if we are") >> CFILE
588 printf(" going to log non-durable\n") >> CFILE
589 printf("\t\t * transactions so they will be ignored") >> CFILE
590 printf(" by recovery.\n") >> CFILE
591 printf("\t\t */\n") >> CFILE
592 printf("\t\tmemcpy(lr->data, logrec.data, ") >> CFILE
593 printf("logrec.size);\n") >> CFILE
594 printf("\t\trectype |= DB_debug_FLAG;\n") >> CFILE
595 printf("\t\tLOGCOPY_32(") >> CFILE
596 printf("env, logrec.data, &rectype);\n\n") >> CFILE
597 # Output the log record.
598 printf("\t\tif (!IS_REP_CLIENT(env))\n") >> CFILE
599 printf("\t\t\tret = __log_put(env,\n") >> CFILE
600 printf("\t\t\t rlsnp, (DBT *)&logrec, ") >> CFILE
601 printf("flags | DB_LOG_NOCOPY);\n") >> CFILE
602 printf("#endif\n") >> CFILE
603 # Add a ND record to the txn list.
604 printf("\t\tSTAILQ_INSERT_HEAD(&txnp") >> CFILE
605 printf("->logs, lr, links);\n") >> CFILE
606 printf("\t\tF_SET((TXN_DETAIL *)") >> CFILE
607 printf("txnp->td, TXN_DTL_INMEMORY);\n") >> CFILE
608 # Update the return LSN.
609 printf("\t\tLSN_NOT_LOGGED(*ret_lsnp);\n") >> CFILE
610 printf("\t}\n\n") >> CFILE
612 printf("\tif ((ret = dbenv->log_put(dbenv, rlsnp,") >> CFILE
613 printf(" (DBT *)&logrec,\n") >> CFILE
614 printf("\t flags | DB_LOG_NOCOPY)) == 0") >> CFILE
615 printf(" && txnp != NULL) {\n") >> CFILE
617 # Update the transactions last_lsn.
618 printf("\t\t*lsnp = *rlsnp;\n") >> CFILE
619 printf("\t\tif (rlsnp != ret_lsnp)\n") >> CFILE
620 printf("\t\t\t *ret_lsnp = *rlsnp;\n") >> CFILE
621 printf("\t}\n") >> CFILE
624 # If out of disk space log writes may fail. If we are debugging
625 # that print out which records did not make it to disk.
626 printf("#ifdef LOG_DIAGNOSTIC\n") >> CFILE
627 printf("\tif (ret != 0)\n") >> CFILE
628 printf("\t\t(void)%s_print(%s,\n", funcname, env_var) >> CFILE
629 printf("\t\t (DBT *)&logrec, ret_lsnp, ") >> CFILE
630 printf("DB_TXN_PRINT%s);\n#endif\n\n",\
631 dbprivate ? ", NULL" : "") >> CFILE
634 printf("#ifdef DIAGNOSTIC\n") >> CFILE
635 write_free("\t", "logrec.data", CFILE)
636 printf("#else\n") >> CFILE
637 printf("\tif (is_durable || txnp == NULL)\n") >> CFILE
638 write_free("\t\t", "logrec.data", CFILE)
639 printf("#endif\n") >> CFILE
641 write_free("\t", "logrec.data", CFILE)
644 printf("\treturn (ret);\n}\n\n") >> CFILE
647 function log_prototype(fname, with_type)
649 # Write the log function; function prototype
651 p[pi++] = sprintf("int %s_log", fname);
654 p[pi++] = "__P((DB *";
656 p[pi++] = sprintf("__P((%s *", env_type);
658 p[pi++] = ", DB_TXN *, DB_LSN *, u_int32_t";
659 for (i = 0; i < nvars; i++) {
660 if (modes[i] == "DB")
663 p[pi++] = sprintf("%s%s%s", (modes[i] == "DBT" ||
664 modes[i] == "LOCKS" || modes[i] == "PGDBT" ||
665 modes[i] == "PGDDBT") ? "const " : "", types[i],
666 (modes[i] == "DBT" || modes[i] == "LOCKS" ||
667 modes[i] == "PGDBT" || modes[i] == "PGDDBT") ? " *" : "");
670 # If this is a logging call with type, add the type here.
672 p[pi++] = ", u_int32_t";
677 proto_format(p, CFILE);
680 # If we're logging a DB handle, make sure we have a log
682 function db_handle_id_function(modes, n)
684 for (i = 0; i < n; i++)
685 if (modes[i] == "DB") {
686 # We actually log the DB handle's fileid; from
687 # that ID we're able to acquire an open handle
690 "\tDB_ASSERT(env, dbp->log_filename != NULL);\n")\
692 printf("\tif (dbp->log_filename->id == ")\
694 printf("DB_LOGFILEID_INVALID &&\n\t ")\
696 printf("(ret = __dbreg_lazy_id(dbp)) != 0)\n")\
698 printf("\t\treturn (ret);\n\n") >> CFILE
703 function print_function()
705 # Write the print function; function prototype
706 p[1] = sprintf("int %s_print", funcname);
709 p[3] = "__P((ENV *, DBT *, DB_LSN *, db_recops, void *));";
711 p[3] = "__P((DB_ENV *, DBT *, DB_LSN *, db_recops));";
713 proto_format(p, PFILE);
715 # Function declaration
716 printf("int\n%s_print(%s, ", funcname, env_var) >> PFILE
717 printf("dbtp, lsnp, notused2") >> PFILE
719 printf(", notused3") >> PFILE
720 printf(")\n") >> PFILE
721 printf("\t%s *%s;\n", env_type, env_var) >> PFILE
722 printf("\tDBT *dbtp;\n") >> PFILE
723 printf("\tDB_LSN *lsnp;\n") >> PFILE
724 printf("\tdb_recops notused2;\n") >> PFILE
726 printf("\tvoid *notused3;\n") >> PFILE
727 printf("{\n") >> PFILE
730 printf("\t%s_args *argp;\n", funcname) >> PFILE
732 printf("\t%s\n", read_proto) >> PFILE
733 for (i = 0; i < nvars; i ++)
734 if (modes[i] == "TIME") {
735 printf("\tstruct tm *lt;\n") >> PFILE
736 printf("\ttime_t timeval;\n") >> PFILE
737 printf("\tchar time_buf[CTIME_BUFLEN];\n") >> PFILE
740 for (i = 0; i < nvars; i ++)
741 if (modes[i] == "DBT" ||
742 modes[i] == "PGDBT" || modes[i] == "PGDDBT") {
743 printf("\tu_int32_t i;\n") >> PFILE
744 printf("\tint ch;\n") >> PFILE
747 printf("\tint ret;\n\n") >> PFILE
749 # Get rid of complaints about unused parameters.
750 printf("\tnotused2 = DB_TXN_PRINT;\n") >> PFILE
752 printf("\tnotused3 = NULL;\n") >> PFILE
753 printf("\n") >> PFILE
755 # Call read routine to initialize structure
757 printf("\tif ((ret =\n") >> PFILE
759 "\t %s_read(%s, NULL, NULL, dbtp->data, &argp)) != 0)\n",
760 funcname, env_var) >> PFILE
762 printf("\tif ((ret = %s_read(%s, dbtp->data, &argp)) != 0)\n",
763 funcname, env_var) >> PFILE
765 printf("\t\treturn (ret);\n") >> PFILE
767 # Print values in every record
768 printf("\t(void)printf(\n \"[%%lu][%%lu]%s%%s: ", funcname) >> PFILE
769 printf("rec: %%lu txnp %%lx prevlsn [%%lu][%%lu]\\n\",\n") >> PFILE
770 printf("\t (u_long)lsnp->file, (u_long)lsnp->offset,\n") >> PFILE
771 printf("\t (argp->type & DB_debug_FLAG) ? \"_debug\" : \"\",\n")\
773 printf("\t (u_long)argp->type,\n") >> PFILE
774 printf("\t (u_long)argp->txnp->txnid,\n") >> PFILE
775 printf("\t (u_long)argp->prev_lsn.file, ") >> PFILE
776 printf("(u_long)argp->prev_lsn.offset);\n") >> PFILE
778 # Now print fields of argp
779 for (i = 0; i < nvars; i ++) {
780 if (modes[i] == "TIME") {
781 printf("\ttimeval = (time_t)argp->%s;\n",
783 printf("\tlt = localtime(&timeval);\n") >> PFILE
784 printf("\t(void)printf(\n\t \"\\t%s: ",
787 printf("\t(void)printf(\"\\t%s: ", vars[i]) >> PFILE
789 if (modes[i] == "DBT" ||
790 modes[i] == "PGDBT" || modes[i] == "PGDDBT") {
791 printf("\");\n") >> PFILE
792 printf("\tfor (i = 0; i < ") >> PFILE
793 printf("argp->%s.size; i++) {\n", vars[i]) >> PFILE
794 printf("\t\tch = ((u_int8_t *)argp->%s.data)[i];\n",\
796 printf("\t\tprintf(isprint(ch) || ch == 0x0a") >> PFILE
797 printf(" ? \"%%c\" : \"%%#x \", ch);\n") >> PFILE
798 printf("\t}\n\t(void)printf(\"\\n\");\n") >> PFILE
799 } else if (types[i] == "DB_LSN *") {
800 printf("[%%%s][%%%s]\\n\",\n",\
801 formats[i], formats[i]) >> PFILE
802 printf("\t (u_long)argp->%s.file,",\
804 printf(" (u_long)argp->%s.offset);\n",\
806 } else if (modes[i] == "TIME") {
807 # Time values are displayed in two ways: the standard
808 # string returned by ctime, and in the input format
809 # expected by db_recover -t.
811 "%%%s (%%.24s, 20%%02lu%%02lu%%02lu%%02lu%%02lu.%%02lu)\\n\",\n",\
813 printf("\t (long)argp->%s, ", vars[i]) >> PFILE
814 printf("__os_ctime(&timeval, time_buf),",\
816 printf("\n\t (u_long)lt->tm_year - 100, ") >> PFILE
817 printf("(u_long)lt->tm_mon+1,") >> PFILE
818 printf("\n\t (u_long)lt->tm_mday, ") >> PFILE
819 printf("(u_long)lt->tm_hour,") >> PFILE
820 printf("\n\t (u_long)lt->tm_min, ") >> PFILE
821 printf("(u_long)lt->tm_sec);\n") >> PFILE
822 } else if (modes[i] == "LOCKS") {
823 printf("\\n\");\n") >> PFILE
824 printf("\t__lock_list_print(env, &argp->locks);\n")\
827 if (formats[i] == "lx")
828 printf("0x") >> PFILE
829 printf("%%%s\\n\", ", formats[i]) >> PFILE
830 if (formats[i] == "lx" || formats[i] == "lu")
831 printf("(u_long)") >> PFILE
832 if (formats[i] == "ld")
833 printf("(long)") >> PFILE
834 printf("argp->%s);\n", vars[i]) >> PFILE
837 printf("\t(void)printf(\"\\n\");\n") >> PFILE
838 write_free("\t", "argp", PFILE);
839 printf("\treturn (0);\n") >> PFILE
840 printf("}\n\n") >> PFILE
843 function read_function()
845 # Write the read function; function prototype
847 p[1] = sprintf("int %s_read __P((%s *, DB **, void *, void *,",
850 p[1] = sprintf("int %s_read __P((%s *, void *,",
854 p[3] = sprintf("%s_args **));", funcname);
856 read_proto = sprintf("%s %s", p[1], p[3]);
857 proto_format(p, CFILE);
859 # Function declaration
861 printf("int\n%s_read(%s, dbpp, td, recbuf, argpp)\n",
862 funcname, env_var) >> CFILE
864 printf("int\n%s_read(%s, recbuf, argpp)\n",
865 funcname, env_var) >> CFILE
868 # Now print the parameters
869 printf("\t%s *%s;\n", env_type, env_var) >> CFILE
871 printf("\tDB **dbpp;\n") >> CFILE
872 printf("\tvoid *td;\n") >> CFILE
874 printf("\tvoid *recbuf;\n") >> CFILE
875 printf("\t%s_args **argpp;\n", funcname) >> CFILE
877 # Function body and local decls
878 printf("{\n\t%s_args *argp;\n", funcname) >> CFILE
880 printf("\tu_int32_t uinttmp;\n") >> CFILE
881 printf("\tu_int8_t *bp;\n") >> CFILE
884 # We only use ret in the private malloc case.
885 printf("\tint ret;\n\n") >> CFILE
887 printf("\tENV *env;\n\n") >> CFILE
888 printf("\tenv = dbenv->env;\n\n") >> CFILE
891 malloc_size = sprintf("sizeof(%s_args) + sizeof(DB_TXN)", funcname)
892 write_malloc("\t", "argp", malloc_size, CFILE)
894 # Set up the pointers to the DB_TXN *.
895 printf("\tbp = recbuf;\n") >> CFILE
897 printf("\targp->txnp = (DB_TXN *)&argp[1];\n") >> CFILE
898 printf("\tmemset(argp->txnp, 0, sizeof(DB_TXN));\n\n")\
901 printf("\targp->txnp->td = td;\n") >> CFILE
903 # First get the record type, prev_lsn, and txnp fields.
904 printf("\tLOGCOPY_32(env, &argp->type, bp);\n") >> CFILE
905 printf("\tbp += sizeof(argp->type);\n\n") >> CFILE
906 printf("\tLOGCOPY_32(env, &argp->txnp->txnid, bp);\n") >> CFILE
907 printf("\tbp += sizeof(argp->txnp->txnid);\n\n") >> CFILE
908 printf("\tLOGCOPY_TOLSN(env, &argp->prev_lsn, bp);\n") >> CFILE
909 printf("\tbp += sizeof(DB_LSN);\n\n") >> CFILE
911 # Now get rest of data.
912 for (i = 0; i < nvars; i ++) {
913 if (modes[i] == "DBT" || modes[i] == "LOCKS" ||
914 modes[i] == "PGDBT" || modes[i] == "PGDDBT") {
915 printf("\tmemset(&argp->%s, 0, sizeof(argp->%s));\n",\
916 vars[i], vars[i]) >> CFILE
917 printf("\tLOGCOPY_32(env,") >> CFILE
918 printf("&argp->%s.size, bp);\n", vars[i]) >> CFILE
919 printf("\tbp += sizeof(u_int32_t);\n") >> CFILE
920 printf("\targp->%s.data = bp;\n", vars[i]) >> CFILE
921 printf("\tbp += argp->%s.size;\n", vars[i]) >> CFILE
922 if (modes[i] == "PGDBT" && ddbt == "NULL" &&
924 printf("\tif (LOG_SWAPPED(env) && ") >> CFILE
925 printf("dbpp != NULL && ") >> CFILE
926 printf("*dbpp != NULL) {\n") >> CFILE
927 printf("\t\tint t_ret;\n") >> CFILE
929 "\t\tif ((t_ret = __db_pageswap(*dbpp, (PAGE *)argp->%s.data,\n",
932 "\t\t (size_t)argp->%s.size, NULL, 1)) != 0)\n",
934 printf("\t\t\treturn (t_ret);\n") >> CFILE
935 printf("\t}\n") >> CFILE
936 } else if (modes[i] == "PGDDBT" && !is_compat) {
937 printf("\tif (LOG_SWAPPED(env) && ") >> CFILE
938 printf("dbpp != NULL && ") >> CFILE
939 printf("*dbpp != NULL) {\n") >> CFILE
940 printf("\t\tint t_ret;\n") >> CFILE
942 "\t\tif ((t_ret = __db_pageswap(*dbpp,\n") >> CFILE
944 "\t\t (PAGE *)argp->%s.data, (size_t)argp->%s.size,\n",
945 hdrdbt, hdrdbt) >> CFILE
946 printf("\t\t &argp->%s, 1)) != 0)\n",
948 printf("\t\t\treturn (t_ret);\n") >> CFILE
949 printf("\t}\n") >> CFILE
951 } else if (modes[i] == "ARG" || modes[i] == "TIME" ||
953 if (types[i] == "u_int32_t") {
954 printf("\tLOGCOPY_32(env, &argp->%s, bp);\n",
956 printf("\tbp += sizeof(argp->%s);\n", vars[i])\
959 printf("\tLOGCOPY_32(env, &uinttmp, bp);\n")\
961 printf("\targp->%s = (%s)uinttmp;\n", vars[i],\
963 printf("\tbp += sizeof(uinttmp);\n") >> CFILE
966 if (modes[i] == "DB") {
967 # We can now get the DB handle.
968 printf("\tif (dbpp != NULL) {\n") >> CFILE
969 printf("\t\t*dbpp = NULL;\n") >> CFILE
971 "\t\tret = __dbreg_id_to_db(\n\t\t ") >> CFILE
972 printf("env, argp->txnp, dbpp, argp->%s, 1);\n",
974 printf("\t}\n") >> CFILE
976 } else if (types[i] == "DB_LSN *") {
977 printf("\tLOGCOPY_TOLSN(env, &argp->%s, bp);\n",
979 printf("\tbp += sizeof(DB_LSN);\n", vars[i]) >> CFILE
981 printf("\tDB_ASSERT(env, sizeof(argp->%s) == 4);",
983 printf("\tLOGCOPY_32(env, &argp->%s, bp);",
985 printf("\tbp += sizeof(argp->%s);\n", vars[i]) >> CFILE
987 printf("\n") >> CFILE
990 printf("\t*argpp = argp;\n") >> CFILE
992 printf("\treturn (ret);\n}\n\n") >> CFILE
994 printf("\treturn (0);\n}\n\n") >> CFILE
998 # Pretty-print a function prototype.
999 function proto_format(p, fp)
1001 printf("/*\n") >> fp;
1004 for (i = 1; i in p; ++i)
1008 if (length(s) + length(t) < 80)
1009 printf("%s%s", t, s) >> fp;
1012 len = length(t) + length(p[1]);
1013 printf("%s%s", t, p[1]) >> fp
1015 n = split(p[2], comma, ",");
1016 comma[1] = "__P" comma[1];
1017 for (i = 1; i <= n; i++) {
1018 if (len + length(comma[i]) > 70) {
1019 printf("\n * PUBLIC: ") >> fp;
1022 printf("%s%s", comma[i], i == n ? "" : ",") >> fp;
1023 len += length(comma[i]) + 2;
1026 printf("\n */\n") >> fp;
1030 function write_malloc(tab, ptr, size, file)
1033 print(tab "if ((ret = __os_malloc(env,") >> file
1034 print(tab " " size ", &" ptr ")) != 0)") >> file
1035 print(tab "\treturn (ret);") >> file;
1037 print(tab "if ((" ptr " = malloc(" size ")) == NULL)") >> file
1038 print(tab "\treturn (ENOMEM);") >> file
1042 function write_free(tab, ptr, file)
1045 print(tab "__os_free(env, " ptr ");") >> file
1047 print(tab "free(" ptr ");") >> file
1051 function make_name(unique_name, dup_name, p_version)
1053 logfunc = sprintf("%s_%s", prefix, unique_name);
1054 logname[num_funcs] = logfunc;
1056 funcname = sprintf("%s_%s_%s", prefix, unique_name, p_version);
1062 dupfuncs[num_funcs] = dup_name;
1064 dupfuncs[num_funcs] = funcname;
1066 funcs[num_funcs] = funcname;
1067 functable[num_funcs] = is_compat;
1071 function log_funcdecl(name, withtype)
1073 # Function declaration
1075 printf("int\n%s_log(dbp, txnp, ret_lsnp, flags",\
1078 printf("int\n%s_log(%s, txnp, ret_lsnp, flags",\
1079 name, env_var) >> CFILE
1081 for (i = 0; i < nvars; i++) {
1082 if (modes[i] == "DB") {
1083 # We pass in fileids on the dbp, so if this is one,
1087 printf(",") >> CFILE
1089 printf("\n ") >> CFILE
1091 printf(" ") >> CFILE
1092 printf("%s", vars[i]) >> CFILE
1096 printf(", type") >> CFILE
1098 printf(")\n") >> CFILE
1100 # Now print the parameters
1102 printf("\tDB *dbp;\n") >> CFILE
1104 printf("\t%s *%s;\n", env_type, env_var) >> CFILE
1106 printf("\tDB_TXN *txnp;\n\tDB_LSN *ret_lsnp;\n") >> CFILE
1107 printf("\tu_int32_t flags;\n") >> CFILE
1108 for (i = 0; i < nvars; i++) {
1109 # We just skip for modes == DB.
1110 if (modes[i] == "DBT" || modes[i] == "LOCKS" ||
1111 modes[i] == "PGDBT" || modes[i] == "PGDDBT")
1112 printf("\tconst %s *%s;\n", types[i], vars[i]) >> CFILE
1113 else if (modes[i] != "DB")
1114 printf("\t%s %s;\n", types[i], vars[i]) >> CFILE
1117 printf("\tu_int32_t type;\n") >> CFILE
1120 function log_callint(fname)
1123 printf("\n{\n\treturn (%s_log(dbp, txnp, ret_lsnp, flags",\
1124 internal_name) >> CFILE
1126 printf("\n{\n\treturn (%s_log(%s, txnp, ret_lsnp, flags",\
1127 internal_name, env_var) >> CFILE
1130 for (i = 0; i < nvars; i++) {
1131 if (modes[i] == "DB") {
1132 # We pass in fileids on the dbp, so if this is one,
1136 printf(",") >> CFILE
1138 printf("\n ") >> CFILE
1140 printf(" ") >> CFILE
1141 printf("%s", vars[i]) >> CFILE
1144 printf(", DB_%s", fname) >> CFILE
1145 printf("));\n}\n") >> CFILE