提交 00df2d41 authored 作者: Thomas Mueller's avatar Thomas Mueller

Page store: long keys

上级 c670a577
......@@ -737,6 +737,11 @@ CREATE USER statement. If you run the script against a database that was created
user, or if there are conflicting users, running the script will fail. Consider running the script
against a database that was created with a user name that is not in the script.
</p>
<p>
The recover tool creates a SQL script from the .data.db file. It also processes the transaction log file(s),
however it does not automatically apply those changes. Usually, many of those changes are already
applied in the .data.db file.
</p>
<br /><a name="file_locking_protocols"></a>
<h2>File Locking Protocols</h2>
......@@ -760,10 +765,10 @@ The two methods are 'file method' and 'socket methods'.
The default method for database file locking is the 'File Method'. The algorithm is:
</p>
<ul>
<li>When the lock file does not exist, it is created (using the atomic operation File.createNewFile).
<li>If the lock file does not exist, it is created (using the atomic operation File.createNewFile).
Then, the process waits a little bit (20ms) and checks the file again. If the file was changed
during this time, the operation is aborted. This protects against a race condition
when a process deletes the lock file just after one create it, and a third process creates
when one process deletes the lock file just after another one create it, and a third process creates
the file again. It does not occur if there are only two writers.
</li><li>
If the file can be created, a random number is inserted together with the locking method
......@@ -775,7 +780,7 @@ not get through undetected even if the system is very busy. However, the watchdo
does use very little resources (CPU time), because it waits most of the time. Also, the watchdog only reads from the hard disk
and does not write to it.
</li><li>
If the lock file exists, and it was modified in the 20 ms, the process waits for some time (up to 10 times).
If the lock file exists and was recently modified, the process waits for some time (up to two seconds).
If it was still changed, an exception is thrown (database is locked). This is done to eliminate race conditions with many concurrent
writers. Afterwards, the file is overwritten with a new version (challenge).
After that, the thread waits for 2 seconds.
......
......@@ -18,7 +18,9 @@ Change Log
<h1>Change Log</h1>
<h2>Next Version (unreleased)</h2>
<ul><li>New sample application that shows how to pass data to a trigger.
<ul><li>The Recover tool now also processes the log files, however applying those changes
is still a manual process.
</li><li>New sample application that shows how to pass data to a trigger.
</li><li>More bugs in the server-less multi-connection mode have been fixed:
On Windows, two processes could write to the same database at the same time.
</li><li>When loading triggers or other client classes
......
......@@ -336,7 +336,7 @@ public class ConstraintReferential extends Constraint {
while (cursor.next()) {
SearchRow found;
found = cursor.getSearchRow();
if (excluding != null && found.getPos() == excluding.getPos()) {
if (excluding != null && found.getKey() == excluding.getKey()) {
continue;
}
Column[] cols = searchIndex.getColumns();
......
......@@ -270,8 +270,8 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
}
public int compareKeys(SearchRow rowData, SearchRow compare) {
int k1 = rowData.getPos();
int k2 = compare.getPos();
long k1 = rowData.getKey();
long k2 = compare.getKey();
if (k1 == k2) {
if (isMultiVersion) {
int v1 = rowData.getVersion();
......
......@@ -76,7 +76,7 @@ public class BtreeCursor implements Cursor {
public Row get() throws SQLException {
if (currentRow == null && currentSearchRow != null) {
currentRow = index.getRow(session, currentSearchRow.getPos());
currentRow = index.getRow(session, currentSearchRow.getKey());
}
return currentRow;
}
......@@ -85,8 +85,8 @@ public class BtreeCursor implements Cursor {
return currentSearchRow;
}
public int getPos() {
return currentSearchRow.getPos();
public long getKey() {
return currentSearchRow.getKey();
}
public boolean next() throws SQLException {
......
......@@ -217,7 +217,7 @@ public class BtreeIndex extends BaseIndex implements RecordReader {
// create a row that only contains the key values
setChanged(session);
Row row = table.getTemplateRow();
row.setPosAndVersion(r);
row.setKeyAndVersion(r);
for (int i = 0; i < columns.length; i++) {
Column col = columns[i];
int idx = col.getColumnId();
......@@ -247,7 +247,7 @@ public class BtreeIndex extends BaseIndex implements RecordReader {
*/
SearchRow getSearchRow(Row row) {
SearchRow r = table.getTemplateSimpleRow(columns.length == 1);
r.setPosAndVersion(row);
r.setKeyAndVersion(row);
for (int j = 0; j < columns.length; j++) {
int idx = columns[j].getColumnId();
r.setValue(idx, row.getValue(idx));
......@@ -324,7 +324,7 @@ public class BtreeIndex extends BaseIndex implements RecordReader {
r = null;
} else {
r = table.getTemplateSimpleRow(columns.length == 1);
r.setPos(pos);
r.setKey(pos);
for (int j = 0; j < columns.length; j++) {
int idx = columns[j].getColumnId();
r.setValue(idx, s.readValue());
......@@ -339,11 +339,11 @@ public class BtreeIndex extends BaseIndex implements RecordReader {
* Get a row from the data file.
*
* @param session the session
* @param pos the position in the data file
* @param key the unique key
* @return the row
*/
Row getRow(Session session, int pos) throws SQLException {
return tableData.getRow(session, pos);
Row getRow(Session session, long key) throws SQLException {
return tableData.getRow(session, key);
}
private void flushHead(Session session) throws SQLException {
......
......@@ -245,7 +245,7 @@ public class BtreeLeaf extends BtreePage {
Column[] columns = index.getColumns();
for (int i = 0; i < len; i++) {
SearchRow row = pageData.get(i);
buff.writeInt(row.getPos());
buff.writeInt((int) row.getKey());
if (!writePos) {
for (int j = 0; j < columns.length; j++) {
Value v = row.getValue(columns[j].getColumnId());
......
......@@ -350,7 +350,7 @@ public class BtreeNode extends BtreePage {
buff.writeInt(-1);
} else {
SearchRow row = getData(i);
buff.writeInt(row.getPos());
buff.writeInt((int) row.getKey());
for (int j = 0; j < columns.length; j++) {
Value v = row.getValue(columns[j].getColumnId());
buff.writeValue(v);
......
......@@ -39,11 +39,11 @@ public interface Cursor {
SearchRow getSearchRow() throws SQLException;
/**
* Get the position of the current row.
* Get the unique key of the current row.
*
* @return the position
* @return the key
*/
int getPos();
long getKey();
/**
* Skip to the next row if one is available.
......
......@@ -41,7 +41,7 @@ public class FunctionCursor implements Cursor {
return get();
}
public int getPos() {
public long getKey() {
throw Message.throwInternalError();
}
......
......@@ -30,8 +30,8 @@ public class HashCursor implements Cursor {
return row;
}
public int getPos() {
return row.getPos();
public long getKey() {
return row.getKey();
}
public boolean next() {
......
......@@ -47,7 +47,7 @@ public class HashIndex extends BaseHashIndex {
public void add(Session session, Row row) throws SQLException {
if (intMap != null) {
int key = row.getValue(columns[0].getColumnId()).getInt();
intMap.put(key, row.getPos());
intMap.put(key, (int) row.getKey());
} else {
Value key = getKey(row);
Object old = rows.get(key);
......@@ -55,7 +55,7 @@ public class HashIndex extends BaseHashIndex {
// TODO index duplicate key for hash indexes: is this allowed?
throw getDuplicateKeyException();
}
rows.put(getKey(row), row.getPos());
rows.put(getKey(row), (int) row.getKey());
}
}
......
......@@ -147,8 +147,8 @@ public class IndexCursor implements Cursor {
return cursor.get();
}
public int getPos() {
return cursor.getPos();
public long getKey() {
return cursor.getKey();
}
public SearchRow getSearchRow() throws SQLException {
......
......@@ -52,7 +52,7 @@ public class LinkedCursor implements Cursor {
return current;
}
public int getPos() {
public long getKey() {
throw Message.throwInternalError();
}
......
......@@ -33,7 +33,7 @@ public class MetaCursor implements Cursor {
return current;
}
public int getPos() {
public long getKey() {
throw Message.throwInternalError();
}
......
......@@ -82,12 +82,12 @@ public class MultiVersionCursor implements Cursor {
}
}
public int getPos() {
public long getKey() {
synchronized (sync) {
if (SysProperties.CHECK && end) {
Message.throwInternalError();
}
return onBase ? baseCursor.getPos() : deltaCursor.getPos();
return onBase ? baseCursor.getKey() : deltaCursor.getKey();
}
}
......@@ -147,8 +147,8 @@ public class MultiVersionCursor implements Cursor {
if (compare == 0) {
// can't use compareKeys because the
// version would be compared as well
int k1 = deltaRow.getPos();
int k2 = baseRow.getPos();
long k1 = deltaRow.getKey();
long k2 = baseRow.getKey();
compare = k1 == k2 ? 0 : k1 > k2 ? 1 : -1;
}
if (compare == 0) {
......
......@@ -128,7 +128,7 @@ public class MultiVersionIndex implements Index {
Cursor c = delta.find(session, row, row);
while (c.next()) {
Row r = c.get();
if (r.getPos() == row.getPos() && r.getVersion() == row.getVersion()) {
if (r.getKey() == row.getKey() && r.getVersion() == row.getVersion()) {
if (r != row && table.getScanIndex(session).compareRows(r, row) != 0) {
row.setVersion(r.getVersion() + 1);
} else {
......
......@@ -39,7 +39,7 @@ public class NonUniqueHashCursor implements Cursor {
return tableData.getRow(session, positions.get(index));
}
public int getPos() {
public long getKey() {
return index;
}
......
......@@ -50,7 +50,7 @@ public class NonUniqueHashIndex extends BaseHashIndex {
positions = new IntArray(1);
rows.put(key, positions);
}
positions.add(row.getPos());
positions.add((int) row.getKey());
rowCount++;
}
......@@ -65,7 +65,7 @@ public class NonUniqueHashIndex extends BaseHashIndex {
// last row with such key
rows.remove(key);
} else {
positions.removeValue(row.getPos());
positions.removeValue((int) row.getKey());
}
rowCount--;
}
......
......@@ -43,13 +43,13 @@ public class PageBtreeCursor implements Cursor {
public Row get() throws SQLException {
if (currentRow == null && currentSearchRow != null) {
currentRow = index.getRow(session, currentSearchRow.getPos());
currentRow = index.getRow(session, currentSearchRow.getKey());
}
return currentRow;
}
public int getPos() {
return currentSearchRow.getPos();
public long getKey() {
return currentSearchRow.getKey();
}
public SearchRow getSearchRow() {
......
......@@ -74,7 +74,7 @@ public class PageBtreeIndex extends PageIndex {
public void add(Session session, Row row) throws SQLException {
if (trace.isDebugEnabled()) {
trace.debug("add " + row.getPos());
trace.debug("add " + row.getKey());
}
// safe memory
SearchRow newRow = getSearchRow(row);
......@@ -113,7 +113,7 @@ public class PageBtreeIndex extends PageIndex {
*/
private SearchRow getSearchRow(Row row) {
SearchRow r = table.getTemplateSimpleRow(columns.length == 1);
r.setPosAndVersion(row);
r.setKeyAndVersion(row);
for (int j = 0; j < columns.length; j++) {
int idx = columns[j].getColumnId();
r.setValue(idx, row.getValue(idx));
......@@ -199,7 +199,7 @@ public class PageBtreeIndex extends PageIndex {
public void remove(Session session, Row row) throws SQLException {
if (trace.isDebugEnabled()) {
trace.debug("remove " + row.getPos());
trace.debug("remove " + row.getKey());
}
if (tableData.getContainsLargeObject()) {
for (int i = 0; i < row.getColumnCount(); i++) {
......@@ -260,7 +260,7 @@ public class PageBtreeIndex extends PageIndex {
* @param key the row key
* @return the row
*/
Row getRow(Session session, int key) throws SQLException {
Row getRow(Session session, long key) throws SQLException {
return tableData.getRow(session, key);
}
......@@ -293,12 +293,12 @@ public class PageBtreeIndex extends PageIndex {
*/
SearchRow readRow(Data data, int offset, boolean onlyPosition) throws SQLException {
data.setPos(offset);
long pos = data.readVarLong();
long key = data.readVarLong();
if (onlyPosition) {
return tableData.getRow(null, (int) pos);
return tableData.getRow(null, key);
}
SearchRow row = table.getTemplateSimpleRow(columns.length == 1);
row.setPos((int) pos);
row.setKey(key);
for (Column col : columns) {
int idx = col.getColumnId();
row.setValue(idx, data.readValue());
......@@ -316,7 +316,7 @@ public class PageBtreeIndex extends PageIndex {
*/
void writeRow(Data data, int offset, SearchRow row, boolean onlyPosition) throws SQLException {
data.setPos(offset);
data.writeVarLong(row.getPos());
data.writeVarLong(row.getKey());
if (!onlyPosition) {
for (Column col : columns) {
int idx = col.getColumnId();
......
......@@ -194,7 +194,7 @@ public class PageBtreeLeaf extends PageBtree {
SearchRow remove(SearchRow row) throws SQLException {
int at = find(row, false, false, true);
SearchRow delete = getRow(at);
if (index.compareRows(row, delete) != 0 || delete.getPos() != row.getPos()) {
if (index.compareRows(row, delete) != 0 || delete.getKey() != row.getKey()) {
throw Message.getSQLException(ErrorCode.ROW_NOT_FOUND_WHEN_DELETING_1, index.getSQL() + ": " + row);
}
if (entryCount == 1) {
......
......@@ -30,7 +30,7 @@ abstract class PageData extends Page {
/**
* The index.
*/
protected final PageScanIndex index;
protected final PageDataIndex index;
/**
* The page number of the parent.
......@@ -57,7 +57,7 @@ abstract class PageData extends Page {
*/
protected boolean written;
PageData(PageScanIndex index, int pageId, Data data) {
PageData(PageDataIndex index, int pageId, Data data) {
this.index = index;
this.data = data;
setPos(pageId);
......@@ -184,7 +184,7 @@ abstract class PageData extends Page {
* @param key the key of the row to remove
* @return true if this page is now empty
*/
abstract boolean remove(int key) throws SQLException;
abstract boolean remove(long key) throws SQLException;
/**
* Free up all child pages.
......
......@@ -17,7 +17,7 @@ import org.h2.result.SearchRow;
/**
* The cursor implementation for the page scan index.
*/
class PageScanCursor implements Cursor {
class PageDataCursor implements Cursor {
private PageDataLeaf current;
private int idx;
......@@ -27,7 +27,7 @@ class PageScanCursor implements Cursor {
private final Session session;
private Iterator<Row> delta;
PageScanCursor(Session session, PageDataLeaf current, int idx, long max, boolean multiVersion) {
PageDataCursor(Session session, PageDataLeaf current, int idx, long max, boolean multiVersion) {
this.current = current;
this.idx = idx;
this.max = max;
......@@ -42,8 +42,8 @@ class PageScanCursor implements Cursor {
return row;
}
public int getPos() {
return row.getPos();
public long getKey() {
return row.getKey();
}
public SearchRow getSearchRow() {
......
......@@ -34,7 +34,7 @@ import org.h2.value.ValueNull;
* all rows of a table. Each regular table has one such object, even if no
* primary key or indexes are defined.
*/
public class PageScanIndex extends PageIndex implements RowIndex {
public class PageDataIndex extends PageIndex implements RowIndex {
private PageStore store;
private TableData tableData;
......@@ -47,7 +47,7 @@ public class PageScanIndex extends PageIndex implements RowIndex {
private SQLException fastDuplicateKeyException;
private int memorySizePerPage;
public PageScanIndex(TableData table, int id, IndexColumn[] columns, IndexType indexType, int headPos, Session session) throws SQLException {
public PageDataIndex(TableData table, int id, IndexColumn[] columns, IndexType indexType, int headPos, Session session) throws SQLException {
initBaseIndex(table, id, table.getName() + "_TABLE_SCAN", columns, indexType);
// trace.setLevel(TraceSystem.DEBUG);
if (database.isMultiVersion()) {
......@@ -83,7 +83,8 @@ public class PageScanIndex extends PageIndex implements RowIndex {
table.setRowCount(rowCount);
fastDuplicateKeyException = super.getDuplicateKeyException();
// estimate the memory usage as follows:
// the less column, the more memory is required, because the more rows fit on a page
// the less column, the more memory is required,
// because the more rows fit on a page
memorySizePerPage = store.getPageSize();
int estimatedRowsPerPage = store.getPageSize() / ((1 + columns.length) * 8);
memorySizePerPage += estimatedRowsPerPage * 64;
......@@ -96,10 +97,10 @@ public class PageScanIndex extends PageIndex implements RowIndex {
public void add(Session session, Row row) throws SQLException {
boolean retry = false;
if (mainIndexColumn != -1) {
row.setPos(row.getValue(mainIndexColumn).getInt());
row.setKey(row.getValue(mainIndexColumn).getLong());
} else {
if (row.getPos() == 0) {
row.setPos((int) ++lastKey);
if (row.getKey() == 0) {
row.setKey((int) ++lastKey);
retry = true;
}
}
......@@ -135,16 +136,14 @@ public class PageScanIndex extends PageIndex implements RowIndex {
if (add == 0) {
// in the first re-try add a small random number,
// to avoid collisions after a re-start
// TODO use long
row.setPos((int) (row.getPos() + Math.random() * 10000));
row.setKey((long) (row.getKey() + Math.random() * 10000));
} else {
// TODO use long
row.setPos((int) (row.getPos() + add));
row.setKey(row.getKey() + add);
}
add++;
}
}
lastKey = Math.max(lastKey, row.getPos() + 1);
lastKey = Math.max(lastKey, row.getKey() + 1);
}
private void addTry(Session session, Row row) throws SQLException {
......@@ -157,7 +156,7 @@ public class PageScanIndex extends PageIndex implements RowIndex {
if (trace.isDebugEnabled()) {
trace.debug("split " + splitPoint);
}
long pivot = splitPoint == 0 ? row.getPos() : root.getKey(splitPoint - 1);
long pivot = splitPoint == 0 ? row.getKey() : root.getKey(splitPoint - 1);
PageData page1 = root;
PageData page2 = root.split(splitPoint);
int rootPageId = root.getPos();
......@@ -284,7 +283,7 @@ public class PageScanIndex extends PageIndex implements RowIndex {
public void remove(Session session, Row row) throws SQLException {
if (trace.isDebugEnabled()) {
trace.debug("remove " + row.getPos());
trace.debug("remove " + row.getKey());
}
if (tableData.getContainsLargeObject()) {
for (int i = 0; i < row.getColumnCount(); i++) {
......@@ -297,7 +296,7 @@ public class PageScanIndex extends PageIndex implements RowIndex {
if (rowCount == 1) {
removeAllRows();
} else {
int key = row.getPos();
long key = row.getKey();
PageData root = getPage(rootPageId, 0);
root.remove(key);
invalidateRowCount();
......@@ -361,7 +360,7 @@ public class PageScanIndex extends PageIndex implements RowIndex {
throw Message.getUnsupportedException("PAGE");
}
public Row getRow(Session session, int key) throws SQLException {
public Row getRow(Session session, long key) throws SQLException {
return getRow(key);
}
......
......@@ -67,7 +67,7 @@ public class PageDataLeaf extends PageData {
private int memorySize;
private PageDataLeaf(PageScanIndex index, int pageId, Data data) {
private PageDataLeaf(PageDataIndex index, int pageId, Data data) {
super(index, pageId, data);
}
......@@ -79,7 +79,7 @@ public class PageDataLeaf extends PageData {
* @param parentPageId the parent
* @return the page
*/
static PageDataLeaf create(PageScanIndex index, int pageId, int parentPageId) {
static PageDataLeaf create(PageDataIndex index, int pageId, int parentPageId) {
PageDataLeaf p = new PageDataLeaf(index, pageId, index.getPageStore().createData());
p.parentPageId = parentPageId;
p.columnCount = index.getTable().getColumns().length;
......@@ -96,7 +96,7 @@ public class PageDataLeaf extends PageData {
* @param pageId the page id
* @return the page
*/
public static Page read(PageScanIndex index, Data data, int pageId) throws SQLException {
public static Page read(PageDataIndex index, Data data, int pageId) throws SQLException {
PageDataLeaf p = new PageDataLeaf(index, pageId, data);
p.read();
return p;
......@@ -139,9 +139,9 @@ public class PageDataLeaf extends PageData {
int rowLength = getRowLength(row);
int pageSize = index.getPageStore().getPageSize();
int last = entryCount == 0 ? pageSize : offsets[entryCount - 1];
int keyOffsetPairLen = 2 + data.getVarLongLen(row.getPos());
int keyOffsetPairLen = 2 + data.getVarLongLen(row.getKey());
if (entryCount > 0 && last - rowLength < start + keyOffsetPairLen) {
int x = find(row.getPos());
int x = find(row.getKey());
if (entryCount > 1) {
if (entryCount < 5) {
// required, otherwise the index doesn't work correctly
......@@ -164,8 +164,8 @@ public class PageDataLeaf extends PageData {
x = 0;
} else {
readAllRows();
x = find(row.getPos());
if (x < keys.length && keys[x] == row.getPos()) {
x = find(row.getKey());
if (x < keys.length && keys[x] == row.getKey()) {
throw index.getDuplicateKeyException();
}
System.arraycopy(offsets, 0, newOffsets, 0, x);
......@@ -185,7 +185,7 @@ public class PageDataLeaf extends PageData {
entryCount++;
start += keyOffsetPairLen;
newOffsets[x] = offset;
newKeys[x] = row.getPos();
newKeys[x] = row.getKey();
newRows[x] = row;
memorySize += row.getMemorySize();
offsets = newOffsets;
......@@ -270,7 +270,7 @@ public class PageDataLeaf extends PageData {
Cursor find(Session session, long min, long max, boolean multiVersion) {
int x = find(min);
return new PageScanCursor(session, this, x, max, multiVersion);
return new PageDataCursor(session, this, x, max, multiVersion);
}
/**
......@@ -302,12 +302,11 @@ public class PageDataLeaf extends PageData {
PageDataOverflow page = index.getPageOverflow(next);
next = page.readInto(buff);
} while (next != 0);
int checkRequired;
overflowRowSize = pageSize + buff.length();
buff.setPos(0);
r = index.readRow(buff, columnCount);
}
r.setPos((int) keys[at]);
r.setKey(keys[at]);
if (firstOverflowPageId != 0) {
rowRef = new SoftReference<Row>(r);
} else {
......@@ -337,7 +336,7 @@ int checkRequired;
if (entryCount == 0) {
return 0;
}
return getRowAt(entryCount - 1).getPos();
return getRowAt(entryCount - 1).getKey();
}
PageDataLeaf getNextPage() throws SQLException {
......@@ -361,7 +360,7 @@ int checkRequired;
index.getPageStore().updateRecord(overflow, true, null);
}
boolean remove(int key) throws SQLException {
boolean remove(long key) throws SQLException {
int i = find(key);
if (keys[i] != key) {
throw Message.getSQLException(ErrorCode.ROW_NOT_FOUND_WHEN_DELETING_1, index.getSQL() + ": " + key);
......@@ -436,10 +435,10 @@ int checkRequired;
}
readAllRows();
data.reset();
data.checkCapacity(overflowRowSize);
writeHead();
if (firstOverflowPageId != 0) {
data.writeInt(firstOverflowPageId);
data.checkCapacity(overflowRowSize);
}
for (int i = 0; i < entryCount; i++) {
data.writeVarLong(keys[i]);
......
......@@ -48,7 +48,7 @@ public class PageDataNode extends PageData {
*/
private int length;
private PageDataNode(PageScanIndex index, int pageId, Data data) {
private PageDataNode(PageDataIndex index, int pageId, Data data) {
super(index, pageId, data);
}
......@@ -60,7 +60,7 @@ public class PageDataNode extends PageData {
* @param parentPageId the parent
* @return the page
*/
static PageDataNode create(PageScanIndex index, int pageId, int parentPageId) {
static PageDataNode create(PageDataIndex index, int pageId, int parentPageId) {
PageDataNode p = new PageDataNode(index, pageId, index.getPageStore().createData());
p.parentPageId = parentPageId;
p.writeHead();
......@@ -77,7 +77,7 @@ public class PageDataNode extends PageData {
* @param pageId the page id
* @return the page
*/
public static Page read(PageScanIndex index, Data data, int pageId) throws SQLException {
public static Page read(PageDataIndex index, Data data, int pageId) throws SQLException {
PageDataNode p = new PageDataNode(index, pageId, data);
p.read();
return p;
......@@ -129,9 +129,9 @@ public class PageDataNode extends PageData {
}
int addRowTry(Row row) throws SQLException {
int keyOffsetPairLen = 4 + data.getVarLongLen(row.getPos());
int keyOffsetPairLen = 4 + data.getVarLongLen(row.getKey());
while (true) {
int x = find(row.getPos());
int x = find(row.getKey());
PageData page = index.getPage(childPageIds[x], getPos());
int splitPoint = page.addRowTry(row);
if (splitPoint == -1) {
......@@ -140,7 +140,7 @@ public class PageDataNode extends PageData {
if (length + keyOffsetPairLen > index.getPageStore().getPageSize()) {
return entryCount / 2;
}
long pivot = splitPoint == 0 ? row.getPos() : page.getKey(splitPoint - 1);
long pivot = splitPoint == 0 ? row.getKey() : page.getKey(splitPoint - 1);
PageData page2 = page.split(splitPoint);
index.getPageStore().updateRecord(page, true, page.data);
index.getPageStore().updateRecord(page2, true, page2.data);
......@@ -234,7 +234,7 @@ public class PageDataNode extends PageData {
return index.getPage(child, getPos()).getFirstLeaf();
}
boolean remove(int key) throws SQLException {
boolean remove(long key) throws SQLException {
int at = find(key);
// merge is not implemented to allow concurrent usage
// TODO maybe implement merge
......
......@@ -21,9 +21,9 @@ import org.h2.table.TableData;
*/
public class PageDelegateIndex extends PageIndex {
private final PageScanIndex mainIndex;
private final PageDataIndex mainIndex;
public PageDelegateIndex(TableData table, int id, String name, IndexType indexType, PageScanIndex mainIndex, int headPos, Session session) throws SQLException {
public PageDelegateIndex(TableData table, int id, String name, IndexType indexType, PageDataIndex mainIndex, int headPos, Session session) throws SQLException {
IndexColumn[] columns = IndexColumn.wrap(new Column[] { table.getColumn(mainIndex.getMainIndexColumn())});
this.initBaseIndex(table, id, name, columns, indexType);
this.mainIndex = mainIndex;
......
......@@ -36,7 +36,7 @@ class RangeCursor implements Cursor {
return currentRow;
}
public int getPos() {
public long getKey() {
throw Message.throwInternalError();
}
......
......@@ -20,9 +20,9 @@ public interface RowIndex extends Index {
* Get the row with the given key.
*
* @param session the session
* @param key the position
* @param key the unique key
* @return the row
*/
Row getRow(Session session, int key) throws SQLException;
Row getRow(Session session, long key) throws SQLException;
}
......@@ -41,8 +41,8 @@ public class ScanCursor implements Cursor {
return row;
}
public int getPos() {
return row.getPos();
public long getKey() {
return row.getKey();
}
public boolean next() throws SQLException {
......
......@@ -35,7 +35,7 @@ import org.h2.value.ValueLob;
* indexes are defined.
*/
public class ScanIndex extends BaseIndex implements RowIndex {
private int firstFree = -1;
private long firstFree = -1;
private ObjectArray<Row> rows = ObjectArray.newInstance();
private Storage storage;
private TableData tableData;
......@@ -95,11 +95,11 @@ public class ScanIndex extends BaseIndex implements RowIndex {
}
}
public Row getRow(Session session, int key) throws SQLException {
public Row getRow(Session session, long key) throws SQLException {
if (storage != null) {
return (Row) storage.getRecord(session, key);
return (Row) storage.getRecord(session, (int) key);
}
return rows.get(key);
return rows.get((int) key);
}
public void add(Session session, Row row) throws SQLException {
......@@ -121,14 +121,16 @@ public class ScanIndex extends BaseIndex implements RowIndex {
// in-memory
if (firstFree == -1) {
int key = rows.size();
row.setKey(key);
row.setPos(key);
rows.add(row);
} else {
int key = firstFree;
Row free = rows.get(key);
firstFree = free.getPos();
row.setPos(key);
rows.set(key, row);
long key = firstFree;
Row free = rows.get((int) key);
firstFree = free.getKey();
row.setPos((int) key);
row.setKey(key);
rows.set((int) key, row);
}
row.setDeleted(false);
}
......@@ -166,7 +168,7 @@ public class ScanIndex extends BaseIndex implements RowIndex {
public void remove(Session session, Row row) throws SQLException {
if (storage != null) {
storage.removeRecord(session, row.getPos());
storage.removeRecord(session, (int) row.getKey());
if (tableData.getContainsLargeObject()) {
for (int i = 0; i < row.getColumnCount(); i++) {
Value v = row.getValue(i);
......@@ -182,9 +184,10 @@ public class ScanIndex extends BaseIndex implements RowIndex {
firstFree = -1;
} else {
Row free = new Row(null, 0);
free.setPos(firstFree);
int key = row.getPos();
rows.set(key, free);
free.setPos((int) firstFree);
free.setKey(firstFree);
long key = row.getKey();
rows.set((int) key, free);
firstFree = key;
}
}
......@@ -235,18 +238,18 @@ public class ScanIndex extends BaseIndex implements RowIndex {
*/
Row getNextRow(Session session, Row row) throws SQLException {
if (storage == null) {
int key;
long key;
if (row == null) {
key = -1;
} else {
key = row.getPos();
key = row.getKey();
}
while (true) {
key++;
if (key >= rows.size()) {
return null;
}
row = rows.get(key);
row = rows.get((int) key);
if (!row.isEmpty()) {
return row;
}
......
......@@ -36,8 +36,8 @@ public class TreeCursor implements Cursor {
return get();
}
public int getPos() {
return node.row.getPos();
public long getKey() {
return node.row.getKey();
}
public boolean next() throws SQLException {
......
......@@ -38,7 +38,7 @@ public class ViewCursor implements Cursor {
return current;
}
public int getPos() {
public long getKey() {
throw Message.throwInternalError();
}
......
......@@ -115,7 +115,7 @@ public class UndoLogRecord {
break;
case DELETE:
try {
row.setPos(0);
row.setKey(0);
table.addRow(session, row);
// reset session id, otherwise other session think
// that this row was inserted by this session
......
......@@ -7,7 +7,6 @@
package org.h2.result;
import java.sql.SQLException;
import org.h2.store.DataPage;
import org.h2.store.DiskFile;
import org.h2.store.Record;
......@@ -19,6 +18,7 @@ import org.h2.value.Value;
*/
public class Row extends Record implements SearchRow {
public static final int MEMORY_CALCULATE = -1;
private long key;
private final Value[] data;
private final int memory;
private int version;
......@@ -28,8 +28,8 @@ public class Row extends Record implements SearchRow {
this.memory = memory;
}
public void setPosAndVersion(SearchRow row) {
setPos(row.getPos());
public void setKeyAndVersion(SearchRow row) {
setKey(row.getKey());
setVersion(row.getVersion());
}
......@@ -41,6 +41,19 @@ public class Row extends Record implements SearchRow {
this.version = version;
}
public long getKey() {
return key;
}
public void setKey(long key) {
this.key = key;
}
public void setPos(int pos) {
super.setPos(pos);
key = pos;
}
public Value getValue(int i) {
return data[i];
}
......@@ -86,8 +99,8 @@ public class Row extends Record implements SearchRow {
}
public String toString() {
StatementBuilder buff = new StatementBuilder("( /* pos:");
buff.append(getPos());
StatementBuilder buff = new StatementBuilder("( /* key:");
buff.append(getKey());
if (version != 0) {
buff.append(" v:" + version);
}
......
......@@ -55,7 +55,7 @@ public class RowList {
buff.writeByte((byte) 1);
buff.writeInt(r.getMemorySize());
buff.writeInt(r.getColumnCount());
buff.writeInt(r.getPos());
buff.writeLong(r.getKey());
buff.writeInt(r.getVersion());
buff.writeInt(r.isDeleted() ? 1 : 0);
buff.writeInt(r.getSessionId());
......@@ -170,10 +170,10 @@ public class RowList {
}
int memory = buff.readInt();
int columnCount = buff.readInt();
int pos = buff.readInt();
long key = buff.readLong();
int version = buff.readInt();
if (readUncached) {
pos = 0;
key = 0;
}
boolean deleted = buff.readInt() == 1;
int sessionId = buff.readInt();
......@@ -191,14 +191,14 @@ public class RowList {
}
values[i] = v;
}
if (pos != 0 && cache != null) {
CacheObject found = cache.find(pos);
if (key != 0 && cache != null) {
CacheObject found = cache.find((int) key);
if (found != null) {
return (Row) found;
}
}
Row row = new Row(values, memory);
row.setPos(pos);
row.setKey(key);
row.setVersion(version);
row.setDeleted(deleted);
row.setSessionId(sessionId);
......
......@@ -42,27 +42,27 @@ public interface SearchRow {
*
* @param old the other row.
*/
void setPosAndVersion(SearchRow old);
void setKeyAndVersion(SearchRow old);
/**
* Set the position (where the row is stored in the data file).
* Get the version of the row.
*
* @param pos the position.
* @return the version
*/
void setPos(int pos);
int getVersion();
/**
* Get the position of the row in the data file.
* Set the unique key of the row.
*
* @return the position
* @param key the key
*/
int getPos();
void setKey(long key);
/**
* Get the version of the row.
* Get the unique key of the row.
*
* @return the version
* @return the key
*/
int getVersion();
long getKey();
}
......@@ -14,7 +14,7 @@ import org.h2.value.Value;
*/
public class SimpleRow implements SearchRow {
private int pos;
private long key;
private int version;
private Value[] data;
......@@ -26,16 +26,16 @@ public class SimpleRow implements SearchRow {
return data.length;
}
public int getPos() {
return pos;
public long getKey() {
return key;
}
public void setPos(int pos) {
this.pos = pos;
public void setKey(long key) {
this.key = key;
}
public void setPosAndVersion(SearchRow row) {
pos = row.getPos();
public void setKeyAndVersion(SearchRow row) {
key = row.getKey();
version = row.getVersion();
}
......@@ -52,8 +52,8 @@ public class SimpleRow implements SearchRow {
}
public String toString() {
StatementBuilder buff = new StatementBuilder("( /* pos:");
buff.append(getPos());
StatementBuilder buff = new StatementBuilder("( /* key:");
buff.append(getKey());
if (version != 0) {
buff.append(" v:" + version);
}
......
......@@ -13,7 +13,7 @@ import org.h2.value.Value;
*/
public class SimpleRowValue implements SearchRow {
private int pos;
private long key;
private int version;
private int index;
private int virtualColumnCount;
......@@ -23,8 +23,8 @@ public class SimpleRowValue implements SearchRow {
this.virtualColumnCount = columnCount;
}
public void setPosAndVersion(SearchRow row) {
pos = row.getPos();
public void setKeyAndVersion(SearchRow row) {
key = row.getKey();
version = row.getVersion();
}
......@@ -35,15 +35,26 @@ public class SimpleRowValue implements SearchRow {
public int getColumnCount() {
return virtualColumnCount;
}
public int getPos() {
return pos;
return (int) key;
}
public void setPos(int pos) {
this.key = pos;
}
public long getKey() {
return key;
}
public void setKey(long key) {
this.key = key;
}
public Value getValue(int idx) {
return idx == index ? data : null;
}
public void setPos(int pos) {
this.pos = pos;
}
public void setValue(int idx, Value v) {
index = idx;
......@@ -51,7 +62,7 @@ public class SimpleRowValue implements SearchRow {
}
public String toString() {
return "( /* " + pos + " */ " + data.getTraceSQL() + " )";
return "( /* " + key + " */ " + data.getTraceSQL() + " )";
}
}
......@@ -397,7 +397,7 @@ public class PageLog {
* @return the row
*/
public static Row readRow(DataReader in, Data data) throws IOException, SQLException {
long pos = in.readVarLong();
long key = in.readVarLong();
int len = in.readVarInt();
data.reset();
data.checkCapacity(len);
......@@ -409,7 +409,7 @@ public class PageLog {
}
// TODO maybe calculate the memory usage
Row row = new Row(values, 0);
row.setPos((int) pos);
row.setKey(key);
return row;
}
......@@ -462,7 +462,7 @@ public class PageLog {
outBuffer.writeByte((byte) FREE_LOG);
outBuffer.writeVarInt(pages.size());
for (int i = 0; i < pages.size(); i++) {
outBuffer.writeInt(pages.get(i));
outBuffer.writeVarInt(pages.get(i));
}
flushOut();
} catch (IOException e) {
......@@ -566,7 +566,7 @@ public class PageLog {
outBuffer.writeByte((byte) (add ? ADD : REMOVE));
outBuffer.writeVarInt(session.getId());
outBuffer.writeVarInt(tableId);
outBuffer.writeVarLong(row.getPos());
outBuffer.writeVarLong(row.getKey());
if (add) {
outBuffer.writeVarInt(data.length());
outBuffer.checkCapacity(data.length());
......
......@@ -27,7 +27,7 @@ import org.h2.index.PageDataNode;
import org.h2.index.PageDataOverflow;
import org.h2.index.PageDelegateIndex;
import org.h2.index.PageIndex;
import org.h2.index.PageScanIndex;
import org.h2.index.PageDataIndex;
import org.h2.log.InDoubtTransaction;
import org.h2.log.LogSystem;
import org.h2.message.Message;
......@@ -80,9 +80,7 @@ import org.h2.value.ValueString;
public class PageStore implements CacheWriter {
// TODO check commit delay
// TODO record: replace getPos() with long getKey() in page store
// TODO long primary keys don't use delegating index yet (setPos(): int)
// TODO do not trim large databases fully, only up to x seconds
// TODO implement checksum; 0 for empty pages
// TODO undo log: don't store empty space between head and data
......@@ -103,6 +101,7 @@ public class PageStore implements CacheWriter {
// synchronized correctly (on the index?)
// TODO remove trace or use isDebugEnabled
// TODO recover tool: don't re-do uncommitted operations
// TODO recover tool: support syntax to delete a row with a key
// TODO don't store default values (store a special value)
// TODO split files (1 GB max size)
// TODO add a setting (that can be changed at runtime) to call fsync
......@@ -119,6 +118,7 @@ public class PageStore implements CacheWriter {
// remove Record.getByteCount
// remove Database.objectIds
// remove TableData.checkRowCount
// remove Row.setPos
/**
* The smallest possible page size.
......@@ -186,7 +186,7 @@ public class PageStore implements CacheWriter {
private Schema metaSchema;
private TableData metaTable;
private PageScanIndex metaIndex;
private PageDataIndex metaIndex;
private IntIntHashMap metaRootPageId = new IntIntHashMap();
private HashMap<Integer, Index> metaObjects = New.hashMap();
......@@ -456,7 +456,7 @@ public class PageStore implements CacheWriter {
break;
case Page.TYPE_DATA_LEAF: {
int indexId = data.readVarInt();
PageScanIndex index = (PageScanIndex) metaObjects.get(indexId);
PageDataIndex index = (PageDataIndex) metaObjects.get(indexId);
if (index == null) {
Message.throwInternalError("index not found " + indexId);
}
......@@ -465,7 +465,7 @@ public class PageStore implements CacheWriter {
}
case Page.TYPE_DATA_NODE: {
int indexId = data.readVarInt();
PageScanIndex index = (PageScanIndex) metaObjects.get(indexId);
PageDataIndex index = (PageDataIndex) metaObjects.get(indexId);
if (index == null) {
Message.throwInternalError("index not found " + indexId);
}
......@@ -709,12 +709,12 @@ public class PageStore implements CacheWriter {
private PageFreeList getFreeList(int i) throws SQLException {
PageFreeList list = null;
if (i < freeLists.size()) {
list = freeLists.get(i);
if (list != null) {
return list;
}
}
// if (i < freeLists.size()) {
// list = freeLists.get(i);
// if (list != null) {
// return list;
// }
// }
int p = PAGE_ID_FREE_LIST_ROOT + i * freeListPagesPerList;
while (p >= pageCount) {
increaseFileSize(INCREMENT_PAGES);
......@@ -958,7 +958,7 @@ public class PageStore implements CacheWriter {
setReadOnly = true;
}
}
PageScanIndex systemTable = (PageScanIndex) metaObjects.get(0);
PageDataIndex systemTable = (PageDataIndex) metaObjects.get(0);
if (systemTable == null) {
systemTableHeadPos = Index.EMPTY_HEAD;
} else {
......@@ -1060,7 +1060,7 @@ public class PageStore implements CacheWriter {
*/
void redoDelete(int logPos, int tableId, long key) throws SQLException {
Index index = metaObjects.get(tableId);
PageScanIndex scan = (PageScanIndex) index;
PageDataIndex scan = (PageDataIndex) index;
Row row = scan.getRow(key);
redo(logPos, tableId, row, false);
}
......@@ -1123,7 +1123,7 @@ public class PageStore implements CacheWriter {
data.headPos = 0;
data.session = systemSession;
metaTable = new TableData(data);
metaIndex = (PageScanIndex) metaTable.getScanIndex(
metaIndex = (PageDataIndex) metaTable.getScanIndex(
systemSession);
metaObjects.clear();
metaObjects.put(-1, metaIndex);
......@@ -1250,7 +1250,7 @@ public class PageStore implements CacheWriter {
* @param session the session
*/
public void addMeta(PageIndex index, Session session) throws SQLException {
int type = index instanceof PageScanIndex ? META_TYPE_SCAN_INDEX : META_TYPE_BTREE_INDEX;
int type = index instanceof PageDataIndex ? META_TYPE_SCAN_INDEX : META_TYPE_BTREE_INDEX;
IndexColumn[] columns = index.getIndexColumns();
StatementBuilder buff = new StatementBuilder();
for (IndexColumn col : columns) {
......
......@@ -1681,7 +1681,7 @@ public class MetaTable extends Table {
values[i] = v;
}
Row row = new Row(values, 0);
row.setPos(rows.size());
row.setKey(rows.size());
rows.add(row);
}
......
......@@ -29,7 +29,7 @@ import org.h2.index.MultiVersionIndex;
import org.h2.index.NonUniqueHashIndex;
import org.h2.index.PageBtreeIndex;
import org.h2.index.PageDelegateIndex;
import org.h2.index.PageScanIndex;
import org.h2.index.PageDataIndex;
import org.h2.index.RowIndex;
import org.h2.index.ScanIndex;
import org.h2.index.TreeIndex;
......@@ -66,7 +66,7 @@ public class TableData extends Table implements RecordReader {
private final ObjectArray<Index> indexes = ObjectArray.newInstance();
private long lastModificationId;
private boolean containsLargeObject;
private PageScanIndex mainIndex;
private PageDataIndex mainIndex;
public TableData(CreateTableData data) throws SQLException {
super(data.schema, data.id, data.tableName, data.persistIndexes, data.persistData);
......@@ -75,7 +75,7 @@ public class TableData extends Table implements RecordReader {
setColumns(cols);
setTemporary(data.temporary);
if (database.isPageStoreEnabled() && data.persistData && database.isPersistent()) {
mainIndex = new PageScanIndex(this, data.id, IndexColumn.wrap(cols), IndexType.createScan(data.persistData), data.headPos, data.session);
mainIndex = new PageDataIndex(this, data.id, IndexColumn.wrap(cols), IndexType.createScan(data.persistData), data.headPos, data.session);
scanIndex = mainIndex;
} else {
scanIndex = new ScanIndex(this, data.id, IndexColumn.wrap(cols), IndexType.createScan(data.persistData));
......@@ -104,10 +104,10 @@ public class TableData extends Table implements RecordReader {
* Read the given row.
*
* @param session the session
* @param key the position of the row in the file
* @param key unique key
* @return the row
*/
public Row getRow(Session session, int key) throws SQLException {
public Row getRow(Session session, long key) throws SQLException {
return scanIndex.getRow(session, key);
}
......@@ -302,8 +302,7 @@ public class TableData extends Table implements RecordReader {
case Value.BYTE:
case Value.SHORT:
case Value.INT:
int todoPosIsInt;
// case Value.LONG:
case Value.LONG:
break;
default:
return -1;
......
......@@ -82,6 +82,7 @@ public class Recover extends Tool implements DataHandler {
private ObjectArray<MetaRecord> schema;
private HashSet<Integer> objectIdSet;
private HashMap<Integer, String> tableMap;
private HashMap<Integer, Integer> sessionCommit;
private boolean remove;
private long pageDataEmpty;
......@@ -324,7 +325,8 @@ public class Recover extends Tool implements DataHandler {
} else if (fileName.endsWith(Constants.SUFFIX_INDEX_FILE)) {
dumpIndex(fileName);
} else if (fileName.endsWith(Constants.SUFFIX_LOG_FILE)) {
dumpLog(fileName);
dumpLog(fileName, true);
dumpLog(fileName, false);
} else if (fileName.endsWith(Constants.SUFFIX_LOB_FILE)) {
dumpLob(fileName, true);
dumpLob(fileName, false);
......@@ -405,7 +407,7 @@ public class Recover extends Tool implements DataHandler {
}
}
private void writeLogRecord(PrintWriter writer, DataPage s) {
private void writeLogRecord(PrintWriter writer, DataPage s, boolean insert) {
recordLength = s.readInt();
if (recordLength <= 0) {
writeDataError(writer, "recordLength<0", s.getBytes(), blockCount);
......@@ -419,13 +421,24 @@ public class Recover extends Tool implements DataHandler {
return;
}
StringBuilder sb = new StringBuilder();
sb.append("// data: ");
if (insert) {
sb.append("MERGE INTO ").append(storageName).append(" VALUES(");
} else {
sb.append("DELETE FROM ").append(storageName).append(" WHERE ");
}
for (valueId = 0; valueId < recordLength; valueId++) {
try {
Value v = s.readValue();
data[valueId] = v;
if (valueId > 0) {
if (insert) {
sb.append(", ");
} else {
sb.append(" AND ");
}
}
if (!insert) {
sb.append(" C").append(valueId).append('=');
}
sb.append(getSQL(v));
} catch (Exception e) {
......@@ -439,6 +452,10 @@ public class Recover extends Tool implements DataHandler {
continue;
}
}
if (insert) {
sb.append(')');
}
sb.append(';');
writer.println(sb.toString());
writer.flush();
}
......@@ -463,15 +480,22 @@ public class Recover extends Tool implements DataHandler {
lobFilesInDirectories = FileUtils.exists(databaseName + Constants.SUFFIX_LOBS_DIRECTORY);
}
private void dumpLog(String fileName) {
private void dumpLog(String fileName, boolean sessionState) {
PrintWriter writer = null;
FileStore store = null;
try {
if (sessionState) {
sessionCommit = New.hashMap();
}
setDatabaseName(fileName.substring(fileName.length() - Constants.SUFFIX_LOG_FILE.length()));
if (!sessionState) {
writer = getWriter(fileName, ".txt");
}
store = FileStore.open(null, fileName, "r");
long length = store.length();
if (!sessionState) {
writer.println("// length: " + length);
}
int offset = FileStore.HEADER_LENGTH;
int blockSize = LogFile.BLOCK_SIZE;
int blocks = (int) (length / blockSize);
......@@ -482,7 +506,9 @@ public class Recover extends Tool implements DataHandler {
s.reset();
if (length < FileStore.HEADER_LENGTH + len) {
// this is an empty file
if (!sessionState) {
writer.println("// empty file");
}
return;
}
store.seek(offset);
......@@ -490,11 +516,13 @@ public class Recover extends Tool implements DataHandler {
int id = s.readInt();
int firstUncommittedPos = s.readInt();
int firstUnwrittenPos = s.readInt();
int max = (int) (length / blockSize);
if (!sessionState) {
writer.println("// id: " + id);
writer.println("// firstUncommittedPos: " + firstUncommittedPos);
writer.println("// firstUnwrittenPos: " + firstUnwrittenPos);
int max = (int) (length / blockSize);
writer.println("// max: " + max);
}
while (true) {
int pos = (int) (store.getFilePointer() / blockSize);
if ((long) pos * blockSize >= length) {
......@@ -521,16 +549,24 @@ public class Recover extends Tool implements DataHandler {
// Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUE
blocks = MathUtils.convertLongToInt(Math.abs(s.readInt()));
if (blocks == 0) {
if (!sessionState) {
writer.println("// [" + pos + "] blocks: " + blocks + " (end)");
}
break;
}
char type = (char) s.readByte();
int sessionId = s.readInt();
if (type == 'P') {
String transaction = s.readString();
if (!sessionState) {
writer.println("// prepared session: " + sessionId + " tx: " + transaction);
}
} else if (type == 'C') {
if (!sessionState) {
writer.println("// commit session: " + sessionId);
} else {
sessionCommit.put(sessionId, pos);
}
} else {
int storageId = s.readInt();
int recId = s.readInt();
......@@ -546,32 +582,54 @@ public class Recover extends Tool implements DataHandler {
if (sumLength > 0) {
s.read(summary, 0, sumLength);
}
if (!sessionState) {
writer.println("// summary session: "+sessionId+" fileType: " + fileType + " sumLength: " + sumLength);
dumpSummary(writer, summary);
}
break;
}
case 'T':
if (!sessionState) {
writer.println("// truncate session: "+sessionId+" storage: " + storageId + " pos: " + recId + " blockCount: "+blockCount);
if (sessionCommit.get(sessionId) >= pos) {
setStorage(storageId);
writer.println("TRUNCATE TABLE " + storageName + ";");
}
}
break;
case 'I':
if (!sessionState) {
writer.println("// insert session: "+sessionId+" storage: " + storageId + " pos: " + recId + " blockCount: "+blockCount);
if (storageId >= 0) {
writeLogRecord(writer, s);
if (sessionCommit.get(sessionId) >= pos) {
setStorage(storageId);
writeLogRecord(writer, s, true);
}
}
}
break;
case 'D':
if (!sessionState) {
writer.println("// delete session: "+sessionId+" storage: " + storageId + " pos: " + recId + " blockCount: "+blockCount);
if (storageId >= 0) {
writeLogRecord(writer, s);
if (sessionCommit.get(sessionId) >= pos) {
setStorage(storageId);
writeLogRecord(writer, s, false);
}
}
}
break;
default:
if (!sessionState) {
writer.println("// type?: "+type+" session: "+sessionId+" storage: " + storageId + " pos: " + recId + " blockCount: "+blockCount);
}
break;
}
}
}
if (!sessionState) {
writer.close();
}
} catch (Throwable e) {
writeError(writer, e);
} finally {
......@@ -911,13 +969,20 @@ public class Recover extends Tool implements DataHandler {
int pageId = in.readVarInt();
in.readFully(new byte[pageSize], 0, pageSize);
writer.println("-- undo page " + pageId);
} else if (x == PageLog.ADD || x == PageLog.REMOVE) {
} else if (x == PageLog.ADD) {
int sessionId = in.readVarInt();
setStorage(in.readVarInt());
Row row = PageLog.readRow(in, s);
writer.println("-- session " + sessionId +
" table " + storageId +
" " + (x == PageLog.ADD ? "add" : "remove") + " " + row.toString());
" add " + row.toString());
} else if (x == PageLog.REMOVE) {
int sessionId = in.readVarInt();
setStorage(in.readVarInt());
long key = in.readVarLong();
writer.println("-- session " + sessionId +
" table " + storageId +
" remove " + key);
} else if (x == PageLog.TRUNCATE) {
int sessionId = in.readVarInt();
setStorage(in.readVarInt());
......
......@@ -126,6 +126,10 @@ public class ValueInt extends Value {
return value;
}
public long getLong() {
return value;
}
protected int compareSecure(Value o, CompareMode mode) {
ValueInt v = (ValueInt) o;
if (value == v.value) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论