"""Low level database file. This abstraction allows the user to treat a database as a collection of pages. It turns out that there really isn't an actual file under here; it's simulated with an array in memory. But no one needs to know that, except you who are reading this comment. This file once had roots in the UW-Madison Minibase project. It has been rewritten many times since then.""" import array PAGESIZE = 1024 def makePage(): """One page's worth of data in memory. DO NOT MODIFY THIS FUNCTION.""" return array.array('c','\0' * PAGESIZE) class DBFileException(Exception): pass class BadPageNumberException(Exception): pass class BadFileException(Exception): pass # Directory of files: _files = {} def create(filename, numPages): """Creates a 'file' with the given name, with the specified number of pages. Overwrites the file if it already exists.""" pages = [makePage() for i in range(numPages)] _files[filename] = pages def erase(filename): """Erases the file. Returns True if operation succeeded (the file was in there).""" if _files.has_key(filename): _files.pop(filename) return True return False def exists(filename): """Tests to see if the 'file' with the given filename exists.""" return _files.has_key(filename) def allocatePages(filename,runSize): """Allocates a set of pages. runSize is the number of pages to be allocated in the run. Return the page number of the first page of the allocated run. Pages are always allocated at the end, for simplicity, even if there's room in the middle. Raise an exception if the run size is less than or equal to zero.""" if runSize <= 0: raise DBFileException("Non positive run size.") pages = _files[filename] runStart = len(pages) pages.extend([makePage() for i in range(runSize)]) return runStart def deallocatePages(filename,startPageNum, runSize): """Deallocates a set of pages. Does not ensure that the pages being deallocated are in fact allocated to begin with. If the pages were already deallocated, they remain so. startPageNum is the page number at the beginning of the run to be deallocated. runSize is the number of pages to deallocate. Raises BadPageNumberException if startPageNum is illegal.""" if runSize <= 0: raise DBFileException("Non positive run size.") pages = _files[filename] if (startPageNum < 0) or (startPageNum + runSize - 1 >= len(pages)): raise BadPageNumberException(str(startPageNum)+" "+str(runSize)) pages[startPageNum:startPageNum+runSize] = [None]*runSize def readPage(filename,pageNum, page): """Copies the contents of the specified page from disk into the page object provided. pageNum is the page number to be read, and page is the array of bytes to copy it into. page should already be declared to be of size PAGESIZE. Using makePage() would be a fine way to do it. Raises BadFileException if the file does not exist, BadPageNumberException if pageNum is not in the file.""" if not _files.has_key(filename): raise BadFileException pages = _files[filename] if (pageNum < 0) or (pageNum >= len(pages)): raise BadPageNumberException if (pages[pageNum] == None): raise DBFileException("Page not allocated.") page[:] = pages[pageNum][:] def writePage(filename,pageNum,page): """Writes the contents of the specified page to disk. pageNum is the page number to be written, and page has data on it to be written to the file. Raises BadPageNumberException if pageNum is not in the file.""" pages = _files[filename] if (pageNum < 0) or (pageNum >= len(pages)): raise BadPageNumberException if len(pages) == 0: raise DBFileException("Empty file.") # Make sure that page has actually been allocated if pages[pageNum] == None: raise DBFileException("Page not allocated.") pages[pageNum][:] = page[:] def main(): """Stub for testing.""" create("testing",5) print exists("testing") print exists("whoa") allocatePages("testing",4) deallocatePages("testing",1,2); print allocatePages("testing",2) print allocatePages("testing",1) page = makePage() page[1] = 'K' page[2] = 'R' writePage("testing",3,page) readPage("testing",0,page) print page[1:10] print readPage("testing",3,page) print page[1:10] print create("testagain",7) print allocatePages("testagain",3) writePage("testagain",2,page); readPage("testagain",1,page); print page[1:10] print readPage("testagain",2,page); print page[1:10] print try: readPage("testing",1,page) except DBFileException,e: print "Correctly caught unallocated page read" print e try: writePage("testing",2,page) except DBFileException,e: print "Correctly caught unallocated page write" print e print erase("testing") print erase("testagain") print _files if __name__ == '__main__': main()