예제 #1
0
 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)
예제 #2
0
 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()
예제 #3
0
 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()  # 同步锁
예제 #4
0
 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))
예제 #5
0
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
예제 #6
0
 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
예제 #7
0
 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
예제 #8
0
 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)
예제 #9
0
    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()
예제 #10
0
    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)
예제 #11
0
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)
예제 #12
0
 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
예제 #13
0
 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)
예제 #14
0
 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)
예제 #15
0
 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)
예제 #16
0
 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))
예제 #17
0
 def writeToLog(lm):
     rec = bytearray(Integer.BYTES)
     p = Page(rec)
     p.setInt(0, LogRecord.CHECKPOINT)
     return lm.append(rec)
예제 #18
0
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