Files
mongo/dist/log.py

261 lines
6.2 KiB
Python

#!/usr/bin/env python
import os, re, sys, textwrap
from dist import compare_srcfile
import log_data
# Temporary file.
tmp_file = '__tmp'
# Map log record types to:
# (C type, pack type, printf format, printf arg(s))
field_types = {
'string' : ('const char *', 'S', '%s', 'arg'),
'item' : ('WT_ITEM *', 'u', '%.*s',
'(int)arg.size, (const char *)arg.data'),
'recno' : ('uint64_t', 'r', '%" PRIu64 "', 'arg'),
'uint32' : ('uint32_t', 'I', '%" PRIu32 "', 'arg'),
'uint64' : ('uint64_t', 'Q', '%" PRIu64 "', 'arg'),
}
def cintype(f):
return field_types[f[0]][0]
def couttype(f):
type = cintype(f)
# We already have a pointer to a WT_ITEM
if f[0] == 'item':
return type
if type[-1] != '*':
type += ' '
return type + '*'
def clocaltype(f):
type = cintype(f)
# Allocate a WT_ITEM struct on the stack
if f[0] == 'item':
return type[:-2]
return type
def pack_fmt(fields):
return ''.join(field_types[f[0]][1] for f in fields)
def op_pack_fmt(r):
return 'II' + pack_fmt(r.fields)
def rec_pack_fmt(r):
return 'I' + pack_fmt(r.fields)
def printf_fmt(f):
return field_types[f[0]][2]
def printf_arg(f):
arg = field_types[f[0]][3].replace('arg', f[1])
return '\n\t ' + arg if f[0] == 'item' else ' ' + arg
#####################################################################
# Update log.h with #defines for types
#####################################################################
log_defines = (
''.join('#define\t%s\t%d\n' % (r.macro_name(), i)
for i, r in enumerate(log_data.rectypes)) +
''.join('#define\t%s\t%d\n' % (r.macro_name(), i)
for i, r in enumerate(log_data.optypes))
)
tfile = open(tmp_file, 'w')
skip = 0
for line in open('../src/include/log.h', 'r'):
if skip:
if 'Log record declarations: END' in line:
tfile.write('/*\n' + line)
skip = 0
else:
tfile.write(line)
if 'Log record declarations: BEGIN' in line:
skip = 1
tfile.write(' */\n')
tfile.write(log_defines)
tfile.close()
compare_srcfile(tmp_file, '../src/include/log.h')
#####################################################################
# Create log_auto.c with handlers for each record / operation type.
#####################################################################
f='../src/log/log_auto.c'
tfile = open(tmp_file, 'w')
tfile.write('/* DO NOT EDIT: automatically built by dist/log.py. */\n')
tfile.write('''
#include "wt_internal.h"
int
__wt_logrec_alloc(WT_SESSION_IMPL *session, size_t size, WT_ITEM **logrecp)
{
WT_ITEM *logrec;
WT_RET(__wt_scr_alloc(session, WT_ALIGN(size + 1, LOG_ALIGN), &logrec));
WT_CLEAR(*(WT_LOG_RECORD *)logrec->data);
logrec->size = offsetof(WT_LOG_RECORD, record);
*logrecp = logrec;
return (0);
}
void
__wt_logrec_free(WT_SESSION_IMPL *session, WT_ITEM **logrecp)
{
WT_UNUSED(session);
__wt_scr_free(logrecp);
}
int
__wt_logrec_read(WT_SESSION_IMPL *session,
const uint8_t **pp, const uint8_t *end, uint32_t *rectypep)
{
uint64_t rectype;
WT_UNUSED(session);
WT_RET(__wt_vunpack_uint(pp, WT_PTRDIFF(end, *pp), &rectype));
*rectypep = (uint32_t)rectype;
return (0);
}
int
__wt_logop_read(WT_SESSION_IMPL *session,
const uint8_t **pp, const uint8_t *end,
uint32_t *optypep, uint32_t *opsizep)
{
return (__wt_struct_unpack(
session, *pp, WT_PTRDIFF(end, *pp), "II", optypep, opsizep));
}
''')
# Emit code to read, write and print log operations (within a log record)
for optype in log_data.optypes:
if not optype.fields:
continue
tfile.write('''
int
__wt_logop_%(name)s_pack(
WT_SESSION_IMPL *session, WT_ITEM *logrec,
%(arg_decls)s)
{
const char *fmt = WT_UNCHECKED_STRING(%(fmt)s);
size_t size;
uint32_t optype, recsize;
optype = %(macro)s;
WT_RET(__wt_struct_size(session, &size, fmt,
optype, 0%(arg_names)s));
size += __wt_vsize_uint(size) - 1;
WT_RET(__wt_buf_extend(session, logrec, logrec->size + size));
recsize = (uint32_t)size;
WT_RET(__wt_struct_pack(session,
(uint8_t *)logrec->data + logrec->size, size, fmt,
optype, recsize%(arg_names)s));
logrec->size += (uint32_t)size;
return (0);
}
''' % {
'name' : optype.name,
'macro' : optype.macro_name(),
'arg_decls' : ', '.join(
'%s%s%s' % (cintype(f), '' if cintype(f)[-1] == '*' else ' ', f[1])
for f in optype.fields),
'arg_names' : ''.join(', %s' % f[1] for f in optype.fields),
'fmt' : op_pack_fmt(optype)
})
tfile.write('''
int
__wt_logop_%(name)s_unpack(
WT_SESSION_IMPL *session, const uint8_t **pp, const uint8_t *end,
%(arg_decls)s)
{
const char *fmt = WT_UNCHECKED_STRING(%(fmt)s);
uint32_t optype, size;
WT_RET(__wt_struct_unpack(session, *pp, WT_PTRDIFF(end, *pp), fmt,
&optype, &size%(arg_names)s));
WT_ASSERT(session, optype == %(macro)s);
*pp += size;
return (0);
}
''' % {
'name' : optype.name,
'macro' : optype.macro_name(),
'arg_decls' : ', '.join(
'%s%sp' % (couttype(f), f[1]) for f in optype.fields),
'arg_names' : ''.join(', %sp' % f[1] for f in optype.fields),
'fmt' : op_pack_fmt(optype)
})
tfile.write('''
int
__wt_logop_%(name)s_print(
WT_SESSION_IMPL *session, const uint8_t **pp, const uint8_t *end, FILE *out)
{
%(arg_decls)s
WT_RET(__wt_logop_%(name)s_unpack(
session, pp, end%(arg_addrs)s));
%(print_args)s
return (0);
}
''' % {
'name' : optype.name,
'arg_decls' : '\n\t'.join('%s%s%s;' %
(clocaltype(f), '' if clocaltype(f)[-1] == '*' else ' ', f[1])
for f in optype.fields),
'arg_addrs' : ''.join(', &%s' % f[1] for f in optype.fields),
'print_args' : '\n\t'.join(
'fprintf(out, " \\"%s\\": \\"%s\\",\\n",%s);' %
(f[1], printf_fmt(f), printf_arg(f))
for f in optype.fields),
})
# Emit the printlog entry point
tfile.write('''
int
__wt_txn_op_printlog(
WT_SESSION_IMPL *session, const uint8_t **pp, const uint8_t *end, FILE *out)
{
uint32_t optype, opsize;
/* Peek at the size and the type. */
WT_RET(__wt_logop_read(session, pp, end, &optype, &opsize));
end = *pp + opsize;
switch (optype) {''')
for optype in log_data.optypes:
if not optype.fields:
continue
tfile.write('''
case %(macro)s:
WT_RET(%(print_func)s(session, pp, end, out));
break;
''' % {
'macro' : optype.macro_name(),
'print_func' : '__wt_logop_' + optype.name + '_print',
})
tfile.write('''
WT_ILLEGAL_VALUE(session);
}
return (0);
}
''')
tfile.close()
compare_srcfile(tmp_file, f)