1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
#!/usr/bin/python2
# This script generates the boilerplate versions of most fops and cbks in the
# server. This allows the details of leadership-status checking, sequencing
# between leader and followers (including fan-out), and basic error checking
# to be centralized one place, with per-operation code kept to a minimum.
from __future__ import print_function
import os
import re
import string
import sys
curdir = os.path.dirname(sys.argv[0])
gendir = os.path.join(curdir, '../../../../libglusterfs/src')
sys.path.append(gendir)
from generator import ops, fop_subs, cbk_subs, generate
# We really want the callback argument list, even when we're generating fop
# code, so we propagate here.
# TBD: this should probably be right in generate.py
for k, v in cbk_subs.iteritems():
fop_subs[k]['@ERROR_ARGS@'] = v['@ERROR_ARGS@']
# Stolen from old codegen.py
def load_templates (path):
templates = {}
tmpl_re = re.compile("/\* template-name (.*) \*/")
templates = {}
t_name = None
for line in open(path, "r").readlines():
if not line:
break
m = tmpl_re.match(line)
if m:
if t_name:
templates[t_name] = string.join(t_contents, '')
t_name = m.group(1).strip()
t_contents = []
elif t_name:
t_contents.append(line)
if t_name:
templates[t_name] = string.join(t_contents, '')
return templates
# We need two types of templates. The first, for pure read operations, just
# needs to do a simple am-i-leader check (augmented to allow dirty reads).
# The second, for pure writes, needs to do fan-out to followers between those
# initial checks and local execution. There are other operations that don't
# fit neatly into either category - e.g. lock ops or fsync - so we'll just have
# to handle those manually. The table thus includes entries only for those we
# can categorize. The special cases, plus any new operations we've never even
# heard of, aren't in there.
#
# Various keywords can be used to define/undefine preprocessor symbols used
# in the templates, on a per-function basis. For example, if the keyword here
# is "fsync" (lowercase word or abbreviation) that will cause JBR_CG_FSYNC
# (prefix plus uppercase version) to be defined above all of the generated code
# for that fop.
fop_table = {
"access": "read",
"create": "write",
"discard": "write",
# "entrylk": "read",
"fallocate": "write",
# "fentrylk": "read",
"fgetxattr": "read",
# "finodelk": "read",
# "flush": "read",
"fremovexattr": "write",
"fsetattr": "write",
"fsetxattr": "write",
"fstat": "read",
# "fsync": "read",
# "fsyncdir": "read",
"ftruncate": "write",
"fxattrop": "write",
"getxattr": "read",
# "inodelk": "read",
"link": "write",
"lk": "write,queue",
# "lookup": "read",
"mkdir": "write",
"mknod": "write",
"open": "write",
"opendir": "read",
"rchecksum": "read",
"readdir": "read",
"readdirp": "read",
"readlink": "read",
"readv": "read",
"removexattr": "write",
"rename": "write",
"rmdir": "write",
"setattr": "write",
"setxattr": "write",
"stat": "read",
"statfs": "read",
"symlink": "write",
"truncate": "write",
"unlink": "write",
"writev": "write,fsync,queue",
"xattrop": "write",
"ipc": "write",
}
# Mention those fops in the selective_generate table, for which
# only a few common functions will be generated, and mention those
# functions. Rest of the functions can be customized
selective_generate = {
"lk": "fop,dispatch,call_dispatch",
"ipc": "dispatch,call_dispatch",
}
# Stolen from gen_fdl.py
def gen_server (templates):
fops_done = []
for name in fop_table.keys():
info = fop_table[name].split(",")
kind = info[0]
flags = info[1:]
# generate all functions for the fops in fop_table
# except for the ones in selective_generate for which
# generate only the functions mentioned in the
# selective_generate table
gen_funcs = "fop,complete,continue,fan-in,dispatch, \
call_dispatch,perform_local_op"
if name in selective_generate:
gen_funcs = selective_generate[name].split(",")
if ("fsync" in flags) or ("queue" in flags):
flags.append("need_fd")
for fname in flags:
print("#define JBR_CG_%s" % fname.upper())
if 'complete' in gen_funcs:
print(generate(templates[kind+"-complete"],
name, cbk_subs))
if 'continue' in gen_funcs:
print(generate(templates[kind+"-continue"],
name, fop_subs))
if 'fan-in' in gen_funcs:
print(generate(templates[kind+"-fan-in"],
name, cbk_subs))
if 'dispatch' in gen_funcs:
print(generate(templates[kind+"-dispatch"],
name, fop_subs))
if 'call_dispatch' in gen_funcs:
print(generate(templates[kind+"-call_dispatch"],
name, fop_subs))
if 'perform_local_op' in gen_funcs:
print(generate(templates[kind+"-perform_local_op"],
name, fop_subs))
if 'fop' in gen_funcs:
print(generate(templates[kind+"-fop"], name, fop_subs))
for fname in flags:
print("#undef JBR_CG_%s" % fname.upper())
fops_done.append(name)
# Just for fun, emit the fops table too.
print("struct xlator_fops fops = {")
for x in fops_done:
print((" .%s = jbr_%s,"%(x, x)))
print("};")
tmpl = load_templates(sys.argv[1])
for l in open(sys.argv[2], 'r').readlines():
if l.find('#pragma generate') != -1:
print("/* BEGIN GENERATED CODE - DO NOT MODIFY */")
gen_server(tmpl)
print("/* END GENERATED CODE */")
else:
print(l[:-1])
|