453 lines
14 KiB
Python
453 lines
14 KiB
Python
# Read the api file and output C for the SESSION/BTREE structures, getter/setter
|
|
# functions, and other API initialization.
|
|
|
|
import os, string, sys
|
|
from dist import compare_srcfile
|
|
|
|
# Temporary file.
|
|
tmp_file = '__tmp'
|
|
|
|
# func_method_std --
|
|
# Set methods to reference their underlying function.
|
|
def func_method_std(handle, method, config, f):
|
|
f.write('\t' + handle + '->' +
|
|
method + ' = __wt_api_' + handle + '_' + method + ';\n')
|
|
|
|
# func_method_single --
|
|
# Set methods to a single underlying function.
|
|
def func_method_single(handle, method, config, args, func, f):
|
|
f.write('\t' + handle + '->' + method + ' = (')
|
|
if config.count('methodV'):
|
|
f.write('void')
|
|
else:
|
|
f.write('int')
|
|
f.write(' (*)\n\t (' + handle.upper() + ' *')
|
|
for l in args:
|
|
f.write(', ' + l.split('/')[1].replace('@S', ''))
|
|
f.write('))\n\t __wt_' + handle + '_' + func + ';\n')
|
|
|
|
# func_method_init --
|
|
# Set getter/setter initialization values.
|
|
def func_method_init(handle, decl, f):
|
|
f.write('void\n__wt_methods_' +
|
|
handle + '_config_default(' + decl + ')\n{\n')
|
|
for i in sorted(filter(lambda _i:
|
|
_i[1].handle == handle, api.items())):
|
|
for l in i[1].args:
|
|
if l.count('/') == 2:
|
|
f.write('\t' + handle + '->' +
|
|
l.split('/')[0] + ' = ' +
|
|
l.split('/')[2] + ';\n')
|
|
f.write('}\n\n')
|
|
|
|
# func_method_lockout --
|
|
# Set a handle's methods to the lockout function (skipping the close
|
|
# method, it's always legal).
|
|
def func_method_lockout(handle, decl, f):
|
|
quiet = 1
|
|
f.write('void\n__wt_methods_' + handle + '_lockout(' + decl + ')\n{\n')
|
|
for i in sorted(filter(lambda _i:
|
|
_i[1].handle == handle and _i[1].method != 'close',
|
|
api.items())):
|
|
func_method_single(i[1].handle,
|
|
i[1].method, i[1].config, i[1].args, 'lockout', f)
|
|
quiet = 0;
|
|
if quiet:
|
|
f.write('\tWT_UNUSED(' + handle + ');\n')
|
|
f.write('}\n\n')
|
|
|
|
# func_method_transition --
|
|
# Write functions that transition a handle's methods on or off.
|
|
def func_method_transition(handle, decl, f):
|
|
# Build dictionaries of methods that need on/off transitions, keyed
|
|
# by the name of the transition, and a list of the transition names.
|
|
on={}
|
|
off={}
|
|
trans=[]
|
|
for i in sorted(filter(lambda _i:
|
|
_i[1].handle == handle, api.items())):
|
|
for j in i[1].off:
|
|
if j not in off:
|
|
off[j] = []
|
|
if j not in on:
|
|
on[j] = []
|
|
off[j].append(i[1])
|
|
for j in i[1].on:
|
|
if j not in trans:
|
|
trans.append(j)
|
|
if j not in off:
|
|
off[j] = []
|
|
if j not in on:
|
|
on[j] = []
|
|
on[j].append(i[1])
|
|
|
|
# Write a transition function that turns methods on/off.
|
|
for i in trans:
|
|
f.write('void\n__wt_methods_' +\
|
|
handle + '_' + i + '_transition' + '(' + decl + ')\n{\n')
|
|
for j in off[i]:
|
|
func_method_single(
|
|
j.handle, j.method, j.config, j.args, 'lockout', f)
|
|
for j in on[i]:
|
|
func_method_std(j.handle, j.method, j.config, f)
|
|
f.write('}\n\n')
|
|
|
|
# func_struct_all
|
|
# Write out the struct entries for a handle's methods.
|
|
def func_struct_all(handle, f):
|
|
for i in sorted(filter(lambda _i:
|
|
_i[1].handle.count(handle), api.items())):
|
|
func_struct(i[1], f)
|
|
|
|
# func_struct --
|
|
# Output method name for a structure entry.
|
|
def func_struct(a, f):
|
|
handle = a.handle
|
|
method = a.method
|
|
config = a.config
|
|
args = a.args
|
|
|
|
f.write('\n\t')
|
|
if config.count('methodV'):
|
|
f.write('void')
|
|
else:
|
|
f.write('int')
|
|
f.write(' (*' + method + ')(\n\t ' + handle.upper() + ' *')
|
|
for l in args:
|
|
f.write(', ' + l.split('/')[1].replace('@S', ''))
|
|
f.write(');\n')
|
|
|
|
# func_struct_variable_all
|
|
# Output include file getter/setter variables for all methods.
|
|
def func_struct_variable_all(handle, f):
|
|
for i in sorted(filter(lambda _i:
|
|
_i[1].handle.count(handle) and
|
|
_i[1].config.count('setter') and not
|
|
_i[1].config.count('extfunc'), api.items())):
|
|
func_struct_variable(i[1].args, f)
|
|
|
|
# func_struct_variable
|
|
# Output include file getter/setter variables for a method.
|
|
def func_struct_variable(args, f):
|
|
# Put blanks between each function's variables.
|
|
f.write('\n')
|
|
|
|
# Flags to the setter don't get propagated into the structure.
|
|
for l in args:
|
|
if not l.count('flags'):
|
|
f.write('\t' + l.split
|
|
('/')[1].replace('@S', l.split('/')[0]) + ';\n')
|
|
|
|
# func_method_decl --
|
|
# Generate the API methods declaration.
|
|
def func_method_decl(a, f):
|
|
handle = a.handle
|
|
method = a.method
|
|
config = a.config
|
|
args = a.args
|
|
|
|
s = 'static '
|
|
if config.count('methodV'):
|
|
s += 'void'
|
|
else:
|
|
s += 'int'
|
|
s += ' __wt_api_' + handle +\
|
|
'_' + method + '(\n\t' + handle.upper() + ' *' + handle
|
|
for l in args:
|
|
s += ',\n\t' +\
|
|
l.split('/')[1].replace('@S', l.split('/')[0])
|
|
s += ')'
|
|
f.write(s + ';\n')
|
|
f.write(s + '\n{\n')
|
|
|
|
# func_method_getset --
|
|
# Generate the getter/setter functions.
|
|
def func_method_getset(a, f):
|
|
func_method_decl(a, f)
|
|
|
|
handle = a.handle
|
|
method = a.method
|
|
config = a.config
|
|
args = a.args
|
|
|
|
extfunc = config.count('extfunc')
|
|
|
|
# Declarations:
|
|
# If we don't have a connection handle, acquire one.
|
|
if handle != 'connection':
|
|
if handle == 'session':
|
|
f.write('\tCONNECTION *connection = S2C(' + handle + ');\n')
|
|
else:
|
|
f.write('\tCONNECTION *connection = ' + handle + '->conn;\n')
|
|
if handle != 'session':
|
|
f.write('\tSESSION *session = &connection->default_session;\n')
|
|
# If we are hand-coding the routine, we'll need a place to save the
|
|
# return value.
|
|
if extfunc:
|
|
f.write('\tint ret;\n')
|
|
if handle != 'connection' or extfunc:
|
|
f.write('\n')
|
|
|
|
# If we have a "flags" argument to a setter function, check it
|
|
# before we continue.
|
|
if config.count('setter'):
|
|
for l in args:
|
|
if l.count('flags/'):
|
|
f.write('\tWT_CONN_FCHK(connection, "' +
|
|
handle.upper() + '.' + method +
|
|
'",\n\t ' + l.split('/')[0] +
|
|
', WT_APIMASK_' + handle.upper() +
|
|
'_' + method.upper() + ');\n\n')
|
|
break
|
|
|
|
# Verify means call a standard verification routine because there are
|
|
# constraints or side-effects on setting the value. The setter fails
|
|
# if the verification routine fails.
|
|
if config.count('verify'):
|
|
f.write('\tWT_RET((__wt_' +
|
|
handle + '_' + method + '_verify(\n\t ' + handle)
|
|
s = ''
|
|
for l in args:
|
|
s += ', ' + l.split('/')[0]
|
|
s += ')'
|
|
f.write(s + '));\n')
|
|
|
|
# getter/setter implies connlock: lock the data structure.
|
|
f.write('\t__wt_lock(session, connection->mtx);\n')
|
|
|
|
# Count the call.
|
|
s = a.handle + '_' + a.method
|
|
f.write('\tWT_STAT_INCR(connection->method_stats, ' + s.upper() + ');\n')
|
|
|
|
# If the function is hand-coded, just call it.
|
|
if extfunc:
|
|
f.write('\tret = __wt_' +
|
|
handle + '_' + method + '(\n\t ' + handle)
|
|
for l in args:
|
|
f.write(', ' + l.split('/')[0])
|
|
f.write(');\n')
|
|
elif config.count('getter'):
|
|
for l in args:
|
|
if l.count('flags/') and flags[a.key][0] == '__NONE__':
|
|
continue
|
|
f.write('\t*' + l.split('/')[0] + ' = ' +
|
|
handle + '->' + l.split('/')[0] + ';\n')
|
|
else:
|
|
for l in args:
|
|
if l.count('flags/'):
|
|
if flags[a.key][0] != '__NONE__':
|
|
f.write('\tF_SET(' + handle + ', flags);\n')
|
|
continue
|
|
f.write('\t' + handle + '->' +
|
|
l.split('/')[0] + ' = ' + l.split('/')[0] + ';\n')
|
|
|
|
# getter/setter implies connlock: unlock the data structure.
|
|
f.write('\t__wt_unlock(session, connection->mtx);\n')
|
|
f.write('\treturn (')
|
|
if extfunc:
|
|
f.write('ret')
|
|
else:
|
|
f.write('0')
|
|
f.write(');\n}\n\n')
|
|
|
|
# func_method --
|
|
# Generate all non-getter/setter API entry functions.
|
|
def func_method(a, f):
|
|
# Write the declaration for this function.
|
|
func_method_decl(a, f)
|
|
|
|
handle = a.handle
|
|
method = a.method
|
|
config = a.config
|
|
args = a.args
|
|
|
|
colonly = config.count('colonly') # Check row-only databases
|
|
locking = config.count('connlock') # Lock
|
|
rdonly = config.count('rdonly') # Check read-only databases
|
|
restart = config.count('restart') # Handle WT_RESTART
|
|
rowonly = config.count('rowonly') # Check row-only databases
|
|
|
|
flagchk = 0 # We're checking flags
|
|
for l in args:
|
|
if l.count('flags/'):
|
|
flagchk = 1
|
|
|
|
session = config.count('session') # Handle a SESSION
|
|
have_session = handle == 'session' or args[0].count('session/')
|
|
|
|
# We may need a method name.
|
|
if colonly or flagchk or rdonly or rowonly or session:
|
|
f.write('\tconst char *method_name = "' +
|
|
handle.upper() + '.' + method + '";\n')
|
|
|
|
# We need a CONNECTION handle, find it.
|
|
if handle != 'connection':
|
|
if handle == 'session':
|
|
f.write('\tCONNECTION *connection = S2C(' + handle + ');\n')
|
|
else:
|
|
f.write('\tCONNECTION *connection = ' + handle + '->conn;\n')
|
|
|
|
# If we're allocating a SESSION, we'll need a pointer on the stack.
|
|
if session and not have_session:
|
|
f.write('\tSESSION *session = NULL;\n')
|
|
elif locking and not have_session:
|
|
f.write('\tSESSION *session = &connection->default_session;\n')
|
|
f.write('\tint ret;\n\n')
|
|
|
|
# Check if the method is illegal for the database type.
|
|
if colonly:
|
|
f.write('\tWT_DB_COL_ONLY(session, btree, method_name);\n')
|
|
if rowonly:
|
|
f.write('\tWT_DB_ROW_ONLY(session, btree, method_name);\n')
|
|
|
|
# Check if the method is illegal for read-only databases.
|
|
if rdonly:
|
|
f.write('\tWT_DB_RDONLY(session, btree, method_name);\n')
|
|
|
|
# If entering the API with a SESSION handle, allocate/initialize it.
|
|
if session:
|
|
f.write('\tWT_RET(' +
|
|
'__wt_session_api_set(connection, method_name, btree, &session));\n')
|
|
|
|
# Check flags.
|
|
if flagchk:
|
|
f.write('\tWT_CONN_FCHK(connection, method_name, flags, WT_APIMASK_' +
|
|
handle.upper() + '_' + method.upper() + ');\n')
|
|
|
|
# Acquire the lock.
|
|
if locking:
|
|
f.write('\t__wt_lock(session, connection->mtx);\n')
|
|
|
|
# Method call statistics -- we put the update inside the lock just to
|
|
# make the stat value a little more precise.
|
|
stat = a.handle + '_' + a.method
|
|
stat = stat.upper()
|
|
f.write('\tWT_STAT_INCR(connection->method_stats, ' + stat + ');\n')
|
|
|
|
# Call the underlying method function, handling restart as necessary.
|
|
f.write('\t')
|
|
if restart:
|
|
f.write('while ((')
|
|
f.write('ret = __wt_' + handle + '_' + method + '(')
|
|
|
|
# Some functions take BTREE handles but pass SESSION handles; some functions
|
|
# take BTREE and SESSION handles, and pass SESSION handles.
|
|
if session:
|
|
handle = 'session'
|
|
f.write(handle)
|
|
for l in args:
|
|
if l.count('flags/') and flags[a.key][0] == '__NONE__':
|
|
continue
|
|
if not session or not l.count('session/'):
|
|
f.write(', ' + l.split('/')[0])
|
|
if restart:
|
|
f.write(')) == WT_RESTART)\n')
|
|
f.write('\t\tWT_STAT_INCR(connection->method_stats, ' +
|
|
stat + '_RESTART);\n')
|
|
else:
|
|
f.write(');\n')
|
|
|
|
# Unlock.
|
|
if locking:
|
|
if handle == 'session' and method == 'close':
|
|
f.write('\tsession = &connection->default_session;\n')
|
|
f.write('\t__wt_unlock(session, connection->mtx);\n')
|
|
|
|
# If entering the API with a SESSION handle, free/clear it.
|
|
if session:
|
|
f.write('\tWT_TRET(__wt_session_api_clr(session, method_name, ')
|
|
if not have_session:
|
|
f.write('1')
|
|
else:
|
|
f.write('0')
|
|
f.write('));\n')
|
|
|
|
# And return.
|
|
f.write('\treturn (ret);\n}\n\n')
|
|
|
|
#####################################################################
|
|
# Build the API dictionary.
|
|
#####################################################################
|
|
import api_class
|
|
api = api_class.methods
|
|
flags = api_class.flags
|
|
|
|
#####################################################################
|
|
# Update api_int.c, the API source file.
|
|
#####################################################################
|
|
tfile = open(tmp_file, 'w')
|
|
tfile.write('/* DO NOT EDIT: automatically built by dist/api.py. */\n\n')
|
|
tfile.write('#include "wt_internal.h"\n\n')
|
|
|
|
# We need an API function for any method not marked 'noauto'.
|
|
for i in sorted(api.items()):
|
|
if i[1].config.count('noauto'):
|
|
continue
|
|
if i[1].config.count('getter') or i[1].config.count('setter'):
|
|
func_method_getset(i[1], tfile)
|
|
else:
|
|
func_method(i[1], tfile)
|
|
|
|
# Write the method default initialization, lockout and transition functions.
|
|
func_method_init('btree', 'BTREE *btree', tfile)
|
|
func_method_lockout('btree', 'BTREE *btree', tfile)
|
|
func_method_transition('btree', 'BTREE *btree', tfile)
|
|
|
|
func_method_init('connection', 'CONNECTION *connection', tfile)
|
|
func_method_lockout('connection', 'CONNECTION *connection', tfile)
|
|
func_method_transition('connection', 'CONNECTION *connection', tfile)
|
|
|
|
func_method_lockout('session', 'SESSION *session', tfile)
|
|
func_method_transition('session', 'SESSION *session', tfile)
|
|
|
|
tfile.close()
|
|
compare_srcfile(tmp_file, '../src/api/api_int.c')
|
|
|
|
#####################################################################
|
|
# Update api.h file with SESSION/BTREE methods and BTREE/CONNECTION
|
|
# getter/setter variables.
|
|
#####################################################################
|
|
tfile = open(tmp_file, 'w')
|
|
skip = 0
|
|
for line in open('../src/include/api.h', 'r'):
|
|
if skip:
|
|
if line.count('BTREE methods: END') or\
|
|
line.count('CONNECTION methods: END') or\
|
|
line.count('SESSION methods: END') or\
|
|
line.count('SESSION getter/setter variables: END') or\
|
|
line.count('BTREE getter/setter variables: END') or\
|
|
line.count('CONNECTION getter/setter variables: END'):
|
|
tfile.write('\t/*\n' + line)
|
|
skip = 0
|
|
else:
|
|
tfile.write(line)
|
|
if line.count('BTREE methods: BEGIN'):
|
|
skip = 1
|
|
tfile.write('\t */')
|
|
func_struct_all('btree', tfile)
|
|
elif line.count('CONNECTION methods: BEGIN'):
|
|
skip = 1
|
|
tfile.write('\t */')
|
|
func_struct_all('connection', tfile)
|
|
elif line.count('SESSION methods: BEGIN'):
|
|
skip = 1
|
|
tfile.write('\t */')
|
|
func_struct_all('session', tfile)
|
|
elif line.count('BTREE getter/setter variables: BEGIN'):
|
|
skip = 1
|
|
tfile.write('\t */')
|
|
func_struct_variable_all('btree', tfile)
|
|
elif line.count('CONNECTION getter/setter variables: BEGIN'):
|
|
skip = 1
|
|
tfile.write('\t */')
|
|
func_struct_variable_all('connection', tfile)
|
|
elif line.count('SESSION getter/setter variables: BEGIN'):
|
|
skip = 1
|
|
tfile.write('\t */')
|
|
func_struct_variable_all('session', tfile)
|
|
|
|
tfile.close()
|
|
compare_srcfile(tmp_file, '../src/include/api.h')
|
|
|
|
os.remove(tmp_file)
|