def __init__(self, fm, blk): self.fm = fm self.blk = blk self.currentpos = 0 self.boundary = 0 b = bytearray(fm.blockSize()) self.p = Page(b) self.moveToBlock(blk)
def printLogRecords(cls, msg): print(msg) iterator = cls.lm.iterator() while iterator.hasNext(): rec = iterator.next() p = Page(rec) s = p.getString(0) npos = Page.maxLength(len(s)) val = p.getInt(npos) print("[" + s + ", " + str(val) + "]") print()
def __init__(self, fm, logfile): self.fm = fm self.logfile = logfile b = bytearray(fm.blockSize()) self.logpage = Page(b) logsize = fm.length(logfile) if logsize == 0: self.currentblk = self.appendNewBlock() else: self.currentblk = BlockId(logfile, logsize - 1) self.fm.read(self.currentblk, self.logpage) self.latestLSN = 0 self.lastSavedLSN = 0 self.lock = threading.Lock() # 同步锁
def lengthInBytes(self, fldname): fldtype = self._schema.type(fldname) if fldtype == INTEGER: return Integer.BYTES else: # fldtype == VARCHAR return Page.maxLength(self._schema.length(fldname))
class LogIterator: # # * Creates an iterator for the records in the log file, # * positioned after the last log record. # def __init__(self, fm, blk): self.fm = fm self.blk = blk self.currentpos = 0 self.boundary = 0 b = bytearray(fm.blockSize()) self.p = Page(b) self.moveToBlock(blk) # # * Determines if the current log record # * is the earliest record in the log file. # * @return true if there is an earlier record # def hasNext(self): return self.currentpos < self.fm.blockSize() or self.blk.number() > 0 # # * Moves to the next log record in the block. # * If there are no more log records in the block, # * then move to the previous block # * and return the log record from there. # * @return the next earliest log record # def next(self): if self.currentpos == self.fm.blockSize(): self.blk = BlockId(self.blk.fileName(), self.blk.number() - 1) self.moveToBlock(self.blk) rec = self.p.getBytes(self.currentpos) self.currentpos += Integer.BYTES + len(rec) return rec # # * Moves to the specified log block # * and positions it at the first record in that block # * (i.e., the most recent one). # def moveToBlock(self, blk): self.fm.read(blk, self.p) self.boundary = self.p.getInt(0) self.currentpos = self.boundary
def __init__(self, fm, lm): self.fm = fm self.lm = lm self._contents = Page(fm.blockSize()) self.blk = None self.pins = 0 self.txnum = -1 self.lsn = -1
def createLogRecord(cls, s, n): spos = 0 npos = spos + Page.maxLength(len(s)) b = bytearray(npos + Integer.BYTES) p = Page(b) p.setString(spos, s) p.setInt(npos, n) return b
def __init__(self, p): super(SetStringRecord, self).__init__() tpos = Integer.BYTES self.txnum = p.getInt(tpos) fpos = tpos + Integer.BYTES filename = p.getString(fpos) bpos = fpos + Page.maxLength(len(filename)) blknum = p.getInt(bpos) self.blk = BlockId(filename, blknum) opos = bpos + Integer.BYTES self.offset = p.getInt(opos) vpos = opos + Integer.BYTES self.val = p.getString(vpos)
def printValues(msg): print(msg) p0 = Page(RecoveryTest.fm.blockSize()) p1 = Page(RecoveryTest.fm.blockSize()) RecoveryTest.fm.read(RecoveryTest.blk0, p0) RecoveryTest.fm.read(RecoveryTest.blk1, p1) pos = 0 for i in range(6): print(str(p0.getInt(pos)) + " ", end='') print(str(p1.getInt(pos)) + " ", end='') pos += Integer.BYTES print(p0.getString(30) + " ", end='') print(p1.getString(30) + " ", end='') print()
def main(cls, args): # db = SimpleDB("studentdb", 400, 8) fm = FileMgr(File("recoverytest"), 400) lm = LogMgr(fm, "simpledb.log") filename = "simpledb.log" lastblock = fm.length(filename) - 1 blk = BlockId(filename, lastblock) p = Page(fm.blockSize()) fm.read(blk, p) iterator = lm.iterator() while iterator.hasNext(): byte_array = iterator.next() rec = LogRecord.createLogRecord(byte_array) print(rec)
def test3(): db = SimpleDB("studentdb") lm = db.logMgr() fm = db.fileMgr() filename = "simpledb.log" lastblock = fm.length(filename) - 1 blk = BlockId(filename, lastblock) p = Page(fm.blockSize()) fm.read(blk, p) iterator = lm.iterator() while iterator.hasNext(): byte_array = iterator.next() rec = LogRecord.createLogRecord(byte_array) print(rec)
def createLogRecord(byte_array): p = Page(byte_array) if p.getInt(0) == LogRecord.CHECKPOINT: from simpledb.tx.recovery.CheckpointRecord import CheckpointRecord return CheckpointRecord() elif p.getInt(0) == LogRecord.START: from simpledb.tx.recovery.StartRecord import StartRecord return StartRecord(p) elif p.getInt(0) == LogRecord.COMMIT: from simpledb.tx.recovery.CommitRecord import CommitRecord return CommitRecord(p) elif p.getInt(0) == LogRecord.ROLLBACK: from simpledb.tx.recovery.RollbackRecord import RollbackRecord return RollbackRecord(p) elif p.getInt(0) == LogRecord.SETINT: from simpledb.tx.recovery.SetIntRecord import SetIntRecord return SetIntRecord(p) elif p.getInt(0) == LogRecord.SETSTRING: from simpledb.tx.recovery.SetStringRecord import SetStringRecord return SetStringRecord(p) else: return None
def main(cls, args): # db = SimpleDB("bufferfiletest", 400, 8) # bm = db.bufferMgr() fm = FileMgr(File("buffertest"), 400) lm = LogMgr(fm, "logfile") bm = BufferMgr(fm, lm, 8) blk = BlockId("testfile", 2) pos1 = 88 b1 = bm.pin(blk) p1 = b1.contents() p1.setString(pos1, "abcdefghijklm") size = Page.maxLength(len("abcdefghijklm")) pos2 = pos1 + size p1.setInt(pos2, 345) b1.setModified(1, 0) bm.unpin(b1) b2 = bm.pin(blk) p2 = b2.contents() print("offset " + str(pos2) + " contains " + str(p2.getInt(pos2))) print("offset " + str(pos1) + " contains " + p2.getString(pos1)) bm.unpin(b2)
def writeToLog(lm, txnum, blk, offset, val): tpos = Integer.BYTES fpos = tpos + Integer.BYTES bpos = fpos + Page.maxLength(len(blk.fileName())) opos = bpos + Integer.BYTES vpos = opos + Integer.BYTES reclen = vpos + Page.maxLength(len(val)) rec = bytearray(reclen) p = Page(rec) p.setInt(0, LogRecord.SETSTRING) p.setInt(tpos, txnum) p.setString(fpos, blk.fileName()) p.setInt(bpos, blk.number()) p.setInt(opos, offset) p.setString(vpos, val) return lm.append(rec)
def writeToLog(lm, txnum): rec = bytearray(2 * Integer.BYTES) p = Page(rec) p.setInt(0, LogRecord.COMMIT) p.setInt(Integer.BYTES, txnum) return lm.append(rec)
def main(cls, args): # db = SimpleDB("filetest", 400, 8) # fm = db.fileMgr() fm = FileMgr(File("filetest"), 400) blk = BlockId("testfile", 2) pos1 = 88 p1 = Page(fm.blockSize()) p1.setString(pos1, "abcdefghijklm") size = Page.maxLength(len("abcdefghijklm")) pos2 = pos1 + size p1.setInt(pos2, 345) fm.write(blk, p1) p2 = Page(fm.blockSize()) fm.read(blk, p2) print("offset " + str(pos2) + " contains " + str(p2.getInt(pos2))) print("offset " + str(pos1) + " contains " + p2.getString(pos1))
def writeToLog(lm): rec = bytearray(Integer.BYTES) p = Page(rec) p.setInt(0, LogRecord.CHECKPOINT) return lm.append(rec)
class LogMgr: # Creates the manager for the specified log file. # If the log file does not yet exist, it is created # with an empty first block. # @param FileMgr the file manager # @param logfile the name of the log file def __init__(self, fm, logfile): self.fm = fm self.logfile = logfile b = bytearray(fm.blockSize()) self.logpage = Page(b) logsize = fm.length(logfile) if logsize == 0: self.currentblk = self.appendNewBlock() else: self.currentblk = BlockId(logfile, logsize - 1) self.fm.read(self.currentblk, self.logpage) self.latestLSN = 0 self.lastSavedLSN = 0 self.lock = threading.Lock() # 同步锁 # Ensures that the log record corresponding to the # specified LSN has been written to disk. # All earlier log records will also be written to disk. # @param lsn the LSN of a log record def flush(self, *args): if len(args) == 1: lsn = args[0] if lsn >= self.lastSavedLSN: self.flush() # Write the buffer to the log file. elif len(args) == 0: self.fm.write(self.currentblk, self.logpage) self.lastSavedLSN = self.latestLSN def iterator(self): self.flush() return LogIterator(self.fm, self.currentblk) # Appends a log record to the log buffer. # The record consists of an arbitrary array of bytes. # Log records are written right to left in the buffer. # The size of the record is written before the bytes. # The beginning of the buffer contains the location # of the last-written record (the "boundary"). # Storing the records backwards makes it easy to read # them in reverse order. # @param logrec a byte buffer containing the bytes. # @return the LSN of the final value @synchronized def append(self, logrec): boundary = self.logpage.getInt(0) recsize = len(logrec) bytesneeded = recsize + Integer.BYTES if boundary - bytesneeded < Integer.BYTES: # the log record doesn't fit, self.flush() # so move to the next block. self.currentblk = self.appendNewBlock() boundary = self.logpage.getInt(0) recpos = boundary - bytesneeded self.logpage.setBytes(recpos, logrec) self.logpage.setInt(0, recpos) # the new boundary self.latestLSN += 1 return self.latestLSN # Initialize the bytebuffer and append it to the log file. def appendNewBlock(self): blk = self.fm.append(self.logfile) self.logpage.setInt(0, self.fm.blockSize()) self.fm.write(blk, self.logpage) return blk