View Javadoc

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 }