|
|
- #! /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)
-
-
|