QuizGenerator 0.4.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- QuizGenerator/README.md +5 -0
- QuizGenerator/__init__.py +27 -0
- QuizGenerator/__main__.py +7 -0
- QuizGenerator/canvas/__init__.py +13 -0
- QuizGenerator/canvas/canvas_interface.py +627 -0
- QuizGenerator/canvas/classes.py +235 -0
- QuizGenerator/constants.py +149 -0
- QuizGenerator/contentast.py +1955 -0
- QuizGenerator/generate.py +253 -0
- QuizGenerator/logging.yaml +55 -0
- QuizGenerator/misc.py +579 -0
- QuizGenerator/mixins.py +548 -0
- QuizGenerator/performance.py +202 -0
- QuizGenerator/premade_questions/__init__.py +0 -0
- QuizGenerator/premade_questions/basic.py +103 -0
- QuizGenerator/premade_questions/cst334/__init__.py +1 -0
- QuizGenerator/premade_questions/cst334/languages.py +391 -0
- QuizGenerator/premade_questions/cst334/math_questions.py +297 -0
- QuizGenerator/premade_questions/cst334/memory_questions.py +1400 -0
- QuizGenerator/premade_questions/cst334/ostep13_vsfs.py +572 -0
- QuizGenerator/premade_questions/cst334/persistence_questions.py +451 -0
- QuizGenerator/premade_questions/cst334/process.py +648 -0
- QuizGenerator/premade_questions/cst463/__init__.py +0 -0
- QuizGenerator/premade_questions/cst463/gradient_descent/__init__.py +3 -0
- QuizGenerator/premade_questions/cst463/gradient_descent/gradient_calculation.py +369 -0
- QuizGenerator/premade_questions/cst463/gradient_descent/gradient_descent_questions.py +305 -0
- QuizGenerator/premade_questions/cst463/gradient_descent/loss_calculations.py +650 -0
- QuizGenerator/premade_questions/cst463/gradient_descent/misc.py +73 -0
- QuizGenerator/premade_questions/cst463/math_and_data/__init__.py +2 -0
- QuizGenerator/premade_questions/cst463/math_and_data/matrix_questions.py +631 -0
- QuizGenerator/premade_questions/cst463/math_and_data/vector_questions.py +534 -0
- QuizGenerator/premade_questions/cst463/models/__init__.py +0 -0
- QuizGenerator/premade_questions/cst463/models/attention.py +192 -0
- QuizGenerator/premade_questions/cst463/models/cnns.py +186 -0
- QuizGenerator/premade_questions/cst463/models/matrices.py +24 -0
- QuizGenerator/premade_questions/cst463/models/rnns.py +202 -0
- QuizGenerator/premade_questions/cst463/models/text.py +203 -0
- QuizGenerator/premade_questions/cst463/models/weight_counting.py +227 -0
- QuizGenerator/premade_questions/cst463/neural-network-basics/__init__.py +6 -0
- QuizGenerator/premade_questions/cst463/neural-network-basics/neural_network_questions.py +1314 -0
- QuizGenerator/premade_questions/cst463/tensorflow-intro/__init__.py +6 -0
- QuizGenerator/premade_questions/cst463/tensorflow-intro/tensorflow_questions.py +936 -0
- QuizGenerator/qrcode_generator.py +293 -0
- QuizGenerator/question.py +715 -0
- QuizGenerator/quiz.py +467 -0
- QuizGenerator/regenerate.py +472 -0
- QuizGenerator/typst_utils.py +113 -0
- quizgenerator-0.4.2.dist-info/METADATA +265 -0
- quizgenerator-0.4.2.dist-info/RECORD +52 -0
- quizgenerator-0.4.2.dist-info/WHEEL +4 -0
- quizgenerator-0.4.2.dist-info/entry_points.txt +3 -0
- quizgenerator-0.4.2.dist-info/licenses/LICENSE +674 -0
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
#! /usr/bin/env python
|
|
2
|
+
import io
|
|
3
|
+
import random
|
|
4
|
+
import sys
|
|
5
|
+
from optparse import OptionParser
|
|
6
|
+
from functools import wraps
|
|
7
|
+
|
|
8
|
+
DEBUG = False
|
|
9
|
+
|
|
10
|
+
def dprint(str):
|
|
11
|
+
if DEBUG:
|
|
12
|
+
print(str)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def capture_output(func):
|
|
16
|
+
"""
|
|
17
|
+
Decorator to capture the output of a function that uses print statements
|
|
18
|
+
and return it as a string.
|
|
19
|
+
"""
|
|
20
|
+
@wraps(func)
|
|
21
|
+
def wrapper(*args, **kwargs):
|
|
22
|
+
captured_output = io.StringIO() # Create a StringIO object
|
|
23
|
+
original_stdout = sys.stdout # Save the original sys.stdout
|
|
24
|
+
sys.stdout = captured_output # Redirect sys.stdout to StringIO
|
|
25
|
+
try:
|
|
26
|
+
func(*args, **kwargs) # Call the wrapped function
|
|
27
|
+
finally:
|
|
28
|
+
sys.stdout = original_stdout # Restore sys.stdout
|
|
29
|
+
return captured_output.getvalue() # Return the captured output as a string
|
|
30
|
+
return wrapper
|
|
31
|
+
|
|
32
|
+
printOps = False
|
|
33
|
+
printState = False
|
|
34
|
+
printFinal = False
|
|
35
|
+
|
|
36
|
+
class bitmap:
|
|
37
|
+
def __init__(self, size):
|
|
38
|
+
self.size = size
|
|
39
|
+
self.bmap = []
|
|
40
|
+
for num in range(size):
|
|
41
|
+
self.bmap.append(0)
|
|
42
|
+
|
|
43
|
+
def alloc(self):
|
|
44
|
+
for num in range(len(self.bmap)):
|
|
45
|
+
if self.bmap[num] == 0:
|
|
46
|
+
self.bmap[num] = 1
|
|
47
|
+
return num
|
|
48
|
+
return -1
|
|
49
|
+
|
|
50
|
+
def free(self, num):
|
|
51
|
+
assert(self.bmap[num] == 1)
|
|
52
|
+
self.bmap[num] = 0
|
|
53
|
+
|
|
54
|
+
def markAllocated(self, num):
|
|
55
|
+
assert(self.bmap[num] == 0)
|
|
56
|
+
self.bmap[num] = 1
|
|
57
|
+
|
|
58
|
+
def dump(self):
|
|
59
|
+
s = ''
|
|
60
|
+
for i in range(len(self.bmap)):
|
|
61
|
+
s += str(self.bmap[i])
|
|
62
|
+
return s
|
|
63
|
+
|
|
64
|
+
class block:
|
|
65
|
+
def __init__(self, ftype):
|
|
66
|
+
assert(ftype == 'd' or ftype == 'f' or ftype == 'free')
|
|
67
|
+
self.ftype = ftype
|
|
68
|
+
# only for directories, properly a subclass but who cares
|
|
69
|
+
self.dirUsed = 0
|
|
70
|
+
self.maxUsed = 32
|
|
71
|
+
self.dirList = []
|
|
72
|
+
self.data = ''
|
|
73
|
+
|
|
74
|
+
def dump(self):
|
|
75
|
+
if self.ftype == 'free':
|
|
76
|
+
return '[]'
|
|
77
|
+
elif self.ftype == 'd':
|
|
78
|
+
rc = ''
|
|
79
|
+
for d in self.dirList:
|
|
80
|
+
# d is of the form ('name', inum)
|
|
81
|
+
short = '(%s,%s)' % (d[0], d[1])
|
|
82
|
+
if rc == '':
|
|
83
|
+
rc = short
|
|
84
|
+
else:
|
|
85
|
+
rc += ' ' + short
|
|
86
|
+
return '['+rc+']'
|
|
87
|
+
# return '%s' % self.dirList
|
|
88
|
+
else:
|
|
89
|
+
return '[%s]' % self.data
|
|
90
|
+
|
|
91
|
+
def setType(self, ftype):
|
|
92
|
+
assert(self.ftype == 'free')
|
|
93
|
+
self.ftype = ftype
|
|
94
|
+
|
|
95
|
+
def addData(self, data):
|
|
96
|
+
assert(self.ftype == 'f')
|
|
97
|
+
self.data = data
|
|
98
|
+
|
|
99
|
+
def getNumEntries(self):
|
|
100
|
+
assert(self.ftype == 'd')
|
|
101
|
+
return self.dirUsed
|
|
102
|
+
|
|
103
|
+
def getFreeEntries(self):
|
|
104
|
+
assert(self.ftype == 'd')
|
|
105
|
+
return self.maxUsed - self.dirUsed
|
|
106
|
+
|
|
107
|
+
def getEntry(self, num):
|
|
108
|
+
assert(self.ftype == 'd')
|
|
109
|
+
assert(num < self.dirUsed)
|
|
110
|
+
return self.dirList[num]
|
|
111
|
+
|
|
112
|
+
def addDirEntry(self, name, inum):
|
|
113
|
+
assert(self.ftype == 'd')
|
|
114
|
+
self.dirList.append((name, inum))
|
|
115
|
+
self.dirUsed += 1
|
|
116
|
+
assert(self.dirUsed <= self.maxUsed)
|
|
117
|
+
|
|
118
|
+
def delDirEntry(self, name):
|
|
119
|
+
assert(self.ftype == 'd')
|
|
120
|
+
tname = name.split('/')
|
|
121
|
+
dname = tname[len(tname) - 1]
|
|
122
|
+
for i in range(len(self.dirList)):
|
|
123
|
+
if self.dirList[i][0] == dname:
|
|
124
|
+
self.dirList.pop(i)
|
|
125
|
+
self.dirUsed -= 1
|
|
126
|
+
return
|
|
127
|
+
assert(1 == 0)
|
|
128
|
+
|
|
129
|
+
def dirEntryExists(self, name):
|
|
130
|
+
assert(self.ftype == 'd')
|
|
131
|
+
for d in self.dirList:
|
|
132
|
+
if name == d[0]:
|
|
133
|
+
return True
|
|
134
|
+
return False
|
|
135
|
+
|
|
136
|
+
def free(self):
|
|
137
|
+
assert(self.ftype != 'free')
|
|
138
|
+
if self.ftype == 'd':
|
|
139
|
+
# check for only dot, dotdot here
|
|
140
|
+
assert(self.dirUsed == 2)
|
|
141
|
+
self.dirUsed = 0
|
|
142
|
+
self.data = ''
|
|
143
|
+
self.ftype = 'free'
|
|
144
|
+
|
|
145
|
+
class inode:
|
|
146
|
+
def __init__(self, ftype='free', addr=-1, refCnt=1):
|
|
147
|
+
self.setAll(ftype, addr, refCnt)
|
|
148
|
+
|
|
149
|
+
def setAll(self, ftype, addr, refCnt):
|
|
150
|
+
assert(ftype == 'd' or ftype == 'f' or ftype == 'free')
|
|
151
|
+
self.ftype = ftype
|
|
152
|
+
self.addr = addr
|
|
153
|
+
self.refCnt = refCnt
|
|
154
|
+
|
|
155
|
+
def incRefCnt(self):
|
|
156
|
+
self.refCnt += 1
|
|
157
|
+
|
|
158
|
+
def decRefCnt(self):
|
|
159
|
+
self.refCnt -= 1
|
|
160
|
+
|
|
161
|
+
def getRefCnt(self):
|
|
162
|
+
return self.refCnt
|
|
163
|
+
|
|
164
|
+
def setType(self, ftype):
|
|
165
|
+
assert(ftype == 'd' or ftype == 'f' or ftype == 'free')
|
|
166
|
+
self.ftype = ftype
|
|
167
|
+
|
|
168
|
+
def setAddr(self, block):
|
|
169
|
+
self.addr = block
|
|
170
|
+
|
|
171
|
+
def getSize(self):
|
|
172
|
+
if self.addr == -1:
|
|
173
|
+
return 0
|
|
174
|
+
else:
|
|
175
|
+
return 1
|
|
176
|
+
|
|
177
|
+
def getAddr(self):
|
|
178
|
+
return self.addr
|
|
179
|
+
|
|
180
|
+
def getType(self):
|
|
181
|
+
return self.ftype
|
|
182
|
+
|
|
183
|
+
def free(self):
|
|
184
|
+
self.ftype = 'free'
|
|
185
|
+
self.addr = -1
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class fs:
|
|
189
|
+
def __init__(self, numInodes, numData, rng):
|
|
190
|
+
self.rng = rng
|
|
191
|
+
self.numInodes = numInodes
|
|
192
|
+
self.numData = numData
|
|
193
|
+
|
|
194
|
+
self.ibitmap = bitmap(self.numInodes)
|
|
195
|
+
self.inodes = []
|
|
196
|
+
for i in range(self.numInodes):
|
|
197
|
+
self.inodes.append(inode())
|
|
198
|
+
|
|
199
|
+
self.dbitmap = bitmap(self.numData)
|
|
200
|
+
self.data = []
|
|
201
|
+
for i in range(self.numData):
|
|
202
|
+
self.data.append(block('free'))
|
|
203
|
+
|
|
204
|
+
# root inode
|
|
205
|
+
self.ROOT = 0
|
|
206
|
+
|
|
207
|
+
# create root directory
|
|
208
|
+
self.ibitmap.markAllocated(self.ROOT)
|
|
209
|
+
self.inodes[self.ROOT].setAll('d', 0, 2)
|
|
210
|
+
self.dbitmap.markAllocated(self.ROOT)
|
|
211
|
+
self.data[0].setType('d')
|
|
212
|
+
self.data[0].addDirEntry('.', self.ROOT)
|
|
213
|
+
self.data[0].addDirEntry('..', self.ROOT)
|
|
214
|
+
|
|
215
|
+
# these is just for the fake workload generator
|
|
216
|
+
self.files = []
|
|
217
|
+
self.dirs = ['/']
|
|
218
|
+
self.nameToInum = {'/':self.ROOT}
|
|
219
|
+
|
|
220
|
+
@capture_output
|
|
221
|
+
def dump(self):
|
|
222
|
+
print('inode bitmap ', self.ibitmap.dump())
|
|
223
|
+
print('inodes ', end=' ')
|
|
224
|
+
for i in range(0,self.numInodes):
|
|
225
|
+
ftype = self.inodes[i].getType()
|
|
226
|
+
if ftype == 'free':
|
|
227
|
+
print('[]', end=' ')
|
|
228
|
+
else:
|
|
229
|
+
print('[%s a:%s r:%d]' % (ftype, self.inodes[i].getAddr(), self.inodes[i].getRefCnt()), end=' ')
|
|
230
|
+
print('')
|
|
231
|
+
print('data bitmap ', self.dbitmap.dump())
|
|
232
|
+
print('data ', end=' ')
|
|
233
|
+
for i in range(self.numData):
|
|
234
|
+
print(self.data[i].dump(), end=' ')
|
|
235
|
+
print('')
|
|
236
|
+
|
|
237
|
+
def makeName(self):
|
|
238
|
+
p = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
|
|
239
|
+
return p[int(self.rng.random() * len(p))]
|
|
240
|
+
p = ['b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 's', 't', 'v', 'w', 'x', 'y', 'z']
|
|
241
|
+
f = p[int(self.rng.random() * len(p))]
|
|
242
|
+
p = ['a', 'e', 'i', 'o', 'u']
|
|
243
|
+
s = p[int(self.rng.random() * len(p))]
|
|
244
|
+
p = ['b', 'c', 'd', 'f', 'g', 'j', 'k', 'l', 'm', 'n', 'p', 's', 't', 'v', 'w', 'x', 'y', 'z']
|
|
245
|
+
l = p[int(self.rng.random() * len(p))]
|
|
246
|
+
return '%c%c%c' % (f, s, l)
|
|
247
|
+
|
|
248
|
+
def inodeAlloc(self):
|
|
249
|
+
return self.ibitmap.alloc()
|
|
250
|
+
|
|
251
|
+
def inodeFree(self, inum):
|
|
252
|
+
self.ibitmap.free(inum)
|
|
253
|
+
self.inodes[inum].free()
|
|
254
|
+
|
|
255
|
+
def dataAlloc(self):
|
|
256
|
+
return self.dbitmap.alloc()
|
|
257
|
+
|
|
258
|
+
def dataFree(self, bnum):
|
|
259
|
+
self.dbitmap.free(bnum)
|
|
260
|
+
self.data[bnum].free()
|
|
261
|
+
|
|
262
|
+
def getParent(self, name):
|
|
263
|
+
tmp = name.split('/')
|
|
264
|
+
if len(tmp) == 2:
|
|
265
|
+
return '/'
|
|
266
|
+
pname = ''
|
|
267
|
+
for i in range(1, len(tmp)-1):
|
|
268
|
+
pname = pname + '/' + tmp[i]
|
|
269
|
+
return pname
|
|
270
|
+
|
|
271
|
+
def deleteFile(self, tfile):
|
|
272
|
+
if printOps:
|
|
273
|
+
print('unlink("%s");' % tfile)
|
|
274
|
+
|
|
275
|
+
inum = self.nameToInum[tfile]
|
|
276
|
+
|
|
277
|
+
if self.inodes[inum].getRefCnt() == 1:
|
|
278
|
+
# free data blocks first
|
|
279
|
+
dblock = self.inodes[inum].getAddr()
|
|
280
|
+
if dblock != -1:
|
|
281
|
+
self.dataFree(dblock)
|
|
282
|
+
# then free inode
|
|
283
|
+
self.inodeFree(inum)
|
|
284
|
+
else:
|
|
285
|
+
self.inodes[inum].decRefCnt()
|
|
286
|
+
|
|
287
|
+
# remove from parent directory
|
|
288
|
+
parent = self.getParent(tfile)
|
|
289
|
+
# print '--> delete from parent', parent
|
|
290
|
+
pinum = self.nameToInum[parent]
|
|
291
|
+
# print '--> delete from parent inum', pinum
|
|
292
|
+
pblock = self.inodes[pinum].getAddr()
|
|
293
|
+
# FIXED BUG: DECREASE PARENT INODE REF COUNT! (thanks to Srinivasan Thirunarayanan)
|
|
294
|
+
self.inodes[pinum].decRefCnt()
|
|
295
|
+
# print '--> delete from parent addr', pblock
|
|
296
|
+
self.data[pblock].delDirEntry(tfile)
|
|
297
|
+
|
|
298
|
+
# finally, remove from files list
|
|
299
|
+
self.files.remove(tfile)
|
|
300
|
+
return 0, ('unlink("%s");' % tfile)
|
|
301
|
+
|
|
302
|
+
def createLink(self, target, newfile, parent):
|
|
303
|
+
# find info about parent
|
|
304
|
+
parentInum = self.nameToInum[parent]
|
|
305
|
+
|
|
306
|
+
# is there room in the parent directory?
|
|
307
|
+
pblock = self.inodes[parentInum].getAddr()
|
|
308
|
+
if self.data[pblock].getFreeEntries() <= 0:
|
|
309
|
+
dprint('*** createLink failed: no room in parent directory ***')
|
|
310
|
+
return -1, ""
|
|
311
|
+
|
|
312
|
+
# print 'is %s in directory %d' % (newfile, pblock)
|
|
313
|
+
if self.data[pblock].dirEntryExists(newfile):
|
|
314
|
+
dprint('*** createLink failed: not a unique name ***')
|
|
315
|
+
return -1, ""
|
|
316
|
+
|
|
317
|
+
# now, find inumber of target
|
|
318
|
+
tinum = self.nameToInum[target]
|
|
319
|
+
self.inodes[tinum].incRefCnt()
|
|
320
|
+
|
|
321
|
+
# inc parent ref count
|
|
322
|
+
self.inodes[parentInum].incRefCnt()
|
|
323
|
+
|
|
324
|
+
# now add to directory
|
|
325
|
+
tmp = newfile.split('/')
|
|
326
|
+
ename = tmp[len(tmp)-1]
|
|
327
|
+
self.data[pblock].addDirEntry(ename, tinum)
|
|
328
|
+
return tinum, ""
|
|
329
|
+
|
|
330
|
+
def createFile(self, parent, newfile, ftype):
|
|
331
|
+
# find info about parent
|
|
332
|
+
parentInum = self.nameToInum[parent]
|
|
333
|
+
|
|
334
|
+
# is there room in the parent directory?
|
|
335
|
+
pblock = self.inodes[parentInum].getAddr()
|
|
336
|
+
if self.data[pblock].getFreeEntries() <= 0:
|
|
337
|
+
dprint('*** createFile failed: no room in parent directory ***')
|
|
338
|
+
return -1, ""
|
|
339
|
+
|
|
340
|
+
# have to make sure file name is unique
|
|
341
|
+
block = self.inodes[parentInum].getAddr()
|
|
342
|
+
# print 'is %s in directory %d' % (newfile, block)
|
|
343
|
+
if self.data[block].dirEntryExists(newfile):
|
|
344
|
+
dprint('*** createFile failed: not a unique name ***')
|
|
345
|
+
return -1, ""
|
|
346
|
+
|
|
347
|
+
# find free inode
|
|
348
|
+
inum = self.inodeAlloc()
|
|
349
|
+
if inum == -1:
|
|
350
|
+
dprint('*** createFile failed: no inodes left ***')
|
|
351
|
+
return -1, ""
|
|
352
|
+
|
|
353
|
+
# if a directory, have to allocate directory block for basic (., ..) info
|
|
354
|
+
fblock = -1
|
|
355
|
+
if ftype == 'd':
|
|
356
|
+
refCnt = 2
|
|
357
|
+
fblock = self.dataAlloc()
|
|
358
|
+
if fblock == -1:
|
|
359
|
+
dprint('*** createFile failed: no data blocks left ***')
|
|
360
|
+
self.inodeFree(inum)
|
|
361
|
+
return -1, ""
|
|
362
|
+
else:
|
|
363
|
+
self.data[fblock].setType('d')
|
|
364
|
+
self.data[fblock].addDirEntry('.', inum)
|
|
365
|
+
self.data[fblock].addDirEntry('..', parentInum)
|
|
366
|
+
else:
|
|
367
|
+
refCnt = 1
|
|
368
|
+
|
|
369
|
+
# now ok to init inode properly
|
|
370
|
+
self.inodes[inum].setAll(ftype, fblock, refCnt)
|
|
371
|
+
|
|
372
|
+
# inc parent ref count
|
|
373
|
+
self.inodes[parentInum].incRefCnt()
|
|
374
|
+
|
|
375
|
+
# and add to directory of parent
|
|
376
|
+
self.data[pblock].addDirEntry(newfile, inum)
|
|
377
|
+
return inum, ""
|
|
378
|
+
|
|
379
|
+
def writeFile(self, tfile, data):
|
|
380
|
+
inum = self.nameToInum[tfile]
|
|
381
|
+
curSize = self.inodes[inum].getSize()
|
|
382
|
+
dprint('writeFile: inum:%d cursize:%d refcnt:%d' % (inum, curSize, self.inodes[inum].getRefCnt()))
|
|
383
|
+
if curSize == 1:
|
|
384
|
+
dprint('*** writeFile failed: file is full ***')
|
|
385
|
+
return -1, ""
|
|
386
|
+
fblock = self.dataAlloc()
|
|
387
|
+
if fblock == -1:
|
|
388
|
+
dprint('*** writeFile failed: no data blocks left ***')
|
|
389
|
+
return -1, ""
|
|
390
|
+
else:
|
|
391
|
+
self.data[fblock].setType('f')
|
|
392
|
+
self.data[fblock].addData(data)
|
|
393
|
+
self.inodes[inum].setAddr(fblock)
|
|
394
|
+
if printOps:
|
|
395
|
+
print('fd=open("%s", O_WRONLY|O_APPEND); write(fd, buf, BLOCKSIZE); close(fd);' % tfile)
|
|
396
|
+
return 0, ('fd=open("%s", O_WRONLY|O_APPEND); write(fd, buf, BLOCKSIZE); close(fd);' % tfile)
|
|
397
|
+
|
|
398
|
+
def doDelete(self):
|
|
399
|
+
dprint('doDelete')
|
|
400
|
+
if len(self.files) == 0:
|
|
401
|
+
return -1, ""
|
|
402
|
+
dfile = self.files[int(self.rng.random() * len(self.files))]
|
|
403
|
+
dprint('try delete(%s)' % dfile)
|
|
404
|
+
return self.deleteFile(dfile)
|
|
405
|
+
|
|
406
|
+
def doLink(self):
|
|
407
|
+
dprint('doLink')
|
|
408
|
+
if len(self.files) == 0:
|
|
409
|
+
return -1, ""
|
|
410
|
+
parent = self.dirs[int(self.rng.random() * len(self.dirs))]
|
|
411
|
+
nfile = self.makeName()
|
|
412
|
+
|
|
413
|
+
# pick random target
|
|
414
|
+
target = self.files[int(self.rng.random() * len(self.files))]
|
|
415
|
+
|
|
416
|
+
# get full name of newfile
|
|
417
|
+
if parent == '/':
|
|
418
|
+
fullName = parent + nfile
|
|
419
|
+
else:
|
|
420
|
+
fullName = parent + '/' + nfile
|
|
421
|
+
|
|
422
|
+
dprint('try createLink(%s %s %s)' % (target, nfile, parent))
|
|
423
|
+
inum, _ = self.createLink(target, nfile, parent)
|
|
424
|
+
if inum >= 0:
|
|
425
|
+
self.files.append(fullName)
|
|
426
|
+
self.nameToInum[fullName] = inum
|
|
427
|
+
if printOps:
|
|
428
|
+
print('link("%s", "%s");' % (target, fullName))
|
|
429
|
+
return 0, ('link("%s", "%s");' % (target, fullName))
|
|
430
|
+
return -1, ""
|
|
431
|
+
|
|
432
|
+
def doCreate(self, ftype):
|
|
433
|
+
dprint('doCreate')
|
|
434
|
+
parent = self.dirs[int(self.rng.random() * len(self.dirs))]
|
|
435
|
+
nfile = self.makeName()
|
|
436
|
+
if ftype == 'd':
|
|
437
|
+
tlist = self.dirs
|
|
438
|
+
else:
|
|
439
|
+
tlist = self.files
|
|
440
|
+
|
|
441
|
+
if parent == '/':
|
|
442
|
+
fullName = parent + nfile
|
|
443
|
+
else:
|
|
444
|
+
fullName = parent + '/' + nfile
|
|
445
|
+
|
|
446
|
+
dprint('try createFile(%s %s %s)' % (parent, nfile, ftype))
|
|
447
|
+
inum, _ = self.createFile(parent, nfile, ftype)
|
|
448
|
+
if inum >= 0:
|
|
449
|
+
tlist.append(fullName)
|
|
450
|
+
self.nameToInum[fullName] = inum
|
|
451
|
+
if parent == '/':
|
|
452
|
+
parent = ''
|
|
453
|
+
if ftype == 'd':
|
|
454
|
+
if printOps:
|
|
455
|
+
print('mkdir("%s/%s");' % (parent, nfile))
|
|
456
|
+
cmd = ('mkdir("%s/%s");' % (parent, nfile))
|
|
457
|
+
else:
|
|
458
|
+
if printOps:
|
|
459
|
+
print('creat("%s/%s");' % (parent, nfile))
|
|
460
|
+
cmd = ('creat("%s/%s");' % (parent, nfile))
|
|
461
|
+
return 0, cmd
|
|
462
|
+
return -1, ""
|
|
463
|
+
|
|
464
|
+
def doAppend(self):
|
|
465
|
+
dprint('doAppend')
|
|
466
|
+
if len(self.files) == 0:
|
|
467
|
+
return -1, ""
|
|
468
|
+
afile = self.files[int(self.rng.random() * len(self.files))]
|
|
469
|
+
dprint('try writeFile(%s)' % afile)
|
|
470
|
+
data = chr(ord('a') + int(self.rng.random() * 26))
|
|
471
|
+
rc = self.writeFile(afile, data)
|
|
472
|
+
return rc
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
def run_for_steps(self, numRequests):
|
|
477
|
+
self.percentMkdir = 0.40
|
|
478
|
+
self.percentWrite = 0.40
|
|
479
|
+
self.percentDelete = 0.20
|
|
480
|
+
self.numRequests = 20
|
|
481
|
+
|
|
482
|
+
operations = []
|
|
483
|
+
|
|
484
|
+
for i in range(numRequests):
|
|
485
|
+
start_state = self.dump()
|
|
486
|
+
rc = -1
|
|
487
|
+
attempts = 0
|
|
488
|
+
while rc == -1:
|
|
489
|
+
attempts += 1
|
|
490
|
+
if attempts > 1000:
|
|
491
|
+
return operations
|
|
492
|
+
r = self.rng.random()
|
|
493
|
+
if r < 0.3:
|
|
494
|
+
rc, cmd = self.doAppend()
|
|
495
|
+
dprint('doAppend rc:%d' % rc)
|
|
496
|
+
elif r < 0.5:
|
|
497
|
+
rc, cmd = self.doDelete()
|
|
498
|
+
dprint('doDelete rc:%d' % rc)
|
|
499
|
+
elif r < 0.7:
|
|
500
|
+
rc, cmd = self.doLink()
|
|
501
|
+
dprint('doLink rc:%d' % rc)
|
|
502
|
+
else:
|
|
503
|
+
if self.rng.random() < 0.75:
|
|
504
|
+
rc, cmd = self.doCreate('f')
|
|
505
|
+
dprint('doCreate(f) rc:%d' % rc)
|
|
506
|
+
else:
|
|
507
|
+
rc, cmd = self.doCreate('d')
|
|
508
|
+
dprint('doCreate(d) rc:%d' % rc)
|
|
509
|
+
end_state = self.dump()
|
|
510
|
+
operations.append({
|
|
511
|
+
"start_state" : start_state,
|
|
512
|
+
"end_state" : end_state,
|
|
513
|
+
"cmd" : cmd
|
|
514
|
+
})
|
|
515
|
+
return operations
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
if __name__ == "__main__":
|
|
521
|
+
#
|
|
522
|
+
# main program
|
|
523
|
+
#
|
|
524
|
+
parser = OptionParser()
|
|
525
|
+
|
|
526
|
+
parser.add_option('-s', '--seed', default=0, help='the random seed', action='store', type='int', dest='seed')
|
|
527
|
+
parser.add_option('-i', '--numInodes', default=8, help='number of inodes in file system', action='store', type='int', dest='numInodes')
|
|
528
|
+
parser.add_option('-d', '--numData', default=8, help='number of data blocks in file system', action='store', type='int', dest='numData')
|
|
529
|
+
parser.add_option('-n', '--numRequests', default=10, help='number of requests to simulate', action='store', type='int', dest='numRequests')
|
|
530
|
+
parser.add_option('-r', '--reverse', default=False, help='instead of printing state, print ops', action='store_true', dest='reverse')
|
|
531
|
+
parser.add_option('-p', '--printFinal', default=False, help='print the final set of files/dirs', action='store_true', dest='printFinal')
|
|
532
|
+
parser.add_option('-c', '--compute', default=False, help='compute answers for me', action='store_true', dest='solve')
|
|
533
|
+
|
|
534
|
+
(options, args) = parser.parse_args()
|
|
535
|
+
|
|
536
|
+
print('ARG seed', options.seed)
|
|
537
|
+
print('ARG numInodes', options.numInodes)
|
|
538
|
+
print('ARG numData', options.numData)
|
|
539
|
+
print('ARG numRequests', options.numRequests)
|
|
540
|
+
print('ARG reverse', options.reverse)
|
|
541
|
+
print('ARG printFinal', options.printFinal)
|
|
542
|
+
print('')
|
|
543
|
+
|
|
544
|
+
random.seed(options.seed)
|
|
545
|
+
|
|
546
|
+
if options.reverse:
|
|
547
|
+
printState = False
|
|
548
|
+
printOps = True
|
|
549
|
+
else:
|
|
550
|
+
printState = True
|
|
551
|
+
printOps = False
|
|
552
|
+
|
|
553
|
+
if options.solve:
|
|
554
|
+
printOps = True
|
|
555
|
+
printState = True
|
|
556
|
+
|
|
557
|
+
printFinal = options.printFinal
|
|
558
|
+
|
|
559
|
+
#
|
|
560
|
+
# have to generate RANDOM requests to the file system
|
|
561
|
+
# that are VALID!
|
|
562
|
+
#
|
|
563
|
+
|
|
564
|
+
f = fs(options.numInodes, options.numData)
|
|
565
|
+
|
|
566
|
+
#
|
|
567
|
+
# ops: mkdir rmdir : create delete : append write
|
|
568
|
+
#
|
|
569
|
+
|
|
570
|
+
f.run(options.numRequests)
|
|
571
|
+
|
|
572
|
+
|