提交 5799af16 authored 作者: Thomas Mueller's avatar Thomas Mueller

New experimental page store.

上级 edce6934
...@@ -54,12 +54,16 @@ public class PageScanIndex extends BaseIndex implements RowIndex { ...@@ -54,12 +54,16 @@ public class PageScanIndex extends BaseIndex implements RowIndex {
int todo; int todo;
return; return;
} }
this.store = database.getPageStorage(); this.store = database.getPageStore();
if (headPos == Index.EMPTY_HEAD || store.isNew()) { if (headPos == Index.EMPTY_HEAD) {
// new table, or the system table for a new database // new table
headPos = store.allocatePage(); headPos = store.allocatePage();
PageDataLeaf root = new PageDataLeaf(this, headPos, Page.ROOT, store.createDataPage()); PageDataLeaf root = new PageDataLeaf(this, headPos, Page.ROOT, store.createDataPage());
store.updateRecord(root, root.data); store.updateRecord(root, root.data);
} else if (store.isNew()) {
// the system table for a new database
PageDataLeaf root = new PageDataLeaf(this, headPos, Page.ROOT, store.createDataPage());
store.updateRecord(root, root.data);
} else { } else {
lastKey = getPage(headPos).getLastKey(); lastKey = getPage(headPos).getLastKey();
rowCount = getPage(headPos).getRowCount(); rowCount = getPage(headPos).getRowCount();
...@@ -100,6 +104,8 @@ public class PageScanIndex extends BaseIndex implements RowIndex { ...@@ -100,6 +104,8 @@ public class PageScanIndex extends BaseIndex implements RowIndex {
root = newRoot; root = newRoot;
} }
rowCount++; rowCount++;
int todo;
// store.getLog().addRow(headPos, row);
} }
/** /**
...@@ -125,6 +131,9 @@ public class PageScanIndex extends BaseIndex implements RowIndex { ...@@ -125,6 +131,9 @@ public class PageScanIndex extends BaseIndex implements RowIndex {
case Page.TYPE_DATA_NODE: case Page.TYPE_DATA_NODE:
result = new PageDataNode(this, id, parentPageId, data); result = new PageDataNode(this, id, parentPageId, data);
break; break;
case Page.TYPE_EMPTY:
PageDataLeaf empty = new PageDataLeaf(this, id, parentPageId, data);
return empty;
default: default:
throw Message.getSQLException(ErrorCode.FILE_CORRUPTED_1, "page=" + id + " type=" + type); throw Message.getSQLException(ErrorCode.FILE_CORRUPTED_1, "page=" + id + " type=" + type);
} }
...@@ -229,8 +238,8 @@ public class PageScanIndex extends BaseIndex implements RowIndex { ...@@ -229,8 +238,8 @@ public class PageScanIndex extends BaseIndex implements RowIndex {
} }
private void trace(String message) { private void trace(String message) {
int todoSometimeSlow;
if (headPos != 1) { if (headPos != 1) {
int test;
// System.out.println(message); // System.out.println(message);
} }
} }
......
...@@ -18,6 +18,8 @@ import org.h2.message.Message; ...@@ -18,6 +18,8 @@ import org.h2.message.Message;
import org.h2.message.Trace; import org.h2.message.Trace;
import org.h2.store.DataPage; import org.h2.store.DataPage;
import org.h2.store.DiskFile; import org.h2.store.DiskFile;
import org.h2.store.PageLog;
import org.h2.store.PageStore;
import org.h2.store.Record; import org.h2.store.Record;
import org.h2.store.Storage; import org.h2.store.Storage;
import org.h2.util.FileUtils; import org.h2.util.FileUtils;
...@@ -61,6 +63,7 @@ public class LogSystem { ...@@ -61,6 +63,7 @@ public class LogSystem {
private int keepFiles; private int keepFiles;
private boolean closed; private boolean closed;
private String accessMode; private String accessMode;
private PageLog pageLog;
/** /**
* Create new transaction log object. This will not open or create files * Create new transaction log object. This will not open or create files
...@@ -70,9 +73,13 @@ public class LogSystem { ...@@ -70,9 +73,13 @@ public class LogSystem {
* @param fileNamePrefix the name of the database file * @param fileNamePrefix the name of the database file
* @param readOnly if the log should be opened in read-only mode * @param readOnly if the log should be opened in read-only mode
* @param accessMode the file access mode (r, rw, rws, rwd) * @param accessMode the file access mode (r, rw, rws, rwd)
* @param pageStore
*/ */
public LogSystem(Database database, String fileNamePrefix, boolean readOnly, String accessMode) { public LogSystem(Database database, String fileNamePrefix, boolean readOnly, String accessMode, PageStore pageStore) {
this.database = database; this.database = database;
if (pageStore != null) {
this.pageLog = pageStore.getLog();
}
this.readOnly = readOnly; this.readOnly = readOnly;
this.accessMode = accessMode; this.accessMode = accessMode;
closed = true; closed = true;
...@@ -465,6 +472,9 @@ public class LogSystem { ...@@ -465,6 +472,9 @@ public class LogSystem {
if (closed) { if (closed) {
return; return;
} }
if (pageLog != null) {
pageLog.commit(session);
}
currentLog.commit(session); currentLog.commit(session);
session.setAllCommitted(); session.setAllCommitted();
} }
......
...@@ -18,7 +18,7 @@ import org.h2.message.Message; ...@@ -18,7 +18,7 @@ import org.h2.message.Message;
* The format is: * The format is:
* <ul><li>0-3: parent page id * <ul><li>0-3: parent page id
* </li><li>4-4: page type * </li><li>4-4: page type
* </li><li>5-8: the next page (if there are more) or length * </li><li>5-8: the next page (if there is one) or length
* </li><li>9-remainder: data * </li><li>9-remainder: data
* </li></ul> * </li></ul>
*/ */
......
...@@ -10,6 +10,7 @@ import java.io.DataInputStream; ...@@ -10,6 +10,7 @@ import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.engine.Session;
import org.h2.index.Page; import org.h2.index.Page;
import org.h2.message.Message; import org.h2.message.Message;
import org.h2.util.BitField; import org.h2.util.BitField;
...@@ -17,7 +18,7 @@ import org.h2.util.BitField; ...@@ -17,7 +18,7 @@ import org.h2.util.BitField;
/** /**
* Transaction log mechanism. * Transaction log mechanism.
* The data format is: * The data format is:
* <ul><li>0-0: type (0: undo) * <ul><li>0-0: type (0: undo,...)
* </li><li>1-4: page id * </li><li>1-4: page id
* </li><li>5-: data * </li><li>5-: data
* </li></ul> * </li></ul>
...@@ -25,6 +26,7 @@ import org.h2.util.BitField; ...@@ -25,6 +26,7 @@ import org.h2.util.BitField;
public class PageLog { public class PageLog {
private static final int UNDO = 0; private static final int UNDO = 0;
private static final int COMMIT = 1;
private PageStore store; private PageStore store;
private BitField undo = new BitField(); private BitField undo = new BitField();
private DataOutputStream out; private DataOutputStream out;
...@@ -57,13 +59,17 @@ public class PageLog { ...@@ -57,13 +59,17 @@ public class PageLog {
} }
if (x == UNDO) { if (x == UNDO) {
int pageId = in.readInt(); int pageId = in.readInt();
int test;
System.out.println("redo " + pageId);
in.read(data.getBytes(), 0, store.getPageSize()); in.read(data.getBytes(), 0, store.getPageSize());
store.writePage(pageId, data); store.writePage(pageId, data);
} }
} }
} catch (IOException e) { } catch (IOException e) {
throw Message.convertIOException(e, "recovering"); int todoSomeExceptionAreOkSomeNot;
// throw Message.convertIOException(e, "recovering");
} }
int todoDeleteAfterRecovering;
} }
/** /**
...@@ -78,6 +84,8 @@ public class PageLog { ...@@ -78,6 +84,8 @@ public class PageLog {
if (undo.get(pageId)) { if (undo.get(pageId)) {
return; return;
} }
int test;
System.out.println("undo " + 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());
...@@ -87,4 +95,18 @@ public class PageLog { ...@@ -87,4 +95,18 @@ public class PageLog {
} }
} }
/**
* Mark a committed transaction.
*
* @param session the session
*/
public void commit(Session session) throws SQLException {
try {
out.write(COMMIT);
out.writeInt(session.getId());
} catch (IOException e) {
throw Message.convertIOException(e, "recovering");
}
}
} }
...@@ -98,6 +98,10 @@ public class PageOutputStream extends OutputStream { ...@@ -98,6 +98,10 @@ public class PageOutputStream extends OutputStream {
store = null; store = null;
} }
public void flush() throws IOException {
int todo;
}
// public void write(byte[] buff, int off, int len) throws IOException { // public void write(byte[] buff, int off, int len) throws IOException {
// if (len > 0) { // if (len > 0) {
// try { // try {
......
...@@ -21,46 +21,46 @@ import org.h2.util.FileUtils; ...@@ -21,46 +21,46 @@ import org.h2.util.FileUtils;
import org.h2.util.ObjectArray; import org.h2.util.ObjectArray;
/** /**
* This class represents a file that is split into pages. The first page (page * This class represents a file that is organized as a number of pages. The
* 0) contains the file header, the second page (page 1) is the root of the * first page (page 0) contains the file header, which is never modified once
* system table. The file header is 128 bytes, the format is: * the database is created. The format is:
* <ul><li>0-47: file header (3 time "-- H2 0.5/B -- \n") * <ul>
* </li><li>48-51: database page size in bytes * <li>0-47: file header (3 time "-- H2 0.5/B -- \n")</li>
* (512 - 32768, must be a power of 2) * <li>48-51: database page size in bytes
* </li><li>52: write version (0, otherwise the file is opened in read-only mode) * (512 - 32768, must be a power of 2)</li>
* </li><li>53: read version (0, otherwise opening the file fails) * <li>52: write version (0, otherwise the file is opened in read-only mode)</li>
* </li><li>54-57: page number of the system table root * <li>53: read version (0, otherwise opening the file fails)</li>
* </li><li>58-61: page number of the first free list page * <li>54-57: system table root page number (usually 1)</li>
* </li><li>62-65: number of free pages * <li>58-61: free list head page number (usually 2)</li>
* </li><li>66-69: log head page number * <li>62-65: log head page number (usually 3)</li>
* </li><li>70-73: last used page number * </ul>
* </li></ul>
*/ */
public class PageStore implements CacheWriter { public class PageStore implements CacheWriter {
private static final int PAGE_SIZE_MIN = 512; private static final int PAGE_SIZE_MIN = 512;
private static final int PAGE_SIZE_MAX = 32768; private static final int PAGE_SIZE_MAX = 32768;
private static final int PAGE_SIZE_DEFAULT = 1024; private static final int PAGE_SIZE_DEFAULT = 1024;
private static final int FILE_HEADER_SIZE = 128;
private static final int INCREMENT_PAGES = 128; private static final int INCREMENT_PAGES = 128;
private static final int READ_VERSION = 0; private static final int READ_VERSION = 0;
private static final int WRITE_VERSION = 0; private static final int WRITE_VERSION = 0;
private Database database; private Database database;
private int pageSize;
private int pageSizeShift;
private String fileName; private String fileName;
private FileStore file; private FileStore file;
private String accessMode; private String accessMode;
private int cacheSize; private int cacheSize;
private Cache cache; private Cache cache;
private DataPage fileHeader;
private int pageSize;
private int pageSizeShift;
private int systemRootPageId; private int systemRootPageId;
private int freeListRootPageId; private int freeListRootPageId;
private int freePageCount;
private int logRootPageId; private int logRootPageId;
private PageLog log;
private int lastUsedPage; /**
* The file size in bytes.
*/
private long fileLength;
/** /**
* Number of pages (including free pages). * Number of pages (including free pages).
...@@ -68,12 +68,26 @@ public class PageStore implements CacheWriter { ...@@ -68,12 +68,26 @@ public class PageStore implements CacheWriter {
private int pageCount; private int pageCount;
/** /**
* True if this * The last page that is in use.
*/ */
private boolean isNew; private int lastUsedPage;
private int writeCount; /**
private long fileLength; * Number of free pages in the free list.
* This does not include empty pages at the end of the file
* (after the last used page).
*/
private int freePageCount;
/**
* The transaction log.
*/
private PageLog log;
/**
* True if this is a new file.
*/
private boolean isNew;
/** /**
* Create a new page store object. * Create a new page store object.
...@@ -101,25 +115,27 @@ public class PageStore implements CacheWriter { ...@@ -101,25 +115,27 @@ public class PageStore implements CacheWriter {
*/ */
public void open() throws SQLException { public void open() throws SQLException {
try { try {
fileHeader = DataPage.create(database, new byte[FILE_HEADER_SIZE - FileStore.HEADER_LENGTH]);
if (FileUtils.exists(fileName)) { if (FileUtils.exists(fileName)) {
file = database.openFile(fileName, accessMode, true); file = database.openFile(fileName, accessMode, true);
readHeader(); readHeader();
fileLength = file.length();
pageCount = (int) (fileLength / pageSize);
log = new PageLog(this, logRootPageId);
log.recover();
} else { } else {
isNew = true; isNew = true;
setPageSize(PAGE_SIZE_DEFAULT); setPageSize(PAGE_SIZE_DEFAULT);
file = database.openFile(fileName, accessMode, false); file = database.openFile(fileName, accessMode, false);
// page 0 is the file header systemRootPageId = 1;
// page 1 is the root of the system table freeListRootPageId = 2;
pageCount = 2; PageFreeList free = new PageFreeList(this, freeListRootPageId, 0);
logRootPageId = allocatePage(); updateRecord(free, null);
logRootPageId = 3;
lastUsedPage = 3;
pageCount = 3;
increaseFileSize(INCREMENT_PAGES - pageCount);
writeHeader(); writeHeader();
}
log = new PageLog(this, logRootPageId); log = new PageLog(this, logRootPageId);
fileLength = file.length();
pageCount = (int) (fileLength / pageSize);
if (!isNew) {
log.recover();
} }
log.openForWriting(); log.openForWriting();
} catch (SQLException e) { } catch (SQLException e) {
...@@ -147,15 +163,16 @@ public class PageStore implements CacheWriter { ...@@ -147,15 +163,16 @@ public class PageStore implements CacheWriter {
private void readHeader() throws SQLException { private void readHeader() throws SQLException {
long length = file.length(); long length = file.length();
if (length < FILE_HEADER_SIZE) { if (length < PAGE_SIZE_MIN) {
throw Message.getSQLException(ErrorCode.FILE_CORRUPTED_1, fileName); throw Message.getSQLException(ErrorCode.FILE_CORRUPTED_1, fileName);
} }
database.notifyFileSize(length); database.notifyFileSize(length);
file.seek(FileStore.HEADER_LENGTH); file.seek(FileStore.HEADER_LENGTH);
file.readFully(fileHeader.getBytes(), 0, FILE_HEADER_SIZE - FileStore.HEADER_LENGTH); DataPage page = DataPage.create(database, new byte[PAGE_SIZE_MIN - FileStore.HEADER_LENGTH]);
setPageSize(fileHeader.readInt()); file.readFully(page.getBytes(), 0, PAGE_SIZE_MIN - FileStore.HEADER_LENGTH);
int writeVersion = fileHeader.readByte(); setPageSize(page.readInt());
int readVersion = fileHeader.readByte(); int writeVersion = page.readByte();
int readVersion = page.readByte();
if (readVersion != 0) { if (readVersion != 0) {
throw Message.getSQLException(ErrorCode.FILE_VERSION_ERROR_1, fileName); throw Message.getSQLException(ErrorCode.FILE_VERSION_ERROR_1, fileName);
} }
...@@ -168,12 +185,9 @@ public class PageStore implements CacheWriter { ...@@ -168,12 +185,9 @@ public class PageStore implements CacheWriter {
accessMode = "r"; accessMode = "r";
file = database.openFile(fileName, accessMode, true); file = database.openFile(fileName, accessMode, true);
} }
fileHeader.reset(); systemRootPageId = page.readInt();
systemRootPageId = fileHeader.readInt(); freeListRootPageId = page.readInt();
freeListRootPageId = fileHeader.readInt(); logRootPageId = page.readInt();
freePageCount = fileHeader.readInt();
logRootPageId = fileHeader.readInt();
lastUsedPage = fileHeader.readInt();
} }
/** /**
...@@ -213,19 +227,16 @@ public class PageStore implements CacheWriter { ...@@ -213,19 +227,16 @@ public class PageStore implements CacheWriter {
} }
private void writeHeader() throws SQLException { private void writeHeader() throws SQLException {
fileHeader.reset(); int todoChecksumForHeader;
fileHeader.writeInt(pageSize); DataPage page = DataPage.create(database, new byte[pageSize - FileStore.HEADER_LENGTH]);
fileHeader.writeByte((byte) WRITE_VERSION); page.writeInt(pageSize);
fileHeader.writeByte((byte) READ_VERSION); page.writeByte((byte) WRITE_VERSION);
fileHeader.writeInt(systemRootPageId); page.writeByte((byte) READ_VERSION);
fileHeader.writeInt(freeListRootPageId); page.writeInt(systemRootPageId);
fileHeader.writeInt(freePageCount); page.writeInt(freeListRootPageId);
fileHeader.writeInt(logRootPageId); page.writeInt(logRootPageId);
fileHeader.writeInt(lastUsedPage);
file.seek(FileStore.HEADER_LENGTH); file.seek(FileStore.HEADER_LENGTH);
file.write(fileHeader.getBytes(), 0, FILE_HEADER_SIZE - FileStore.HEADER_LENGTH); file.write(page.getBytes(), 0, pageSize - FileStore.HEADER_LENGTH);
byte[] filler = new byte[pageSize - FILE_HEADER_SIZE];
file.write(filler, 0, filler.length);
} }
/** /**
...@@ -253,7 +264,6 @@ public class PageStore implements CacheWriter { ...@@ -253,7 +264,6 @@ public class PageStore implements CacheWriter {
public void writeBack(CacheObject obj) throws SQLException { public void writeBack(CacheObject obj) throws SQLException {
synchronized (database) { synchronized (database) {
writeCount++;
Record record = (Record) obj; Record record = (Record) obj;
record.write(null); record.write(null);
record.setChanged(false); record.setChanged(false);
...@@ -285,19 +295,12 @@ public class PageStore implements CacheWriter { ...@@ -285,19 +295,12 @@ public class PageStore implements CacheWriter {
*/ */
public int allocatePage() throws SQLException { public int allocatePage() throws SQLException {
if (freePageCount == 0) { if (freePageCount == 0) {
if (freeListRootPageId != 0) {
Message.throwInternalError("freeListRootPageId:" + freeListRootPageId);
}
if (pageCount * pageSize >= fileLength) { if (pageCount * pageSize >= fileLength) {
long newLength = (pageCount + INCREMENT_PAGES) * pageSize; increaseFileSize(INCREMENT_PAGES);
file.setLength(newLength);
fileLength = newLength;
freePageCount = INCREMENT_PAGES;
} }
return pageCount++;
} }
if (lastUsedPage < pageCount) { if (lastUsedPage < pageCount) {
return lastUsedPage++; return ++lastUsedPage;
} }
if (freeListRootPageId == 0) { if (freeListRootPageId == 0) {
Message.throwInternalError(); Message.throwInternalError();
...@@ -312,6 +315,13 @@ public class PageStore implements CacheWriter { ...@@ -312,6 +315,13 @@ public class PageStore implements CacheWriter {
return id; return id;
} }
private void increaseFileSize(int increment) throws SQLException {
pageCount += increment;
long newLength = pageCount * pageSize;
file.setLength(newLength);
fileLength = newLength;
}
/** /**
* Add a page to the free list. * Add a page to the free list.
* *
...@@ -321,9 +331,6 @@ public class PageStore implements CacheWriter { ...@@ -321,9 +331,6 @@ public class PageStore implements CacheWriter {
freePageCount++; freePageCount++;
PageFreeList free; PageFreeList free;
cache.remove(pageId); cache.remove(pageId);
if (freeListRootPageId == 0) {
setFreeListRootPage(pageId, false, 0);
} else {
free = (PageFreeList) cache.find(freeListRootPageId); free = (PageFreeList) cache.find(freeListRootPageId);
if (free == null) { if (free == null) {
free = new PageFreeList(this, freeListRootPageId, 0); free = new PageFreeList(this, freeListRootPageId, 0);
...@@ -331,7 +338,6 @@ public class PageStore implements CacheWriter { ...@@ -331,7 +338,6 @@ public class PageStore implements CacheWriter {
} }
free.free(pageId); free.free(pageId);
} }
}
/** /**
* Create a data page. * Create a data page.
...@@ -429,4 +435,17 @@ public class PageStore implements CacheWriter { ...@@ -429,4 +435,17 @@ public class PageStore implements CacheWriter {
} }
} }
/**
* Get the system table root page number.
*
* @return the page number
*/
public int getSystemRootPageId() {
return systemRootPageId;
}
public PageLog getLog() {
return log;
}
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论