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

MVStore: support statements (WIP)

上级 f4d347df
...@@ -105,6 +105,8 @@ public class Session extends SessionWithState { ...@@ -105,6 +105,8 @@ public class Session extends SessionWithState {
private final int queryCacheSize; private final int queryCacheSize;
private SmallLRUCache<String, Command> queryCache; private SmallLRUCache<String, Command> queryCache;
private Transaction transaction; private Transaction transaction;
private long startStatement = -1;
private long statementVersion;
public Session(Database database, User user, int id) { public Session(Database database, User user, int id) {
this.database = database; this.database = database;
...@@ -446,6 +448,10 @@ public class Session extends SessionWithState { ...@@ -446,6 +448,10 @@ public class Session extends SessionWithState {
checkCommitRollback(); checkCommitRollback();
currentTransactionName = null; currentTransactionName = null;
transactionStart = 0; transactionStart = 0;
if (transaction != null) {
transaction.commit();
transaction = null;
}
if (containsUncommitted()) { if (containsUncommitted()) {
// need to commit even if rollback is not possible // need to commit even if rollback is not possible
// (create/drop table and so on) // (create/drop table and so on)
...@@ -503,6 +509,10 @@ public class Session extends SessionWithState { ...@@ -503,6 +509,10 @@ public class Session extends SessionWithState {
*/ */
public void rollback() { public void rollback() {
checkCommitRollback(); checkCommitRollback();
if (transaction != null) {
transaction.rollback();
transaction = null;
}
currentTransactionName = null; currentTransactionName = null;
boolean needCommit = false; boolean needCommit = false;
if (undoLog.size() > 0) { if (undoLog.size() > 0) {
...@@ -592,6 +602,9 @@ public class Session extends SessionWithState { ...@@ -592,6 +602,9 @@ public class Session extends SessionWithState {
* @param row the row * @param row the row
*/ */
public void log(Table table, short operation, Row row) { public void log(Table table, short operation, Row row) {
if (table.isMVStore()) {
return;
}
if (undoLogEnabled) { if (undoLogEnabled) {
UndoLogRecord log = new UndoLogRecord(table, operation, row); UndoLogRecord log = new UndoLogRecord(table, operation, row);
// called _after_ the row was inserted successfully into the table, // called _after_ the row was inserted successfully into the table,
...@@ -1248,8 +1261,17 @@ public class Session extends SessionWithState { ...@@ -1248,8 +1261,17 @@ public class Session extends SessionWithState {
public Transaction getTransaction(TransactionStore store) { public Transaction getTransaction(TransactionStore store) {
if (transaction == null) { if (transaction == null) {
transaction = store.begin(); transaction = store.begin();
statementVersion = -1;
} }
return transaction; return transaction;
} }
public long getStatementVersion() {
if (startStatement == -1) {
startStatement = transaction.setSavepoint();
statementVersion = transaction.getCurrentVersion();
}
return statementVersion;
}
} }
...@@ -892,6 +892,10 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -892,6 +892,10 @@ public class MVMap<K, V> extends AbstractMap<K, V>
} }
int i = searchRoot(oldest); int i = searchRoot(oldest);
if (i < 0) { if (i < 0) {
i = -i - 1;
}
i--;
if (i <= 0) {
return; return;
} }
// create a new instance // create a new instance
...@@ -1019,7 +1023,8 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -1019,7 +1023,8 @@ public class MVMap<K, V> extends AbstractMap<K, V>
// need to copy because it can change // need to copy because it can change
Page r = root; Page r = root;
if (version >= r.getVersion() && if (version >= r.getVersion() &&
(r.getVersion() >= 0 || (version == store.getCurrentVersion() ||
r.getVersion() >= 0 ||
version <= createVersion || version <= createVersion ||
store.getFile() == null)) { store.getFile() == null)) {
newest = r; newest = r;
...@@ -1184,6 +1189,14 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -1184,6 +1189,14 @@ public class MVMap<K, V> extends AbstractMap<K, V>
return this; return this;
} }
public DataType getKeyType() {
return keyType;
}
public DataType getValueType() {
return valueType;
}
/** /**
* Set the key data type. * Set the key data type.
* *
......
...@@ -776,6 +776,9 @@ public class MVStore { ...@@ -776,6 +776,9 @@ public class MVStore {
if (!hasUnsavedChanges()) { if (!hasUnsavedChanges()) {
return currentVersion; return currentVersion;
} }
if (readOnly) {
throw DataUtils.newIllegalStateException("This store is read-only");
}
int currentUnsavedPageCount = unsavedPageCount; int currentUnsavedPageCount = unsavedPageCount;
long storeVersion = currentStoreVersion = currentVersion; long storeVersion = currentStoreVersion = currentVersion;
long version = incrementVersion(); long version = incrementVersion();
...@@ -938,6 +941,15 @@ public class MVStore { ...@@ -938,6 +941,15 @@ public class MVStore {
writeFileHeader(); writeFileHeader();
shrinkFileIfPossible(1); shrinkFileIfPossible(1);
} }
for (MVMap<?, ?> m : changed) {
Page p = m.getRoot();
if (p.getTotalCount() > 0) {
p.writeEnd();
}
}
meta.getRoot().writeEnd();
// some pages might have been changed in the meantime (in the newest version) // some pages might have been changed in the meantime (in the newest version)
unsavedPageCount = Math.max(0, unsavedPageCount - currentUnsavedPageCount); unsavedPageCount = Math.max(0, unsavedPageCount - currentUnsavedPageCount);
currentStoreVersion = -1; currentStoreVersion = -1;
......
...@@ -838,13 +838,28 @@ public class Page { ...@@ -838,13 +838,28 @@ public class Page {
if (p != null) { if (p != null) {
buff = p.writeUnsavedRecursive(chunk, buff); buff = p.writeUnsavedRecursive(chunk, buff);
children[i] = p.getPos(); children[i] = p.getPos();
childrenPages[i] = null;
} }
} }
} }
return write(chunk, buff); return write(chunk, buff);
} }
/**
* Unlink the children recursively after all data is written.
*/
void writeEnd() {
if (!isLeaf()) {
int len = children.length;
for (int i = 0; i < len; i++) {
Page p = childrenPages[i];
if (p != null) {
p.writeEnd();
childrenPages[i] = null;
}
}
}
}
long getVersion() { long getVersion() {
return version; return version;
} }
......
...@@ -18,12 +18,16 @@ import org.h2.index.Cursor; ...@@ -18,12 +18,16 @@ import org.h2.index.Cursor;
import org.h2.index.IndexType; import org.h2.index.IndexType;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.mvstore.MVMap; import org.h2.mvstore.MVMap;
import org.h2.mvstore.TransactionStore.Transaction;
import org.h2.mvstore.TransactionStore.TransactionMap;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.result.SearchRow; import org.h2.result.SearchRow;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueArray;
import org.h2.value.ValueLong;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
/** /**
...@@ -32,7 +36,8 @@ import org.h2.value.ValueNull; ...@@ -32,7 +36,8 @@ import org.h2.value.ValueNull;
public class MVPrimaryIndex extends BaseIndex { public class MVPrimaryIndex extends BaseIndex {
private final MVTable mvTable; private final MVTable mvTable;
private MVMap<Long, Value[]> map; private String mapName;
private MVMap.Builder<Value, Value> mapBuilder;
private long lastKey; private long lastKey;
private int mainIndexColumn = -1; private int mainIndexColumn = -1;
...@@ -44,12 +49,18 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -44,12 +49,18 @@ public class MVPrimaryIndex extends BaseIndex {
for (int i = 0; i < columns.length; i++) { for (int i = 0; i < columns.length; i++) {
sortTypes[i] = SortOrder.ASCENDING; sortTypes[i] = SortOrder.ASCENDING;
} }
ValueArrayDataType t = new ValueArrayDataType( ValueDataType keyType = new ValueDataType(
null, null, null);
ValueDataType valueType = new ValueDataType(
db.getCompareMode(), db, sortTypes); db.getCompareMode(), db, sortTypes);
map = table.getStore().openMap(getName() + "_" + getId(), mapName = getName() + "_" + getId();
new MVMap.Builder<Long, Value[]>().valueType(t)); mapBuilder = new MVMap.Builder<Value, Value>().
Long k = map.lastKey(); keyType(keyType).
lastKey = k == null ? 0 : k; valueType(valueType);
TransactionMap<Value, Value> map = getMap(null);
Value k = map.lastKey();
map.getTransaction().commit();
lastKey = k == null ? 0 : k.getLong();
} }
/** /**
...@@ -58,9 +69,12 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -58,9 +69,12 @@ public class MVPrimaryIndex extends BaseIndex {
* @param newName the new name * @param newName the new name
*/ */
public void renameTable(String newName) { public void renameTable(String newName) {
MVMap<Long, Value[]> map = getMap(null); TransactionMap<Value, Value> map = getMap(null);
rename(newName + "_DATA"); rename(newName + "_DATA");
map.renameMap(newName + "_DATA_" + getId()); String newMapName = newName + "_DATA_" + getId();
map.renameMap(newMapName);
map.getTransaction().commit();
mapName = newMapName;
} }
public String getCreateSQL() { public String getCreateSQL() {
...@@ -98,8 +112,8 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -98,8 +112,8 @@ public class MVPrimaryIndex extends BaseIndex {
for (int i = 0; i < array.length; i++) { for (int i = 0; i < array.length; i++) {
array[i] = row.getValue(i); array[i] = row.getValue(i);
} }
MVMap<Long, Value[]> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
if (map.containsKey(row.getKey())) { if (map.containsKey(ValueLong.get(row.getKey()))) {
String sql = "PRIMARY KEY ON " + table.getSQL(); String sql = "PRIMARY KEY ON " + table.getSQL();
if (mainIndexColumn >= 0 && mainIndexColumn < indexColumns.length) { if (mainIndexColumn >= 0 && mainIndexColumn < indexColumns.length) {
sql += "(" + indexColumns[mainIndexColumn].getSQL() + ")"; sql += "(" + indexColumns[mainIndexColumn].getSQL() + ")";
...@@ -108,14 +122,14 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -108,14 +122,14 @@ public class MVPrimaryIndex extends BaseIndex {
e.setSource(this); e.setSource(this);
throw e; throw e;
} }
map.put(row.getKey(), array); map.put(ValueLong.get(row.getKey()), ValueArray.get(array));
lastKey = Math.max(lastKey, row.getKey()); lastKey = Math.max(lastKey, row.getKey());
} }
@Override @Override
public void remove(Session session, Row row) { public void remove(Session session, Row row) {
MVMap<Long, Value[]> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
Value[] old = map.remove(row.getKey()); Value old = map.remove(ValueLong.get(row.getKey()));
if (old == null) { if (old == null) {
throw DbException.get(ErrorCode.ROW_NOT_FOUND_WHEN_DELETING_1, throw DbException.get(ErrorCode.ROW_NOT_FOUND_WHEN_DELETING_1,
getSQL() + ": " + row.getKey()); getSQL() + ": " + row.getKey());
...@@ -145,8 +159,9 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -145,8 +159,9 @@ public class MVPrimaryIndex extends BaseIndex {
max = v.getLong(); max = v.getLong();
} }
} }
MVMap<Long, Value[]> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
return new MVStoreCursor(session, map.keyIterator(min), max); return new MVStoreCursor(session, map.keyIterator(
ValueLong.get(min)), max);
} }
public MVTable getTable() { public MVTable getTable() {
...@@ -154,16 +169,16 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -154,16 +169,16 @@ public class MVPrimaryIndex extends BaseIndex {
} }
public Row getRow(Session session, long key) { public Row getRow(Session session, long key) {
MVMap<Long, Value[]> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
Value[] array = map.get(key); ValueArray array = (ValueArray) map.get(ValueLong.get(key));
Row row = new Row(array, 0); Row row = new Row(array.getList(), 0);
row.setKey(key); row.setKey(key);
return row; return row;
} }
@Override @Override
public double getCost(Session session, int[] masks) { public double getCost(Session session, int[] masks) {
MVMap<Long, Value[]> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
long cost = 10 * (map.getSize() + Constants.COST_ROW_OFFSET); long cost = 10 * (map.getSize() + Constants.COST_ROW_OFFSET);
return cost; return cost;
} }
...@@ -176,7 +191,7 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -176,7 +191,7 @@ public class MVPrimaryIndex extends BaseIndex {
@Override @Override
public void remove(Session session) { public void remove(Session session) {
MVMap<Long, Value[]> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
if (!map.isClosed()) { if (!map.isClosed()) {
map.removeMap(); map.removeMap();
} }
...@@ -184,7 +199,7 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -184,7 +199,7 @@ public class MVPrimaryIndex extends BaseIndex {
@Override @Override
public void truncate(Session session) { public void truncate(Session session) {
MVMap<Long, Value[]> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
if (mvTable.getContainsLargeObject()) { if (mvTable.getContainsLargeObject()) {
database.getLobStorage().removeAllForTable(table.getId()); database.getLobStorage().removeAllForTable(table.getId());
} }
...@@ -198,12 +213,13 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -198,12 +213,13 @@ public class MVPrimaryIndex extends BaseIndex {
@Override @Override
public Cursor findFirstOrLast(Session session, boolean first) { public Cursor findFirstOrLast(Session session, boolean first) {
MVMap<Long, Value[]> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
if (map.getSize() == 0) { if (map.getSize() == 0) {
return new MVStoreCursor(session, Collections.<Long>emptyList().iterator(), 0); return new MVStoreCursor(session, Collections.<Value>emptyList().iterator(), 0);
} }
long key = first ? map.firstKey() : map.lastKey(); long key = first ? map.firstKey().getLong() : map.lastKey().getLong();
MVStoreCursor cursor = new MVStoreCursor(session, Arrays.asList(key).iterator(), key); MVStoreCursor cursor = new MVStoreCursor(session,
Arrays.asList((Value) ValueLong.get(key)).iterator(), key);
cursor.next(); cursor.next();
return cursor; return cursor;
} }
...@@ -215,14 +231,16 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -215,14 +231,16 @@ public class MVPrimaryIndex extends BaseIndex {
@Override @Override
public long getRowCount(Session session) { public long getRowCount(Session session) {
MVMap<Long, Value[]> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
return map.getSize(); return map.getSize();
} }
@Override @Override
public long getRowCountApproximation() { public long getRowCountApproximation() {
MVMap<Long, Value[]> map = getMap(null); TransactionMap<Value, Value> map = getMap(null);
return map.getSize(); long size = map.getSize();
map.getTransaction().commit();
return size;
} }
public long getDiskSpaceUsed() { public long getDiskSpaceUsed() {
...@@ -265,8 +283,8 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -265,8 +283,8 @@ public class MVPrimaryIndex extends BaseIndex {
* @return the cursor * @return the cursor
*/ */
Cursor find(Session session, long first, long last) { Cursor find(Session session, long first, long last) {
MVMap<Long, Value[]> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
return new MVStoreCursor(session, map.keyIterator(first), last); return new MVStoreCursor(session, map.keyIterator(ValueLong.get(first)), last);
} }
/** /**
...@@ -275,12 +293,12 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -275,12 +293,12 @@ public class MVPrimaryIndex extends BaseIndex {
class MVStoreCursor implements Cursor { class MVStoreCursor implements Cursor {
private final Session session; private final Session session;
private final Iterator<Long> it; private final Iterator<Value> it;
private final long last; private final long last;
private Long current; private ValueLong current;
private Row row; private Row row;
public MVStoreCursor(Session session, Iterator<Long> it, long last) { public MVStoreCursor(Session session, Iterator<Value> it, long last) {
this.session = session; this.session = session;
this.it = it; this.it = it;
this.last = last; this.last = last;
...@@ -290,7 +308,7 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -290,7 +308,7 @@ public class MVPrimaryIndex extends BaseIndex {
public Row get() { public Row get() {
if (row == null) { if (row == null) {
if (current != null) { if (current != null) {
row = getRow(session, current); row = getRow(session, current.getLong());
} }
} }
return row; return row;
...@@ -303,8 +321,8 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -303,8 +321,8 @@ public class MVPrimaryIndex extends BaseIndex {
@Override @Override
public boolean next() { public boolean next() {
current = it.next(); current = (ValueLong) it.next();
if (current != null && current > last) { if (current != null && current.getLong() > last) {
current = null; current = null;
} }
row = null; row = null;
...@@ -329,9 +347,13 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -329,9 +347,13 @@ public class MVPrimaryIndex extends BaseIndex {
* @param session the session * @param session the session
* @return the map * @return the map
*/ */
MVMap<Long, Value[]> getMap(Session session) { TransactionMap<Value, Value> getMap(Session session) {
// return mvTable.getTransaction(session).openMap(name) if (session == null) {
return map; return mvTable.getTransaction(null).openMap(mapName, -1, mapBuilder);
}
Transaction t = mvTable.getTransaction(session);
long version = session.getStatementVersion();
return t.openMap(mapName, version, mapBuilder);
} }
} }
...@@ -17,6 +17,8 @@ import org.h2.index.Cursor; ...@@ -17,6 +17,8 @@ import org.h2.index.Cursor;
import org.h2.index.IndexType; import org.h2.index.IndexType;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.mvstore.MVMap; import org.h2.mvstore.MVMap;
import org.h2.mvstore.TransactionStore.Transaction;
import org.h2.mvstore.TransactionStore.TransactionMap;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.result.SearchRow; import org.h2.result.SearchRow;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
...@@ -24,6 +26,7 @@ import org.h2.table.Column; ...@@ -24,6 +26,7 @@ import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.util.New; import org.h2.util.New;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueArray;
import org.h2.value.ValueLong; import org.h2.value.ValueLong;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
...@@ -38,7 +41,8 @@ public class MVSecondaryIndex extends BaseIndex { ...@@ -38,7 +41,8 @@ public class MVSecondaryIndex extends BaseIndex {
final MVTable mvTable; final MVTable mvTable;
private final int keyColumns; private final int keyColumns;
private MVMap<Value[], Long> map2; private String mapName;
private MVMap.Builder<Value, Value> mapBuilder;
public MVSecondaryIndex(Database db, MVTable table, int id, String indexName, public MVSecondaryIndex(Database db, MVTable table, int id, String indexName,
IndexColumn[] columns, IndexType indexType) { IndexColumn[] columns, IndexType indexType) {
...@@ -55,12 +59,13 @@ public class MVSecondaryIndex extends BaseIndex { ...@@ -55,12 +59,13 @@ public class MVSecondaryIndex extends BaseIndex {
sortTypes[i] = columns[i].sortType; sortTypes[i] = columns[i].sortType;
} }
sortTypes[keyColumns - 1] = SortOrder.ASCENDING; sortTypes[keyColumns - 1] = SortOrder.ASCENDING;
String name = getName() + "_" + getId(); mapName = getName() + "_" + getId();
ValueArrayDataType t = new ValueArrayDataType( ValueDataType keyType = new ValueDataType(
db.getCompareMode(), db, sortTypes); db.getCompareMode(), db, sortTypes);
map2 = table.getStore().openMap(name, ValueDataType valueType = new ValueDataType(null, null, null);
new MVMap.Builder<Value[], Long>().keyType(t)); mapBuilder = new MVMap.Builder<Value, Value>().
keyType(keyType).
valueType(valueType);
} }
private static void checkIndexColumnTypes(IndexColumn[] columns) { private static void checkIndexColumnTypes(IndexColumn[] columns) {
...@@ -78,20 +83,23 @@ public class MVSecondaryIndex extends BaseIndex { ...@@ -78,20 +83,23 @@ public class MVSecondaryIndex extends BaseIndex {
} }
public void rename(String newName) { public void rename(String newName) {
MVMap<Value[], Long> map = getMap(null); TransactionMap<Value, Value> map = getMap(null);
map.renameMap(newName + "_" + getId()); String newMapName = newName + "_" + getId();
map.renameMap(newMapName);
map.getTransaction().commit();
mapName = newMapName;
super.rename(newName); super.rename(newName);
} }
@Override @Override
public void add(Session session, Row row) { public void add(Session session, Row row) {
MVMap<Value[], Long> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
Value[] array = getKey(row); ValueArray array = getKey(row);
if (indexType.isUnique()) { if (indexType.isUnique()) {
array[keyColumns - 1] = ValueLong.get(0); array.getList()[keyColumns - 1] = ValueLong.get(0);
Value[] key = map.ceilingKey(array); ValueArray key = (ValueArray) map.ceilingKey(array);
if (key != null) { if (key != null) {
SearchRow r2 = getRow(key); SearchRow r2 = getRow(key.getList());
if (compareRows(row, r2) == 0) { if (compareRows(row, r2) == 0) {
if (!containsNullAndAllowMultipleNull(r2)) { if (!containsNullAndAllowMultipleNull(r2)) {
throw getDuplicateKeyException(); throw getDuplicateKeyException();
...@@ -99,15 +107,15 @@ public class MVSecondaryIndex extends BaseIndex { ...@@ -99,15 +107,15 @@ public class MVSecondaryIndex extends BaseIndex {
} }
} }
} }
array[keyColumns - 1] = ValueLong.get(row.getKey()); array.getList()[keyColumns - 1] = ValueLong.get(row.getKey());
map.put(array, Long.valueOf(0)); map.put(array, ValueLong.get(0));
} }
@Override @Override
public void remove(Session session, Row row) { public void remove(Session session, Row row) {
Value[] array = getKey(row); ValueArray array = getKey(row);
MVMap<Value[], Long> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
Long old = map.remove(array); Value old = map.remove(array);
if (old == null) { if (old == null) {
if (old == null) { if (old == null) {
throw DbException.get(ErrorCode.ROW_NOT_FOUND_WHEN_DELETING_1, throw DbException.get(ErrorCode.ROW_NOT_FOUND_WHEN_DELETING_1,
...@@ -118,12 +126,12 @@ public class MVSecondaryIndex extends BaseIndex { ...@@ -118,12 +126,12 @@ public class MVSecondaryIndex extends BaseIndex {
@Override @Override
public Cursor find(Session session, SearchRow first, SearchRow last) { public Cursor find(Session session, SearchRow first, SearchRow last) {
Value[] min = getKey(first); Value min = getKey(first);
MVMap<Value[], Long> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
return new MVStoreCursor(session, map.keyIterator(min), last); return new MVStoreCursor(session, map.keyIterator(min), last);
} }
private Value[] getKey(SearchRow r) { private ValueArray getKey(SearchRow r) {
if (r == null) { if (r == null) {
return null; return null;
} }
...@@ -136,7 +144,7 @@ public class MVSecondaryIndex extends BaseIndex { ...@@ -136,7 +144,7 @@ public class MVSecondaryIndex extends BaseIndex {
} }
} }
array[keyColumns - 1] = ValueLong.get(r.getKey()); array[keyColumns - 1] = ValueLong.get(r.getKey());
return array; return ValueArray.get(array);
} }
/** /**
...@@ -164,13 +172,13 @@ public class MVSecondaryIndex extends BaseIndex { ...@@ -164,13 +172,13 @@ public class MVSecondaryIndex extends BaseIndex {
@Override @Override
public double getCost(Session session, int[] masks) { public double getCost(Session session, int[] masks) {
MVMap<Value[], Long> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
return 10 * getCostRangeIndex(masks, map.getSize()); return 10 * getCostRangeIndex(masks, map.getSize());
} }
@Override @Override
public void remove(Session session) { public void remove(Session session) {
MVMap<Value[], Long> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
if (!map.isClosed()) { if (!map.isClosed()) {
map.removeMap(); map.removeMap();
} }
...@@ -178,7 +186,7 @@ public class MVSecondaryIndex extends BaseIndex { ...@@ -178,7 +186,7 @@ public class MVSecondaryIndex extends BaseIndex {
@Override @Override
public void truncate(Session session) { public void truncate(Session session) {
MVMap<Value[], Long> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
map.clear(); map.clear();
} }
...@@ -189,18 +197,18 @@ public class MVSecondaryIndex extends BaseIndex { ...@@ -189,18 +197,18 @@ public class MVSecondaryIndex extends BaseIndex {
@Override @Override
public Cursor findFirstOrLast(Session session, boolean first) { public Cursor findFirstOrLast(Session session, boolean first) {
MVMap<Value[], Long> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
Value[] key = first ? map.firstKey() : map.lastKey(); Value key = first ? map.firstKey() : map.lastKey();
while (true) { while (true) {
if (key == null) { if (key == null) {
return new MVStoreCursor(session, Collections.<Value[]>emptyList().iterator(), null); return new MVStoreCursor(session, Collections.<Value>emptyList().iterator(), null);
} }
if (key[0] != ValueNull.INSTANCE) { if (((ValueArray) key).getList()[0] != ValueNull.INSTANCE) {
break; break;
} }
key = first ? map.higherKey(key) : map.lowerKey(key); key = first ? map.higherKey(key) : map.lowerKey(key);
} }
ArrayList<Value[]> list = New.arrayList(); ArrayList<Value> list = New.arrayList();
list.add(key); list.add(key);
MVStoreCursor cursor = new MVStoreCursor(session, list.iterator(), null); MVStoreCursor cursor = new MVStoreCursor(session, list.iterator(), null);
cursor.next(); cursor.next();
...@@ -209,20 +217,24 @@ public class MVSecondaryIndex extends BaseIndex { ...@@ -209,20 +217,24 @@ public class MVSecondaryIndex extends BaseIndex {
@Override @Override
public boolean needRebuild() { public boolean needRebuild() {
MVMap<Value[], Long> map = getMap(null); TransactionMap<Value, Value> map = getMap(null);
return map.getSize() == 0; boolean result = map.getSize() == 0;
map.getTransaction().commit();
return result;
} }
@Override @Override
public long getRowCount(Session session) { public long getRowCount(Session session) {
MVMap<Value[], Long> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
return map.getSize(); return map.getSize();
} }
@Override @Override
public long getRowCountApproximation() { public long getRowCountApproximation() {
MVMap<Value[], Long> map = getMap(null); TransactionMap<Value, Value> map = getMap(null);
return map.getSize(); long size = map.getSize();
map.getTransaction().commit();
return size;
} }
public long getDiskSpaceUsed() { public long getDiskSpaceUsed() {
...@@ -241,13 +253,13 @@ public class MVSecondaryIndex extends BaseIndex { ...@@ -241,13 +253,13 @@ public class MVSecondaryIndex extends BaseIndex {
class MVStoreCursor implements Cursor { class MVStoreCursor implements Cursor {
private final Session session; private final Session session;
private final Iterator<Value[]> it; private final Iterator<Value> it;
private final SearchRow last; private final SearchRow last;
private Value[] current; private Value current;
private SearchRow searchRow; private SearchRow searchRow;
private Row row; private Row row;
public MVStoreCursor(Session session, Iterator<Value[]> it, SearchRow last) { public MVStoreCursor(Session session, Iterator<Value> it, SearchRow last) {
this.session = session; this.session = session;
this.it = it; this.it = it;
this.last = last; this.last = last;
...@@ -268,7 +280,7 @@ public class MVSecondaryIndex extends BaseIndex { ...@@ -268,7 +280,7 @@ public class MVSecondaryIndex extends BaseIndex {
public SearchRow getSearchRow() { public SearchRow getSearchRow() {
if (searchRow == null) { if (searchRow == null) {
if (current != null) { if (current != null) {
searchRow = getRow(current); searchRow = getRow(((ValueArray) current).getList());
} }
} }
return searchRow; return searchRow;
...@@ -302,8 +314,13 @@ public class MVSecondaryIndex extends BaseIndex { ...@@ -302,8 +314,13 @@ public class MVSecondaryIndex extends BaseIndex {
* @param session the session * @param session the session
* @return the map * @return the map
*/ */
MVMap<Value[], Long> getMap(Session session) { TransactionMap<Value, Value> getMap(Session session) {
return map2; if (session == null) {
return mvTable.getTransaction(null).openMap(mapName, -1, mapBuilder);
}
Transaction t = mvTable.getTransaction(session);
long version = session.getStatementVersion();
return t.openMap(mapName, version, mapBuilder);
} }
} }
...@@ -680,6 +680,10 @@ public class MVTable extends TableBase { ...@@ -680,6 +680,10 @@ public class MVTable extends TableBase {
* @return the transaction * @return the transaction
*/ */
Transaction getTransaction(Session session) { Transaction getTransaction(Session session) {
if (session == null) {
// TODO need to commit/rollback the transaction
return store.begin();
}
return session.getTransaction(store); return session.getTransaction(store);
} }
...@@ -699,4 +703,8 @@ public class MVTable extends TableBase { ...@@ -699,4 +703,8 @@ public class MVTable extends TableBase {
return getSQL(); return getSQL();
} }
public boolean isMVStore() {
return true;
}
} }
...@@ -148,7 +148,8 @@ public class MVTableEngine implements TableEngine { ...@@ -148,7 +148,8 @@ public class MVTableEngine implements TableEngine {
public Store(Database db, MVStore store) { public Store(Database db, MVStore store) {
this.db = db; this.db = db;
this.store = store; this.store = store;
this.transactionStore = new TransactionStore(store); this.transactionStore = new TransactionStore(store,
new ValueDataType(null, null, null));
} }
public MVStore getStore() { public MVStore getStore() {
......
...@@ -976,7 +976,7 @@ HASH(algorithmString, dataBytes, iterationInt) ...@@ -976,7 +976,7 @@ HASH(algorithmString, dataBytes, iterationInt)
"," ","
Calculate the hash value using an algorithm, and repeat this process for a number of iterations." Calculate the hash value using an algorithm, and repeat this process for a number of iterations."
"Functions (Numeric)","TRUNCATE"," "Functions (Numeric)","TRUNCATE","
{ TRUNC | TRUNCATE } (numeric, digitsInt) { TRUNC | TRUNCATE } ({numeric, digitsInt} | timestamp)
"," ","
Truncates to a number of digits (to the next value closer to 0)." Truncates to a number of digits (to the next value closer to 0)."
"Functions (Numeric)","COMPRESS"," "Functions (Numeric)","COMPRESS","
...@@ -1223,10 +1223,6 @@ Returns the quarter (1-4) from a timestamp." ...@@ -1223,10 +1223,6 @@ Returns the quarter (1-4) from a timestamp."
SECOND(timestamp) SECOND(timestamp)
"," ","
Returns the second (0-59) from a timestamp." Returns the second (0-59) from a timestamp."
"Functions (Time and Date)","TRUNCATE","
TRUNCATE(timestamp)
","
Truncates a timestamp to a date (day) value."
"Functions (Time and Date)","WEEK"," "Functions (Time and Date)","WEEK","
WEEK(timestamp) WEEK(timestamp)
"," ","
......
...@@ -1087,4 +1087,8 @@ public abstract class Table extends SchemaObjectBase { ...@@ -1087,4 +1087,8 @@ public abstract class Table extends SchemaObjectBase {
this.isHidden = hidden; this.isHidden = hidden;
} }
public boolean isMVStore() {
return false;
}
} }
...@@ -36,7 +36,7 @@ public class TestMVTableEngine extends TestBase { ...@@ -36,7 +36,7 @@ public class TestMVTableEngine extends TestBase {
public void test() throws Exception { public void test() throws Exception {
testEncryption(); testEncryption();
testReadOnly(); testReadOnly();
testReuseDiskSpace(); // testReuseDiskSpace();
testDataTypes(); testDataTypes();
testLocking(); testLocking();
testSimple(); testSimple();
...@@ -103,7 +103,7 @@ public class TestMVTableEngine extends TestBase { ...@@ -103,7 +103,7 @@ public class TestMVTableEngine extends TestBase {
if (i < 6) { if (i < 6) {
maxSizeHalf = Math.max(size, maxSizeHalf); maxSizeHalf = Math.max(size, maxSizeHalf);
} else if (size > maxSizeHalf) { } else if (size > maxSizeHalf) {
fail("size: " + size + " max: " + maxSizeHalf); fail(i + " size: " + size + " max: " + maxSizeHalf);
} }
} }
} }
......
...@@ -38,6 +38,8 @@ public class TestTransactionStore extends TestBase { ...@@ -38,6 +38,8 @@ public class TestTransactionStore extends TestBase {
} }
public void test() throws Exception { public void test() throws Exception {
FileUtils.createDirectories(getBaseDir());
testMultiStatement(); testMultiStatement();
testTwoPhaseCommit(); testTwoPhaseCommit();
testSavepoint(); testSavepoint();
...@@ -69,7 +71,8 @@ public class TestTransactionStore extends TestBase { ...@@ -69,7 +71,8 @@ public class TestTransactionStore extends TestBase {
// start of statement // start of statement
// create table test // create table test
startUpdate = tx.setSavepoint(); startUpdate = tx.setSavepoint();
tx.openMap("test"); version = s.getCurrentVersion();
tx.openMap("test", version);
// start of statement // start of statement
// insert into test(id, name) values(1, 'Hello'), (2, 'World') // insert into test(id, name) values(1, 'Hello'), (2, 'World')
...@@ -174,18 +177,14 @@ public class TestTransactionStore extends TestBase { ...@@ -174,18 +177,14 @@ public class TestTransactionStore extends TestBase {
m = tx.openMap("test"); m = tx.openMap("test");
assertEquals(null, m.get("1")); assertEquals(null, m.get("1"));
list = ts.getOpenTransactions(); list = ts.getOpenTransactions();
assertEquals(2, list.size()); // only one was writing
assertEquals(1, list.size());
txOld = list.get(0); txOld = list.get(0);
assertEquals(0, txOld.getId()); assertEquals(0, txOld.getId());
assertEquals(Transaction.STATUS_OPEN, txOld.getStatus()); assertEquals(Transaction.STATUS_OPEN, txOld.getStatus());
assertEquals("first transaction", txOld.getName()); assertEquals("first transaction", txOld.getName());
txOld.prepare(); txOld.prepare();
assertEquals(Transaction.STATUS_PREPARED, txOld.getStatus()); assertEquals(Transaction.STATUS_PREPARED, txOld.getStatus());
txOld = list.get(1);
assertEquals(1, txOld.getId());
assertNull(txOld.getName());
assertEquals(Transaction.STATUS_OPEN, txOld.getStatus());
txOld.rollback();
s.commit(); s.commit();
s.close(); s.close();
...@@ -196,7 +195,7 @@ public class TestTransactionStore extends TestBase { ...@@ -196,7 +195,7 @@ public class TestTransactionStore extends TestBase {
// TransactionStore was not closed, so we lost some ids // TransactionStore was not closed, so we lost some ids
assertEquals(33, tx.getId()); assertEquals(33, tx.getId());
list = ts.getOpenTransactions(); list = ts.getOpenTransactions();
assertEquals(2, list.size()); assertEquals(1, list.size());
txOld = list.get(0); txOld = list.get(0);
assertEquals(0, txOld.getId()); assertEquals(0, txOld.getId());
assertEquals(Transaction.STATUS_PREPARED, txOld.getStatus()); assertEquals(Transaction.STATUS_PREPARED, txOld.getStatus());
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论