1 package simpledb.file; 2 3 import simpledb.server.SimpleDB; 4 import java.nio.ByteBuffer; 5 import java.nio.charset.Charset; 6 7 /** 8 * The contents of a disk block in memory. 9 * A page is treated as an array of BLOCK_SIZE bytes. 10 * There are methods to get/set values into this array, 11 * and to read/write the contents of this array to a disk block. 12 * 13 * For an example of how to use Page and 14 * {@link Block} objects, 15 * consider the following code fragment. 16 * The first portion increments the integer at offset 792 of block 6 of file junk. 17 * The second portion stores the string "hello" at offset 20 of a page, 18 * and then appends it to a new block of the file. 19 * It then reads that block into another page 20 * and extracts the value "hello" into variable s. 21 * <pre> 22 * Page p1 = new Page(); 23 * Block blk = new Block("junk", 6); 24 * p1.read(blk); 25 * int n = p1.getInt(792); 26 * p1.setInt(792, n+1); 27 * p1.write(blk); 28 * 29 * Page p2 = new Page(); 30 * p2.setString(20, "hello"); 31 * blk = p2.append("junk"); 32 * Page p3 = new Page(); 33 * p3.read(blk); 34 * String s = p3.getString(20); 35 * </pre> 36 * @author Edward Sciore 37 */ 38 public class Page { 39 /** 40 * The number of bytes in a block. 41 * This value is set unreasonably low, so that it is easier 42 * to create and test databases having a lot of blocks. 43 * A more realistic value would be 4K. 44 */ 45 public static final int BLOCK_SIZE = 400; 46 47 /** 48 * The size of an integer in bytes. 49 * This value is almost certainly 4, but it is 50 * a good idea to encode this value as a constant. 51 */ 52 public static final int INT_SIZE = Integer.SIZE / Byte.SIZE; 53 54 /** 55 * The maximum size, in bytes, of a string of length n. 56 * A string is represented as the encoding of its characters, 57 * preceded by an integer denoting the number of bytes in this encoding. 58 * If the JVM uses the US-ASCII encoding, then each char 59 * is stored in one byte, so a string of n characters 60 * has a size of 4+n bytes. 61 * @param n the size of the string 62 * @return the maximum number of bytes required to store a string of size n 63 */ 64 public static final int STR_SIZE(int n) { 65 float bytesPerChar = Charset.defaultCharset().newEncoder().maxBytesPerChar(); 66 return INT_SIZE + (n * (int)bytesPerChar); 67 } 68 69 private ByteBuffer contents = ByteBuffer.allocateDirect(BLOCK_SIZE); 70 private FileMgr filemgr = SimpleDB.fileMgr(); 71 72 /** 73 * Creates a new page. Although the constructor takes no arguments, 74 * it depends on a {@link FileMgr} object that it gets from the 75 * method {@link simpledb.server.SimpleDB#fileMgr()}. 76 * That object is created during system initialization. 77 * Thus this constructor cannot be called until either 78 * {@link simpledb.server.SimpleDB#init(String)} or 79 * {@link simpledb.server.SimpleDB#initFileMgr(String)} or 80 * {@link simpledb.server.SimpleDB#initFileAndLogMgr(String)} or 81 * {@link simpledb.server.SimpleDB#initFileLogAndBufferMgr(String)} 82 * is called first. 83 */ 84 public Page() {} 85 86 /** 87 * Populates the page with the contents of the specified disk block. 88 * @param blk a reference to a disk block 89 */ 90 public synchronized void read(Block blk) { 91 filemgr.read(blk, contents); 92 } 93 94 /** 95 * Writes the contents of the page to the specified disk block. 96 * @param blk a reference to a disk block 97 */ 98 public synchronized void write(Block blk) { 99 filemgr.write(blk, contents); 100 } 101 102 /** 103 * Appends the contents of the page to the specified file. 104 * @param filename the name of the file 105 * @return the reference to the newly-created disk block 106 */ 107 public synchronized Block append(String filename) { 108 return filemgr.append(filename, contents); 109 } 110 111 /** 112 * Returns the integer value at a specified offset of the page. 113 * If an integer was not stored at that location, 114 * the behavior of the method is unpredictable. 115 * @param offset the byte offset within the page 116 * @return the integer value at that offset 117 */ 118 public synchronized int getInt(int offset) { 119 contents.position(offset); 120 return contents.getInt(); 121 } 122 123 /** 124 * Writes an integer to the specified offset on the page. 125 * @param offset the byte offset within the page 126 * @param val the integer to be written to the page 127 */ 128 public synchronized void setInt(int offset, int val) { 129 contents.position(offset); 130 contents.putInt(val); 131 } 132 133 /** 134 * Returns the string value at the specified offset of the page. 135 * If a string was not stored at that location, 136 * the behavior of the method is unpredictable. 137 * @param offset the byte offset within the page 138 * @return the string value at that offset 139 */ 140 public synchronized String getString(int offset) { 141 contents.position(offset); 142 int len = contents.getInt(); 143 byte[] byteval = new byte[len]; 144 contents.get(byteval); 145 return new String(byteval); 146 } 147 148 /** 149 * Writes a string to the specified offset on the page. 150 * @param offset the byte offset within the page 151 * @param val the string to be written to the page 152 */ 153 public synchronized void setString(int offset, String val) { 154 contents.position(offset); 155 byte[] byteval = val.getBytes(); 156 contents.putInt(byteval.length); 157 contents.put(byteval); 158 } 159 }