mirror of
https://github.com/MariaDB/server.git
synced 2025-01-22 23:04:20 +01:00
5d7a5dfaa3
Modified makefile to be more modular with icc and gcc options. Modified portability.h with some stubs and some real portability code Removed named variadic macros for unnamed variadic macros (c99 only supports unnamed) Removed ', ## __VAR_ARGS__' in favor of ', __VAR_ARGS__' due to apparent bug in the intel compiler (on windows at least) __ICC means the linux intel compiler, __ICL means the windows intel compiler __INTEL_COMPILER is set by both Removed some include files (for windows) that don't exist. git-svn-id: file:///svn/tokudb.1131b+1080a+1185+nostatementexprs@6473 c7de825b-a66e-492c-adef-691d508d4ae1
597 lines
24 KiB
C
597 lines
24 KiB
C
/* -*- mode: C; c-basic-offset: 4 -*- */
|
|
#ident "Copyright (c) 2007, 2008 Tokutek Inc. All rights reserved."
|
|
|
|
/* This file defines the logformat in an executable fashion.
|
|
* This code is used to generate
|
|
* The code that writes into the log.
|
|
* The code that reads the log and prints it to stdout (the log_print utility)
|
|
* The code that reads the log for recovery.
|
|
* The struct definitions.
|
|
* The Latex documentation.
|
|
*/
|
|
#include "portability.h"
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#if !defined(TOKU_WINDOWS)
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
typedef struct field {
|
|
char *type;
|
|
char *name;
|
|
char *format; // optional format string
|
|
} F;
|
|
|
|
#define NULLFIELD {0,0,0}
|
|
#define FA (F[])
|
|
|
|
struct logtype {
|
|
char *name;
|
|
unsigned int command_and_flags;
|
|
struct field *fields;
|
|
};
|
|
|
|
// In the fields, don't mention the command, the LSN, the CRC or the trailing LEN.
|
|
|
|
int logformat_version_number = 0;
|
|
|
|
const struct logtype rollbacks[] = {
|
|
{"fcreate", 'F', FA{{"TXNID", "xid", 0},
|
|
{"BYTESTRING", "fname", 0},
|
|
NULLFIELD}},
|
|
{"cmdinsert", 'i', FA{{"TXNID", "xid", 0},
|
|
{"FILENUM", "filenum", 0},
|
|
{"BYTESTRING", "key", 0},
|
|
{"BYTESTRING", "data", 0},
|
|
NULLFIELD}},
|
|
{"cmddeleteboth", 'D', FA{{"TXNID", "xid", 0},
|
|
{"FILENUM", "filenum", 0},
|
|
{"BYTESTRING", "key", 0},
|
|
{"BYTESTRING", "data", 0},
|
|
NULLFIELD}},
|
|
{"cmddelete", 'd', FA{{"TXNID", "xid", 0},
|
|
{"FILENUM", "filenum", 0},
|
|
{"BYTESTRING", "key", 0},
|
|
NULLFIELD}},
|
|
{"rollinclude", 'I', FA{{"BYTESTRING", "fname", 0},
|
|
NULLFIELD}},
|
|
// {"fclose", 'c', FA{{"FILENUM", "filenum", 0},
|
|
// {"BYTESTRING", "fname", 0},
|
|
// NULLFIELD}},
|
|
// {"deleteatleaf", 'd', FA{{"FILENUM", "filenum", 0}, // Note a delete for rollback. The delete takes place in a leaf.
|
|
// {"BYTESTRING", "key", 0},
|
|
// {"BYTESTRING", "data", 0},
|
|
// NULLFIELD}},
|
|
// {"insertatleaf", 'i', FA{{"FILENUM", "filenum", 0}, // Note an insert for rollback. The insert takes place in a leaf.
|
|
// {"BYTESTRING", "key", 0},
|
|
// {"BYTESTRING", "data", 0},
|
|
// NULLFIELD}},
|
|
// {"xactiontouchednonleaf", 'n', FA{{"FILENUM", "filenum", 0},
|
|
// {"DISKOFFARRAY", "parents", 0},
|
|
// {"DISKOFF", "diskoff", 0},
|
|
// NULLFIELD}},
|
|
{0,0,FA{NULLFIELD}}
|
|
};
|
|
|
|
const struct logtype logtypes[] = {
|
|
{"checkpoint", 'x', FA{NULLFIELD}},
|
|
{"commit", 'C', FA{{"TXNID", "txnid", 0},NULLFIELD}},
|
|
{"xabort", 'q', FA{{"TXNID", "txnid", 0},NULLFIELD}},
|
|
{"xbegin", 'b', FA{{"TXNID", "parenttxnid", 0},NULLFIELD}},
|
|
#if 0
|
|
{"tl_delete", 'D', FA{{"FILENUM", "filenum", 0}, // tl logentries can be used, by themselves, to rebuild the whole DB from scratch.
|
|
{"BLOCKNUM", "blocknum", 0},
|
|
{"BYTESTRING", "key", 0},
|
|
{"BYTESTRING", "data", 0},
|
|
NULLFIELD}},
|
|
#endif
|
|
{"fcreate", 'F', FA{{"TXNID", "txnid", 0},
|
|
{"BYTESTRING", "fname", 0},
|
|
{"u_int32_t", "mode", "0%o"},
|
|
NULLFIELD}},
|
|
{"fheader", 'H', FA{{"TXNID", "txnid", 0},
|
|
{"FILENUM", "filenum", 0},
|
|
{"LOGGEDBRTHEADER", "header", 0},
|
|
NULLFIELD}},
|
|
{"newbrtnode", 'N', FA{{"FILENUM", "filenum", 0},
|
|
{"BLOCKNUM", "blocknum", 0},
|
|
{"u_int32_t", "height", 0},
|
|
{"u_int32_t", "nodesize", 0},
|
|
{"u_int8_t", "is_dup_sort", 0},
|
|
{"u_int32_t", "rand4fingerprint", "%08x"},
|
|
NULLFIELD}},
|
|
{"changeunnamedroot", 'u', FA{{"FILENUM", "filenum", 0},
|
|
{"BLOCKNUM", "oldroot", 0},
|
|
{"BLOCKNUM", "newroot", 0},
|
|
NULLFIELD}},
|
|
{"changenamedroot", 'n', FA{{"FILENUM", "filenum", 0},
|
|
{"BYTESTRING", "name", 0},
|
|
{"BLOCKNUM", "oldroot", 0},
|
|
{"BLOCKNUM", "newroot", 0},
|
|
NULLFIELD}},
|
|
{"changeunusedmemory", 'm', FA{{"FILENUM", "filenum", 0},
|
|
{"BLOCKNUM", "oldunused", 0},
|
|
{"BLOCKNUM", "newunused", 0},
|
|
NULLFIELD}},
|
|
{"addchild", 'c', FA{{"FILENUM", "filenum", 0},
|
|
{"BLOCKNUM", "blocknum", 0},
|
|
{"u_int32_t", "childnum", 0}, // children scoot over
|
|
{"BLOCKNUM", "child", 0},
|
|
{"u_int32_t", "childfingerprint", "%08x"},
|
|
NULLFIELD}},
|
|
{"delchild", 'r', FA{{"FILENUM", "filenum", 0},
|
|
{"BLOCKNUM", "blocknum", 0},
|
|
{"u_int32_t", "childnum", 0}, // children scoot over
|
|
{"BLOCKNUM", "child", 0},
|
|
{"u_int32_t", "childfingerprint", "%08x"},
|
|
{"BYTESTRING", "pivotkey", 0},
|
|
NULLFIELD}},
|
|
{"setchild", 'i', FA{{"FILENUM", "filenum", 0},
|
|
{"BLOCKNUM", "blocknum", 0},
|
|
{"u_int32_t", "childnum", 0},
|
|
{"BLOCKNUM", "oldchild", 0},
|
|
{"BLOCKNUM", "newchild", 0},
|
|
NULLFIELD}},
|
|
{"setpivot", 'k', FA{{"FILENUM", "filenum", 0},
|
|
{"BLOCKNUM", "blocknum", 0},
|
|
{"u_int32_t", "childnum", 0},
|
|
{"BYTESTRING", "pivotkey", 0},
|
|
NULLFIELD}},
|
|
{"fopen", 'O', FA{{"TXNID", "txnid", 0},
|
|
{"BYTESTRING", "fname", 0},
|
|
{"FILENUM", "filenum", 0},
|
|
NULLFIELD}},
|
|
{"brtclose", 'e', FA{{"BYTESTRING", "fname", 0}, // brtclose is logged when a particular brt is closed
|
|
{"FILENUM", "filenum", 0},
|
|
NULLFIELD}},
|
|
{"cfclose", 'o', FA{{"BYTESTRING", "fname", 0}, // cfclose is logged when a cachefile actually closes ("cfclose" means cache file close)
|
|
{"FILENUM", "filenum", 0},
|
|
NULLFIELD}},
|
|
// Note that brtdeq and brtenq don't name the new size or fingerprint. We can calculate them properly.
|
|
{"brtdeq", 'U', FA{{"FILENUM", "filenum", 0},
|
|
{"BLOCKNUM", "blocknum", 0},
|
|
{"u_int32_t", "childnum", 0},
|
|
NULLFIELD}},
|
|
{"brtenq", 'Q', FA{{"FILENUM", "filenum", 0},
|
|
{"BLOCKNUM", "blocknum", 0},
|
|
{"u_int32_t", "childnum", 0},
|
|
{"TXNID", "xid", 0},
|
|
{"u_int32_t", "typ", 0},
|
|
{"BYTESTRING", "key", 0},
|
|
{"BYTESTRING", "data", 0},
|
|
NULLFIELD}},
|
|
// {"insertinleaf", 'I', FA{{"TXNID", "txnid", 0},
|
|
// {"FILENUM", "filenum", 0},
|
|
// {"BLOCKNUM", "blocknum", 0},
|
|
// {"u_int32_t", "pmaidx", 0},
|
|
// {"BYTESTRING", "key", 0},
|
|
// {"BYTESTRING", "data", 0},
|
|
// NULLFIELD}},
|
|
// {"replaceleafentry", 'L', FA{{"FILENUM", "filenum", 0},
|
|
// {"BLOCKNUM", "blocknum", 0},
|
|
// {"u_int32_t", "pmaidx", 0},
|
|
// {"LEAFENTRY", "oldleafentry", 0},
|
|
// {"LEAFENTRY", "newleafentry", 0},
|
|
// NULLFIELD}},
|
|
{"enqrootentry", 'a', FA{{"FILENUM", "filenum", 0},
|
|
{"TXNID", "xid", 0},
|
|
{"u_int32_t", "typ", 0},
|
|
{"BYTESTRING", "key", 0},
|
|
{"BYTESTRING", "data", 0},
|
|
NULLFIELD}},
|
|
{"deqrootentry", 'A', FA{{"FILENUM", "filenum", 0},
|
|
NULLFIELD}},
|
|
{"insertleafentry", 'I', FA{{"FILENUM", "filenum", 0},
|
|
{"BLOCKNUM", "blocknum", 0},
|
|
{"u_int32_t", "idx", 0},
|
|
{"LEAFENTRY", "newleafentry", 0},
|
|
NULLFIELD}},
|
|
{"deleteleafentry", 'D', FA{{"FILENUM", "filenum", 0},
|
|
{"BLOCKNUM", "blocknum", 0},
|
|
{"u_int32_t", "idx", 0},
|
|
NULLFIELD}},
|
|
{"leafsplit", 's', FA{{"FILENUM", "filenum", 0}, // log the creation of a new node by splitting stuff out of an old node
|
|
{"BLOCKNUM", "old_blocknum", 0},
|
|
{"BLOCKNUM", "new_blocknum", 0},
|
|
{"u_int32_t", "old_n", 0},
|
|
{"u_int32_t", "split_at", 0},
|
|
{"u_int32_t", "new_nodesize", 0},
|
|
{"u_int32_t", "new_rand4", "%08x"},
|
|
{"u_int8_t", "is_dupsort", 0},
|
|
NULLFIELD}},
|
|
{0,0,FA{NULLFIELD}}
|
|
};
|
|
|
|
|
|
#define DO_STRUCTS(lt, array, body) do { \
|
|
const struct logtype *lt; \
|
|
for (lt=&array[0]; lt->name; lt++) { \
|
|
body; \
|
|
} } while (0)
|
|
|
|
#define DO_ROLLBACKS(lt, body) DO_STRUCTS(lt, rollbacks, body)
|
|
|
|
#define DO_LOGTYPES(lt, body) DO_STRUCTS(lt, logtypes, body)
|
|
|
|
#define DO_LOGTYPES_AND_ROLLBACKS(lt, body) (DO_ROLLBACKS(lt,body), DO_LOGTYPES(lt, body))
|
|
|
|
#define DO_FIELDS(fld, lt, body) do { \
|
|
struct field *fld; \
|
|
for (fld=lt->fields; fld->type; fld++) { \
|
|
body; \
|
|
} } while (0)
|
|
|
|
|
|
static void __attribute__((format (printf, 3, 4))) fprintf2 (FILE *f1, FILE *f2, const char *format, ...) {
|
|
va_list ap;
|
|
int r;
|
|
va_start(ap, format);
|
|
r=vfprintf(f1, format, ap); assert(r>=0);
|
|
va_end(ap);
|
|
va_start(ap, format);
|
|
r=vfprintf(f2, format, ap); assert(r>=0);
|
|
va_end(ap);
|
|
}
|
|
|
|
FILE *hf=0, *cf=0;
|
|
|
|
static void
|
|
generate_enum_internal (char *enum_name, char *enum_prefix, const struct logtype *lts) {
|
|
char used_cmds[256];
|
|
int count=0;
|
|
memset(used_cmds, 0, 256);
|
|
fprintf(hf, "enum %s {", enum_name);
|
|
DO_STRUCTS(lt, lts,
|
|
{
|
|
unsigned char cmd = (unsigned char)(lt->command_and_flags&0xff);
|
|
if (count!=0) fprintf(hf, ",");
|
|
count++;
|
|
fprintf(hf, "\n");
|
|
fprintf(hf," %s_%-16s = '%c'", enum_prefix, lt->name, cmd);
|
|
if (used_cmds[cmd]!=0) { fprintf(stderr, "%s:%d: error: Command %d (%c) was used twice (second time for %s)\n", __FILE__, __LINE__, cmd, cmd, lt->name); abort(); }
|
|
used_cmds[cmd]=1;
|
|
});
|
|
fprintf(hf, "\n};\n\n");
|
|
|
|
}
|
|
|
|
static void
|
|
generate_enum (void) {
|
|
generate_enum_internal("lt_cmd", "LT", logtypes);
|
|
generate_enum_internal("rt_cmd", "RT", rollbacks);
|
|
}
|
|
|
|
static void
|
|
generate_log_struct (void) {
|
|
DO_LOGTYPES(lt,
|
|
{ fprintf(hf, "struct logtype_%s {\n", lt->name);
|
|
fprintf(hf, " %-16s lsn;\n", "LSN");
|
|
DO_FIELDS(ft, lt,
|
|
fprintf(hf, " %-16s %s;\n", ft->type, ft->name));
|
|
fprintf(hf, " %-16s crc;\n", "u_int32_t");
|
|
fprintf(hf, " %-16s len;\n", "u_int32_t");
|
|
fprintf(hf, "};\n");
|
|
//fprintf(hf, "void toku_recover_%s (LSN lsn", lt->name);
|
|
//DO_FIELDS(ft, lt, fprintf(hf, ", %s %s", ft->type, ft->name));
|
|
//fprintf(hf, ");\n");
|
|
});
|
|
DO_ROLLBACKS(lt,
|
|
{ fprintf(hf, "struct rolltype_%s {\n", lt->name);
|
|
DO_FIELDS(ft, lt,
|
|
fprintf(hf, " %-16s %s;\n", ft->type, ft->name));
|
|
fprintf(hf, "};\n");
|
|
fprintf(hf, "int toku_rollback_%s (", lt->name);
|
|
DO_FIELDS(ft, lt, fprintf(hf, "%s %s,", ft->type, ft->name));
|
|
fprintf(hf, "TOKUTXN txn);\n");
|
|
fprintf(hf, "int toku_commit_%s (", lt->name);
|
|
DO_FIELDS(ft, lt, fprintf(hf, "%s %s,", ft->type, ft->name));
|
|
fprintf(hf, "TOKUTXN txn);\n");
|
|
});
|
|
fprintf(hf, "struct log_entry {\n");
|
|
fprintf(hf, " enum lt_cmd cmd;\n");
|
|
fprintf(hf, " union {\n");
|
|
DO_LOGTYPES(lt, fprintf(hf," struct logtype_%s %s;\n", lt->name, lt->name));
|
|
fprintf(hf, " } u;\n");
|
|
fprintf(hf, "};\n");
|
|
|
|
fprintf(hf, "struct roll_entry {\n");
|
|
fprintf(hf, " enum rt_cmd cmd;\n");
|
|
fprintf(hf, " union {\n");
|
|
DO_ROLLBACKS(lt, fprintf(hf," struct rolltype_%s %s;\n", lt->name, lt->name));
|
|
fprintf(hf, " } u;\n");
|
|
fprintf(hf, " struct roll_entry *prev; /* for in-memory list of log entries. Threads from newest to oldest. */\n");
|
|
fprintf(hf, " struct roll_entry *next; /* Points to a newer logentry. Needed for flushing to disk, since we want to write the oldest one first. */\n");
|
|
fprintf(hf, "};\n");
|
|
|
|
}
|
|
|
|
static void
|
|
generate_dispatch (void) {
|
|
fprintf(hf, "#define rolltype_dispatch(s, funprefix) ({ switch((s)->cmd) {\\\n");
|
|
DO_ROLLBACKS(lt, fprintf(hf, " case RT_%s: funprefix ## %s (&(s)->u.%s); break;\\\n", lt->name, lt->name, lt->name));
|
|
fprintf(hf, " }})\n");
|
|
|
|
fprintf(hf, "#define logtype_dispatch_assign(s, funprefix, var, ...) do { switch((s)->cmd) {\\\n");
|
|
DO_LOGTYPES(lt, fprintf(hf, " case LT_%s: var = funprefix ## %s (&(s)->u.%s, __VA_ARGS__); break;\\\n", lt->name, lt->name, lt->name));
|
|
fprintf(hf, " }} while (0)\n");
|
|
|
|
fprintf(hf, "#define rolltype_dispatch_assign(s, funprefix, var, ...) do { \\\n");
|
|
fprintf(hf, " switch((s)->cmd) {\\\n");
|
|
DO_ROLLBACKS(lt, {
|
|
fprintf(hf, " case RT_%s: var = funprefix ## %s (", lt->name, lt->name);
|
|
int fieldcount=0;
|
|
DO_FIELDS(ft, lt, {
|
|
if (fieldcount>0) fprintf(hf, ",");
|
|
fprintf(hf, "(s)->u.%s.%s", lt->name, ft->name);
|
|
fieldcount++;
|
|
});
|
|
fprintf(hf, ", __VA_ARGS__); break;\\\n");
|
|
});
|
|
fprintf(hf, " default: assert(0);} } while (0)\n");
|
|
|
|
fprintf(hf, "#define logtype_dispatch_args(s, funprefix) do { switch((s)->cmd) {\\\n");
|
|
DO_LOGTYPES(lt,
|
|
{
|
|
fprintf(hf, " case LT_%s: funprefix ## %s ((s)->u.%s.lsn", lt->name, lt->name, lt->name);
|
|
DO_FIELDS(ft, lt, fprintf(hf, ",(s)->u.%s.%s", lt->name, ft->name));
|
|
fprintf(hf, "); break;\\\n");
|
|
});
|
|
fprintf(hf, " }} while (0)\n");
|
|
}
|
|
|
|
static void
|
|
generate_log_writer (void) {
|
|
DO_LOGTYPES(lt, {
|
|
fprintf2(cf, hf, "int toku_log_%s (TOKULOGGER logger, LSN *lsnp, int do_fsync", lt->name);
|
|
DO_FIELDS(ft, lt, fprintf2(cf, hf, ", %s %s", ft->type, ft->name));
|
|
fprintf(hf, ");\n");
|
|
fprintf(cf, ") {\n");
|
|
fprintf(cf, " if (logger==0) return 0;\n");
|
|
fprintf(cf, " const unsigned int buflen= (+4 // len at the beginning\n");
|
|
fprintf(cf, " +1 // log command\n");
|
|
fprintf(cf, " +8 // lsn\n");
|
|
DO_FIELDS(ft, lt,
|
|
fprintf(cf, " +toku_logsizeof_%s(%s)\n", ft->type, ft->name));
|
|
fprintf(cf, " +8 // crc + len\n");
|
|
fprintf(cf, " );\n");
|
|
fprintf(cf, " struct wbuf wbuf;\n");
|
|
fprintf(cf, " struct logbytes *lbytes = MALLOC_LOGBYTES(buflen);\n");
|
|
fprintf(cf, " if (lbytes==0) return errno;\n");
|
|
fprintf(cf, " wbuf_init(&wbuf, &lbytes->bytes[0], buflen);\n");
|
|
fprintf(cf, " wbuf_int(&wbuf, buflen);\n");
|
|
fprintf(cf, " wbuf_char(&wbuf, '%c');\n", (char)(0xff<->command_and_flags));
|
|
fprintf(cf, " ml_lock(&logger->input_lock);\n");
|
|
fprintf(cf, " logger->lsn.lsn++;\n");
|
|
fprintf(cf, " LSN lsn = logger->lsn;\n");
|
|
fprintf(cf, " wbuf_LSN(&wbuf, lsn);\n");
|
|
fprintf(cf, " lbytes->lsn = lsn;\n");
|
|
fprintf(cf, " if (lsnp) *lsnp=logger->lsn;\n");
|
|
DO_FIELDS(ft, lt,
|
|
fprintf(cf, " wbuf_%s(&wbuf, %s);\n", ft->type, ft->name));
|
|
fprintf(cf, " int r= toku_logger_finish(logger, lbytes, &wbuf, do_fsync);\n");
|
|
fprintf(cf, " assert(wbuf.ndone==buflen);\n");
|
|
fprintf(cf, " return r;\n");
|
|
fprintf(cf, "}\n\n");
|
|
});
|
|
}
|
|
|
|
static void
|
|
generate_log_reader (void) {
|
|
DO_LOGTYPES(lt, {
|
|
fprintf(cf, "static int toku_log_fread_%s (FILE *infile, struct logtype_%s *data, struct x1764 *checksum)", lt->name, lt->name);
|
|
fprintf(cf, " {\n");
|
|
fprintf(cf, " int r=0;\n");
|
|
fprintf(cf, " u_int32_t actual_len=5; // 1 for the command, 4 for the first len.\n");
|
|
fprintf(cf, " r=toku_fread_%-16s(infile, &data->%-16s, checksum, &actual_len); if (r!=0) return r;\n", "LSN", "lsn");
|
|
DO_FIELDS(ft, lt,
|
|
fprintf(cf, " r=toku_fread_%-16s(infile, &data->%-16s, checksum, &actual_len); if (r!=0) return r;\n", ft->type, ft->name));
|
|
fprintf(cf, " u_int32_t checksum_in_file, len_in_file;\n");
|
|
fprintf(cf, " r=toku_fread_u_int32_t_nocrclen(infile, &checksum_in_file); actual_len+=4; if (r!=0) return r;\n");
|
|
fprintf(cf, " r=toku_fread_u_int32_t_nocrclen(infile, &len_in_file); actual_len+=4; if (r!=0) return r;\n");
|
|
fprintf(cf, " if (checksum_in_file!=x1764_finish(checksum) || len_in_file!=actual_len) return DB_BADFORMAT;\n");
|
|
fprintf(cf, " return 0;\n");
|
|
fprintf(cf, "}\n\n");
|
|
});
|
|
fprintf2(cf, hf, "int toku_log_fread (FILE *infile, struct log_entry *le)");
|
|
fprintf(hf, ";\n");
|
|
fprintf(cf, " {\n");
|
|
fprintf(cf, " u_int32_t len1; int r;\n");
|
|
fprintf(cf, " u_int32_t ignorelen=0;\n");
|
|
fprintf(cf, " struct x1764 checksum;\n");
|
|
fprintf(cf, " x1764_init(&checksum);\n");
|
|
fprintf(cf, " r = toku_fread_u_int32_t(infile, &len1, &checksum, &ignorelen); if (r!=0) return r;\n");
|
|
fprintf(cf, " int cmd=fgetc(infile);\n");
|
|
fprintf(cf, " if (cmd==EOF) return EOF;\n");
|
|
fprintf(cf, " char cmdchar = (char)cmd;\n");
|
|
fprintf(cf, " x1764_add(&checksum, &cmdchar, 1);\n");
|
|
fprintf(cf, " le->cmd=(enum lt_cmd)cmd;\n");
|
|
fprintf(cf, " switch ((enum lt_cmd)cmd) {\n");
|
|
DO_LOGTYPES(lt, {
|
|
fprintf(cf, " case LT_%s:\n", lt->name);
|
|
fprintf(cf, " return toku_log_fread_%s (infile, &le->u.%s, &checksum);\n", lt->name, lt->name);
|
|
});
|
|
fprintf(cf, " };\n");
|
|
fprintf(cf, " return DB_BADFORMAT;\n"); // Should read past the record using the len field.
|
|
fprintf(cf, "}\n\n");
|
|
}
|
|
|
|
static void
|
|
generate_logprint (void) {
|
|
unsigned maxnamelen=0;
|
|
fprintf2(cf, hf, "int toku_logprint_one_record(FILE *outf, FILE *f)");
|
|
fprintf(hf, ";\n");
|
|
fprintf(cf, " {\n");
|
|
fprintf(cf, " int cmd, r;\n");
|
|
fprintf(cf, " u_int32_t len1, crc_in_file;\n");
|
|
fprintf(cf, " u_int32_t ignorelen=0;\n");
|
|
fprintf(cf, " struct x1764 checksum;\n");
|
|
fprintf(cf, " x1764_init(&checksum);\n");
|
|
fprintf(cf, " r=toku_fread_u_int32_t(f, &len1, &checksum, &ignorelen);\n");
|
|
fprintf(cf, " if (r==EOF) return EOF;\n");
|
|
fprintf(cf, " cmd=fgetc(f);\n");
|
|
fprintf(cf, " if (cmd==EOF) return DB_BADFORMAT;\n");
|
|
fprintf(cf, " u_int32_t len_in_file, len=1+4; // cmd + len1\n");
|
|
fprintf(cf, " char charcmd = (char)cmd;\n");
|
|
fprintf(cf, " x1764_add(&checksum, &charcmd, 1);\n");
|
|
fprintf(cf, " switch ((enum lt_cmd)cmd) {\n");
|
|
DO_LOGTYPES(lt, { if (strlen(lt->name)>maxnamelen) maxnamelen=strlen(lt->name); });
|
|
DO_LOGTYPES(lt, {
|
|
unsigned char cmd = (unsigned char)(0xff<->command_and_flags);
|
|
fprintf(cf, " case LT_%s: \n", lt->name);
|
|
// We aren't using the log reader here because we want better diagnostics as soon as things go wrong.
|
|
fprintf(cf, " fprintf(outf, \"%%-%us \", \"%s\");\n", maxnamelen, lt->name);
|
|
if (isprint(cmd)) fprintf(cf," fprintf(outf, \" '%c':\");\n", cmd);
|
|
else fprintf(cf," fprintf(outf, \"0%03o:\");\n", cmd);
|
|
fprintf(cf, " r = toku_logprint_%-16s(outf, f, \"lsn\", &checksum, &len, 0); if (r!=0) return r;\n", "LSN");
|
|
DO_FIELDS(ft, lt, {
|
|
fprintf(cf, " r = toku_logprint_%-16s(outf, f, \"%s\", &checksum, &len,", ft->type, ft->name);
|
|
if (ft->format) fprintf(cf, "\"%s\"", ft->format);
|
|
else fprintf(cf, "0");
|
|
fprintf(cf, "); if (r!=0) return r;\n");
|
|
});
|
|
fprintf(cf, " {\n");
|
|
fprintf(cf, " u_int32_t actual_murmur = x1764_finish(&checksum);\n");
|
|
fprintf(cf, " r = toku_fread_u_int32_t_nocrclen (f, &crc_in_file); len+=4; if (r!=0) return r;\n");
|
|
fprintf(cf, " fprintf(outf, \" crc=%%08x\", crc_in_file);\n");
|
|
fprintf(cf, " if (crc_in_file!=actual_murmur) fprintf(outf, \" actual_fingerprint=%%08x\", actual_murmur);\n");
|
|
fprintf(cf, " r = toku_fread_u_int32_t_nocrclen (f, &len_in_file); len+=4; if (r!=0) return r;\n");
|
|
fprintf(cf, " fprintf(outf, \" len=%%u\", len_in_file);\n");
|
|
fprintf(cf, " if (len_in_file!=len) fprintf(outf, \" actual_len=%%u\", len);\n");
|
|
fprintf(cf, " if (len_in_file!=len || crc_in_file!=actual_murmur) return DB_BADFORMAT;\n");
|
|
fprintf(cf, " };\n");
|
|
fprintf(cf, " fprintf(outf, \"\\n\");\n");
|
|
fprintf(cf, " return 0;;\n\n");
|
|
});
|
|
fprintf(cf, " }\n");
|
|
fprintf(cf, " fprintf(outf, \"Unknown command %%d ('%%c')\", cmd, cmd);\n");
|
|
fprintf(cf, " return DB_BADFORMAT;\n");
|
|
fprintf(cf, "}\n\n");
|
|
}
|
|
|
|
static void
|
|
generate_rollbacks (void) {
|
|
DO_ROLLBACKS(lt, {
|
|
fprintf2(cf, hf, "int toku_logger_save_rollback_%s (TOKUTXN txn", lt->name);
|
|
DO_FIELDS(ft, lt, fprintf2(cf, hf, ", %s %s", ft->type, ft->name));
|
|
fprintf(hf, ");\n");
|
|
fprintf(cf, ") {\n");
|
|
{
|
|
int count=0;
|
|
fprintf(cf, " u_int32_t rollback_fsize = toku_logger_rollback_fsize_%s(", lt->name);
|
|
DO_FIELDS(ft, lt, fprintf(cf, "%s%s", (count++>0)?", ":"", ft->name));
|
|
fprintf(cf, ");\n");
|
|
}
|
|
fprintf(cf, " struct roll_entry *v = toku_malloc_in_rollback(txn, sizeof(*v));\n");
|
|
fprintf(cf, " if (v==0) return errno;\n");
|
|
fprintf(cf, " v->cmd = (enum rt_cmd)%u;\n", lt->command_and_flags&0xff);
|
|
DO_FIELDS(ft, lt, fprintf(cf, " v->u.%s.%s = %s;\n", lt->name, ft->name, ft->name));
|
|
fprintf(cf, " v->prev = txn->newest_logentry;\n");
|
|
fprintf(cf, " v->next = 0;\n");
|
|
fprintf(cf, " if (txn->oldest_logentry==0) txn->oldest_logentry=v;\n");
|
|
fprintf(cf, " else txn->newest_logentry->next = v;\n");
|
|
fprintf(cf, " txn->newest_logentry = v;\n");
|
|
fprintf(cf, " txn->rollentry_resident_bytecount += rollback_fsize;\n");
|
|
fprintf(cf, " return toku_maybe_spill_rollbacks(txn);\n}\n");
|
|
});
|
|
|
|
DO_ROLLBACKS(lt, {
|
|
fprintf2(cf, hf, "void toku_logger_rollback_wbufwrite_%s (struct wbuf *wbuf", lt->name);
|
|
DO_FIELDS(ft, lt, fprintf2(cf, hf, ", %s %s", ft->type, ft->name));
|
|
fprintf2(cf, hf, ")");
|
|
fprintf(hf, ";\n");
|
|
fprintf(cf, " {\n");
|
|
fprintf(cf, " u_int32_t ndone_at_start = wbuf->ndone;\n");
|
|
fprintf(cf, " wbuf_char(wbuf, '%c');\n", (char)(0xff<->command_and_flags));
|
|
DO_FIELDS(ft, lt, fprintf(cf, " wbuf_%s(wbuf, %s);\n", ft->type, ft->name));
|
|
fprintf(cf, " wbuf_int(wbuf, 4+wbuf->ndone - ndone_at_start);\n");
|
|
fprintf(cf, "}\n");
|
|
});
|
|
fprintf2(cf, hf, "void toku_logger_rollback_wbufwrite (struct wbuf *wbuf, struct roll_entry *r)");
|
|
fprintf(hf, ";\n");
|
|
fprintf(cf, " {\n switch (r->cmd) {\n");
|
|
DO_ROLLBACKS(lt, {
|
|
fprintf(cf, " case RT_%s: toku_logger_rollback_wbufwrite_%s(wbuf", lt->name, lt->name);
|
|
DO_FIELDS(ft, lt, fprintf(cf, ", r->u.%s.%s", lt->name, ft->name));
|
|
fprintf(cf, "); return;\n");
|
|
});
|
|
fprintf(cf, " }\n assert(0);\n");
|
|
fprintf(cf, "}\n");
|
|
DO_ROLLBACKS(lt, {
|
|
fprintf2(cf, hf, "u_int32_t toku_logger_rollback_fsize_%s (", lt->name);
|
|
int count=0;
|
|
DO_FIELDS(ft, lt, fprintf2(cf, hf, "%s%s %s", (count++>0)?", ":"", ft->type, ft->name));
|
|
fprintf(hf, ");\n");
|
|
fprintf(cf, ") {\n");
|
|
fprintf(cf, " return 1 /* the cmd*/\n");
|
|
fprintf(cf, " + 4 /* the int at the end saying the size */");
|
|
DO_FIELDS(ft, lt,
|
|
fprintf(cf, "\n + toku_logsizeof_%s(%s)", ft->type, ft->name));
|
|
fprintf(cf, ";\n}\n");
|
|
});
|
|
fprintf2(cf, hf, "u_int32_t toku_logger_rollback_fsize(struct roll_entry *item)");
|
|
fprintf(hf, ";\n");
|
|
fprintf(cf, "{\n switch(item->cmd) {\n");
|
|
DO_ROLLBACKS(lt, {
|
|
fprintf(cf, " case RT_%s: return toku_logger_rollback_fsize_%s(", lt->name, lt->name);
|
|
int count=0;
|
|
DO_FIELDS(ft, lt, fprintf(cf, "%sitem->u.%s.%s", (count++>0)?", ":"", lt->name, ft->name));
|
|
fprintf(cf, ");\n");
|
|
});
|
|
fprintf(cf, " }\n assert(0);\n return 0;\n");
|
|
fprintf(cf, "}\n");
|
|
|
|
fprintf2(cf, hf, "int toku_parse_rollback(unsigned char *buf, u_int32_t n_bytes, struct roll_entry **itemp, MEMARENA ma)");
|
|
fprintf(hf, ";\n");
|
|
fprintf(cf, " {\n assert(n_bytes>0);\n struct roll_entry *item = malloc_in_memarena(ma, sizeof(*item));\n item->cmd=(enum rt_cmd)(buf[0]);\n");
|
|
fprintf(cf, " struct rbuf rc = {buf, n_bytes, 1};\n");
|
|
fprintf(cf, " switch(item->cmd) {\n");
|
|
DO_ROLLBACKS(lt, {
|
|
fprintf(cf, " case RT_%s:\n", lt->name);
|
|
DO_FIELDS(ft, lt, fprintf(cf, " rbuf_ma_%s(&rc, ma, &item->u.%s.%s);\n", ft->type, lt->name, ft->name));
|
|
fprintf(cf, " *itemp = item;\n");
|
|
fprintf(cf, " return 0;\n");
|
|
});
|
|
fprintf(cf, " }\n return EINVAL;\n}\n");
|
|
}
|
|
|
|
|
|
const char *codepath = "log_code.c";
|
|
const char *headerpath = "log_header.h";
|
|
int main (int argc __attribute__((__unused__)), char *argv[] __attribute__((__unused__))) {
|
|
unlink(codepath);
|
|
unlink(headerpath);
|
|
cf = fopen(codepath, "w"); assert(cf!=0);
|
|
hf = fopen(headerpath, "w"); assert(hf!=0);
|
|
fprintf(hf, "#ifndef LOG_HEADER_H\n");
|
|
fprintf(hf, "#define LOG_HEADER_H\n");
|
|
fprintf2(cf, hf, "/* Do not edit this file. This code generated by logformat.c. Copyright 2007, 2008 Tokutek. */\n");
|
|
fprintf2(cf, hf, "#ident \"Copyright (c) 2007, 2008 Tokutek Inc. All rights reserved.\"\n");
|
|
fprintf(cf, "#include \"includes.h\"\n");
|
|
fprintf(hf, "#include \"brt-internal.h\"\n");
|
|
fprintf(hf, "#include \"memarena.h\"\n");
|
|
generate_enum();
|
|
generate_log_struct();
|
|
generate_dispatch();
|
|
generate_log_writer();
|
|
generate_log_reader();
|
|
generate_logprint();
|
|
generate_rollbacks();
|
|
fprintf(hf, "#endif\n");
|
|
{
|
|
int r=fclose(hf);
|
|
assert(r==0);
|
|
r=fclose(cf);
|
|
assert(r==0);
|
|
// Make it tougher to modify by mistake
|
|
chmod(codepath, S_IRUSR|S_IRGRP|S_IROTH);
|
|
chmod(headerpath, S_IRUSR|S_IRGRP|S_IROTH);
|
|
}
|
|
return 0;
|
|
}
|
|
|