提交 47fee83f authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #617 from h2database/reindex_opt

Replace TreeSet with PriorityQueue in MVSecondaryIndex re-build
...@@ -10,7 +10,8 @@ import java.util.Collections; ...@@ -10,7 +10,8 @@ import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.TreeSet; import java.util.PriorityQueue;
import java.util.Queue;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.Session; import org.h2.engine.Session;
...@@ -37,16 +38,14 @@ import org.h2.value.ValueNull; ...@@ -37,16 +38,14 @@ import org.h2.value.ValueNull;
/** /**
* A table stored in a MVStore. * A table stored in a MVStore.
*/ */
public class MVSecondaryIndex extends BaseIndex implements MVIndex { public final class MVSecondaryIndex extends BaseIndex implements MVIndex {
/** /**
* The multi-value table. * The multi-value table.
*/ */
final MVTable mvTable; private final MVTable mvTable;
private final int keyColumns; private final int keyColumns;
private final String mapName; private final TransactionMap<Value,Value> dataMap;
private TransactionMap<Value, Value> dataMap;
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) {
...@@ -58,7 +57,7 @@ public class MVSecondaryIndex extends BaseIndex implements MVIndex { ...@@ -58,7 +57,7 @@ public class MVSecondaryIndex extends BaseIndex implements MVIndex {
// always store the row key in the map key, // always store the row key in the map key,
// even for unique indexes, as some of the index columns could be null // even for unique indexes, as some of the index columns could be null
keyColumns = columns.length + 1; keyColumns = columns.length + 1;
mapName = "index." + getId(); String mapName = "index." + getId();
int[] sortTypes = new int[keyColumns]; int[] sortTypes = new int[keyColumns];
for (int i = 0; i < columns.length; i++) { for (int i = 0; i < columns.length; i++) {
sortTypes[i] = columns[i].sortType; sortTypes[i] = columns[i].sortType;
...@@ -77,84 +76,91 @@ public class MVSecondaryIndex extends BaseIndex implements MVIndex { ...@@ -77,84 +76,91 @@ public class MVSecondaryIndex extends BaseIndex implements MVIndex {
@Override @Override
public void addRowsToBuffer(List<Row> rows, String bufferName) { public void addRowsToBuffer(List<Row> rows, String bufferName) {
MVMap<Value, Value> map = openMap(bufferName); MVMap<ValueArray, Value> map = openMap(bufferName);
for (Row row : rows) { for (Row row : rows) {
ValueArray key = convertToKey(row); ValueArray key = convertToKey(row);
map.put(key, ValueNull.INSTANCE); map.put(key, ValueNull.INSTANCE);
} }
} }
private static final class Source {
private final Iterator<ValueArray> iterator;
private ValueArray currentRowData;
public Source(Iterator<ValueArray> iterator) {
this.iterator = iterator;
this.currentRowData = iterator.next();
}
public boolean hasNext() {
boolean result = iterator.hasNext();
if(result) {
currentRowData = iterator.next();
}
return result;
}
public ValueArray next() {
return currentRowData;
}
public static final class Comparator implements java.util.Comparator<Source> {
private final CompareMode compareMode;
public Comparator(CompareMode compareMode) {
this.compareMode = compareMode;
}
@Override @Override
public void addBufferedRows(List<String> bufferNames) { public int compare(Source one, Source two) {
ArrayList<String> mapNames = New.arrayList(bufferNames); return one.currentRowData.compareTo(two.currentRowData, compareMode);
final CompareMode compareMode = database.getCompareMode();
/**
* A source of values.
*/
class Source implements Comparable<Source> {
Value value;
Iterator<Value> next;
int sourceId;
@Override
public int compareTo(Source o) {
int comp = value.compareTo(o.value, compareMode);
if (comp == 0) {
comp = sourceId - o.sourceId;
} }
return comp;
} }
} }
TreeSet<Source> sources = new TreeSet<>();
for (int i = 0; i < bufferNames.size(); i++) { @Override
MVMap<Value, Value> map = openMap(bufferNames.get(i)); public void addBufferedRows(List<String> bufferNames) {
Iterator<Value> it = map.keyIterator(null); ArrayList<String> mapNames = New.arrayList(bufferNames);
if (it.hasNext()) { CompareMode compareMode = database.getCompareMode();
Source s = new Source(); int buffersCount = bufferNames.size();
s.value = it.next(); Queue<Source> queue = new PriorityQueue<>(buffersCount, new Source.Comparator(compareMode));
s.next = it; for (String bufferName : bufferNames) {
s.sourceId = i; Iterator<ValueArray> iter = openMap(bufferName).keyIterator(null);
sources.add(s); if (iter.hasNext()) {
queue.add(new Source(iter));
} }
} }
try { try {
while (true) { while (!queue.isEmpty()) {
Source s = sources.first(); Source s = queue.remove();
Value v = s.value; ValueArray rowData = s.next();
if (indexType.isUnique()) { if (indexType.isUnique()) {
Value[] array = ((ValueArray) v).getList(); Value[] array = rowData.getList();
// don't change the original value // don't change the original value
array = array.clone(); array = array.clone();
array[keyColumns - 1] = ValueLong.get(Long.MIN_VALUE); array[keyColumns - 1] = ValueLong.get(Long.MIN_VALUE);
ValueArray unique = ValueArray.get(array); ValueArray unique = ValueArray.get(array);
SearchRow row = convertToSearchRow((ValueArray) v); SearchRow row = convertToSearchRow(rowData);
checkUnique(row, dataMap, unique); checkUnique(row, dataMap, unique);
} }
dataMap.putCommitted(v, ValueNull.INSTANCE); dataMap.putCommitted(rowData, ValueNull.INSTANCE);
Iterator<Value> it = s.next; if (s.hasNext()) {
if (!it.hasNext()) { queue.offer(s);
sources.remove(s);
if (sources.size() == 0) {
break;
}
} else {
Value nextValue = it.next();
sources.remove(s);
s.value = nextValue;
sources.add(s);
} }
} }
} finally { } finally {
for (String tempMapName : mapNames) { for (String tempMapName : mapNames) {
MVMap<Value, Value> map = openMap(tempMapName); MVMap<ValueArray, Value> map = openMap(tempMapName);
map.getStore().removeMap(map); map.getStore().removeMap(map);
} }
} }
} }
private MVMap<Value, Value> openMap(String mapName) { private MVMap<ValueArray, Value> openMap(String mapName) {
int[] sortTypes = new int[keyColumns]; int[] sortTypes = new int[keyColumns];
for (int i = 0; i < indexColumns.length; i++) { for (int i = 0; i < indexColumns.length; i++) {
sortTypes[i] = indexColumns[i].sortType; sortTypes[i] = indexColumns[i].sortType;
...@@ -163,9 +169,9 @@ public class MVSecondaryIndex extends BaseIndex implements MVIndex { ...@@ -163,9 +169,9 @@ public class MVSecondaryIndex extends BaseIndex implements MVIndex {
ValueDataType keyType = new ValueDataType( ValueDataType keyType = new ValueDataType(
database.getCompareMode(), database, sortTypes); database.getCompareMode(), database, sortTypes);
ValueDataType valueType = new ValueDataType(null, null, null); ValueDataType valueType = new ValueDataType(null, null, null);
MVMap.Builder<Value, Value> builder = MVMap.Builder<ValueArray, Value> builder =
new MVMap.Builder<Value, Value>().keyType(keyType).valueType(valueType); new MVMap.Builder<ValueArray, Value>().keyType(keyType).valueType(valueType);
MVMap<Value, Value> map = database.getMvStore(). MVMap<ValueArray, Value> map = database.getMvStore().
getStore().openMap(mapName, builder); getStore().openMap(mapName, builder);
if (!keyType.equals(map.getKeyType())) { if (!keyType.equals(map.getKeyType())) {
throw DbException.throwInternalError("Incompatible key type"); throw DbException.throwInternalError("Incompatible key type");
...@@ -332,7 +338,7 @@ public class MVSecondaryIndex extends BaseIndex implements MVIndex { ...@@ -332,7 +338,7 @@ public class MVSecondaryIndex extends BaseIndex implements MVIndex {
* @param key the index key * @param key the index key
* @return the row * @return the row
*/ */
SearchRow convertToSearchRow(ValueArray key) { private SearchRow convertToSearchRow(ValueArray key) {
Value[] array = key.getList(); Value[] array = key.getList();
SearchRow searchRow = mvTable.getTemplateRow(); SearchRow searchRow = mvTable.getTemplateRow();
searchRow.setKey((array[array.length - 1]).getLong()); searchRow.setKey((array[array.length - 1]).getLong());
...@@ -455,7 +461,7 @@ public class MVSecondaryIndex extends BaseIndex implements MVIndex { ...@@ -455,7 +461,7 @@ public class MVSecondaryIndex extends BaseIndex implements MVIndex {
* @param session the session * @param session the session
* @return the map * @return the map
*/ */
TransactionMap<Value, Value> getMap(Session session) { private TransactionMap<Value, Value> getMap(Session session) {
if (session == null) { if (session == null) {
return dataMap; return dataMap;
} }
...@@ -466,7 +472,7 @@ public class MVSecondaryIndex extends BaseIndex implements MVIndex { ...@@ -466,7 +472,7 @@ public class MVSecondaryIndex extends BaseIndex implements MVIndex {
/** /**
* A cursor. * A cursor.
*/ */
class MVStoreCursor implements Cursor { final class MVStoreCursor implements Cursor {
private final Session session; private final Session session;
private final Iterator<Value> it; private final Iterator<Value> it;
...@@ -475,7 +481,7 @@ public class MVSecondaryIndex extends BaseIndex implements MVIndex { ...@@ -475,7 +481,7 @@ public class MVSecondaryIndex extends BaseIndex implements MVIndex {
private SearchRow searchRow; private SearchRow searchRow;
private Row row; private Row row;
public MVStoreCursor(Session session, Iterator<Value> it, SearchRow last) { private 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;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论