Skip to content

Commit d29e2c9

Browse files
committed
feat(recovery): fuzzy (non-quiescent) checkpoints
1 parent 118de84 commit d29e2c9

File tree

9 files changed

+742
-504
lines changed

9 files changed

+742
-504
lines changed

simpledb/tx/Transaction.java

Lines changed: 240 additions & 208 deletions
Large diffs are not rendered by default.

simpledb/tx/recovery/LogRecord.java

Lines changed: 52 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,56 +5,63 @@
55

66
/**
77
* The interface implemented by each type of log record.
8+
*
89
* @author Edward Sciore
910
*/
1011
public interface LogRecord {
11-
static final int CHECKPOINT = 0, START = 1,
12-
COMMIT = 2, ROLLBACK = 3,
13-
SETINT = 4, SETSTRING = 5;
12+
static final int CHECKPOINT = 0, START = 1,
13+
COMMIT = 2, ROLLBACK = 3,
14+
SETINT = 4, SETSTRING = 5, NQCKPT = 6;
1415

15-
/**
16-
* Returns the log record's type.
17-
* @return the log record's type
18-
*/
19-
int op();
16+
/**
17+
* Returns the log record's type.
18+
*
19+
* @return the log record's type
20+
*/
21+
int op();
2022

21-
/**
22-
* Returns the transaction id stored with
23-
* the log record.
24-
* @return the log record's transaction id
25-
*/
26-
int txNumber();
23+
/**
24+
* Returns the transaction id stored with
25+
* the log record.
26+
*
27+
* @return the log record's transaction id
28+
*/
29+
int txNumber();
2730

28-
/**
29-
* Undoes the operation encoded by this log record.
30-
* The only log record types for which this method
31-
* does anything interesting are SETINT and SETSTRING.
32-
* @param txnum the id of the transaction that is performing the undo.
33-
*/
34-
void undo(Transaction tx);
31+
/**
32+
* Undoes the operation encoded by this log record.
33+
* The only log record types for which this method
34+
* does anything interesting are SETINT and SETSTRING.
35+
*
36+
* @param txnum the id of the transaction that is performing the undo.
37+
*/
38+
void undo(Transaction tx);
3539

36-
/**
37-
* Interpret the bytes returned by the log iterator.
38-
* @param bytes
39-
* @return
40-
*/
41-
static LogRecord createLogRecord(byte[] bytes) {
42-
Page p = new Page(bytes);
43-
switch (p.getInt(0)) {
44-
case CHECKPOINT:
45-
return new CheckpointRecord();
46-
case START:
47-
return new StartRecord(p);
48-
case COMMIT:
49-
return new CommitRecord(p);
50-
case ROLLBACK:
51-
return new RollbackRecord(p);
52-
case SETINT:
53-
return new SetIntRecord(p);
54-
case SETSTRING:
55-
return new SetStringRecord(p);
56-
default:
57-
return null;
58-
}
59-
}
40+
/**
41+
* Interpret the bytes returned by the log iterator.
42+
*
43+
* @param bytes
44+
* @return
45+
*/
46+
static LogRecord createLogRecord(byte[] bytes) {
47+
Page p = new Page(bytes);
48+
switch (p.getInt(0)) {
49+
case CHECKPOINT:
50+
return new CheckpointRecord();
51+
case START:
52+
return new StartRecord(p);
53+
case COMMIT:
54+
return new CommitRecord(p);
55+
case ROLLBACK:
56+
return new RollbackRecord(p);
57+
case SETINT:
58+
return new SetIntRecord(p);
59+
case SETSTRING:
60+
return new SetStringRecord(p);
61+
case NQCKPT:
62+
return new NQCheckpointRecord(p);
63+
default:
64+
return null;
65+
}
66+
}
6067
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package simpledb.tx.recovery;
2+
3+
import simpledb.file.Page;
4+
import simpledb.log.LogMgr;
5+
import simpledb.tx.Transaction;
6+
7+
import java.util.Arrays;
8+
9+
/**
10+
* The NQCKPT log record.
11+
*
12+
* @author Amr
13+
*/
14+
public class NQCheckpointRecord implements LogRecord {
15+
private int[] activeTxns;
16+
17+
/**
18+
* Create a new non-quiescent checkpoint log record.
19+
*
20+
* @param p the page containing the non-quiescent checkpoint log
21+
*/
22+
public NQCheckpointRecord(Page p) {
23+
int txnCountPos = Integer.BYTES;
24+
int txnCount = p.getInt(txnCountPos);
25+
activeTxns = new int[txnCount];
26+
for (int i = 0; i < txnCount; i++) {
27+
txnCountPos += Integer.BYTES;
28+
activeTxns[i] = p.getInt(txnCountPos);
29+
}
30+
}
31+
32+
public int op() {
33+
return NQCKPT;
34+
}
35+
36+
/**
37+
* NQCKPT records have no associated transaction,
38+
* and so the method returns a "dummy", negative txid.
39+
*/
40+
public int txNumber() {
41+
return -1; // dummy value
42+
}
43+
44+
/**
45+
* Does nothing, because a checkpoint record
46+
* contains no undo information.
47+
*/
48+
public void undo(Transaction tx) {
49+
}
50+
51+
public String toString() {
52+
return "<NQCKPT " + activeTxns.length + " " + Arrays.toString(activeTxns) + " >";
53+
}
54+
55+
/**
56+
* A static method to write a checkpoint record to the log.
57+
* This log record contains the NQCKPT operator, count of txns and the txns themselves,
58+
* e.g. <6, 2, 22, 24>
59+
*
60+
* @return the LSN of the last log value
61+
*/
62+
public static int writeToLog(LogMgr lm, int[] activeTxns) {
63+
int cpos = Integer.BYTES;
64+
byte[] rec = new byte[2 * Integer.BYTES + activeTxns.length * Integer.BYTES];
65+
Page p = new Page(rec);
66+
p.setInt(0, NQCKPT);
67+
p.setInt(cpos, activeTxns.length);
68+
for (int i = 0; i < activeTxns.length; i++) {
69+
cpos += Integer.BYTES;
70+
p.setInt(cpos, activeTxns[i]);
71+
}
72+
return lm.append(rec);
73+
}
74+
75+
/**
76+
* @return activeTxns
77+
*/
78+
public int[] txList() {
79+
return activeTxns;
80+
}
81+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package simpledb.tx.recovery;
2+
3+
import simpledb.server.SimpleDB;
4+
import simpledb.file.*;
5+
import simpledb.log.LogMgr;
6+
import simpledb.buffer.BufferMgr;
7+
import simpledb.tx.Transaction;
8+
9+
import java.util.*;
10+
11+
public class NQCheckpointTest {
12+
private static Collection<Transaction> uncommittedTxs = new ArrayList<Transaction>();
13+
14+
public static void main(String[] args) {
15+
SimpleDB db = new SimpleDB("txtest", 400, 8);
16+
FileMgr fm = db.fileMgr();
17+
LogMgr lm = db.logMgr();
18+
BufferMgr bm = db.bufferMgr();
19+
20+
Transaction[] txs = new Transaction[18];
21+
Transaction master = new Transaction(fm, lm, bm);
22+
for (int i = 2; i < 18; i++) {
23+
BlockId blk = master.append("testfile");
24+
txs[i] = new Transaction(fm, lm, bm);
25+
uncommittedTxs.add(txs[i]);
26+
txs[i].pin(blk);
27+
int x = txs[i].getInt(blk, 99);
28+
txs[i].setInt(blk, 99, 1000 + i, true);
29+
System.out.println("transaction " + i + " setint old=" + x + " new=" + 1000 + i);
30+
txs[i].unpin(blk);
31+
if (i % 3 == 2)
32+
pareDown();
33+
}
34+
master.commit();
35+
}
36+
37+
// commit half of the uncommitted txs
38+
private static void pareDown() {
39+
Iterator<Transaction> iter = uncommittedTxs.iterator();
40+
int count = 0;
41+
while (iter.hasNext()) { // loop back to the beginning
42+
Transaction tx = iter.next();
43+
if (count % 2 == 0) {
44+
tx.commit();
45+
iter.remove();
46+
}
47+
count++;
48+
}
49+
}
50+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package simpledb.tx.recovery;
2+
3+
import simpledb.buffer.BufferMgr;
4+
import simpledb.file.FileMgr;
5+
import simpledb.log.LogMgr;
6+
import simpledb.server.SimpleDB;
7+
import simpledb.tx.Transaction;
8+
9+
public class NQRecoveryTest {
10+
public static void main(String[] args) {
11+
SimpleDB db = new SimpleDB("txtest", 400, 8);
12+
FileMgr fm = db.fileMgr();
13+
LogMgr lm = db.logMgr();
14+
BufferMgr bm = db.bufferMgr();
15+
Transaction tx = new Transaction(fm, lm, bm);
16+
System.out.println("Initiating Recovery");
17+
System.out.println("Here are the visited log records");
18+
tx.recover();
19+
}
20+
}
Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,27 @@
11
package simpledb.tx.recovery;
22

33
import java.util.Iterator;
4+
45
import simpledb.server.SimpleDB;
56
import simpledb.file.*;
67
import simpledb.log.*;
78

89
public class PrintLogFile {
9-
public static void main(String[] args) {
10-
SimpleDB db = new SimpleDB("studentdb", 400, 8);
11-
FileMgr fm = db.fileMgr();
12-
LogMgr lm = db.logMgr();
13-
String filename = "simpledb.log";
10+
public static void main(String[] args) {
11+
SimpleDB db = new SimpleDB("txtest", 400, 8);
12+
FileMgr fm = db.fileMgr();
13+
LogMgr lm = db.logMgr();
14+
String filename = "simpledb.log";
1415

15-
int lastblock = fm.length(filename) - 1;
16-
BlockId blk = new BlockId(filename, lastblock);
17-
Page p = new Page(fm.blockSize());
18-
fm.read(blk, p);
19-
Iterator<byte[]> iter = lm.iterator();
20-
while (iter.hasNext()) {
21-
byte[] bytes = iter.next();
22-
LogRecord rec = LogRecord.createLogRecord(bytes);
23-
System.out.println(rec);
24-
}
25-
}
16+
int lastblock = fm.length(filename) - 1;
17+
BlockId blk = new BlockId(filename, lastblock);
18+
Page p = new Page(fm.blockSize());
19+
fm.read(blk, p);
20+
Iterator<byte[]> iter = lm.iterator();
21+
while (iter.hasNext()) {
22+
byte[] bytes = iter.next();
23+
LogRecord rec = LogRecord.createLogRecord(bytes);
24+
System.out.println(rec);
25+
}
26+
}
2627
}

0 commit comments

Comments
 (0)