use of org.h2.mvstore.Page in project h2database by h2database.
the class WebApp method query.
private String query() {
String sql = attributes.getProperty("sql").trim();
try {
ScriptReader r = new ScriptReader(new StringReader(sql));
final ArrayList<String> list = New.arrayList();
while (true) {
String s = r.readStatement();
if (s == null) {
break;
}
list.add(s);
}
final Connection conn = session.getConnection();
if (SysProperties.CONSOLE_STREAM && server.getAllowChunked()) {
String page = new String(server.getFile("result.jsp"), StandardCharsets.UTF_8);
int idx = page.indexOf("${result}");
// the first element of the list is the header, the last the
// footer
list.add(0, page.substring(0, idx));
list.add(page.substring(idx + "${result}".length()));
session.put("chunks", new Iterator<String>() {
private int i;
@Override
public boolean hasNext() {
return i < list.size();
}
@Override
public String next() {
String s = list.get(i++);
if (i == 1 || i == list.size()) {
return s;
}
StringBuilder b = new StringBuilder();
query(conn, s, i - 1, list.size() - 2, b);
return b.toString();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
});
return "result.jsp";
}
String result;
StringBuilder buff = new StringBuilder();
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
query(conn, s, i, list.size(), buff);
}
result = buff.toString();
session.put("result", result);
} catch (Throwable e) {
session.put("result", getStackTrace(0, e, session.getContents().isH2()));
}
return "result.jsp";
}
use of org.h2.mvstore.Page in project h2database by h2database.
the class Recover method dumpPageLogStream.
private void dumpPageLogStream(PrintWriter writer, int logKey, int logFirstTrunkPage, int logFirstDataPage, long pageCount) throws IOException {
Data s = Data.create(this, pageSize);
DataReader in = new DataReader(new PageInputStream(writer, this, store, logKey, logFirstTrunkPage, logFirstDataPage, pageSize));
writer.println("---- Transaction log ----");
CompressLZF compress = new CompressLZF();
while (true) {
int x = in.readByte();
if (x < 0) {
break;
}
if (x == PageLog.NOOP) {
// ignore
} else if (x == PageLog.UNDO) {
int pageId = in.readVarInt();
int size = in.readVarInt();
byte[] data = new byte[pageSize];
if (size == 0) {
in.readFully(data, pageSize);
} else if (size == 1) {
// empty
} else {
byte[] compressBuffer = new byte[size];
in.readFully(compressBuffer, size);
try {
compress.expand(compressBuffer, 0, size, data, 0, pageSize);
} catch (ArrayIndexOutOfBoundsException e) {
throw DbException.convertToIOException(e);
}
}
String typeName = "";
int type = data[0];
boolean last = (type & Page.FLAG_LAST) != 0;
type &= ~Page.FLAG_LAST;
switch(type) {
case Page.TYPE_EMPTY:
typeName = "empty";
break;
case Page.TYPE_DATA_LEAF:
typeName = "data leaf " + (last ? "(last)" : "");
break;
case Page.TYPE_DATA_NODE:
typeName = "data node " + (last ? "(last)" : "");
break;
case Page.TYPE_DATA_OVERFLOW:
typeName = "data overflow " + (last ? "(last)" : "");
break;
case Page.TYPE_BTREE_LEAF:
typeName = "b-tree leaf " + (last ? "(last)" : "");
break;
case Page.TYPE_BTREE_NODE:
typeName = "b-tree node " + (last ? "(last)" : "");
break;
case Page.TYPE_FREE_LIST:
typeName = "free list " + (last ? "(last)" : "");
break;
case Page.TYPE_STREAM_TRUNK:
typeName = "log trunk";
break;
case Page.TYPE_STREAM_DATA:
typeName = "log data";
break;
default:
typeName = "ERROR: unknown type " + type;
break;
}
writer.println("-- undo page " + pageId + " " + typeName);
if (trace) {
Data d = Data.create(null, data);
dumpPage(writer, d, pageId, pageCount);
}
} else if (x == PageLog.ADD) {
int sessionId = in.readVarInt();
setStorage(in.readVarInt());
Row row = PageLog.readRow(RowFactory.DEFAULT, in, s);
writer.println("-- session " + sessionId + " table " + storageId + " + " + row.toString());
if (transactionLog) {
if (storageId == 0 && row.getColumnCount() >= 4) {
int tableId = (int) row.getKey();
String sql = row.getValue(3).getString();
String name = extractTableOrViewName(sql);
if (row.getValue(2).getInt() == DbObject.TABLE_OR_VIEW) {
tableMap.put(tableId, name);
}
writer.println(sql + ";");
} else {
String tableName = tableMap.get(storageId);
if (tableName != null) {
StatementBuilder buff = new StatementBuilder();
buff.append("INSERT INTO ").append(tableName).append(" VALUES(");
for (int i = 0; i < row.getColumnCount(); i++) {
buff.appendExceptFirst(", ");
buff.append(row.getValue(i).getSQL());
}
buff.append(");");
writer.println(buff.toString());
}
}
}
} else if (x == PageLog.REMOVE) {
int sessionId = in.readVarInt();
setStorage(in.readVarInt());
long key = in.readVarLong();
writer.println("-- session " + sessionId + " table " + storageId + " - " + key);
if (transactionLog) {
if (storageId == 0) {
int tableId = (int) key;
String tableName = tableMap.get(tableId);
if (tableName != null) {
writer.println("DROP TABLE IF EXISTS " + tableName + ";");
}
} else {
String tableName = tableMap.get(storageId);
if (tableName != null) {
String sql = "DELETE FROM " + tableName + " WHERE _ROWID_ = " + key + ";";
writer.println(sql);
}
}
}
} else if (x == PageLog.TRUNCATE) {
int sessionId = in.readVarInt();
setStorage(in.readVarInt());
writer.println("-- session " + sessionId + " table " + storageId + " truncate");
if (transactionLog) {
writer.println("TRUNCATE TABLE " + storageId);
}
} else if (x == PageLog.COMMIT) {
int sessionId = in.readVarInt();
writer.println("-- commit " + sessionId);
} else if (x == PageLog.ROLLBACK) {
int sessionId = in.readVarInt();
writer.println("-- rollback " + sessionId);
} else if (x == PageLog.PREPARE_COMMIT) {
int sessionId = in.readVarInt();
String transaction = in.readString();
writer.println("-- prepare commit " + sessionId + " " + transaction);
} else if (x == PageLog.NOOP) {
// nothing to do
} else if (x == PageLog.CHECKPOINT) {
writer.println("-- checkpoint");
} else if (x == PageLog.FREE_LOG) {
int size = in.readVarInt();
StringBuilder buff = new StringBuilder("-- free");
for (int i = 0; i < size; i++) {
buff.append(' ').append(in.readVarInt());
}
writer.println(buff);
} else {
writer.println("-- ERROR: unknown operation " + x);
break;
}
}
}
use of org.h2.mvstore.Page in project h2database by h2database.
the class PageLog method recover.
/**
* Run one recovery stage. There are three recovery stages: 0: only the undo
* steps are run (restoring the state before the last checkpoint). 1: the
* pages that are used by the transaction log are allocated. 2: the
* committed operations are re-applied.
*
* @param stage the recovery stage
* @return whether the transaction log was empty
*/
boolean recover(int stage) {
if (trace.isDebugEnabled()) {
trace.debug("log recover stage: " + stage);
}
if (stage == RECOVERY_STAGE_ALLOCATE) {
PageInputStream in = new PageInputStream(store, logKey, firstTrunkPage, firstDataPage);
usedLogPages = in.allocateAllPages();
in.close();
return true;
}
PageInputStream pageIn = new PageInputStream(store, logKey, firstTrunkPage, firstDataPage);
DataReader in = new DataReader(pageIn);
int logId = 0;
Data data = store.createData();
boolean isEmpty = true;
try {
int pos = 0;
while (true) {
int x = in.readByte();
if (x < 0) {
break;
}
pos++;
isEmpty = false;
if (x == UNDO) {
int pageId = in.readVarInt();
int size = in.readVarInt();
if (size == 0) {
in.readFully(data.getBytes(), store.getPageSize());
} else if (size == 1) {
// empty
Arrays.fill(data.getBytes(), 0, store.getPageSize(), (byte) 0);
} else {
in.readFully(compressBuffer, size);
try {
compress.expand(compressBuffer, 0, size, data.getBytes(), 0, store.getPageSize());
} catch (ArrayIndexOutOfBoundsException e) {
DbException.convertToIOException(e);
}
}
if (stage == RECOVERY_STAGE_UNDO) {
if (!undo.get(pageId)) {
if (trace.isDebugEnabled()) {
trace.debug("log undo {0}", pageId);
}
store.writePage(pageId, data);
undo.set(pageId);
undoAll.set(pageId);
} else {
if (trace.isDebugEnabled()) {
trace.debug("log undo skip {0}", pageId);
}
}
}
} else if (x == ADD) {
int sessionId = in.readVarInt();
int tableId = in.readVarInt();
Row row = readRow(store.getDatabase().getRowFactory(), in, data);
if (stage == RECOVERY_STAGE_UNDO) {
store.allocateIfIndexRoot(pos, tableId, row);
} else if (stage == RECOVERY_STAGE_REDO) {
if (isSessionCommitted(sessionId, logId, pos)) {
if (trace.isDebugEnabled()) {
trace.debug("log redo + table: " + tableId + " s: " + sessionId + " " + row);
}
store.redo(tableId, row, true);
} else {
if (trace.isDebugEnabled()) {
trace.debug("log ignore s: " + sessionId + " + table: " + tableId + " " + row);
}
}
}
} else if (x == REMOVE) {
int sessionId = in.readVarInt();
int tableId = in.readVarInt();
long key = in.readVarLong();
if (stage == RECOVERY_STAGE_REDO) {
if (isSessionCommitted(sessionId, logId, pos)) {
if (trace.isDebugEnabled()) {
trace.debug("log redo - table: " + tableId + " s:" + sessionId + " key: " + key);
}
store.redoDelete(tableId, key);
} else {
if (trace.isDebugEnabled()) {
trace.debug("log ignore s: " + sessionId + " - table: " + tableId + " " + key);
}
}
}
} else if (x == TRUNCATE) {
int sessionId = in.readVarInt();
int tableId = in.readVarInt();
if (stage == RECOVERY_STAGE_REDO) {
if (isSessionCommitted(sessionId, logId, pos)) {
if (trace.isDebugEnabled()) {
trace.debug("log redo truncate table: " + tableId);
}
store.redoTruncate(tableId);
} else {
if (trace.isDebugEnabled()) {
trace.debug("log ignore s: " + sessionId + " truncate table: " + tableId);
}
}
}
} else if (x == PREPARE_COMMIT) {
int sessionId = in.readVarInt();
String transaction = in.readString();
if (trace.isDebugEnabled()) {
trace.debug("log prepare commit " + sessionId + " " + transaction + " pos: " + pos);
}
if (stage == RECOVERY_STAGE_UNDO) {
int page = pageIn.getDataPage();
setPrepareCommit(sessionId, page, transaction);
}
} else if (x == ROLLBACK) {
int sessionId = in.readVarInt();
if (trace.isDebugEnabled()) {
trace.debug("log rollback " + sessionId + " pos: " + pos);
}
// ignore - this entry is just informational
} else if (x == COMMIT) {
int sessionId = in.readVarInt();
if (trace.isDebugEnabled()) {
trace.debug("log commit " + sessionId + " pos: " + pos);
}
if (stage == RECOVERY_STAGE_UNDO) {
setLastCommitForSession(sessionId, logId, pos);
}
} else if (x == NOOP) {
// nothing to do
} else if (x == CHECKPOINT) {
logId++;
} else if (x == FREE_LOG) {
int count = in.readVarInt();
for (int i = 0; i < count; i++) {
int pageId = in.readVarInt();
if (stage == RECOVERY_STAGE_REDO) {
if (!usedLogPages.get(pageId)) {
store.free(pageId, false);
}
}
}
} else {
if (trace.isDebugEnabled()) {
trace.debug("log end");
break;
}
}
}
} catch (DbException e) {
if (e.getErrorCode() == ErrorCode.FILE_CORRUPTED_1) {
trace.debug("log recovery stopped");
} else {
throw e;
}
} catch (IOException e) {
trace.debug("log recovery completed");
}
undo = new BitSet();
if (stage == RECOVERY_STAGE_REDO) {
usedLogPages = null;
}
return isEmpty;
}
use of org.h2.mvstore.Page in project h2database by h2database.
the class PageStore method compact.
/**
* Shrink the file so there are no empty pages at the end.
*
* @param compactMode 0 if no compacting should happen, otherwise
* TransactionCommand.SHUTDOWN_COMPACT or TransactionCommand.SHUTDOWN_DEFRAG
*/
public synchronized void compact(int compactMode) {
if (!database.getSettings().pageStoreTrim) {
return;
}
if (SysProperties.MODIFY_ON_WRITE && readMode && compactMode == 0) {
return;
}
openForWriting();
// find the last used page
int lastUsed = -1;
for (int i = getFreeListId(pageCount); i >= 0; i--) {
lastUsed = getFreeList(i).getLastUsed();
if (lastUsed != -1) {
break;
}
}
// open a new log at the very end
// (to be truncated later)
writeBack();
log.free();
recoveryRunning = true;
try {
logFirstTrunkPage = lastUsed + 1;
allocatePage(logFirstTrunkPage);
log.openForWriting(logFirstTrunkPage, true);
// ensure the free list is backed up again
log.checkpoint();
} finally {
recoveryRunning = false;
}
long start = System.nanoTime();
boolean isCompactFully = compactMode == CommandInterface.SHUTDOWN_COMPACT;
boolean isDefrag = compactMode == CommandInterface.SHUTDOWN_DEFRAG;
if (database.getSettings().defragAlways) {
isCompactFully = isDefrag = true;
}
int maxCompactTime = database.getSettings().maxCompactTime;
int maxMove = database.getSettings().maxCompactCount;
if (isCompactFully || isDefrag) {
maxCompactTime = Integer.MAX_VALUE;
maxMove = Integer.MAX_VALUE;
}
int blockSize = isCompactFully ? COMPACT_BLOCK_SIZE : 1;
int firstFree = MIN_PAGE_COUNT;
for (int x = lastUsed, j = 0; x > MIN_PAGE_COUNT && j < maxMove; x -= blockSize) {
for (int full = x - blockSize + 1; full <= x; full++) {
if (full > MIN_PAGE_COUNT && isUsed(full)) {
synchronized (this) {
firstFree = getFirstFree(firstFree);
if (firstFree == -1 || firstFree >= full) {
j = maxMove;
break;
}
if (compact(full, firstFree)) {
j++;
long now = System.nanoTime();
if (now > start + TimeUnit.MILLISECONDS.toNanos(maxCompactTime)) {
j = maxMove;
break;
}
}
}
}
}
}
if (isDefrag) {
log.checkpoint();
writeBack();
cache.clear();
ArrayList<Table> tables = database.getAllTablesAndViews(false);
recordedPagesList = New.arrayList();
recordedPagesIndex = new IntIntHashMap();
recordPageReads = true;
Session sysSession = database.getSystemSession();
for (Table table : tables) {
if (!table.isTemporary() && TableType.TABLE == table.getTableType()) {
Index scanIndex = table.getScanIndex(sysSession);
Cursor cursor = scanIndex.find(sysSession, null, null);
while (cursor.next()) {
cursor.get();
}
for (Index index : table.getIndexes()) {
if (index != scanIndex && index.canScan()) {
cursor = index.find(sysSession, null, null);
while (cursor.next()) {
// the data is already read
}
}
}
}
}
recordPageReads = false;
int target = MIN_PAGE_COUNT - 1;
int temp = 0;
for (int i = 0, size = recordedPagesList.size(); i < size; i++) {
log.checkpoint();
writeBack();
int source = recordedPagesList.get(i);
Page pageSource = getPage(source);
if (!pageSource.canMove()) {
continue;
}
while (true) {
Page pageTarget = getPage(++target);
if (pageTarget == null || pageTarget.canMove()) {
break;
}
}
if (target == source) {
continue;
}
temp = getFirstFree(temp);
if (temp == -1) {
DbException.throwInternalError("no free page for defrag");
}
cache.clear();
swap(source, target, temp);
int index = recordedPagesIndex.get(target);
if (index != IntIntHashMap.NOT_FOUND) {
recordedPagesList.set(index, source);
recordedPagesIndex.put(source, index);
}
recordedPagesList.set(i, target);
recordedPagesIndex.put(target, i);
}
recordedPagesList = null;
recordedPagesIndex = null;
}
// TODO can most likely be simplified
checkpoint();
log.checkpoint();
writeIndexRowCounts();
log.checkpoint();
writeBack();
commit(pageStoreSession);
writeBack();
log.checkpoint();
log.free();
// truncate the log
recoveryRunning = true;
try {
setLogFirstPage(++logKey, 0, 0);
} finally {
recoveryRunning = false;
}
writeBack();
for (int i = getFreeListId(pageCount); i >= 0; i--) {
lastUsed = getFreeList(i).getLastUsed();
if (lastUsed != -1) {
break;
}
}
int newPageCount = lastUsed + 1;
if (newPageCount < pageCount) {
freed.set(newPageCount, pageCount, false);
}
pageCount = newPageCount;
// the easiest way to remove superfluous entries
freeLists.clear();
trace.debug("pageCount: " + pageCount);
long newLength = (long) pageCount << pageSizeShift;
if (file.length() != newLength) {
file.setLength(newLength);
writeCount++;
}
}
use of org.h2.mvstore.Page in project h2database by h2database.
the class PageStore method readStaticHeader.
private void readStaticHeader() {
file.seek(FileStore.HEADER_LENGTH);
Data page = Data.create(database, new byte[PAGE_SIZE_MIN - FileStore.HEADER_LENGTH]);
file.readFully(page.getBytes(), 0, PAGE_SIZE_MIN - FileStore.HEADER_LENGTH);
readCount++;
setPageSize(page.readInt());
int writeVersion = page.readByte();
int readVersion = page.readByte();
if (readVersion > READ_VERSION) {
throw DbException.get(ErrorCode.FILE_VERSION_ERROR_1, fileName);
}
if (writeVersion > WRITE_VERSION) {
close();
database.setReadOnly(true);
accessMode = "r";
file = database.openFile(fileName, accessMode, true);
}
}
Aggregations