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

Page store: when using a very small page size (128 bytes), writing a large row…

Page store: when using a very small page size (128 bytes), writing a large row could result in an endless recursion.
上级 6e0434cd
...@@ -8,10 +8,10 @@ package org.h2.store; ...@@ -8,10 +8,10 @@ package org.h2.store;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.HashMap; import java.util.HashMap;
import org.h2.compress.CompressLZF; import org.h2.compress.CompressLZF;
import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.log.InDoubtTransaction; import org.h2.log.InDoubtTransaction;
...@@ -119,9 +119,8 @@ public class PageLog { ...@@ -119,9 +119,8 @@ public class PageLog {
private int pos; private int pos;
private Trace trace; private Trace trace;
private Data outBuffer; private Data writeBuffer;
private PageInputStream pageIn; private PageInputStream pageIn;
private OutputStream pageBuffer;
private PageOutputStream pageOut; private PageOutputStream pageOut;
private DataReader in; private DataReader in;
private int firstTrunkPage; private int firstTrunkPage;
...@@ -184,19 +183,28 @@ public class PageLog { ...@@ -184,19 +183,28 @@ public class PageLog {
logKey++; logKey++;
pageOut = new PageOutputStream(store, firstTrunkPage, undoAll, logKey, atEnd); pageOut = new PageOutputStream(store, firstTrunkPage, undoAll, logKey, atEnd);
pageOut.reserve(1); pageOut.reserve(1);
// TODO maybe buffer to improve speed
pageBuffer = pageOut;
// pageBuffer = new BufferedOutputStream(pageOut, 8 * 1024); // pageBuffer = new BufferedOutputStream(pageOut, 8 * 1024);
store.setLogFirstPage(logKey, firstTrunkPage, pageOut.getCurrentDataPageId()); store.setLogFirstPage(logKey, firstTrunkPage, pageOut.getCurrentDataPageId());
outBuffer = store.createData(); writeBuffer = store.createData();
} }
/** /**
* Free up all pages allocated by the log. * Free up all pages allocated by the log.
*/ */
void free() throws SQLException { void free() throws SQLException {
while (firstTrunkPage != 0) { while (firstTrunkPage != 0 && firstTrunkPage < store.getPageCount()) {
PageStreamTrunk t = (PageStreamTrunk) store.getPage(firstTrunkPage); PageStreamTrunk t = null;
try {
Page p = store.getPage(firstTrunkPage);
if (p instanceof PageStreamTrunk) {
t = (PageStreamTrunk) p;
}
} catch (SQLException e) {
if (e.getErrorCode() != ErrorCode.FILE_CORRUPTED_1) {
// wrong checksum means end of stream
throw e;
}
}
if (t == null) { if (t == null) {
store.free(firstTrunkPage, false); store.free(firstTrunkPage, false);
// EOF // EOF
...@@ -437,26 +445,27 @@ public class PageLog { ...@@ -437,26 +445,27 @@ public class PageLog {
} }
undo.set(pageId); undo.set(pageId);
undoAll.set(pageId); undoAll.set(pageId);
outBuffer.writeByte((byte) UNDO); Data buffer = getBuffer();
outBuffer.writeVarInt(pageId); buffer.writeByte((byte) UNDO);
buffer.writeVarInt(pageId);
int pageSize = store.getPageSize(); int pageSize = store.getPageSize();
if (COMPRESS_UNDO) { if (COMPRESS_UNDO) {
int size = compress.compress(page.getBytes(), pageSize, compressBuffer, 0); int size = compress.compress(page.getBytes(), pageSize, compressBuffer, 0);
if (size < pageSize) { if (size < pageSize) {
outBuffer.writeVarInt(size); buffer.writeVarInt(size);
outBuffer.checkCapacity(size); buffer.checkCapacity(size);
outBuffer.write(compressBuffer, 0, size); buffer.write(compressBuffer, 0, size);
} else { } else {
outBuffer.writeVarInt(0); buffer.writeVarInt(0);
outBuffer.checkCapacity(pageSize); buffer.checkCapacity(pageSize);
outBuffer.write(page.getBytes(), 0, pageSize); buffer.write(page.getBytes(), 0, pageSize);
} }
} else { } else {
outBuffer.writeVarInt(0); buffer.writeVarInt(0);
outBuffer.checkCapacity(pageSize); buffer.checkCapacity(pageSize);
outBuffer.write(page.getBytes(), 0, pageSize); buffer.write(page.getBytes(), 0, pageSize);
} }
flushOut(); write(buffer);
} catch (IOException e) { } catch (IOException e) {
throw Message.convertIOException(e, null); throw Message.convertIOException(e, null);
} }
...@@ -467,20 +476,21 @@ public class PageLog { ...@@ -467,20 +476,21 @@ public class PageLog {
if (trace.isDebugEnabled()) { if (trace.isDebugEnabled()) {
trace.debug("log frees " + pages.get(0) + ".." + pages.get(pages.size() - 1)); trace.debug("log frees " + pages.get(0) + ".." + pages.get(pages.size() - 1));
} }
outBuffer.writeByte((byte) FREE_LOG); Data buffer = getBuffer();
outBuffer.writeVarInt(pages.size()); buffer.writeByte((byte) FREE_LOG);
buffer.writeVarInt(pages.size());
for (int i = 0; i < pages.size(); i++) { for (int i = 0; i < pages.size(); i++) {
outBuffer.writeVarInt(pages.get(i)); buffer.writeVarInt(pages.get(i));
} }
flushOut(); write(buffer);
} catch (IOException e) { } catch (IOException e) {
throw Message.convertIOException(e, null); throw Message.convertIOException(e, null);
} }
} }
private void flushOut() throws IOException { private void write(Data data) throws IOException {
pageBuffer.write(outBuffer.getBytes(), 0, outBuffer.length()); pageOut.write(data.getBytes(), 0, data.length());
outBuffer.reset(); data.reset();
} }
/** /**
...@@ -498,9 +508,10 @@ public class PageLog { ...@@ -498,9 +508,10 @@ public class PageLog {
// database already closed // database already closed
return; return;
} }
outBuffer.writeByte((byte) COMMIT); Data buffer = getBuffer();
outBuffer.writeVarInt(sessionId); buffer.writeByte((byte) COMMIT);
flushOut(); buffer.writeVarInt(sessionId);
write(buffer);
if (log.getFlushOnEachCommit()) { if (log.getFlushOnEachCommit()) {
flush(); flush();
} }
...@@ -527,17 +538,18 @@ public class PageLog { ...@@ -527,17 +538,18 @@ public class PageLog {
} }
// store it on a separate log page // store it on a separate log page
int pageSize = store.getPageSize(); int pageSize = store.getPageSize();
flushBuffer(); flushOut();
pageOut.fillPage(); pageOut.fillPage();
outBuffer.writeByte((byte) PREPARE_COMMIT); Data buffer = getBuffer();
outBuffer.writeVarInt(session.getId()); buffer.writeByte((byte) PREPARE_COMMIT);
outBuffer.writeString(transaction); buffer.writeVarInt(session.getId());
if (outBuffer.length() >= PageStreamData.getCapacity(pageSize)) { buffer.writeString(transaction);
if (buffer.length() >= PageStreamData.getCapacity(pageSize)) {
throw Message.getInvalidValueException(transaction, "transaction name (too long)"); throw Message.getInvalidValueException(transaction, "transaction name (too long)");
} }
flushOut(); write(buffer);
// store it on a separate log page // store it on a separate log page
flushBuffer(); flushOut();
pageOut.fillPage(); pageOut.fillPage();
if (log.getFlushOnEachCommit()) { if (log.getFlushOnEachCommit()) {
flush(); flush();
...@@ -571,16 +583,17 @@ public class PageLog { ...@@ -571,16 +583,17 @@ public class PageLog {
for (int i = 0; i < columns; i++) { for (int i = 0; i < columns; i++) {
data.writeValue(row.getValue(i)); data.writeValue(row.getValue(i));
} }
outBuffer.writeByte((byte) (add ? ADD : REMOVE)); Data buffer = getBuffer();
outBuffer.writeVarInt(session.getId()); buffer.writeByte((byte) (add ? ADD : REMOVE));
outBuffer.writeVarInt(tableId); buffer.writeVarInt(session.getId());
outBuffer.writeVarLong(row.getKey()); buffer.writeVarInt(tableId);
buffer.writeVarLong(row.getKey());
if (add) { if (add) {
outBuffer.writeVarInt(data.length()); buffer.writeVarInt(data.length());
outBuffer.checkCapacity(data.length()); buffer.checkCapacity(data.length());
outBuffer.write(data.getBytes(), 0, data.length()); buffer.write(data.getBytes(), 0, data.length());
} }
flushOut(); write(buffer);
} catch (IOException e) { } catch (IOException e) {
throw Message.convertIOException(e, null); throw Message.convertIOException(e, null);
} }
...@@ -599,12 +612,11 @@ public class PageLog { ...@@ -599,12 +612,11 @@ public class PageLog {
} }
session.addLogPos(logSectionId, logPos); session.addLogPos(logSectionId, logPos);
logPos++; logPos++;
Data buffer = getBuffer();
data.reset(); buffer.writeByte((byte) TRUNCATE);
outBuffer.writeByte((byte) TRUNCATE); buffer.writeVarInt(session.getId());
outBuffer.writeVarInt(session.getId()); buffer.writeVarInt(tableId);
outBuffer.writeVarInt(tableId); write(buffer);
flushOut();
} catch (IOException e) { } catch (IOException e) {
throw Message.convertIOException(e, null); throw Message.convertIOException(e, null);
} }
...@@ -615,13 +627,8 @@ public class PageLog { ...@@ -615,13 +627,8 @@ public class PageLog {
* Flush the transaction log. * Flush the transaction log.
*/ */
void flush() throws SQLException { void flush() throws SQLException {
try { if (pageOut != null) {
if (pageOut != null) { flushOut();
flushBuffer();
pageOut.flush();
}
} catch (IOException e) {
throw Message.convertIOException(e, null);
} }
} }
...@@ -630,15 +637,16 @@ public class PageLog { ...@@ -630,15 +637,16 @@ public class PageLog {
*/ */
void checkpoint() throws SQLException { void checkpoint() throws SQLException {
try { try {
outBuffer.writeByte((byte) CHECKPOINT); Data buffer = getBuffer();
flushOut(); buffer.writeByte((byte) CHECKPOINT);
write(buffer);
} catch (IOException e) { } catch (IOException e) {
throw Message.convertIOException(e, null); throw Message.convertIOException(e, null);
} }
undo = new BitField(); undo = new BitField();
logSectionId++; logSectionId++;
logPos = 0; logPos = 0;
flushBuffer(); flushOut();
pageOut.fillPage(); pageOut.fillPage();
int currentDataPage = pageOut.getCurrentDataPageId(); int currentDataPage = pageOut.getCurrentDataPageId();
logSectionPageMap.put(logSectionId, currentDataPage); logSectionPageMap.put(logSectionId, currentDataPage);
...@@ -683,7 +691,8 @@ public class PageLog { ...@@ -683,7 +691,8 @@ public class PageLog {
private int removeUntil(int firstTrunkPage, int firstDataPageToKeep) throws SQLException { private int removeUntil(int firstTrunkPage, int firstDataPageToKeep) throws SQLException {
trace.debug("log.removeUntil " + firstDataPageToKeep); trace.debug("log.removeUntil " + firstDataPageToKeep);
while (true) { while (true) {
PageStreamTrunk t = (PageStreamTrunk) store.getPage(firstTrunkPage); Page p = store.getPage(firstTrunkPage);
PageStreamTrunk t = (PageStreamTrunk) p;
logKey = t.getLogKey(); logKey = t.getLogKey();
t.resetIndex(); t.resetIndex();
if (t.contains(firstDataPageToKeep)) { if (t.contains(firstDataPageToKeep)) {
...@@ -713,7 +722,7 @@ public class PageLog { ...@@ -713,7 +722,7 @@ public class PageLog {
pageOut.close(); pageOut.close();
pageOut = null; pageOut = null;
} }
outBuffer = null; writeBuffer = null;
} }
/** /**
...@@ -806,12 +815,20 @@ public class PageLog { ...@@ -806,12 +815,20 @@ public class PageLog {
sessionStates = New.hashMap(); sessionStates = New.hashMap();
} }
private void flushBuffer() throws SQLException { private void flushOut() throws SQLException {
try { try {
pageBuffer.flush(); pageOut.flush();
} catch (IOException e) { } catch (IOException e) {
throw Message.convertIOException(e, null); throw Message.convertIOException(e, null);
} }
} }
private Data getBuffer() {
if (writeBuffer.length() == 0) {
return writeBuffer;
}
//new Error("recurse").printStackTrace();
return store.createData();
}
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论