《操作系统》的实验代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

470 lines
13 KiB

#! /usr/bin/env python
import random
from optparse import OptionParser
DEBUG = False
def dprint(str):
if DEBUG:
print str
printOps = True
printState = True
printFinal = True
class bitmap:
def __init__(self, size):
self.size = size
self.bmap = []
for num in range(size):
self.bmap.append(0)
def alloc(self):
for num in range(len(self.bmap)):
if self.bmap[num] == 0:
self.bmap[num] = 1
return num
return -1
def free(self, num):
assert(self.bmap[num] == 1)
self.bmap[num] = 0
def markAllocated(self, num):
assert(self.bmap[num] == 0)
self.bmap[num] = 1
def dump(self):
s = ''
for i in range(len(self.bmap)):
s += str(self.bmap[i])
return s
class block:
def __init__(self, ftype):
assert(ftype == 'd' or ftype == 'f' or ftype == 'free')
self.ftype = ftype
# only for directories, properly a subclass but who cares
self.dirUsed = 0
self.maxUsed = 32
self.dirList = []
self.data = ''
def dump(self):
if self.ftype == 'free':
return '[]'
elif self.ftype == 'd':
rc = ''
for d in self.dirList:
# d is of the form ('name', inum)
short = '(%s,%s)' % (d[0], d[1])
if rc == '':
rc = short
else:
rc += ' ' + short
return '['+rc+']'
# return '%s' % self.dirList
else:
return '[%s]' % self.data
def setType(self, ftype):
assert(self.ftype == 'free')
self.ftype = ftype
def addData(self, data):
assert(self.ftype == 'f')
self.data = data
def getNumEntries(self):
assert(self.ftype == 'd')
return self.dirUsed
def getFreeEntries(self):
assert(self.ftype == 'd')
return self.maxUsed - self.dirUsed
def getEntry(self, num):
assert(self.ftype == 'd')
assert(num < self.dirUsed)
return self.dirList[num]
def addDirEntry(self, name, inum):
assert(self.ftype == 'd')
self.dirList.append((name, inum))
self.dirUsed += 1
assert(self.dirUsed <= self.maxUsed)
def delDirEntry(self, name):
assert(self.ftype == 'd')
tname = name.split('/')
dname = tname[len(tname) - 1]
for i in range(len(self.dirList)):
if self.dirList[i][0] == dname:
self.dirList.pop(i)
self.dirUsed -= 1
return
assert(1 == 0)
def dirEntryExists(self, name):
assert(self.ftype == 'd')
for d in self.dirList:
if name == d[0]:
return True
return False
def free(self):
assert(self.ftype != 'free')
if self.ftype == 'd':
# check for only dot, dotdot here
assert(self.dirUsed == 2)
self.dirUsed = 0
self.data = ''
self.ftype = 'free'
class inode:
def __init__(self, ftype='free', addr=-1, refCnt=1):
self.setAll(ftype, addr, refCnt)
def setAll(self, ftype, addr, refCnt):
assert(ftype == 'd' or ftype == 'f' or ftype == 'free')
self.ftype = ftype
self.addr = addr
self.refCnt = refCnt
def incRefCnt(self):
self.refCnt += 1
def decRefCnt(self):
self.refCnt -= 1
def getRefCnt(self):
return self.refCnt
def setType(self, ftype):
assert(ftype == 'd' or ftype == 'f' or ftype == 'free')
self.ftype = ftype
def setAddr(self, block):
self.addr = block
def getSize(self):
if self.addr == -1:
return 0
else:
return 1
def getAddr(self):
return self.addr
def getType(self):
return self.ftype
def free(self):
self.ftype = 'free'
self.addr = -1
class fs:
def __init__(self, numInodes, numData):
self.numInodes = numInodes
self.numData = numData
self.ibitmap = bitmap(self.numInodes)
self.inodes = []
for i in range(self.numInodes):
self.inodes.append(inode())
self.dbitmap = bitmap(self.numData)
self.data = []
for i in range(self.numData):
self.data.append(block('free'))
# root inode
self.ROOT = 0
# create root directory
self.ibitmap.markAllocated(self.ROOT)
self.inodes[self.ROOT].setAll('d', 0, 2)
self.dbitmap.markAllocated(self.ROOT)
self.data[0].setType('d')
self.data[0].addDirEntry('.', self.ROOT)
self.data[0].addDirEntry('..', self.ROOT)
# these is just for the fake workload generator
self.files = []
self.dirs = ['/']
self.nameToInum = {'/':self.ROOT}
def dump(self):
print 'inode bitmap ', self.ibitmap.dump()
print 'inodes ',
for i in range(0,self.numInodes):
ftype = self.inodes[i].getType()
if ftype == 'free':
print '[]',
else:
print '[%s a:%s r:%d]' % (ftype, self.inodes[i].getAddr(), self.inodes[i].getRefCnt()),
print ''
print 'data bitmap ', self.dbitmap.dump()
print 'data ',
for i in range(self.numData):
print self.data[i].dump(),
print ''
def makeName(self):
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']
return p[int(random.random() * len(p))]
def inodeAlloc(self):
return self.ibitmap.alloc()
def inodeFree(self, inum):
self.ibitmap.free(inum)
self.inodes[inum].free()
def dataAlloc(self):
return self.dbitmap.alloc()
def dataFree(self, bnum):
self.dbitmap.free(bnum)
self.data[bnum].free()
def getParent(self, name):
tmp = name.split('/')
if len(tmp) == 2:
return '/'
pname = ''
for i in range(1, len(tmp)-1):
pname = pname + '/' + tmp[i]
return pname
def deleteFile(self, tfile):
if printOps:
print 'unlink("%s");' % tfile
inum = self.nameToInum[tfile]
# YOUR CODE, YOUR ID
# IF inode.refcnt ==1, THEN free data blocks first, then free inode, ELSE dec indoe.refcnt
# remove from parent directory: delete from parent inum, delete from parent addr
# DONE
# finally, remove from files list
self.files.remove(tfile)
return 0
def createLink(self, target, newfile, parent):
# YOUR CODE, YOUR ID
# find info about parent
# is there room in the parent directory?
# if the newfile was already in parent dir?
# now, find inumber of target
# inc parent ref count
# now add to directory
# DONE
return tinum
def createFile(self, parent, newfile, ftype):
# YOUR CODE, YOUR ID
# find info about parent
# is there room in the parent directory?
# have to make sure file name is unique
# find free inode
# if a directory, have to allocate directory block for basic (., ..) info
# now ok to init inode properly
# inc parent ref count
# and add to directory of parent
# DONE
return inum
def writeFile(self, tfile, data):
inum = self.nameToInum[tfile]
curSize = self.inodes[inum].getSize()
dprint('writeFile: inum:%d cursize:%d refcnt:%d' % (inum, curSize, self.inodes[inum].getRefCnt()))
# YOUR CODE, YOUR ID
# file is full?
# no data blocks left
# write file data
# DONE
if printOps:
print 'fd=open("%s", O_WRONLY|O_APPEND); write(fd, buf, BLOCKSIZE); close(fd);' % tfile
return 0
def doDelete(self):
dprint('doDelete')
if len(self.files) == 0:
return -1
dfile = self.files[int(random.random() * len(self.files))]
dprint('try delete(%s)' % dfile)
return self.deleteFile(dfile)
def doLink(self):
dprint('doLink')
if len(self.files) == 0:
return -1
parent = self.dirs[int(random.random() * len(self.dirs))]
nfile = self.makeName()
# pick random target
target = self.files[int(random.random() * len(self.files))]
# get full name of newfile
if parent == '/':
fullName = parent + nfile
else:
fullName = parent + '/' + nfile
dprint('try createLink(%s %s %s)' % (target, nfile, parent))
inum = self.createLink(target, nfile, parent)
if inum >= 0:
self.files.append(fullName)
self.nameToInum[fullName] = inum
if printOps:
print 'link("%s", "%s");' % (target, fullName)
return 0
return -1
def doCreate(self, ftype):
dprint('doCreate')
parent = self.dirs[int(random.random() * len(self.dirs))]
nfile = self.makeName()
if ftype == 'd':
tlist = self.dirs
else:
tlist = self.files
if parent == '/':
fullName = parent + nfile
else:
fullName = parent + '/' + nfile
dprint('try createFile(%s %s %s)' % (parent, nfile, ftype))
inum = self.createFile(parent, nfile, ftype)
if inum >= 0:
tlist.append(fullName)
self.nameToInum[fullName] = inum
if parent == '/':
parent = ''
if ftype == 'd':
if printOps:
print 'mkdir("%s/%s");' % (parent, nfile)
else:
if printOps:
print 'creat("%s/%s");' % (parent, nfile)
return 0
return -1
def doAppend(self):
dprint('doAppend')
if len(self.files) == 0:
return -1
afile = self.files[int(random.random() * len(self.files))]
dprint('try writeFile(%s)' % afile)
data = chr(ord('a') + int(random.random() * 26))
rc = self.writeFile(afile, data)
return rc
def run(self, numRequests):
self.percentMkdir = 0.40
self.percentWrite = 0.40
self.percentDelete = 0.20
self.numRequests = numRequests
print 'Initial state'
print ''
self.dump()
print ''
for i in range(numRequests):
if printOps == False:
print 'Which operation took place?'
rc = -1
while rc == -1:
r = random.random()
if r < 0.3:
rc = self.doAppend()
dprint('doAppend rc:%d' % rc)
elif r < 0.5:
rc = self.doDelete()
dprint('doDelete rc:%d' % rc)
elif r < 0.7:
rc = self.doLink()
dprint('doLink rc:%d' % rc)
else:
if random.random() < 0.75:
rc = self.doCreate('f')
dprint('doCreate(f) rc:%d' % rc)
else:
rc = self.doCreate('d')
dprint('doCreate(d) rc:%d' % rc)
if printState == True:
print ''
self.dump()
print ''
else:
print ''
print ' State of file system (inode bitmap, inodes, data bitmap, data)?'
print ''
if printFinal:
print ''
print 'Summary of files, directories::'
print ''
print ' Files: ', self.files
print ' Directories:', self.dirs
print ''
#
# main program
#
parser = OptionParser()
parser.add_option('-s', '--seed', default=0, help='the random seed', action='store', type='int', dest='seed')
parser.add_option('-i', '--numInodes', default=8, help='number of inodes in file system', action='store', type='int', dest='numInodes')
parser.add_option('-d', '--numData', default=8, help='number of data blocks in file system', action='store', type='int', dest='numData')
parser.add_option('-n', '--numRequests', default=10, help='number of requests to simulate', action='store', type='int', dest='numRequests')
parser.add_option('-r', '--reverse', default=False, help='instead of printing state, print ops', action='store_true', dest='reverse')
parser.add_option('-p', '--printFinal', default=False, help='print the final set of files/dirs', action='store_true', dest='printFinal')
(options, args) = parser.parse_args()
print 'ARG seed', options.seed
print 'ARG numInodes', options.numInodes
print 'ARG numData', options.numData
print 'ARG numRequests', options.numRequests
print 'ARG reverse', options.reverse
print 'ARG printFinal', options.printFinal
print ''
random.seed(options.seed)
if options.reverse:
printState = False
printOps = True
else:
printState = True
printOps = False
printOps = True
printState = True
printFinal = options.printFinal
#
# have to generate RANDOM requests to the file system
# that are VALID!
#
f = fs(options.numInodes, options.numData)
#
# ops: mkdir rmdir : create delete : append write
#
f.run(options.numRequests)