package simpledb.buffer; import simpledb.server.SimpleDB; import simpledb.file.*; /** * An individual buffer. * A buffer wraps a page and stores information about its status, * such as the disk block associated with the page, * the number of times the block has been pinned, * whether the contents of the page have been modified, * and if so, the id of the modifying transaction and * the LSN of the corresponding log record. * @author Edward Sciore */ public class Buffer { private Page contents = new Page(); private Block blk = null; private int pins = 0; private int modifiedBy = -1; private int logSequenceNumber; private int id; public Buffer(int id) { this.id = id; } /** * Returns the integer value at the specified offset of the * buffer's page. * If an integer was not stored at that location, * the behavior of the method is unpredictable. * @param offset the byte offset of the page * @return the integer value at that offset */ public int getInt(int offset) { return contents.getInt(offset); } /** * Returns the string value at the specified offset of the * buffer's page. * If a string was not stored at that location, * the behavior of the method is unpredictable. * @param offset the byte offset of the page * @return the string value at that offset */ public String getString(int offset) { return contents.getString(offset); } /** * Writes an integer to the specified offset of the * buffer's page. * This method assumes that the transaction has already * written an appropriate log record. * The buffer saves the id of the transaction * and the LSN of the log record. * @param offset the byte offset within the page * @param val the new integer value to be written * @param txnum the id of the transaction performing the modification * @param lsn the LSN of the corresponding log record */ public void setInt(int offset, int val, int txnum, int lsn) { modifiedBy = txnum; logSequenceNumber = lsn; contents.setInt(offset, val); } /** * Writes a string to the specified offset of the * buffer's page. * This method assumes that the transaction has already * written an appropriate log record. * The buffer saves the id of the transaction * and the LSN of the log record. * @param offset the byte offset within the page * @param val the new string value to be written * @param txnum the id of the transaction performing the modification * @param lsn the LSN of the corresponding log record */ public void setString(int offset, String val, int txnum, int lsn) { modifiedBy = txnum; logSequenceNumber = lsn; contents.setString(offset, val); } /** * Returns a reference to the disk block * that the buffer is pinned to. * @return a reference to a disk block */ public Block block() { return blk; } /** * Writes the page to its disk block if the * page is dirty. * The method ensures that the corresponding log * record has been written to disk prior to writing * the page to disk. */ void flush() { if (modifiedBy >= 0) { SimpleDB.logMgr().flush(logSequenceNumber); contents.write(blk); modifiedBy = -1; } } /** * Increases the buffer's pin count. */ void pin() { pins++; } /** * Decreases the buffer's pin count. */ void unpin() { pins--; } /** * Returns true if the buffer is currently pinned * (that is, if it has a nonzero pin count). * @return true if the buffer is pinned */ boolean isPinned() { return pins > 0; } /** * Returns true if the buffer is dirty * due to a modification by the specified transaction. * @param txnum the id of the transaction * @return true if the transaction modified the buffer */ boolean isModifiedBy(int txnum) { return txnum == modifiedBy; } /** * Reads the contents of the specified block into * the buffer's page. * If the buffer was dirty, then the contents * of the previous page are first written to disk. * @param b a reference to the data block */ void assignToBlock(Block b) { flush(); blk = b; contents.read(blk); pins = 0; } /** * Initializes the buffer's page according to the specified formatter, * and appends the page to the specified file. * If the buffer was dirty, then the contents * of the previous page are first written to disk. * @param filename the name of the file * @param fmtr a pageformatter, used to initialize the page */ void assignToNew(String filename, PageFormatter fmtr) { flush(); fmtr.format(contents); blk = contents.append(filename); pins = 0; } public String toString() { String status = isPinned() ? " pinned" : " unpinned"; return "Buffer " + id + ": contains " + blk + status; } }