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

Page store: bugfixes.

上级 671e444f
...@@ -100,11 +100,7 @@ class PageDataLeaf extends PageData { ...@@ -100,11 +100,7 @@ class PageDataLeaf extends PageData {
if (entryCount > 1) { if (entryCount > 1) {
return entryCount / 2; return entryCount / 2;
} }
int todoIncorrect; return find(row.getPos());
if (find(row.getPos()) != 1) {
System.out.println("todo " + find(row.getPos()));
}
return 1; // find(row.getPos()) + 1;
} }
int offset = last - rowLength; int offset = last - rowLength;
int[] newOffsets = new int[entryCount + 1]; int[] newOffsets = new int[entryCount + 1];
...@@ -188,7 +184,7 @@ class PageDataLeaf extends PageData { ...@@ -188,7 +184,7 @@ class PageDataLeaf extends PageData {
written = false; written = false;
readAllRows(); readAllRows();
entryCount--; entryCount--;
if (entryCount <= 0) { if (entryCount < 0) {
Message.throwInternalError(); Message.throwInternalError();
} }
int[] newOffsets = new int[entryCount]; int[] newOffsets = new int[entryCount];
......
...@@ -40,21 +40,33 @@ public class PageFreeList extends Record { ...@@ -40,21 +40,33 @@ public class PageFreeList extends Record {
/** /**
* Allocate a page from the free list. * Allocate a page from the free list.
* *
* @param exclude the exclude list or null
* @param first the first page to look for
* @return the page, or -1 if all pages are used * @return the page, or -1 if all pages are used
*/ */
int allocate() throws SQLException { int allocate(BitField exclude, int first) throws SQLException {
if (full) { if (full) {
return -1; return -1;
} }
// TODO cache last result // TODO cache last result
int free = used.nextClearBit(0); int start = Math.max(0, first - getPos());
if (free >= pageCount) { while (true) {
full = true; int free = used.nextClearBit(start);
return -1; if (free >= pageCount) {
full = true;
return -1;
}
if (exclude != null && exclude.get(free + getPos())) {
start = exclude.nextClearBit(free + getPos()) - getPos();
if (start >= pageCount) {
return -1;
}
} else {
used.set(free);
store.updateRecord(this, true, data);
return free + getPos();
}
} }
used.set(free);
store.updateRecord(this, true, data);
return free + getPos();
} }
/** /**
......
...@@ -11,6 +11,7 @@ import java.io.IOException; ...@@ -11,6 +11,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.message.Trace; import org.h2.message.Trace;
import org.h2.util.BitField;
/** /**
* An input stream that reads from a page store. * An input stream that reads from a page store.
...@@ -110,10 +111,14 @@ public class PageInputStream extends InputStream { ...@@ -110,10 +111,14 @@ public class PageInputStream extends InputStream {
/** /**
* Set all pages as 'allocated' in the page store. * Set all pages as 'allocated' in the page store.
*
* @return the bit set
*/ */
void allocateAllPages() throws SQLException { BitField allocateAllPages() throws SQLException {
BitField pages = new BitField();
int trunkPage = trunkNext; int trunkPage = trunkNext;
while (trunkPage != 0) { while (trunkPage != 0) {
pages.set(trunkPage);
store.allocatePage(trunkPage); store.allocatePage(trunkPage);
PageStreamTrunk t = new PageStreamTrunk(store, trunkPage); PageStreamTrunk t = new PageStreamTrunk(store, trunkPage);
t.read(); t.read();
...@@ -122,10 +127,12 @@ public class PageInputStream extends InputStream { ...@@ -122,10 +127,12 @@ public class PageInputStream extends InputStream {
if (n == -1) { if (n == -1) {
break; break;
} }
pages.set(n);
store.allocatePage(n); store.allocatePage(n);
} }
trunkPage = t.getNextTrunk(); trunkPage = t.getNextTrunk();
} }
return pages;
} }
int getDataPage() { int getDataPage() {
......
...@@ -36,6 +36,8 @@ import org.h2.value.Value; ...@@ -36,6 +36,8 @@ import org.h2.value.Value;
* <li>1-4: page id</li> * <li>1-4: page id</li>
* <li>5-: data</li> * <li>5-: data</li>
* </ul> * </ul>
* The log file is split into sections, each section starts with a new log id.
* A checkpoint starts a new section.
*/ */
public class PageLog { public class PageLog {
...@@ -125,12 +127,38 @@ public class PageLog { ...@@ -125,12 +127,38 @@ public class PageLog {
private int firstTrunkPage; private int firstTrunkPage;
private int firstDataPage; private int firstDataPage;
private Data data; private Data data;
private int logId, logPos; private int logSectionId, logPos;
private int firstLogId; private int firstLogId;
/**
* If the bit is set, the given page was written to the current log section.
* The undo entry of these pages doesn't need to be written again.
*/
private BitField undo = new BitField(); private BitField undo = new BitField();
private IntIntHashMap logIdPageMap = new IntIntHashMap();
/**
* The undo entry of those pages was written in any log section.
* These pages may not be used in the transaction log.
*/
private BitField undoAll = new BitField();
/**
* The map of section ids (key) and data page where the section starts (value).
*/
private IntIntHashMap logSectionPageMap = new IntIntHashMap();
/**
* The session state map.
* Only used during recovery.
*/
private HashMap<Integer, SessionState> sessionStates = New.hashMap(); private HashMap<Integer, SessionState> sessionStates = New.hashMap();
/**
* The map of pages used by the transaction log.
* Only used during recovery.
*/
private BitField usedLogPages;
PageLog(PageStore store) { PageLog(PageStore store) {
this.store = store; this.store = store;
data = store.createData(); data = store.createData();
...@@ -146,7 +174,7 @@ public class PageLog { ...@@ -146,7 +174,7 @@ public class PageLog {
void openForWriting(int firstTrunkPage) throws SQLException { void openForWriting(int firstTrunkPage) throws SQLException {
trace.debug("log openForWriting firstPage:" + firstTrunkPage); trace.debug("log openForWriting firstPage:" + firstTrunkPage);
this.firstTrunkPage = firstTrunkPage; this.firstTrunkPage = firstTrunkPage;
pageOut = new PageOutputStream(store, firstTrunkPage); pageOut = new PageOutputStream(store, firstTrunkPage, undoAll);
pageOut.reserve(1); pageOut.reserve(1);
store.setLogFirstPage(firstTrunkPage, pageOut.getCurrentDataPageId()); store.setLogFirstPage(firstTrunkPage, pageOut.getCurrentDataPageId());
buffer = new ByteArrayOutputStream(); buffer = new ByteArrayOutputStream();
...@@ -199,7 +227,7 @@ public class PageLog { ...@@ -199,7 +227,7 @@ public class PageLog {
} }
if (stage == RECOVERY_STAGE_ALLOCATE) { if (stage == RECOVERY_STAGE_ALLOCATE) {
PageInputStream in = new PageInputStream(store, firstTrunkPage, firstDataPage); PageInputStream in = new PageInputStream(store, firstTrunkPage, firstDataPage);
in.allocateAllPages(); usedLogPages = in.allocateAllPages();
return; return;
} }
pageIn = new PageInputStream(store, firstTrunkPage, firstDataPage); pageIn = new PageInputStream(store, firstTrunkPage, firstDataPage);
...@@ -224,6 +252,7 @@ public class PageLog { ...@@ -224,6 +252,7 @@ public class PageLog {
} }
store.writePage(pageId, data); store.writePage(pageId, data);
undo.set(pageId); undo.set(pageId);
undoAll.set(pageId);
} }
} }
} else if (x == ADD || x == REMOVE) { } else if (x == ADD || x == REMOVE) {
...@@ -295,7 +324,9 @@ public class PageLog { ...@@ -295,7 +324,9 @@ public class PageLog {
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
int pageId = in.readInt(); int pageId = in.readInt();
if (stage == RECOVERY_STAGE_REDO) { if (stage == RECOVERY_STAGE_REDO) {
store.freePage(pageId, false, null); if (!usedLogPages.get(pageId)) {
store.freePage(pageId, false, null);
}
} }
} }
} else { } else {
...@@ -311,6 +342,9 @@ public class PageLog { ...@@ -311,6 +342,9 @@ public class PageLog {
throw Message.convertIOException(e, "recover"); throw Message.convertIOException(e, "recover");
} }
undo = new BitField(); undo = new BitField();
if (stage == RECOVERY_STAGE_REDO) {
usedLogPages = null;
}
} }
/** /**
...@@ -372,6 +406,7 @@ public class PageLog { ...@@ -372,6 +406,7 @@ public class PageLog {
trace.debug("log undo " + pageId); trace.debug("log undo " + pageId);
} }
undo.set(pageId); undo.set(pageId);
undoAll.set(pageId);
out.write(UNDO); out.write(UNDO);
out.writeInt(pageId); out.writeInt(pageId);
out.write(page.getBytes(), 0, store.getPageSize()); out.write(page.getBytes(), 0, store.getPageSize());
...@@ -482,8 +517,8 @@ public class PageLog { ...@@ -482,8 +517,8 @@ public class PageLog {
trace.debug("log " + (add?"+":"-") + " s:" + session.getId() + " table:" + tableId + trace.debug("log " + (add?"+":"-") + " s:" + session.getId() + " table:" + tableId +
" row:" + row); " row:" + row);
} }
session.addLogPos(logId, logPos); session.addLogPos(logSectionId, logPos);
row.setLastLog(logId, logPos); row.setLastLog(logSectionId, logPos);
data.reset(); data.reset();
data.checkCapacity(row.getByteCount(data)); data.checkCapacity(row.getByteCount(data));
...@@ -499,7 +534,7 @@ public class PageLog { ...@@ -499,7 +534,7 @@ public class PageLog {
throw Message.convertIOException(e, null); throw Message.convertIOException(e, null);
} }
} }
/** /**
* A table is truncated. * A table is truncated.
* *
...@@ -511,7 +546,7 @@ public class PageLog { ...@@ -511,7 +546,7 @@ public class PageLog {
if (trace.isDebugEnabled()) { if (trace.isDebugEnabled()) {
trace.debug("log truncate s:" + session.getId() + " table:" + tableId); trace.debug("log truncate s:" + session.getId() + " table:" + tableId);
} }
session.addLogPos(logId, logPos); session.addLogPos(logSectionId, logPos);
data.reset(); data.reset();
out.write(TRUNCATE); out.write(TRUNCATE);
out.writeInt(session.getId()); out.writeInt(session.getId());
...@@ -545,14 +580,14 @@ public class PageLog { ...@@ -545,14 +580,14 @@ public class PageLog {
throw Message.convertIOException(e, null); throw Message.convertIOException(e, null);
} }
undo = new BitField(); undo = new BitField();
logId++; logSectionId++;
pageOut.fillPage(); pageOut.fillPage();
int currentDataPage = pageOut.getCurrentDataPageId(); int currentDataPage = pageOut.getCurrentDataPageId();
logIdPageMap.put(logId, currentDataPage); logSectionPageMap.put(logSectionId, currentDataPage);
} }
int getLogId() { int getLogSectionId() {
return logId; return logSectionId;
} }
/** /**
...@@ -564,13 +599,13 @@ public class PageLog { ...@@ -564,13 +599,13 @@ public class PageLog {
if (firstUncommittedLog == 0) { if (firstUncommittedLog == 0) {
return; return;
} }
int firstDataPageToKeep = logIdPageMap.get(firstUncommittedLog); int firstDataPageToKeep = logSectionPageMap.get(firstUncommittedLog);
firstTrunkPage = removeUntil(firstTrunkPage, firstDataPageToKeep); firstTrunkPage = removeUntil(firstTrunkPage, firstDataPageToKeep);
store.setLogFirstPage(firstTrunkPage, firstDataPageToKeep); store.setLogFirstPage(firstTrunkPage, firstDataPageToKeep);
while (firstLogId < firstUncommittedLog) { while (firstLogId < firstUncommittedLog) {
if (firstLogId > 0) { if (firstLogId > 0) {
// there is no entry for log 0 // there is no entry for log 0
logIdPageMap.remove(firstLogId); logSectionPageMap.remove(firstLogId);
} }
firstLogId++; firstLogId++;
} }
......
...@@ -11,6 +11,7 @@ import java.io.OutputStream; ...@@ -11,6 +11,7 @@ import java.io.OutputStream;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.message.Message; import org.h2.message.Message;
import org.h2.message.Trace; import org.h2.message.Trace;
import org.h2.util.BitField;
import org.h2.util.IntArray; import org.h2.util.IntArray;
/** /**
...@@ -21,6 +22,8 @@ public class PageOutputStream extends OutputStream { ...@@ -21,6 +22,8 @@ public class PageOutputStream extends OutputStream {
private PageStore store; private PageStore store;
private final Trace trace; private final Trace trace;
private int trunkPageId; private int trunkPageId;
private final BitField exclude;
private int trunkNext; private int trunkNext;
private IntArray reservedPages = new IntArray(); private IntArray reservedPages = new IntArray();
private PageStreamTrunk trunk; private PageStreamTrunk trunk;
...@@ -38,10 +41,11 @@ public class PageOutputStream extends OutputStream { ...@@ -38,10 +41,11 @@ public class PageOutputStream extends OutputStream {
* @param store the page store * @param store the page store
* @param trunkPage the first trunk page (already allocated) * @param trunkPage the first trunk page (already allocated)
*/ */
public PageOutputStream(PageStore store, int trunkPage) { public PageOutputStream(PageStore store, int trunkPage, BitField exclude) {
this.trace = store.getTrace(); this.trace = store.getTrace();
this.store = store; this.store = store;
this.trunkPageId = trunkPage; this.trunkPageId = trunkPage;
this.exclude = exclude;
} }
/** /**
...@@ -64,10 +68,7 @@ public class PageOutputStream extends OutputStream { ...@@ -64,10 +68,7 @@ public class PageOutputStream extends OutputStream {
} }
// allocate the next trunk page as well // allocate the next trunk page as well
pagesToAllocate++; pagesToAllocate++;
for (int i = 0; i < pagesToAllocate; i++) { store.allocatePages(reservedPages, pagesToAllocate, exclude);
int page = store.allocatePage();
reservedPages.add(page);
}
reserved += totalCapacity; reserved += totalCapacity;
if (data == null) { if (data == null) {
initNextData(); initNextData();
......
...@@ -31,11 +31,13 @@ import org.h2.table.Column; ...@@ -31,11 +31,13 @@ import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.table.TableData; import org.h2.table.TableData;
import org.h2.util.BitField;
import org.h2.util.Cache; import org.h2.util.Cache;
import org.h2.util.CacheLRU; import org.h2.util.CacheLRU;
import org.h2.util.CacheObject; import org.h2.util.CacheObject;
import org.h2.util.CacheWriter; import org.h2.util.CacheWriter;
import org.h2.util.FileUtils; import org.h2.util.FileUtils;
import org.h2.util.IntArray;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.ObjectArray; import org.h2.util.ObjectArray;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
...@@ -69,11 +71,6 @@ import org.h2.value.ValueString; ...@@ -69,11 +71,6 @@ import org.h2.value.ValueString;
*/ */
public class PageStore implements CacheWriter { public class PageStore implements CacheWriter {
// TODO what if the log contains undo page for a later log page
// TODO what if the log contains a head page for a later log page
// TODO allocate log: must not use page if undo is in an active log
// TODO or don't redo if page is now a log page
// TODO var int: see google protocol buffers // TODO var int: see google protocol buffers
// TODO don't save parent (only root); remove setPageId // TODO don't save parent (only root); remove setPageId
// TODO implement checksum - 0 for empty // TODO implement checksum - 0 for empty
...@@ -354,7 +351,7 @@ public class PageStore implements CacheWriter { ...@@ -354,7 +351,7 @@ public class PageStore implements CacheWriter {
private void switchLog() throws SQLException { private void switchLog() throws SQLException {
trace.debug("switchLog"); trace.debug("switchLog");
Session[] sessions = database.getSessions(true); Session[] sessions = database.getSessions(true);
int firstUncommittedLog = log.getLogId(); int firstUncommittedLog = log.getLogSectionId();
for (int i = 0; i < sessions.length; i++) { for (int i = 0; i < sessions.length; i++) {
Session session = sessions[i]; Session session = sessions[i];
int log = session.getFirstUncommittedLog(); int log = session.getFirstUncommittedLog();
...@@ -582,18 +579,38 @@ public class PageStore implements CacheWriter { ...@@ -582,18 +579,38 @@ public class PageStore implements CacheWriter {
return getFreeListForPage(pageId).isUsed(pageId); return getFreeListForPage(pageId).isUsed(pageId);
} }
/**
* Allocate a number of pages.
*
* @param list the list where to add the allocated pages
* @param pagesToAllocate the number of pages to allocate
* @param exclude the exclude list
*/
void allocatePages(IntArray list, int pagesToAllocate, BitField exclude) throws SQLException {
int first = 0;
for (int i = 0; i < pagesToAllocate; i++) {
int page = allocatePage(exclude, first);
first = page;
list.add(page);
}
}
/** /**
* Allocate a page. * Allocate a page.
* *
* @return the page id * @return the page id
*/ */
public int allocatePage() throws SQLException { public int allocatePage() throws SQLException {
return allocatePage(null, 0);
}
private int allocatePage(BitField exclude, int first) throws SQLException {
int pos; int pos;
synchronized (database) { synchronized (database) {
// TODO could remember the first possible free list page // TODO could remember the first possible free list page
for (int i = 0;; i++) { for (int i = 0;; i++) {
PageFreeList list = getFreeList(i); PageFreeList list = getFreeList(i);
pos = list.allocate(); pos = list.allocate(exclude, first);
if (pos >= 0) { if (pos >= 0) {
break; break;
} }
...@@ -885,7 +902,7 @@ public class PageStore implements CacheWriter { ...@@ -885,7 +902,7 @@ public class PageStore implements CacheWriter {
table.removeRow(systemSession, row); table.removeRow(systemSession, row);
} }
} }
/** /**
* Redo a truncate. * Redo a truncate.
* *
...@@ -929,7 +946,11 @@ public class PageStore implements CacheWriter { ...@@ -929,7 +946,11 @@ public class PageStore implements CacheWriter {
int headPos = index.getHeadPos(); int headPos = index.getHeadPos();
index.getTable().removeIndex(index); index.getTable().removeIndex(index);
if (index instanceof PageBtreeIndex) { if (index instanceof PageBtreeIndex) {
index.getSchema().remove(index); if (index.isTemporary()) {
systemSession.removeLocalTempTableIndex(index);
} else {
index.getSchema().remove(index);
}
} }
index.remove(systemSession); index.remove(systemSession);
if (reservedPages != null && reservedPages.containsKey(headPos)) { if (reservedPages != null && reservedPages.containsKey(headPos)) {
......
...@@ -904,6 +904,13 @@ public class Recover extends Tool implements DataHandler { ...@@ -904,6 +904,13 @@ public class Recover extends Tool implements DataHandler {
// nothing to do // nothing to do
} else if (x == PageLog.CHECKPOINT) { } else if (x == PageLog.CHECKPOINT) {
writer.println("-- checkpoint"); writer.println("-- checkpoint");
} else if (x == PageLog.FREE_LOG) {
int size = in.readInt();
StringBuilder buff = new StringBuilder("-- free");
for (int i = 0; i < size; i++) {
buff.append(' ').append(in.readInt());
}
writer.println(buff);
} else { } else {
writer.println("-- end " + x); writer.println("-- end " + x);
break; break;
......
...@@ -28,7 +28,6 @@ import java.util.ArrayList; ...@@ -28,7 +28,6 @@ import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
import org.h2.jdbc.JdbcConnection; import org.h2.jdbc.JdbcConnection;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论