提交 cd42fd90 authored 作者: Thomas Mueller's avatar Thomas Mueller

Page store: use a log key, so that pages don't need to be set to zero on checkpoint.

上级 00df2d41
......@@ -69,6 +69,11 @@ public abstract class Page extends Record {
*/
public static final int TYPE_STREAM_DATA = 8;
/**
* A header page.
*/
public static final int TYPE_HEADER = 9;
/**
* Copy the data to a new location, change the parent to point to the new
* location, and free up the current page.
......
......@@ -27,10 +27,13 @@ public class PageInputStream extends InputStream {
private boolean endOfFile;
private int remaining;
private byte[] buffer = new byte[1];
private int logKey;
PageInputStream(PageStore store, int trunkPage, int dataPage) {
PageInputStream(PageStore store, int logKey, int trunkPage, int dataPage) {
this.store = store;
this.trace = store.getTrace();
// minus one, because we increment before reading the trunk page
this.logKey = logKey - 1;
this.trunkNext = trunkPage;
this.dataPage = dataPage;
}
......@@ -88,8 +91,11 @@ public class PageInputStream extends InputStream {
while (true) {
if (trunk == null) {
trunk = (PageStreamTrunk) store.getPage(trunkNext);
logKey++;
if (trunk == null) {
throw new EOFException();
} else if (trunk.getLogKey() != logKey) {
throw new EOFException();
}
trunk.resetIndex();
trunkNext = trunk.getNextTrunk();
......@@ -110,9 +116,11 @@ public class PageInputStream extends InputStream {
data = (PageStreamData) store.getPage(next);
if (data == null) {
throw new EOFException();
} else if (data.getLogKey() != logKey) {
throw new EOFException();
}
data.initRead();
remaining = data.getLength();
remaining = data.getRemaining();
}
/**
......
......@@ -30,11 +30,10 @@ import org.h2.value.Value;
* Transaction log mechanism. The stream contains a list of records. The data
* format for a record is:
* <ul>
* <li>0-0: type (0: undo,...)</li>
* <li>1-4: page id</li>
* <li>5-: data</li>
* <li>type (0: no-op, 1: undo, 2: commit, ...)</li>
* <li>data</li>
* </ul>
* The log file is split into sections, each section starts with a new log id.
* The log file is split into sections.
* A checkpoint starts a new section.
*/
public class PageLog {
......@@ -87,7 +86,7 @@ public class PageLog {
public static final int TRUNCATE = 7;
/**
* Perform a checkpoint. The log id is incremented.
* Perform a checkpoint. The log section id is incremented.
* Format: -
*/
public static final int CHECKPOINT = 8;
......@@ -127,8 +126,9 @@ public class PageLog {
private int firstTrunkPage;
private int firstDataPage;
private Data data;
private int logKey;
private int logSectionId, logPos;
private int firstLogId;
private int firstSectionId;
private CompressLZF compress;
private byte[] compressBuffer;
......@@ -180,12 +180,13 @@ public class PageLog {
void openForWriting(int firstTrunkPage, boolean atEnd) throws SQLException {
trace.debug("log openForWriting firstPage:" + firstTrunkPage);
this.firstTrunkPage = firstTrunkPage;
pageOut = new PageOutputStream(store, firstTrunkPage, undoAll, atEnd);
logKey++;
pageOut = new PageOutputStream(store, firstTrunkPage, undoAll, logKey, atEnd);
pageOut.reserve(1);
// TODO maybe buffer to improve speed
pageBuffer = pageOut;
// pageBuffer = new BufferedOutputStream(pageOut, 8 * 1024);
store.setLogFirstPage(firstTrunkPage, pageOut.getCurrentDataPageId());
store.setLogFirstPage(logKey, firstTrunkPage, pageOut.getCurrentDataPageId());
outBuffer = store.createData();
}
......@@ -208,10 +209,12 @@ public class PageLog {
/**
* Open the log for reading.
*
* @param logKey the first expected log key
* @param firstTrunkPage the first trunk page
* @param firstDataPage the index of the first data page
*/
void openForReading(int firstTrunkPage, int firstDataPage) {
void openForReading(int logKey, int firstTrunkPage, int firstDataPage) {
this.logKey = logKey;
this.firstTrunkPage = firstTrunkPage;
this.firstDataPage = firstDataPage;
}
......@@ -229,12 +232,12 @@ public class PageLog {
trace.debug("log recover stage:" + stage);
}
if (stage == RECOVERY_STAGE_ALLOCATE) {
PageInputStream in = new PageInputStream(store, firstTrunkPage, firstDataPage);
PageInputStream in = new PageInputStream(store, logKey, firstTrunkPage, firstDataPage);
usedLogPages = in.allocateAllPages();
in.close();
return;
}
pageIn = new PageInputStream(store, firstTrunkPage, firstDataPage);
pageIn = new PageInputStream(store, logKey, firstTrunkPage, firstDataPage);
in = new DataReader(pageIn);
int logId = 0;
Data data = store.createData();
......@@ -249,8 +252,8 @@ public class PageLog {
if (x == UNDO) {
int pageId = in.readVarInt();
int size = in.readVarInt();
if (size == store.getPageSize()) {
in.readFully(data.getBytes(), 0, size);
if (size == 0) {
in.readFully(data.getBytes(), 0, store.getPageSize());
} else {
in.readFully(compressBuffer, 0, size);
compress.expand(compressBuffer, 0, size, data.getBytes(), 0, store.getPageSize());
......@@ -440,11 +443,12 @@ public class PageLog {
outBuffer.checkCapacity(size);
outBuffer.write(compressBuffer, 0, size);
} else {
outBuffer.writeVarInt(pageSize);
outBuffer.writeVarInt(0);
outBuffer.checkCapacity(pageSize);
outBuffer.write(page.getBytes(), 0, pageSize);
}
} else {
outBuffer.writeVarInt(0);
outBuffer.checkCapacity(pageSize);
outBuffer.write(page.getBytes(), 0, pageSize);
}
......@@ -616,7 +620,7 @@ public class PageLog {
}
/**
* Switch to a new log id.
* Switch to a new log section.
*/
void checkpoint() throws SQLException {
try {
......@@ -645,21 +649,21 @@ public class PageLog {
/**
* Remove all pages until the given log (excluding).
*
* @param firstUncommittedLog the first log id to keep
* @param firstUncommittedSection the first log section to keep
*/
void removeUntil(int firstUncommittedLog) throws SQLException {
if (firstUncommittedLog == 0) {
void removeUntil(int firstUncommittedSection) throws SQLException {
if (firstUncommittedSection == 0) {
return;
}
int firstDataPageToKeep = logSectionPageMap.get(firstUncommittedLog);
int firstDataPageToKeep = logSectionPageMap.get(firstUncommittedSection);
firstTrunkPage = removeUntil(firstTrunkPage, firstDataPageToKeep);
store.setLogFirstPage(firstTrunkPage, firstDataPageToKeep);
while (firstLogId < firstUncommittedLog) {
if (firstLogId > 0) {
store.setLogFirstPage(logKey, firstTrunkPage, firstDataPageToKeep);
while (firstSectionId < firstUncommittedSection) {
if (firstSectionId > 0) {
// there is no entry for log 0
logSectionPageMap.remove(firstLogId);
logSectionPageMap.remove(firstSectionId);
}
firstLogId++;
firstSectionId++;
}
}
......@@ -674,6 +678,7 @@ public class PageLog {
trace.debug("log.removeUntil " + firstDataPageToKeep);
while (true) {
PageStreamTrunk t = (PageStreamTrunk) store.getPage(firstTrunkPage);
logKey = t.getLogKey();
t.resetIndex();
if (t.contains(firstDataPageToKeep)) {
return t.getPos();
......
......@@ -35,19 +35,24 @@ public class PageOutputStream extends OutputStream {
private boolean writing;
private int pages;
private boolean atEnd;
private int logKey;
/**
* Create a new page output stream.
*
* @param store the page store
* @param trunkPage the first trunk page (already allocated)
* @param exclude the pages not to use
* @param logKey the log key of the first trunk page
* @param atEnd whether only pages at the end of the file should be used
*/
public PageOutputStream(PageStore store, int trunkPage, BitField exclude, boolean atEnd) {
public PageOutputStream(PageStore store, int trunkPage, BitField exclude, int logKey, boolean atEnd) {
this.trace = store.getTrace();
this.store = store;
this.trunkPageId = trunkPage;
this.exclude = exclude;
// minus one, because we increment before creating a trunk page
this.logKey = logKey - 1;
this.atEnd = atEnd;
}
......@@ -102,13 +107,14 @@ public class PageOutputStream extends OutputStream {
pageIds[i] = reservedPages.get(i);
}
trunkNext = reservedPages.get(len);
trunk = PageStreamTrunk.create(store, parent, trunkPageId, trunkNext, pageIds);
logKey++;
trunk = PageStreamTrunk.create(store, parent, trunkPageId, trunkNext, logKey, pageIds);
pages++;
trunk.write(null);
reservedPages.removeRange(0, len + 1);
nextData = trunk.getNextPageData();
}
data = PageStreamData.create(store, nextData, trunk.getPos());
data = PageStreamData.create(store, nextData, trunk.getPos(), logKey);
pages++;
data.initWrite();
}
......@@ -145,7 +151,7 @@ public class PageOutputStream extends OutputStream {
private void storePage() throws IOException {
try {
if (trace.isDebugEnabled()) {
trace.debug("pageOut.storePage " + data.getPos());
trace.debug("pageOut.storePage " + data);
}
data.write(null);
} catch (SQLException e) {
......@@ -195,4 +201,8 @@ public class PageOutputStream extends OutputStream {
pages -= t.free();
}
int getCurrentLogKey() {
return trunk.getLogKey();
}
}
......@@ -22,12 +22,12 @@ import org.h2.index.IndexType;
import org.h2.index.PageBtreeIndex;
import org.h2.index.PageBtreeLeaf;
import org.h2.index.PageBtreeNode;
import org.h2.index.PageDataIndex;
import org.h2.index.PageDataLeaf;
import org.h2.index.PageDataNode;
import org.h2.index.PageDataOverflow;
import org.h2.index.PageDelegateIndex;
import org.h2.index.PageIndex;
import org.h2.index.PageDataIndex;
import org.h2.log.InDoubtTransaction;
import org.h2.log.LogSystem;
import org.h2.message.Message;
......@@ -69,19 +69,24 @@ import org.h2.value.ValueString;
* </ul>
* The format of page 1 and 2 is:
* <ul>
* <li>0-7: write counter (incremented each time the header changes)</li>
* <li>8-11: log trunk page (0 for none)</li>
* <li>12-15: log data page (0 for none)</li>
* <li>16-23: checksum of bytes 0-15 (CRC32)</li>
* <li>page type: byte (0)</li>
* <li>write counter (incremented each time the header changes): long (1-8)</li>
* <li>log trunk key: int (9-12)</li>
* <li>log trunk page (0 for none): int (13-16)</li>
* <li>log data page (0 for none): int (17-20)</li>
* <li>CRC32 checksum of the page: int (20-23)</li>
* </ul>
* Page 3 contains the first free list page.
* Page 4 contains the meta table root page.
*/
public class PageStore implements CacheWriter {
// TODO freed: truncate when decreasing size
// TODO check commit delay
// TODO do not trim large databases fully, only up to x seconds
// TODO use regular page type for page 1 and 2
// TODO implement checksum; 0 for empty pages
// TODO undo log: don't store empty space between head and data
// TODO update: only log the key and changed values
......@@ -164,7 +169,7 @@ public class PageStore implements CacheWriter {
private int pageSize;
private int pageSizeShift;
private long writeCount;
private int logFirstTrunkPage, logFirstDataPage;
private int logKey, logFirstTrunkPage, logFirstDataPage;
private Cache cache;
......@@ -264,7 +269,6 @@ public class PageStore implements CacheWriter {
} else {
openNew();
}
// lastUsedPage = getFreeList().getLastUsed() + 1;
} catch (SQLException e) {
close();
throw e;
......@@ -301,7 +305,7 @@ public class PageStore implements CacheWriter {
}
readVariableHeader();
log = new PageLog(this);
log.openForReading(logFirstTrunkPage, logFirstDataPage);
log.openForReading(logKey, logFirstTrunkPage, logFirstDataPage);
recover();
if (!database.isReadOnly()) {
recoveryRunning = true;
......@@ -384,7 +388,7 @@ public class PageStore implements CacheWriter {
recoveryRunning = true;
try {
log.free();
setLogFirstPage(0, 0);
setLogFirstPage(0, 0, 0);
} finally {
recoveryRunning = false;
}
......@@ -443,7 +447,7 @@ public class PageStore implements CacheWriter {
if (rec != null) {
return (Page) rec;
}
Data data = Data.create(database, pageSize);
Data data = createData();
readPage(pageId, data);
data.readInt();
int type = data.readByte();
......@@ -510,17 +514,17 @@ public class PageStore implements CacheWriter {
private void switchLog() throws SQLException {
trace.debug("switchLog");
Session[] sessions = database.getSessions(true);
int firstUncommittedLog = log.getLogSectionId();
int firstUncommittedSection = log.getLogSectionId();
for (int i = 0; i < sessions.length; i++) {
Session session = sessions[i];
int log = session.getFirstUncommittedLog();
if (log != LogSystem.LOG_WRITTEN) {
if (log < firstUncommittedLog) {
firstUncommittedLog = log;
if (log < firstUncommittedSection) {
firstUncommittedSection = log;
}
}
}
log.removeUntil(firstUncommittedLog);
log.removeUntil(firstUncommittedSection);
}
private void readStaticHeader() throws SQLException {
......@@ -544,22 +548,30 @@ public class PageStore implements CacheWriter {
}
private void readVariableHeader() throws SQLException {
Data page = Data.create(database, pageSize);
Data page = createData();
for (int i = 1;; i++) {
if (i == 3) {
throw Message.getSQLException(ErrorCode.FILE_CORRUPTED_1, fileName);
}
page.reset();
readPage(i, page);
writeCount = page.readLong();
logFirstTrunkPage = page.readInt();
logFirstDataPage = page.readInt();
CRC32 crc = new CRC32();
crc.update(page.getBytes(), 0, page.length());
long expected = crc.getValue();
long got = page.readLong();
if (expected == got) {
break;
int type = page.readByte();
if (type == Page.TYPE_HEADER) {
writeCount = page.readLong();
logKey = page.readInt();
logFirstTrunkPage = page.readInt();
logFirstDataPage = page.readInt();
// read the CRC, then reset it to 0
int start = page.length();
int got = page.readInt();
page.setPos(start);
page.writeInt(0);
CRC32 crc = new CRC32();
crc.update(page.getBytes(), 0, pageSize);
int expected = (int) crc.getValue();
if (expected == got) {
break;
}
}
}
}
......@@ -603,23 +615,30 @@ public class PageStore implements CacheWriter {
/**
* Set the trunk page and data page id of the log.
*
* @param logKey the log key of the trunk page
* @param trunkPageId the trunk page id
* @param dataPageId the data page id
*/
void setLogFirstPage(int trunkPageId, int dataPageId) throws SQLException {
void setLogFirstPage(int logKey, int trunkPageId, int dataPageId) throws SQLException {
if (trace.isDebugEnabled()) {
trace.debug("setLogFirstPage key: " + logKey + " trunk: " + trunkPageId + " data: " + dataPageId);
}
this.logKey = logKey;
this.logFirstTrunkPage = trunkPageId;
this.logFirstDataPage = dataPageId;
writeVariableHeader();
}
private void writeVariableHeader() throws SQLException {
Data page = Data.create(database, pageSize);
Data page = createData();
page.writeByte((byte) Page.TYPE_HEADER);
page.writeLong(writeCount);
page.writeInt(logKey);
page.writeInt(logFirstTrunkPage);
page.writeInt(logFirstDataPage);
CRC32 crc = new CRC32();
crc.update(page.getBytes(), 0, page.length());
page.writeLong(crc.getValue());
crc.update(page.getBytes(), 0, pageSize);
page.writeInt((int) crc.getValue());
file.seek(pageSize);
file.write(page.getBytes(), 0, pageSize);
file.seek(pageSize + pageSize);
......@@ -709,12 +728,12 @@ public class PageStore implements CacheWriter {
private PageFreeList getFreeList(int i) throws SQLException {
PageFreeList list = null;
// if (i < freeLists.size()) {
// list = freeLists.get(i);
// if (list != null) {
// return list;
// }
// }
if (i < freeLists.size()) {
list = freeLists.get(i);
if (list != null) {
return list;
}
}
int p = PAGE_ID_FREE_LIST_ROOT + i * freeListPagesPerList;
while (p >= pageCount) {
increaseFileSize(INCREMENT_PAGES);
......@@ -799,6 +818,9 @@ public class PageStore implements CacheWriter {
}
private void increaseFileSize(int increment) throws SQLException {
for (int i = pageCount; i < pageCount + increment; i++) {
freed.set(i);
}
pageCount += increment;
long newLength = (long) pageCount << pageSizeShift;
file.setLength(newLength);
......
......@@ -14,25 +14,25 @@ import org.h2.engine.Session;
* <ul>
* <li>the trunk page id: int (0-3)</li>
* <li>page type: byte (4)</li>
* <li>the number of bytes used: short (5-6)</li>
* <li>log key: int (5-8)</li>
* <li>data (9-)</li>
* </ul>
*/
public class PageStreamData extends Page {
private static final int LENGTH_START = 5;
private static final int DATA_START = 9;
private final PageStore store;
private int trunk;
private int logKey;
private Data data;
private int remaining;
private int length;
private PageStreamData(PageStore store, int pageId, int trunk) {
private PageStreamData(PageStore store, int pageId, int trunk, int logKey) {
setPos(pageId);
this.store = store;
this.trunk = trunk;
this.logKey = logKey;
}
/**
......@@ -44,7 +44,7 @@ public class PageStreamData extends Page {
* @return the page
*/
static PageStreamData read(PageStore store, Data data, int pageId) {
PageStreamData p = new PageStreamData(store, pageId, 0);
PageStreamData p = new PageStreamData(store, pageId, 0, 0);
p.data = data;
p.read();
return p;
......@@ -56,10 +56,11 @@ public class PageStreamData extends Page {
* @param store the page store
* @param pageId the page id
* @param trunk the trunk page
* @param logKey the log key
* @return the page
*/
static PageStreamData create(PageStore store, int pageId, int trunk) {
return new PageStreamData(store, pageId, trunk);
static PageStreamData create(PageStore store, int pageId, int trunk, int logKey) {
return new PageStreamData(store, pageId, trunk, logKey);
}
/**
......@@ -68,9 +69,8 @@ public class PageStreamData extends Page {
private void read() {
data.reset();
trunk = data.readInt();
data.setPos(4);
data.readByte();
length = data.readInt();
logKey = data.readInt();
}
public int getByteCount(DataPage dummy) {
......@@ -84,9 +84,8 @@ public class PageStreamData extends Page {
data = store.createData();
data.writeInt(trunk);
data.writeByte((byte) Page.TYPE_STREAM_DATA);
data.writeInt(0);
data.writeInt(logKey);
remaining = store.getPageSize() - data.length();
length = 0;
}
/**
......@@ -100,13 +99,11 @@ public class PageStreamData extends Page {
int write(byte[] buff, int offset, int len) {
int max = Math.min(remaining, len);
data.write(buff, offset, max);
length += max;
remaining -= max;
return max;
}
public void write(DataPage buff) throws SQLException {
data.setInt(LENGTH_START, length);
store.writePage(getPos(), data);
}
......@@ -120,10 +117,6 @@ public class PageStreamData extends Page {
return pageSize - DATA_START;
}
int getLength() {
return length;
}
/**
* Read the next bytes from the buffer.
*
......@@ -158,11 +151,19 @@ public class PageStreamData extends Page {
*/
void initRead() {
data.setPos(DATA_START);
remaining = length;
remaining = store.getPageSize() - DATA_START;
}
public void moveTo(Session session, int newPos) {
// not required
}
int getLogKey() {
return logKey;
}
public String toString() {
return "[" + getPos() + "] stream data pos:" + data.length() + " remaining:" + remaining;
}
}
\ No newline at end of file
......@@ -15,28 +15,31 @@ import org.h2.engine.Session;
* <ul>
* <li>previous trunk page, or 0 if none: int (0-3)</li>
* <li>page type: byte (4)</li>
* <li>next trunk page: int (5-8)</li>
* <li>number of pages (9-10)</li>
* <li>remainder: page ids (11-)</li>
* <li>log key: int (5-8)</li>
* <li>next trunk page: int (9-12)</li>
* <li>number of pages: short (13-14)</li>
* <li>page ids (15-)</li>
* </ul>
*/
public class PageStreamTrunk extends Page {
private static final int DATA_START = 11;
private static final int DATA_START = 15;
private final PageStore store;
private int parent;
private int logKey;
private int nextTrunk;
private int[] pageIds;
private int pageCount;
private Data data;
private int index;
private PageStreamTrunk(PageStore store, int parent, int pageId, int next, int[] pageIds) {
private PageStreamTrunk(PageStore store, int parent, int pageId, int next, int logKey, int[] pageIds) {
setPos(pageId);
this.parent = parent;
this.store = store;
this.nextTrunk = next;
this.logKey = logKey;
this.pageCount = pageIds.length;
this.pageIds = pageIds;
}
......@@ -68,11 +71,12 @@ public class PageStreamTrunk extends Page {
* @param parent the parent page
* @param pageId the page id
* @param next the next trunk page
* @param logKey the log key
* @param pageIds the stream data page ids
* @return the page
*/
static PageStreamTrunk create(PageStore store, int parent, int pageId, int next, int[] pageIds) {
return new PageStreamTrunk(store, parent, pageId, next, pageIds);
static PageStreamTrunk create(PageStore store, int parent, int pageId, int next, int logKey, int[] pageIds) {
return new PageStreamTrunk(store, parent, pageId, next, logKey, pageIds);
}
/**
......@@ -82,6 +86,7 @@ public class PageStreamTrunk extends Page {
data.reset();
parent = data.readInt();
data.readByte();
logKey = data.readInt();
nextTrunk = data.readInt();
pageCount = data.readShortInt();
pageIds = new int[pageCount];
......@@ -120,6 +125,7 @@ public class PageStreamTrunk extends Page {
data = store.createData();
data.writeInt(parent);
data.writeByte((byte) Page.TYPE_STREAM_TRUNK);
data.writeInt(logKey);
data.writeInt(nextTrunk);
data.writeShortInt(pageCount);
for (int i = 0; i < pageCount; i++) {
......@@ -159,16 +165,13 @@ public class PageStreamTrunk extends Page {
* @return the number of pages freed
*/
int free() throws SQLException {
Data empty = store.createData();
store.freePage(getPos(), false, null);
int freed = 1;
for (int i = 0; i < pageCount; i++) {
int page = pageIds[i];
store.freePage(page, false, null);
freed++;
store.writePage(page, empty);
}
store.writePage(getPos(), empty);
return freed;
}
......@@ -201,4 +204,8 @@ public class PageStreamTrunk extends Page {
// not required
}
int getLogKey() {
return logKey;
}
}
......@@ -817,7 +817,7 @@ public class Recover extends Tool implements DataHandler {
}
int pageCount = (int) (length / pageSize);
s = Data.create(this, pageSize);
int logFirstTrunkPage = 0, logFirstDataPage = 0;
int logKey = 0, logFirstTrunkPage = 0, logFirstDataPage = 0;
for (int i = 1;; i++) {
if (i == 3) {
break;
......@@ -825,22 +825,28 @@ public class Recover extends Tool implements DataHandler {
s.reset();
store.seek(i * pageSize);
store.readFully(s.getBytes(), 0, pageSize);
int type = s.readByte();
long writeCounter = s.readLong();
int key = s.readInt();
int firstTrunkPage = s.readInt();
int firstDataPage = s.readInt();
int start = s.length();
int got = s.readInt();
s.setPos(start);
s.writeInt(0);
CRC32 crc = new CRC32();
crc.update(s.getBytes(), 0, s.length());
long expected = crc.getValue();
long got = s.readLong();
crc.update(s.getBytes(), 0, pageSize);
int expected = (int) crc.getValue();
if (expected == got) {
if (logFirstTrunkPage == 0) {
logKey = key;
logFirstTrunkPage = firstTrunkPage;
logFirstDataPage = firstDataPage;
}
}
writer.println("-- head " + i +
": writeCounter: " + writeCounter +
" trunk: " + firstTrunkPage + "/" + firstDataPage +
": type: " + type + " writeCounter: " + writeCounter +
" log key: " + key + " trunk: " + firstTrunkPage + "/" + firstDataPage +
" crc expected " + expected +
" got " + got + " (" + (expected == got ? "ok" : "different") + ")");
}
......@@ -934,7 +940,7 @@ public class Recover extends Tool implements DataHandler {
}
writeSchema(writer);
try {
dumpPageLogStream(writer, logFirstTrunkPage, logFirstDataPage);
dumpPageLogStream(writer, logKey, logFirstTrunkPage, logFirstDataPage);
} catch (EOFException e) {
// ignore
}
......@@ -955,10 +961,10 @@ public class Recover extends Tool implements DataHandler {
}
}
private void dumpPageLogStream(PrintWriter writer, int logFirstTrunkPage, int logFirstDataPage) throws IOException, SQLException {
private void dumpPageLogStream(PrintWriter writer, int logKey, int logFirstTrunkPage, int logFirstDataPage) throws IOException, SQLException {
Data s = Data.create(this, pageSize);
DataReader in = new DataReader(
new PageInputStream(writer, this, store, logFirstTrunkPage, logFirstDataPage, pageSize)
new PageInputStream(writer, this, store, logKey, logFirstTrunkPage, logFirstDataPage, pageSize)
);
while (true) {
int x = in.read();
......@@ -1037,16 +1043,17 @@ public class Recover extends Tool implements DataHandler {
private IntArray dataPages = new IntArray();
private boolean endOfFile;
private int remaining;
private int logKey;
public PageInputStream(PrintWriter writer, DataHandler handler,
FileStore store, int firstTrunkPage, int firstDataPage, int pageSize) {
FileStore store, int logKey, int firstTrunkPage, int firstDataPage, int pageSize) {
this.writer = writer;
this.store = store;
this.pageSize = pageSize;
this.logKey = logKey - 1;
this.trunkPage = firstTrunkPage;
this.dataPage = firstDataPage;
page = DataPage.create(handler, pageSize);
}
public int read() throws IOException {
......@@ -1108,7 +1115,12 @@ public class Recover extends Tool implements DataHandler {
return;
}
trunkPage = page.readInt();
int pageCount = page.readInt();
int key = page.readInt();
logKey++;
if (key != logKey) {
writer.println("-- eof page: " +trunkPage + " type: " + t + " expected key: " + logKey + " got: " + key);
}
int pageCount = page.readShortInt();
for (int i = 0; i < pageCount; i++) {
int d = page.readInt();
if (dataPage != 0) {
......@@ -1130,11 +1142,17 @@ public class Recover extends Tool implements DataHandler {
page.reset();
int p = page.readInt();
int t = page.readByte();
int k = page.readInt();
if (t != Page.TYPE_STREAM_DATA) {
writer.println("-- eof page: " +nextPage+ " type: " + t + " parent: " + p +
" expected type: " + Page.TYPE_STREAM_DATA);
endOfFile = true;
return;
} else if (k != logKey) {
writer.println("-- eof page: " +nextPage+ " type: " + t + " parent: " + p +
" expected key: " + logKey + " got: " + k);
endOfFile = true;
return;
}
remaining = page.readInt();
} catch (SQLException e) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论