View Javadoc

1   package simpledb.log;
2   
3   import simpledb.server.SimpleDB;
4   import simpledb.file.*;
5   import static simpledb.file.Page.*;
6   import java.util.*;
7   
8   /**
9    * The low-level log manager.
10   * This log manager is responsible for writing log records
11   * into a log file.
12   * A log record can be any sequence of integer and string values.
13   * The log manager does not understand the meaning of these
14   * values, which are written and read by the
15   * {@link simpledb.tx.recovery.RecoveryMgr recovery manager}.
16   * @author Edward Sciore
17   */
18  public class LogMgr implements Iterable<BasicLogRecord> {
19     /**
20      * The location where the pointer to the last integer in the page is.
21      * A value of 0 means that the pointer is the first value in the page.
22      */
23     public static final int LAST_POS = 0;
24  
25     private String logfile;
26     private Page mypage = new Page();
27     private Block currentblk;
28     private int currentpos;
29  
30     /**
31      * Creates the manager for the specified log file.
32      * If the log file does not yet exist, it is created
33      * with an empty first block.
34      * This constructor depends on a {@link FileMgr} object
35      * that it gets from the method
36      * {@link simpledb.server.SimpleDB#fileMgr()}.
37      * That object is created during system initialization.
38      * Thus this constructor cannot be called until
39      * {@link simpledb.server.SimpleDB#initFileMgr(String)}
40      * is called first.
41      * @param logfile the name of the log file
42      */
43     public LogMgr(String logfile) {
44        this.logfile = logfile;
45        int logsize = SimpleDB.fileMgr().size(logfile);
46        if (logsize == 0)
47           appendNewBlock();
48        else {
49           currentblk = new Block(logfile, logsize-1);
50           mypage.read(currentblk);
51           currentpos = getLastRecordPosition() + INT_SIZE;
52        }
53     }
54  
55     /**
56      * Ensures that the log records corresponding to the
57      * specified LSN has been written to disk.
58      * All earlier log records will also be written to disk.
59      * @param lsn the LSN of a log record
60      */
61     public void flush(int lsn) {
62        if (lsn >= currentLSN())
63           flush();
64     }
65  
66     /**
67      * Returns an iterator for the log records,
68      * which will be returned in reverse order starting with the most recent.
69      * @see java.lang.Iterable#iterator()
70      */
71     public synchronized Iterator<BasicLogRecord> iterator() {
72        flush();
73        return new LogIterator(currentblk);
74     }
75  
76     /**
77      * Appends a log record to the file.
78      * The record contains an arbitrary array of strings and integers.
79      * The method also writes an integer to the end of each log record whose value
80      * is the offset of the corresponding integer for the previous log record.
81      * These integers allow log records to be read in reverse order.
82      * @param rec the list of values
83      * @return the LSN of the final value
84      */
85     public synchronized int append(Object[] rec) {
86        int recsize = INT_SIZE;  // 4 bytes for the integer that points to the previous log record
87        for (Object obj : rec)
88           recsize += size(obj);
89        if (currentpos + recsize >= BLOCK_SIZE){ // the log record doesn't fit,
90           flush();        // so move to the next block.
91           appendNewBlock();
92        }
93        for (Object obj : rec)
94           appendVal(obj);
95        finalizeRecord();
96        return currentLSN();
97     }
98  
99     /**
100     * Adds the specified value to the page at the position denoted by
101     * currentpos.  Then increments currentpos by the size of the value.
102     * @param val the integer or string to be added to the page
103     */
104    private void appendVal(Object val) {
105       if (val instanceof String)
106          mypage.setString(currentpos, (String)val);
107       else
108          mypage.setInt(currentpos, (Integer)val);
109       currentpos += size(val);
110    }
111 
112    /**
113     * Calculates the size of the specified integer or string.
114     * @param val the value
115     * @return the size of the value, in bytes
116     */
117    private int size(Object val) {
118       if (val instanceof String) {
119          String sval = (String) val;
120          return STR_SIZE(sval.length());
121       }
122       else
123          return INT_SIZE;
124    }
125 
126    /**
127     * Returns the LSN of the most recent log record.
128     * As implemented, the LSN is the block number where the record is stored.
129     * Thus every log record in a block has the same LSN.
130     * @return the LSN of the most recent log record
131     */
132    private int currentLSN() {
133       return currentblk.number();
134    }
135 
136    /**
137     * Writes the current page to the log file.
138     */
139    private void flush() {
140       mypage.write(currentblk);
141    }
142 
143    /**
144     * Clear the current page, and append it to the log file.
145     */
146    private void appendNewBlock() {
147       setLastRecordPosition(0);
148       currentpos = INT_SIZE;
149       currentblk = mypage.append(logfile);
150    }
151 
152    /**
153     * Sets up a circular chain of pointers to the records in the page.
154     * There is an integer added to the end of each log record
155     * whose value is the offset of the previous log record.
156     * The first four bytes of the page contain an integer whose value
157     * is the offset of the integer for the last log record in the page.
158     */
159    private void finalizeRecord() {
160       mypage.setInt(currentpos, getLastRecordPosition());
161       setLastRecordPosition(currentpos);
162       currentpos += INT_SIZE;
163    }
164 
165    private int getLastRecordPosition() {
166       return mypage.getInt(LAST_POS);
167    }
168 
169    private void setLastRecordPosition(int pos) {
170       mypage.setInt(LAST_POS, pos);
171    }
172 }