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

New experimental feature "SHUTDOWN DEFRAG".

上级 df07f1a0
...@@ -161,7 +161,7 @@ public class Database implements DataHandler { ...@@ -161,7 +161,7 @@ public class Database implements DataHandler {
private volatile boolean checkpointRunning; private volatile boolean checkpointRunning;
private final Object reconnectSync = new Object(); private final Object reconnectSync = new Object();
private int cacheSize; private int cacheSize;
private int compactMode = -1; private int compactMode;
private SourceCompiler compiler; private SourceCompiler compiler;
private volatile boolean metaTablesInitialized; private volatile boolean metaTablesInitialized;
private boolean flushOnEachCommit; private boolean flushOnEachCommit;
......
...@@ -12,7 +12,6 @@ import java.util.ArrayList; ...@@ -12,7 +12,6 @@ import java.util.ArrayList;
import java.util.BitSet; import java.util.BitSet;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.zip.CRC32; import java.util.zip.CRC32;
import org.h2.command.ddl.CreateTableData; import org.h2.command.ddl.CreateTableData;
import org.h2.command.dml.TransactionCommand; import org.h2.command.dml.TransactionCommand;
...@@ -36,7 +35,6 @@ import org.h2.index.PageDelegateIndex; ...@@ -36,7 +35,6 @@ import org.h2.index.PageDelegateIndex;
import org.h2.index.PageIndex; import org.h2.index.PageIndex;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.message.Trace; import org.h2.message.Trace;
import org.h2.result.ResultInterface;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.schema.Schema; import org.h2.schema.Schema;
import org.h2.table.Column; import org.h2.table.Column;
...@@ -176,7 +174,7 @@ public class PageStore implements CacheWriter { ...@@ -176,7 +174,7 @@ public class PageStore implements CacheWriter {
private boolean recordPageReads; private boolean recordPageReads;
private ArrayList<Integer> recordedPagesList; private ArrayList<Integer> recordedPagesList;
private HashSet<Integer> recordedPagesSet; private BitSet recordedPages;
/** /**
* The change count is something like a "micro-transaction-id". * The change count is something like a "micro-transaction-id".
...@@ -437,7 +435,7 @@ public class PageStore implements CacheWriter { ...@@ -437,7 +435,7 @@ public class PageStore implements CacheWriter {
/** /**
* Shrink the file so there are no empty pages at the end. * Shrink the file so there are no empty pages at the end.
* *
* @param compactMode != -1 if no compacting should happen, otherwise * @param compactMode 0 if no compacting should happen, otherwise
* TransactionCommand.SHUTDOWN_COMPACT or TransactionCommand.SHUTDOWN_DEFRAG * TransactionCommand.SHUTDOWN_COMPACT or TransactionCommand.SHUTDOWN_DEFRAG
*/ */
public void compact(int compactMode) { public void compact(int compactMode) {
...@@ -470,6 +468,9 @@ public class PageStore implements CacheWriter { ...@@ -470,6 +468,9 @@ public class PageStore implements CacheWriter {
boolean isCompactFully = compactMode == TransactionCommand.SHUTDOWN_COMPACT; boolean isCompactFully = compactMode == TransactionCommand.SHUTDOWN_COMPACT;
boolean isDefrag = compactMode == TransactionCommand.SHUTDOWN_DEFRAG; boolean isDefrag = compactMode == TransactionCommand.SHUTDOWN_DEFRAG;
int test;
// isCompactFully = isDefrag = true;
int maxCompactTime = SysProperties.MAX_COMPACT_TIME; int maxCompactTime = SysProperties.MAX_COMPACT_TIME;
int maxMove = SysProperties.MAX_COMPACT_COUNT; int maxMove = SysProperties.MAX_COMPACT_COUNT;
...@@ -504,45 +505,42 @@ public class PageStore implements CacheWriter { ...@@ -504,45 +505,42 @@ public class PageStore implements CacheWriter {
cache.clear(); cache.clear();
ArrayList<Table> tables = database.getAllTablesAndViews(false); ArrayList<Table> tables = database.getAllTablesAndViews(false);
recordedPagesList = New.arrayList(); recordedPagesList = New.arrayList();
recordedPagesSet = New.hashSet(); recordedPages = new BitSet();
recordPageReads = true; recordPageReads = true;
for (int i = 0; i < tables.size(); i++) { for (int i = 0; i < tables.size(); i++) {
Table table = tables.get(i); Table table = tables.get(i);
org.h2.command.Prepared pref = database.getSystemSession().prepare("select * from " + if (!table.isTemporary() && table.getTableType().equals(Table.TABLE)) {
table.getName() + " where -1=abs(rand())"); // rand() < 0 is never true, but the optimizer can't know,
ResultInterface ri = pref.query(Integer.MAX_VALUE); // therefore it's performing a table scan
ri.close(); database.getSystemSession().prepare(
"select * from " +
table.getSQL() +
" where rand() < zero()").query(Integer.MAX_VALUE);
int todoScanIndexesAsWell;
}
} }
recordPageReads = false; recordPageReads = false;
int free = getFirstFree(); // We swap, so this page is fix
if (free == -1) {
DbException.throwInternalError("no free page for defrag");
} else {
for (int i = 0; i < recordedPagesList.size(); i++) { for (int i = 0; i < recordedPagesList.size(); i++) {
writeBack(); writeBack();
cache.clear(); cache.clear();
int a = MIN_PAGE_COUNT + i; int a = MIN_PAGE_COUNT + i;
int b = recordedPagesList.get(i); int b = recordedPagesList.get(i);
if (a == b) { if (a == b) {
continue; continue;
} }
int temp = getFirstFree();
boolean swapped = swap(a, b, free); if (temp == -1) {
if (!swapped) { DbException.throwInternalError("no free page for defrag");
DbException.throwInternalError("swapping not possible: " + a + " with " + b + " via " + free);
} }
swap(a, b, temp);
int index = recordedPagesList.indexOf(a); int index = recordedPagesList.indexOf(a);
if (index != -1) { if (index >= 0) {
recordedPagesList.set(index, b); recordedPagesList.set(index, b);
} }
recordedPagesList.set(i, a); recordedPagesList.set(i, a);
} }
}
recordedPagesList = null; recordedPagesList = null;
recordedPagesSet = null; recordedPages = null;
} }
// TODO can most likely be simplified // TODO can most likely be simplified
checkpoint(); checkpoint();
...@@ -595,36 +593,32 @@ public class PageStore implements CacheWriter { ...@@ -595,36 +593,32 @@ public class PageStore implements CacheWriter {
return free; return free;
} }
private boolean swap(int a, int b, int free) { private void swap(int a, int b, int free) {
if (a < MIN_PAGE_COUNT || b < MIN_PAGE_COUNT || !isUsed(a) || !isUsed(b)) { if (a < MIN_PAGE_COUNT || b < MIN_PAGE_COUNT) {
return false; System.out.println(isUsed(a) + " " + isUsed(b));
DbException.throwInternalError("can't swap " + a + " and " + b);
} }
Page f = (Page) cache.get(free); Page f = (Page) cache.get(free);
if (f != null) { if (f != null) {
DbException.throwInternalError("not free: " + f); DbException.throwInternalError("not free: " + f);
} }
Page pageA = getPage(a); trace.debug("swap " + a + " and " + b + " via " + free);
Page pageB = getPage(b); Page pageA = null;
if (pageA == null) { if (isUsed(a)) {
freePage(a); pageA = getPage(a);
} else if (pageB == null) {
freePage(b);
} else {
trace.debug("swap " + a + " with " + b + " via " + free);
try {
pageA.moveTo(systemSession, free); pageA.moveTo(systemSession, free);
free(a); free(a);
pageB = getPage(b); }
if (isUsed(b)) {
Page pageB = getPage(b);
pageB.moveTo(systemSession, a); pageB.moveTo(systemSession, a);
free(b); free(b);
}
if (pageA != null) {
f = getPage(free); f = getPage(free);
f.moveTo(systemSession, b); f.moveTo(systemSession, b);
free(free); free(free);
} finally {
changeCount++;
}
} }
return true;
} }
private boolean compact(int full, int free) { private boolean compact(int full, int free) {
...@@ -691,10 +685,6 @@ public class PageStore implements CacheWriter { ...@@ -691,10 +685,6 @@ public class PageStore implements CacheWriter {
statisticsIncrement(index.getTable().getName() + "." + index.getName() + " read"); statisticsIncrement(index.getTable().getName() + "." + index.getName() + " read");
} }
p = PageDataLeaf.read(index, data, pageId); p = PageDataLeaf.read(index, data, pageId);
if (recordPageReads && pageId >= MIN_PAGE_COUNT && !recordedPagesSet.contains(pageId)) {
recordedPagesList.add(pageId);
recordedPagesSet.add(pageId);
}
break; break;
} }
case Page.TYPE_DATA_NODE: { case Page.TYPE_DATA_NODE: {
...@@ -1220,6 +1210,12 @@ public class PageStore implements CacheWriter { ...@@ -1220,6 +1210,12 @@ public class PageStore implements CacheWriter {
* @param page the page * @param page the page
*/ */
void readPage(int pos, Data page) { void readPage(int pos, Data page) {
if (recordPageReads) {
if (pos >= MIN_PAGE_COUNT && !recordedPages.get(pos)) {
recordedPagesList.add(pos);
recordedPages.set(pos);
}
}
synchronized (database) { synchronized (database) {
if (pos < 0 || pos >= pageCount) { if (pos < 0 || pos >= pageCount) {
throw DbException.get(ErrorCode.FILE_CORRUPTED_1, pos + " of " + pageCount); throw DbException.get(ErrorCode.FILE_CORRUPTED_1, pos + " of " + pageCount);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论