PageStore的实例在org.h2.engine.Database.getPageStore()中生成
然后按下面的流程调用:
org.h2.store.PageStore.open()
=> org.h2.store.PageStore.openNew() //数据库文件不存在
或 => org.h2.store.PageStore.openExisting() //数据库文件已存在
=> org.h2.engine.Database.openFile(String, String, boolean)
=> org.h2.store.FileStore.open(DataHandler, String, String, String, byte[])
=> org.h2.store.FileStore.FileStore(DataHandler, String, String)
=> org.h2.store.FileStore.init()
PAGE_INDEX表
CREATE CACHED TABLE "".PAGE_INDEX(
ID INTEGER,
TYPE INTEGER,
PARENT INTEGER,
HEAD INTEGER,
OPTIONS VARCHAR,
COLUMNS VARCHAR
)
private void openMetaIndex() {
CreateTableData data = new CreateTableData();
ArrayList<Column> cols = data.columns;
cols.add(new Column("ID", Value.INT)); //index id
cols.add(new Column("TYPE", Value.INT)); //对应META_TYPE_DATA_INDEX和META_TYPE_BTREE_INDEX
cols.add(new Column("PARENT", Value.INT)); //table id
cols.add(new Column("HEAD", Value.INT)); //RootPageId
cols.add(new Column("OPTIONS", Value.STRING)); //CompareMode name,Strength,临时表,d(表示是PageDelegateIndex)
cols.add(new Column("COLUMNS", Value.STRING)); //列id/sortType
metaSchema = new Schema(database, 0, "", null, true);
data.schema = metaSchema;
data.tableName = "PAGE_INDEX";
data.id = META_TABLE_ID; //id是-1
data.temporary = false;
data.persistData = true;
data.persistIndexes = true;
data.create = false;
data.session = systemSession;
metaTable = new RegularTable(data);
metaIndex = (PageDataIndex) metaTable.getScanIndex(
systemSession);
metaObjects.clear();
metaObjects.put(-1, metaIndex);
}
//内存数据库不会生成PageStore实例
//每个Page的size默认是2k
//一个PageStore的 实例就代表一个".h2.db"文件
最先开始调用org.h2.store.PageStore.allocatePage()的是在client端发起的非内存数据库访问时
在org.h2.engine.Database.open的meta = mainSchema.createTable(data)那里
-------------------------------------------------------------
java.lang.Error
at org.h2.index.PageDataIndex.<init>(PageDataIndex.java:78)
at org.h2.table.RegularTable.<init>(RegularTable.java:86)
at org.h2.schema.Schema.createTable(Schema.java:556)
at org.h2.engine.Database.open(Database.java:622)
at org.h2.engine.Database.openDatabase(Database.java:221)
at org.h2.engine.Database.<init>(Database.java:216)
at org.h2.engine.Engine.openSession(Engine.java:59)
at org.h2.engine.Engine.openSession(Engine.java:167)
at org.h2.engine.Engine.createSessionAndValidate(Engine.java:145)
at org.h2.engine.Engine.createSession(Engine.java:127)
at org.h2.server.TcpServerThread.run(TcpServerThread.java:136)
at java.lang.Thread.run(Thread.java:662)
最早调用org.h2.store.PageStore.getFreeList(int)是在这:
-------------------------------------------------------------
java.lang.Error
at org.h2.store.PageStore.getFreeList(PageStore.java:1084)
at org.h2.store.PageStore.getFreeListForPage(PageStore.java:1079)
at org.h2.store.PageStore.allocatePage(PageStore.java:1124)
at org.h2.store.PageStore.update(PageStore.java:1064)
at org.h2.index.PageDataIndex.getPage(PageDataIndex.java:233)
at org.h2.index.PageDataIndex.<init>(PageDataIndex.java:84)
at org.h2.table.RegularTable.<init>(RegularTable.java:86)
at org.h2.store.PageStore.openMetaIndex(PageStore.java:1585)
at org.h2.store.PageStore.openNew(PageStore.java:308)
at org.h2.store.PageStore.open(PageStore.java:290)
at org.h2.engine.Database.getPageStore(Database.java:2129)
at org.h2.engine.Database.open(Database.java:582)
at org.h2.engine.Database.openDatabase(Database.java:221)
at org.h2.engine.Database.<init>(Database.java:216)
at org.h2.engine.Engine.openSession(Engine.java:59)
at org.h2.engine.Engine.openSession(Engine.java:167)
at org.h2.engine.Engine.createSessionAndValidate(Engine.java:145)
at org.h2.engine.Engine.createSession(Engine.java:127)
at org.h2.server.TcpServerThread.run(TcpServerThread.java:136)
at java.lang.Thread.run(Thread.java:662)
org.h2.store.PageStore.addMeta(PageIndex, Session)
( /* key:17 */ 16, 1, 15, 70, 'OFF,0,,', '1')
从org.h2.engine.Database.getPageStore()开始触发PageStore的初始化
//fileName = E:/H2/test.h2.db
//accessMode = rw
//cacheSizeDefault = 16384 (默认16K),可通过CACHE_SIZE参数设置
public PageStore(Database database, String fileName, String accessMode, int cacheSizeDefault) {
this.fileName = fileName;
this.accessMode = accessMode;
this.database = database;
trace = database.getTrace(Trace.PAGE_STORE);
// if (fileName.endsWith("X.h2.db"))
// trace.setLevel(TraceSystem.DEBUG);
String cacheType = database.getCacheType(); //默认LRU
this.cache = CacheLRU.getCache(this, cacheType, cacheSizeDefault);
systemSession = new Session(database, null, 0);
}
//org.h2.store.PageFreeList.getPagesAddressed(int)
public static int getPagesAddressed(int pageSize) { //2048 (2K)
return (pageSize - DATA_START) * 8; //cacheSizeDefault是16K,所以大概能存8个page
}
org.h2.store.PageStore.open()
=> org.h2.store.PageStore.openExisting()
=> org.h2.engine.Database.openFile(String, String, boolean)
=> org.h2.store.FileStore.open(DataHandler, String, String, String, byte[])
=> org.h2.store.FileStore.FileStore(DataHandler, String, String)
=> org.h2.store.FileStore.init()
public void init() {
int len = Constants.FILE_BLOCK_SIZE;
byte[] salt;
byte[] magic = HEADER.getBytes(); //HEADER_LENGTH = 48
if (length() < HEADER_LENGTH) { //第一次建立*.h2.db文件时length为0
// write unencrypted
checkedWriting = false;
//写入三个"-- H2 0.5/B -- \n",每个16字节
writeDirect(magic, 0, len);
salt = generateSalt();
writeDirect(salt, 0, len);
initKey(salt);
// write (maybe) encrypted
write(magic, 0, len);
checkedWriting = true;
} else {
// read unencrypted
seek(0);
byte[] buff = new byte[len];
readFullyDirect(buff, 0, len);
if (Utils.compareNotNull(buff, magic) != 0) {
throw DbException.get(ErrorCode.FILE_VERSION_ERROR_1, name);
}
salt = new byte[len];
readFullyDirect(salt, 0, len);
initKey(salt);
// read (maybe) encrypted
readFully(buff, 0, Constants.FILE_BLOCK_SIZE);
if (textMode) {
buff[10] = 'B';
}
if (Utils.compareNotNull(buff, magic) != 0) {
throw DbException.get(ErrorCode.FILE_ENCRYPTION_ERROR_1, name);
}
}
}
//increment 6
private void increaseFileSize(int increment) {
//pageCount 0
for (int i = pageCount; i < pageCount + increment; i++) {
freed.set(i);
//freed(0,..., 5)
}
pageCount += increment;
long newLength = (long) pageCount << pageSizeShift;
file.setLength(newLength);
writeCount++;
fileLength = newLength;
}
public void setLength(long newLength) {
if (SysProperties.CHECK && newLength % Constants.FILE_BLOCK_SIZE != 0) {
DbException.throwInternalError("unaligned setLength " + name + " pos " + newLength);
}
checkPowerOff();
checkWritingAllowed();
try {
if (newLength > fileLength) {
long pos = filePos;
file.position(newLength - 1);
FileUtils.writeFully(file, ByteBuffer.wrap(new byte[1])); //在最后那个位置写0
file.position(pos);
} else {
file.truncate(newLength);
}
fileLength = newLength;
} catch (IOException e) {
closeFileSilently();
throw DbException.convertIOException(e, name);
}
}
org.h2.store.PageStore.openMetaIndex()
TODO 还有问题
**************非常重要****************************
数据什么时候同步到硬盘
**************************************************
org.h2.engine.Session.commit(boolean)或org.h2.engine.Session.rollback()
=>org.h2.engine.Database.commit(Session)
=>org.h2.store.PageStore.commit(Session)
=>org.h2.store.PageStore.checkpoint()
=>org.h2.store.PageLog.removeUntil(int)
=>org.h2.store.PageStore.setLogFirstPage(int, int, int)
=>org.h2.store.PageStore.writeVariableHeader()
=>org.h2.store.FileStore.sync()
=>java.nio.channels.FileChannel.force(true)
**************************************************
private void openForWriting() {
//readMode只有org.h2.store.PageStore.openExisting()调用了一次
//所以通过openForWriting()这里触发log.openForWriting,再触发setLogFirstPage
//进而触发writeVariableHeader同步数据到硬盘中会发生一次,
//writeVariableHeader的触发更多的是通过commit完成
if (!readMode || database.isReadOnly()) {
return;
}
readMode = false;
recoveryRunning = true;
log.free();
logFirstTrunkPage = allocatePage();
log.openForWriting(logFirstTrunkPage, false);
recoveryRunning = false;
freed.set(0, pageCount, true);
checkpoint();
}
或者还有这个:
java.lang.Error
at org.h2.store.PageStore.writeVariableHeader(PageStore.java:995)
at org.h2.store.PageStore.setLogFirstPage(PageStore.java:975)
at org.h2.store.PageLog.removeUntil(PageLog.java:708)
at org.h2.store.PageStore.checkpoint(PageStore.java:447)
at org.h2.engine.Database.closeOpenFilesAndUnlock(Database.java:1207)
at org.h2.engine.Database.close(Database.java:1160)
at org.h2.engine.Database.removeSession(Database.java:1039)
at org.h2.engine.Session.close(Session.java:562)
at org.h2.server.TcpServerThread.closeSession(TcpServerThread.java:175)
at org.h2.server.TcpServerThread.process(TcpServerThread.java:270)
at org.h2.server.TcpServerThread.run(TcpServerThread.java:149)
at java.lang.Thread.run(Thread.java:662)
和这个:
java.lang.Error
at org.h2.store.PageStore.writeVariableHeader(PageStore.java:995)
at org.h2.store.PageStore.setLogFirstPage(PageStore.java:975)
at org.h2.store.PageLog.openForWriting(PageLog.java:190)
at org.h2.store.PageStore.compact(PageStore.java:509)
at org.h2.engine.Database.closeOpenFilesAndUnlock(Database.java:1210)
at org.h2.engine.Database.close(Database.java:1160)
at org.h2.engine.Database.removeSession(Database.java:1039)
at org.h2.engine.Session.close(Session.java:562)
at org.h2.server.TcpServerThread.closeSession(TcpServerThread.java:175)
at org.h2.server.TcpServerThread.process(TcpServerThread.java:270)
at org.h2.server.TcpServerThread.run(TcpServerThread.java:149)
at java.lang.Thread.run(Thread.java:662)