This is an automated email from the ASF dual-hosted git repository.
ibessonov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new f0a43c18b7 IGNITE-17339 Hash index storage for page-memory based
engines. (#1055)
f0a43c18b7 is described below
commit f0a43c18b7816c8131e937da92843c7697e7e525
Author: ibessonov <[email protected]>
AuthorDate: Wed Sep 7 10:31:04 2022 +0300
IGNITE-17339 Hash index storage for page-memory based engines. (#1055)
---
.../pagememory/freelist/AbstractFreeList.java | 54 -----
.../internal/pagememory/freelist/FreeList.java | 15 --
.../internal/pagememory/io/AbstractDataPageIo.java | 90 +--------
.../pagememory/persistence/PartitionMeta.java | 90 ++++++++-
.../pagememory/persistence/io/PartitionMetaIo.java | 74 +++++--
.../persistence/PartitionMetaManagerTest.java | 6 +-
.../pagememory/persistence/PartitionMetaTest.java | 2 +-
.../persistence/checkpoint/CheckpointerTest.java | 2 +-
.../internal/storage/index/HashIndexStorage.java | 21 +-
.../chm/TestConcurrentHashMapMvTableStorage.java | 7 +-
.../index/AbstractHashIndexStorageTest.java | 30 ++-
.../pagememory/AbstractPageMemoryTableStorage.java | 29 ++-
.../PersistentPageMemoryTableStorage.java | 218 +++++++++++++++------
.../pagememory/VolatilePageMemoryDataRegion.java | 38 +++-
.../pagememory/VolatilePageMemoryTableStorage.java | 45 ++++-
.../index/freelist/IndexColumnsFreeList.java | 19 +-
.../index/freelist/io/IndexColumnsDataIo.java | 5 +
.../hash/InsertHashIndexRowInvokeClosure.java | 2 +-
.../index/hash/PageMemoryHashIndexStorage.java | 135 +++++++++++++
.../hash/RemoveHashIndexRowInvokeClosure.java | 2 +-
.../storage/pagememory/index/meta/IndexMeta.java | 21 +-
.../pagememory/index/meta/io/IndexMetaIo.java | 10 +-
.../mv/AbstractPageMemoryMvPartitionStorage.java | 136 ++++++++++++-
.../mv/PersistentPageMemoryMvPartitionStorage.java | 52 +++--
.../mv/VolatilePageMemoryMvPartitionStorage.java | 29 +--
.../storage/pagememory/util/TreeCursorAdapter.java | 77 ++++++++
.../PersistentPageMemoryHashIndexStorageTest.java | 105 ++++++++++
.../VolatilePageMemoryHashIndexStorageTest.java | 99 ++++++++++
.../AbstractPageMemoryMvPartitionStorageTest.java | 3 +-
.../storage/rocksdb/RocksDbTableStorage.java | 1 +
30 files changed, 1074 insertions(+), 343 deletions(-)
diff --git
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/freelist/AbstractFreeList.java
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/freelist/AbstractFreeList.java
index 9c104cd9a0..fb342ec503 100644
---
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/freelist/AbstractFreeList.java
+++
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/freelist/AbstractFreeList.java
@@ -83,8 +83,6 @@ public abstract class AbstractFreeList<T extends Storable>
extends PagesList imp
/** Page eviction tracker. */
protected final PageEvictionTracker evictionTracker;
- private final PageHandler<T, Boolean> updateRow = new UpdateRowHandler();
-
/** Write a single row on a single page. */
private final WriteRowHandler writeRowHnd = new WriteRowHandler();
@@ -93,31 +91,6 @@ public abstract class AbstractFreeList<T extends Storable>
extends PagesList imp
private final PageHandler<ReuseBag, Long> rmvRow;
- private final class UpdateRowHandler implements PageHandler<T, Boolean> {
- /** {@inheritDoc} */
- @Override
- public Boolean run(
- int cacheId,
- long pageId,
- long page,
- long pageAddr,
- PageIo iox,
- T row,
- int itemId,
- IoStatisticsHolder statHolder
- ) throws IgniteInternalCheckedException {
- AbstractDataPageIo<T> io = (AbstractDataPageIo<T>) iox;
-
- int rowSize = row.size();
-
- boolean updated = io.updateRow(pageAddr, itemId, pageSize(), null,
row, rowSize);
-
- evictionTracker.touchPage(pageId);
-
- return updated;
- }
- }
-
private class WriteRowHandler implements PageHandler<T, Integer> {
/** {@inheritDoc} */
@Override
@@ -722,33 +695,6 @@ public abstract class AbstractFreeList<T extends Storable>
extends PagesList imp
}
}
- /** {@inheritDoc} */
- @Override
- public boolean updateDataRow(
- long link,
- T row,
- IoStatisticsHolder statHolder
- ) throws IgniteInternalCheckedException {
- assert link != 0;
-
- try {
- long pageId = pageId(link);
- int itemId = itemId(link);
-
- Boolean updated = write(pageId, updateRow, row, itemId, null,
statHolder);
-
- assert updated != null; // Can't fail here.
-
- return updated;
- } catch (AssertionError e) {
- throw corruptedFreeListException(e);
- } catch (IgniteInternalCheckedException | Error e) {
- throw e;
- } catch (Throwable t) {
- throw new CorruptedFreeListException("Failed to update data row",
t, grpId);
- }
- }
-
/** {@inheritDoc} */
@Override
public <S, R> R updateDataRow(
diff --git
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/freelist/FreeList.java
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/freelist/FreeList.java
index 9c582bd503..ecfbeceaf9 100644
---
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/freelist/FreeList.java
+++
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/freelist/FreeList.java
@@ -46,21 +46,6 @@ public interface FreeList<T extends Storable> {
*/
void insertDataRows(Collection<T> rows, IoStatisticsHolder statHolder)
throws IgniteInternalCheckedException;
- /**
- * Makes an in-place update of a row identified by the link.
- * This has a couple of restrictions:
- * 1. The size of the payload must not change, otherwise the page will be
broken (and next insertion will fail due
- * to assertion failure).
- * 2. The row cannot be fragmented. If it is, this will return {@code
false} without doing anything.
- *
- * @param link Row link.
- * @param row New row data.
- * @param statHolder Statistics holder to track IO operations.
- * @return {@code True} if was able to update row.
- * @throws IgniteInternalCheckedException If failed.
- */
- boolean updateDataRow(long link, T row, IoStatisticsHolder statHolder)
throws IgniteInternalCheckedException;
-
/**
* Updates a row by link.
*
diff --git
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/io/AbstractDataPageIo.java
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/io/AbstractDataPageIo.java
index ac7b967b7f..01bb2e1a80 100644
---
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/io/AbstractDataPageIo.java
+++
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/io/AbstractDataPageIo.java
@@ -31,7 +31,6 @@ import org.apache.ignite.internal.pagememory.util.PageIdUtils;
import org.apache.ignite.internal.pagememory.util.PageUtils;
import org.apache.ignite.lang.IgniteInternalCheckedException;
import org.apache.ignite.lang.IgniteStringBuilder;
-import org.jetbrains.annotations.Nullable;
/**
* Data pages IO.
@@ -907,45 +906,6 @@ public abstract class AbstractDataPageIo<T extends
Storable> extends PageIo {
return -1;
}
- /**
- * Updates a row.
- *
- * @param pageAddr Page address.
- * @param itemId Item ID.
- * @param pageSize Page size.
- * @param payload Row data.
- * @param row Row.
- * @param rowSize Row size.
- * @return {@code True} if entry is not fragmented.
- * @throws IgniteInternalCheckedException If failed.
- */
- public boolean updateRow(
- final long pageAddr,
- int itemId,
- int pageSize,
- @Nullable byte[] payload,
- @Nullable T row,
- final int rowSize
- ) throws IgniteInternalCheckedException {
- assert checkIndex(itemId) : itemId;
- assert row != null ^ payload != null;
- assertPageType(pageAddr);
-
- final int dataOff = getDataOffset(pageAddr, itemId, pageSize);
-
- if (isFragmented(pageAddr, dataOff)) {
- return false;
- }
-
- if (row != null) {
- writeRowData(pageAddr, dataOff, rowSize, row, false);
- } else {
- writeRowData(pageAddr, dataOff, payload);
- }
-
- return true;
- }
-
/**
* Removes a row.
*
@@ -1083,6 +1043,7 @@ public abstract class AbstractDataPageIo<T extends
Storable> extends PageIo {
final int pageSize
) throws IgniteInternalCheckedException {
assert rowSize <= getFreeSpace(pageAddr) : "can't call addRow if not
enough space for the whole row";
+ assert rowSize <= 0xFFFF : "Row size is too big: " + rowSize;
assertPageType(pageAddr);
int fullEntrySize = getPageEntrySize(rowSize, SHOW_PAYLOAD_LEN |
SHOW_ITEM);
@@ -1099,35 +1060,6 @@ public abstract class AbstractDataPageIo<T extends
Storable> extends PageIo {
setLinkByPageId(row, pageId, itemId);
}
- /**
- * Adds row to this data page and sets respective link to the given row
object.
- *
- * @param pageAddr Page address.
- * @param payload Payload.
- * @param pageSize Page size.
- * @return Item ID.
- * @throws IgniteInternalCheckedException If failed.
- */
- public int addRow(
- long pageAddr,
- byte[] payload,
- int pageSize
- ) throws IgniteInternalCheckedException {
- assert payload.length <= getFreeSpace(pageAddr) : "can't call addRow
if not enough space for the whole row";
- assertPageType(pageAddr);
-
- int fullEntrySize = getPageEntrySize(payload.length, SHOW_PAYLOAD_LEN
| SHOW_ITEM);
-
- int directCnt = getDirectCount(pageAddr);
- int indirectCnt = getIndirectCount(pageAddr);
-
- int dataOff = getDataOffsetForWrite(pageAddr, fullEntrySize,
directCnt, indirectCnt, pageSize);
-
- writeRowData(pageAddr, dataOff, payload);
-
- return addItem(pageAddr, fullEntrySize, directCnt, indirectCnt,
dataOff, pageSize);
- }
-
/**
* Compacts a page if needed.
*
@@ -1506,26 +1438,6 @@ public abstract class AbstractDataPageIo<T extends
Storable> extends PageIo {
boolean newRow
) throws IgniteInternalCheckedException;
- /**
- * Writes a row.
- *
- * @param pageAddr Page address.
- * @param dataOff Data offset.
- * @param payload Payload
- */
- protected void writeRowData(
- long pageAddr,
- int dataOff,
- byte[] payload
- ) {
- assertPageType(pageAddr);
-
- PageUtils.putShort(pageAddr, dataOff, (short) payload.length);
- dataOff += 2;
-
- PageUtils.putBytes(pageAddr, dataOff, payload);
- }
-
/**
* Defines closure interface for applying computations to data page items.
*
diff --git
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PartitionMeta.java
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PartitionMeta.java
index c1234377fb..bb722b7edc 100644
---
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PartitionMeta.java
+++
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PartitionMeta.java
@@ -26,6 +26,7 @@ import java.util.UUID;
import org.apache.ignite.internal.pagememory.persistence.io.PartitionMetaIo;
import org.apache.ignite.internal.tostring.S;
import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.TestOnly;
/**
* Partition meta information.
@@ -47,9 +48,13 @@ public class PartitionMeta {
private volatile long lastAppliedIndex;
+ private volatile long rowVersionFreeListRootPageId;
+
+ private volatile long indexColumnsFreeListRootPageId;
+
private volatile long versionChainTreeRootPageId;
- private volatile long rowVersionFreeListRootPageId;
+ private volatile long indexTreeMetaPageId;
private volatile int pageCount;
@@ -58,6 +63,7 @@ public class PartitionMeta {
/**
* Default constructor.
*/
+ @TestOnly
public PartitionMeta() {
metaSnapshot = new PartitionMetaSnapshot(null, this);
}
@@ -67,20 +73,24 @@ public class PartitionMeta {
*
* @param checkpointId Checkpoint ID.
* @param lastAppliedIndex Last applied index value.
- * @param versionChainTreeRootPageId Version chain tree root page ID.
* @param rowVersionFreeListRootPageId Row version free list root page ID.
+ * @param versionChainTreeRootPageId Version chain tree root page ID.
* @param pageCount Count of pages in the partition.
*/
public PartitionMeta(
@Nullable UUID checkpointId,
long lastAppliedIndex,
- long versionChainTreeRootPageId,
long rowVersionFreeListRootPageId,
+ long indexColumnsFreeListRootPageId,
+ long versionChainTreeRootPageId,
+ long indexTreeMetaPageId,
int pageCount
) {
this.lastAppliedIndex = lastAppliedIndex;
- this.versionChainTreeRootPageId = versionChainTreeRootPageId;
this.rowVersionFreeListRootPageId = rowVersionFreeListRootPageId;
+ this.indexColumnsFreeListRootPageId = indexColumnsFreeListRootPageId;
+ this.versionChainTreeRootPageId = versionChainTreeRootPageId;
+ this.indexTreeMetaPageId = indexTreeMetaPageId;
this.pageCount = pageCount;
metaSnapshot = new PartitionMetaSnapshot(checkpointId, this);
@@ -97,8 +107,10 @@ public class PartitionMeta {
this(
checkpointId,
metaIo.getLastAppliedIndex(pageAddr),
- metaIo.getVersionChainTreeRootPageId(pageAddr),
metaIo.getRowVersionFreeListRootPageId(pageAddr),
+ metaIo.getIndexColumnsFreeListRootPageId(pageAddr),
+ metaIo.getVersionChainTreeRootPageId(pageAddr),
+ metaIo.getIndexTreeMetaPageId(pageAddr),
metaIo.getPageCount(pageAddr)
);
}
@@ -160,6 +172,44 @@ public class PartitionMeta {
this.rowVersionFreeListRootPageId = rowVersionFreeListRootPageId;
}
+ /**
+ * Returns index columns free list root page id.
+ */
+ public long indexColumnsFreeListRootPageId() {
+ return indexColumnsFreeListRootPageId;
+ }
+
+ /**
+ * Sets an index columns free list root page id.
+ *
+ * @param checkpointId Checkpoint id.
+ * @param indexColumnsFreeListRootPageId Index columns free list root page
id.
+ */
+ public void indexColumnsFreeListRootPageId(@Nullable UUID checkpointId,
long indexColumnsFreeListRootPageId) {
+ updateSnapshot(checkpointId);
+
+ this.indexColumnsFreeListRootPageId = indexColumnsFreeListRootPageId;
+ }
+
+ /**
+ * Returns index meta tree meta page id.
+ */
+ public long indexTreeMetaPageId() {
+ return indexTreeMetaPageId;
+ }
+
+ /**
+ * Sets an index meta tree meta page id.
+ *
+ * @param checkpointId Checkpoint id.
+ * @param indexTreeMetaPageId Index meta tree meta page id.
+ */
+ public void indexTreeMetaPageId(@Nullable UUID checkpointId, long
indexTreeMetaPageId) {
+ updateSnapshot(checkpointId);
+
+ this.indexTreeMetaPageId = indexTreeMetaPageId;
+ }
+
/**
* Returns count of pages in the partition.
*/
@@ -219,6 +269,10 @@ public class PartitionMeta {
private final long rowVersionFreeListRootPageId;
+ private final long indexColumnsFreeListRootPageId;
+
+ private final long indexTreeMetaPageId;
+
private final int pageCount;
/**
@@ -229,10 +283,12 @@ public class PartitionMeta {
*/
private PartitionMetaSnapshot(@Nullable UUID checkpointId,
PartitionMeta partitionMeta) {
this.checkpointId = checkpointId;
- this.lastAppliedIndex = partitionMeta.lastAppliedIndex;
- this.versionChainTreeRootPageId =
partitionMeta.versionChainTreeRootPageId;
- this.rowVersionFreeListRootPageId =
partitionMeta.rowVersionFreeListRootPageId;
- this.pageCount = partitionMeta.pageCount;
+ lastAppliedIndex = partitionMeta.lastAppliedIndex;
+ versionChainTreeRootPageId =
partitionMeta.versionChainTreeRootPageId;
+ rowVersionFreeListRootPageId =
partitionMeta.rowVersionFreeListRootPageId;
+ indexColumnsFreeListRootPageId =
partitionMeta.indexColumnsFreeListRootPageId;
+ indexTreeMetaPageId = partitionMeta.indexTreeMetaPageId;
+ pageCount = partitionMeta.pageCount;
}
/**
@@ -256,6 +312,20 @@ public class PartitionMeta {
return rowVersionFreeListRootPageId;
}
+ /**
+ * Returns index columns free list root page ID.
+ */
+ public long indexColumnsFreeListRootPageId() {
+ return indexColumnsFreeListRootPageId;
+ }
+
+ /**
+ * Returns index meta tree meta page ID.
+ */
+ public long indexTreeMetaPageId() {
+ return indexTreeMetaPageId;
+ }
+
/**
* Returns count of pages in the partition.
*/
@@ -272,8 +342,10 @@ public class PartitionMeta {
void writeTo(PartitionMetaIo metaIo, long pageAddr) {
metaIo.setLastAppliedIndex(pageAddr, lastAppliedIndex);
metaIo.setVersionChainTreeRootPageId(pageAddr,
versionChainTreeRootPageId);
+ metaIo.setIndexColumnsFreeListRootPageId(pageAddr,
indexColumnsFreeListRootPageId);
metaIo.setRowVersionFreeListRootPageId(pageAddr,
rowVersionFreeListRootPageId);
metaIo.setPageCount(pageAddr, pageCount);
+ metaIo.setIndexTreeMetaPageId(pageAddr, indexTreeMetaPageId);
}
/** {@inheritDoc} */
diff --git
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/io/PartitionMetaIo.java
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/io/PartitionMetaIo.java
index d2cf8e3af1..e0e8e8bd77 100644
---
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/io/PartitionMetaIo.java
+++
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/io/PartitionMetaIo.java
@@ -33,11 +33,15 @@ import org.apache.ignite.lang.IgniteStringBuilder;
public class PartitionMetaIo extends PageIo {
private static final int LAST_APPLIED_INDEX_OFF = COMMON_HEADER_END;
- private static final int VERSION_CHAIN_TREE_ROOT_PAGE_ID_OFF =
LAST_APPLIED_INDEX_OFF + Long.BYTES;
+ private static final int ROW_VERSION_FREE_LIST_ROOT_PAGE_ID_OFF =
LAST_APPLIED_INDEX_OFF + Long.BYTES;
- private static final int ROW_VERSION_FREE_LIST_ROOT_PAGE_ID_OFF =
VERSION_CHAIN_TREE_ROOT_PAGE_ID_OFF + Long.BYTES;
+ private static final int INDEX_COLUMNS_FREE_LIST_ROOT_PAGE_ID_OFF =
ROW_VERSION_FREE_LIST_ROOT_PAGE_ID_OFF + Long.BYTES;
- private static final int PAGE_COUNT_OFF =
ROW_VERSION_FREE_LIST_ROOT_PAGE_ID_OFF + Long.BYTES;
+ private static final int VERSION_CHAIN_TREE_ROOT_PAGE_ID_OFF =
INDEX_COLUMNS_FREE_LIST_ROOT_PAGE_ID_OFF + Long.BYTES;
+
+ public static final int INDEX_TREE_META_PAGE_ID_OFF =
VERSION_CHAIN_TREE_ROOT_PAGE_ID_OFF + Long.BYTES;
+
+ private static final int PAGE_COUNT_OFF = INDEX_TREE_META_PAGE_ID_OFF +
Long.BYTES;
/** Page IO type. */
public static final short T_TABLE_PARTITION_META_IO = 7;
@@ -60,8 +64,10 @@ public class PartitionMetaIo extends PageIo {
super.initNewPage(pageAddr, pageId, pageSize);
setLastAppliedIndex(pageAddr, 0);
- setVersionChainTreeRootPageId(pageAddr, 0);
setRowVersionFreeListRootPageId(pageAddr, 0);
+ setIndexColumnsFreeListRootPageId(pageAddr, 0);
+ setVersionChainTreeRootPageId(pageAddr, 0);
+ setIndexTreeMetaPageId(pageAddr, 0);
setPageCount(pageAddr, 0);
}
@@ -86,6 +92,48 @@ public class PartitionMetaIo extends PageIo {
return getLong(pageAddr, LAST_APPLIED_INDEX_OFF);
}
+ /**
+ * Sets row version free list root page ID.
+ *
+ * @param pageAddr Page address.
+ * @param pageId Row version free list root page ID.
+ */
+ public void setRowVersionFreeListRootPageId(long pageAddr, long pageId) {
+ assertPageType(pageAddr);
+
+ putLong(pageAddr, ROW_VERSION_FREE_LIST_ROOT_PAGE_ID_OFF, pageId);
+ }
+
+ /**
+ * Returns row version free list root page ID.
+ *
+ * @param pageAddr Page address.
+ */
+ public long getRowVersionFreeListRootPageId(long pageAddr) {
+ return getLong(pageAddr, ROW_VERSION_FREE_LIST_ROOT_PAGE_ID_OFF);
+ }
+
+ /**
+ * Sets an index columns free list root page id.
+ *
+ * @param pageAddr Page address.
+ * @param pageId Root page id.
+ */
+ public void setIndexColumnsFreeListRootPageId(long pageAddr, long pageId) {
+ assertPageType(pageAddr);
+
+ putLong(pageAddr, INDEX_COLUMNS_FREE_LIST_ROOT_PAGE_ID_OFF, pageId);
+ }
+
+ /**
+ * Returns an index columns free list root page id.
+ *
+ * @param pageAddr Page address.
+ */
+ public long getIndexColumnsFreeListRootPageId(long pageAddr) {
+ return getLong(pageAddr, INDEX_COLUMNS_FREE_LIST_ROOT_PAGE_ID_OFF);
+ }
+
/**
* Sets version chain tree root page ID.
*
@@ -108,24 +156,24 @@ public class PartitionMetaIo extends PageIo {
}
/**
- * Sets row version free list root page ID.
+ * Sets an index meta tree meta page id.
*
* @param pageAddr Page address.
- * @param pageId Row version free list root page ID.
+ * @param pageId Meta page id.
*/
- public void setRowVersionFreeListRootPageId(long pageAddr, long pageId) {
+ public void setIndexTreeMetaPageId(long pageAddr, long pageId) {
assertPageType(pageAddr);
- putLong(pageAddr, ROW_VERSION_FREE_LIST_ROOT_PAGE_ID_OFF, pageId);
+ putLong(pageAddr, INDEX_TREE_META_PAGE_ID_OFF, pageId);
}
/**
- * Returns row version free list root page ID.
+ * Returns an index meta tree meta page id.
*
* @param pageAddr Page address.
*/
- public long getRowVersionFreeListRootPageId(long pageAddr) {
- return getLong(pageAddr, ROW_VERSION_FREE_LIST_ROOT_PAGE_ID_OFF);
+ public long getIndexTreeMetaPageId(long pageAddr) {
+ return getLong(pageAddr, INDEX_TREE_META_PAGE_ID_OFF);
}
/**
@@ -154,8 +202,10 @@ public class PartitionMetaIo extends PageIo {
protected void printPage(long addr, int pageSize, IgniteStringBuilder sb) {
sb.app("TablePartitionMeta [").nl()
.app("lastAppliedIndex=").app(getLastAppliedIndex(addr)).nl()
- .app(",
versionChainTreeRootPageId=").appendHex(getVersionChainTreeRootPageId(addr)).nl()
.app(",
rowVersionFreeListRootPageId=").appendHex(getRowVersionFreeListRootPageId(addr)).nl()
+ .app(",
indexColumnsFreeListRootPageId(=").appendHex(getIndexColumnsFreeListRootPageId(addr)).nl()
+ .app(",
versionChainTreeRootPageId=").appendHex(getVersionChainTreeRootPageId(addr)).nl()
+ .app(",
indexTreeMetaPageId=").appendHex(getIndexTreeMetaPageId(addr)).nl()
.app(", pageCount=").app(getPageCount(addr)).nl()
.app(']');
}
diff --git
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/PartitionMetaManagerTest.java
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/PartitionMetaManagerTest.java
index 79a6db2612..5da0648fff 100644
---
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/PartitionMetaManagerTest.java
+++
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/PartitionMetaManagerTest.java
@@ -133,7 +133,7 @@ public class PartitionMetaManagerTest {
try (FilePageStore filePageStore =
createFilePageStore(testFilePath)) {
manager.writeMetaToBuffer(
partId,
- new PartitionMeta(UUID.randomUUID(), 100, 300, 900,
4).metaSnapshot(null),
+ new PartitionMeta(UUID.randomUUID(), 100, 900, 500,
300, 200, 4).metaSnapshot(null),
buffer.rewind()
);
@@ -149,8 +149,10 @@ public class PartitionMetaManagerTest {
PartitionMeta meta = manager.readOrCreateMeta(null, partId,
filePageStore);
assertEquals(100, meta.lastAppliedIndex());
- assertEquals(300, meta.versionChainTreeRootPageId());
assertEquals(900, meta.rowVersionFreeListRootPageId());
+ assertEquals(500, meta.indexColumnsFreeListRootPageId());
+ assertEquals(300, meta.versionChainTreeRootPageId());
+ assertEquals(200, meta.indexTreeMetaPageId());
assertEquals(4, meta.pageCount());
}
diff --git
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/PartitionMetaTest.java
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/PartitionMetaTest.java
index cf203d6e36..7d12c08e57 100644
---
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/PartitionMetaTest.java
+++
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/PartitionMetaTest.java
@@ -99,7 +99,7 @@ public class PartitionMetaTest {
void testSnapshot() {
UUID checkpointId = null;
- PartitionMeta meta = new PartitionMeta(checkpointId, 0, 0, 0, 0);
+ PartitionMeta meta = new PartitionMeta(checkpointId, 0, 0, 0, 0, 0, 0);
checkSnapshot(meta.metaSnapshot(checkpointId), 0, 0, 0, 0);
checkSnapshot(meta.metaSnapshot(checkpointId = UUID.randomUUID()), 0,
0, 0, 0);
diff --git
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/checkpoint/CheckpointerTest.java
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/checkpoint/CheckpointerTest.java
index 466ec92408..f3874ad9b0 100644
---
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/checkpoint/CheckpointerTest.java
+++
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/checkpoint/CheckpointerTest.java
@@ -356,7 +356,7 @@ public class CheckpointerTest {
partitionMetaManager.addMeta(
new GroupPartitionId(0, 0),
- new PartitionMeta(null, 0, 0, 0, 3)
+ new PartitionMeta(null, 0, 0, 0, 0, 0, 3)
);
FilePageStore filePageStore = mock(FilePageStore.class);
diff --git
a/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/index/HashIndexStorage.java
b/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/index/HashIndexStorage.java
index 64f6a209e3..be48a8e027 100644
---
a/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/index/HashIndexStorage.java
+++
b/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/index/HashIndexStorage.java
@@ -17,8 +17,11 @@
package org.apache.ignite.internal.storage.index;
+import java.util.UUID;
import org.apache.ignite.internal.schema.BinaryTuple;
import org.apache.ignite.internal.storage.RowId;
+import org.apache.ignite.internal.storage.StorageException;
+import org.apache.ignite.internal.storage.engine.MvTableStorage;
import org.apache.ignite.internal.util.Cursor;
/**
@@ -37,16 +40,20 @@ public interface HashIndexStorage {
/**
* Returns a cursor over {@code RowId}s associated with the given index
key.
+ *
+ * @throws StorageException If failed to read data.
*/
- Cursor<RowId> get(BinaryTuple key);
+ Cursor<RowId> get(BinaryTuple key) throws StorageException;
/**
* Adds the given index row to the index.
*
* <p>Usage note: this method <b>must</b> always be called inside the
corresponding partition's
* {@link
org.apache.ignite.internal.storage.MvPartitionStorage#runConsistently} closure.
+ *
+ * @throws StorageException If failed to put data.
*/
- void put(IndexRow row);
+ void put(IndexRow row) throws StorageException;
/**
* Removes the given row from the index.
@@ -55,11 +62,17 @@ public interface HashIndexStorage {
*
* <p>Usage note: this method <b>must</b> always be called inside the
corresponding partition's
* {@link
org.apache.ignite.internal.storage.MvPartitionStorage#runConsistently} closure.
+ *
+ * @throws StorageException If failed to remove data.
*/
- void remove(IndexRow row);
+ void remove(IndexRow row) throws StorageException;
/**
* Removes all data from this index.
+ *
+ * @throws StorageException If failed to destory index.
+ * @deprecated IGNITE-17626 Synchronous API should be removed. {@link
MvTableStorage#destroyIndex(UUID)} must be the only public option.
*/
- void destroy();
+ @Deprecated
+ void destroy() throws StorageException;
}
diff --git
a/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/chm/TestConcurrentHashMapMvTableStorage.java
b/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/chm/TestConcurrentHashMapMvTableStorage.java
index fa877e67a3..241026779b 100644
---
a/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/chm/TestConcurrentHashMapMvTableStorage.java
+++
b/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/chm/TestConcurrentHashMapMvTableStorage.java
@@ -137,7 +137,12 @@ public class TestConcurrentHashMapMvTableStorage
implements MvTableStorage {
@Override
public CompletableFuture<Void> destroyIndex(UUID indexId) {
sortedIndicesById.remove(indexId);
- hashIndicesById.remove(indexId);
+
+ HashIndices hashIndex = hashIndicesById.remove(indexId);
+
+ if (hashIndex != null) {
+
hashIndex.storageByPartitionId.values().forEach(HashIndexStorage::destroy);
+ }
return CompletableFuture.completedFuture(null);
}
diff --git
a/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/index/AbstractHashIndexStorageTest.java
b/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/index/AbstractHashIndexStorageTest.java
index 6e33696ee5..11f95d5106 100644
---
a/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/index/AbstractHashIndexStorageTest.java
+++
b/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/index/AbstractHashIndexStorageTest.java
@@ -55,6 +55,8 @@ public abstract class AbstractHashIndexStorageTest {
private static final String STR_COLUMN_NAME = "strVal";
+ private MvTableStorage tableStorage;
+
private MvPartitionStorage partitionStorage;
private HashIndexStorage indexStorage;
@@ -62,6 +64,8 @@ public abstract class AbstractHashIndexStorageTest {
private BinaryTupleRowSerializer serializer;
protected void initialize(MvTableStorage tableStorage) {
+ this.tableStorage = tableStorage;
+
createTestTable(tableStorage.configuration());
this.partitionStorage =
tableStorage.getOrCreateMvPartition(TEST_PARTITION);
@@ -114,7 +118,7 @@ public abstract class AbstractHashIndexStorageTest {
* Tests the {@link HashIndexStorage#get} method.
*/
@Test
- void testGet() {
+ public void testGet() {
// First two rows have the same index key, but different row IDs
IndexRow row1 = serializer.serializeRow(new Object[]{ 1, "foo" }, new
RowId(TEST_PARTITION));
IndexRow row2 = serializer.serializeRow(new Object[]{ 1, "foo" }, new
RowId(TEST_PARTITION));
@@ -137,7 +141,7 @@ public abstract class AbstractHashIndexStorageTest {
* Tests that {@link HashIndexStorage#put} does not create row ID
duplicates.
*/
@Test
- void testPutIdempotence() {
+ public void testPutIdempotence() {
IndexRow row = serializer.serializeRow(new Object[]{ 1, "foo" }, new
RowId(TEST_PARTITION));
put(row);
@@ -150,7 +154,7 @@ public abstract class AbstractHashIndexStorageTest {
* Tests the {@link HashIndexStorage#remove} method.
*/
@Test
- void testRemove() {
+ public void testRemove() {
IndexRow row1 = serializer.serializeRow(new Object[]{ 1, "foo" }, new
RowId(TEST_PARTITION));
IndexRow row2 = serializer.serializeRow(new Object[]{ 1, "foo" }, new
RowId(TEST_PARTITION));
IndexRow row3 = serializer.serializeRow(new Object[]{ 2, "bar" }, new
RowId(TEST_PARTITION));
@@ -186,7 +190,7 @@ public abstract class AbstractHashIndexStorageTest {
* Tests that {@link HashIndexStorage#remove} works normally when removing
a non-existent row.
*/
@Test
- void testRemoveIdempotence() {
+ public void testRemoveIdempotence() {
IndexRow row = serializer.serializeRow(new Object[]{ 1, "foo" }, new
RowId(TEST_PARTITION));
assertDoesNotThrow(() -> remove(row));
@@ -201,7 +205,7 @@ public abstract class AbstractHashIndexStorageTest {
}
@Test
- void testDestroy() {
+ public void testDestroy() throws Exception {
IndexRow row1 = serializer.serializeRow(new Object[]{ 1, "foo" }, new
RowId(TEST_PARTITION));
IndexRow row2 = serializer.serializeRow(new Object[]{ 1, "foo" }, new
RowId(TEST_PARTITION));
IndexRow row3 = serializer.serializeRow(new Object[]{ 2, "bar" }, new
RowId(TEST_PARTITION));
@@ -210,13 +214,27 @@ public abstract class AbstractHashIndexStorageTest {
put(row2);
put(row3);
- indexStorage.destroy();
+ CompletableFuture<Void> destroyFuture =
tableStorage.destroyIndex(indexStorage.indexDescriptor().id());
+ waitForDurableCompletion(destroyFuture);
+
+ //TODO IGNITE-17626 Index must be invalid, we should assert that
getIndex returns null and that in won't surface upon restart.
+ // "destroy" is not "clear", you know. Maybe "getAndCreateIndex" will
do it for the test, idk
assertThat(getAll(row1), is(empty()));
assertThat(getAll(row2), is(empty()));
assertThat(getAll(row3), is(empty()));
}
+ private void waitForDurableCompletion(CompletableFuture<?> future) {
+ while (true) {
+ if (future.isDone()) {
+ return;
+ }
+
+ partitionStorage.flush().join();
+ }
+ }
+
private Collection<RowId> getAll(IndexRow row) {
try (Cursor<RowId> cursor = indexStorage.get(row.indexColumns())) {
return cursor.stream().collect(toList());
diff --git
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/AbstractPageMemoryTableStorage.java
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/AbstractPageMemoryTableStorage.java
index 80a002e6ce..6474da7ae5 100644
---
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/AbstractPageMemoryTableStorage.java
+++
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/AbstractPageMemoryTableStorage.java
@@ -18,14 +18,13 @@
package org.apache.ignite.internal.storage.pagememory;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicReferenceArray;
import org.apache.ignite.configuration.schemas.table.TableConfiguration;
import org.apache.ignite.configuration.schemas.table.TableView;
+import org.apache.ignite.internal.pagememory.DataRegion;
import org.apache.ignite.internal.pagememory.PageMemory;
import org.apache.ignite.internal.storage.MvPartitionStorage;
import org.apache.ignite.internal.storage.StorageException;
@@ -44,9 +43,6 @@ import org.jetbrains.annotations.Nullable;
public abstract class AbstractPageMemoryTableStorage implements MvTableStorage
{
protected final TableConfiguration tableCfg;
- /** List of objects to be closed on the {@link #stop}. */
- protected final List<AutoCloseable> autoCloseables = new
CopyOnWriteArrayList<>();
-
protected volatile boolean started;
protected volatile
AtomicReferenceArray<AbstractPageMemoryMvPartitionStorage> mvPartitions;
@@ -66,6 +62,11 @@ public abstract class AbstractPageMemoryTableStorage
implements MvTableStorage {
return tableCfg;
}
+ /**
+ * Returns a data region instance for the table.
+ */
+ public abstract DataRegion<?> dataRegion();
+
/** {@inheritDoc} */
@Override
public void start() throws StorageException {
@@ -92,7 +93,7 @@ public abstract class AbstractPageMemoryTableStorage
implements MvTableStorage {
/** {@inheritDoc} */
@Override
- public MvPartitionStorage getOrCreateMvPartition(int partitionId) throws
StorageException {
+ public AbstractPageMemoryMvPartitionStorage getOrCreateMvPartition(int
partitionId) throws StorageException {
AbstractPageMemoryMvPartitionStorage partition =
getMvPartition(partitionId);
if (partition != null) {
@@ -101,6 +102,8 @@ public abstract class AbstractPageMemoryTableStorage
implements MvTableStorage {
partition = createMvPartitionStorage(partitionId);
+ partition.start();
+
mvPartitions.set(partitionId, partition);
return partition;
@@ -149,7 +152,7 @@ public abstract class AbstractPageMemoryTableStorage
implements MvTableStorage {
@Override
public HashIndexStorage getOrCreateHashIndex(int partitionId, UUID
indexId) {
- throw new UnsupportedOperationException("Not implemented yet");
+ return
getOrCreateMvPartition(partitionId).getOrCreateHashIndex(indexId);
}
/** {@inheritDoc} */
@@ -159,7 +162,7 @@ public abstract class AbstractPageMemoryTableStorage
implements MvTableStorage {
}
/**
- * Closes all {@link #mvPartitions} and {@link #autoCloseables}.
+ * Closes all {@link #mvPartitions}.
*
* @param destroy Destroy partitions.
* @throws StorageException If failed.
@@ -167,24 +170,20 @@ public abstract class AbstractPageMemoryTableStorage
implements MvTableStorage {
protected void close(boolean destroy) throws StorageException {
started = false;
- List<AutoCloseable> autoCloseables = new
ArrayList<>(this.autoCloseables);
+ List<AutoCloseable> closeables = new ArrayList<>();
for (int i = 0; i < mvPartitions.length(); i++) {
AbstractPageMemoryMvPartitionStorage partition =
mvPartitions.getAndUpdate(i, p -> null);
if (partition != null) {
- autoCloseables.add(destroy ? partition::destroy : partition);
+ closeables.add(destroy ? partition::destroy : partition);
}
}
- Collections.reverse(autoCloseables);
-
try {
- IgniteUtils.closeAll(autoCloseables);
+ IgniteUtils.closeAll(closeables);
} catch (Exception e) {
throw new StorageException("Failed to stop PageMemory table
storage.", e);
}
-
- this.autoCloseables.clear();
}
}
diff --git
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryTableStorage.java
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryTableStorage.java
index be4647428f..58a949f5ce 100644
---
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryTableStorage.java
+++
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryTableStorage.java
@@ -35,11 +35,13 @@ import
org.apache.ignite.internal.pagememory.persistence.store.FilePageStore;
import org.apache.ignite.internal.pagememory.reuse.ReuseList;
import org.apache.ignite.internal.pagememory.util.PageLockListenerNoOp;
import org.apache.ignite.internal.storage.StorageException;
+import
org.apache.ignite.internal.storage.pagememory.index.freelist.IndexColumnsFreeList;
+import org.apache.ignite.internal.storage.pagememory.index.meta.IndexMetaTree;
import
org.apache.ignite.internal.storage.pagememory.mv.PersistentPageMemoryMvPartitionStorage;
import org.apache.ignite.internal.storage.pagememory.mv.RowVersionFreeList;
-import org.apache.ignite.internal.storage.pagememory.mv.VersionChain;
import org.apache.ignite.internal.storage.pagememory.mv.VersionChainTree;
import org.apache.ignite.lang.IgniteInternalCheckedException;
+import org.jetbrains.annotations.Nullable;
/**
* Implementation of {@link AbstractPageMemoryTableStorage} for persistent
case.
@@ -76,6 +78,11 @@ public class PersistentPageMemoryTableStorage extends
AbstractPageMemoryTableSto
return engine;
}
+ @Override
+ public PersistentPageMemoryDataRegion dataRegion() {
+ return dataRegion;
+ }
+
/** {@inheritDoc} */
@Override
public boolean isVolatile() {
@@ -122,16 +129,12 @@ public class PersistentPageMemoryTableStorage extends
AbstractPageMemoryTableSto
checkpointTimeoutLock.checkpointReadLock();
try {
- PersistentPageMemory persistentPageMemory =
dataRegion.pageMemory();
+ PersistentPageMemory pageMemory = dataRegion.pageMemory();
int grpId = tableView.tableId();
- CheckpointProgress lastCheckpointProgress =
checkpointManager.lastCheckpointProgress();
-
- UUID checkpointId = lastCheckpointProgress == null ? null :
lastCheckpointProgress.id();
-
PartitionMeta meta =
dataRegion.partitionMetaManager().readOrCreateMeta(
- checkpointId,
+ lastCheckpointId(),
new GroupPartitionId(grpId, partitionId),
filePageStore
);
@@ -143,53 +146,26 @@ public class PersistentPageMemoryTableStorage extends
AbstractPageMemoryTableSto
filePageStore.setPageAllocationListener(pageIdx -> {
assert checkpointTimeoutLock.checkpointLockIsHeldByThread();
- CheckpointProgress last =
checkpointManager.lastCheckpointProgress();
-
- meta.incrementPageCount(last == null ? null : last.id());
+ meta.incrementPageCount(lastCheckpointId());
});
- boolean initNewVersionChainTree = false;
+ RowVersionFreeList rowVersionFreeList =
createRowVersionFreeList(tableView, partitionId, pageMemory, meta);
- if (meta.versionChainTreeRootPageId() == 0) {
- meta.versionChainTreeRootPageId(checkpointId,
persistentPageMemory.allocatePage(grpId, partitionId, FLAG_AUX));
+ IndexColumnsFreeList indexColumnsFreeList
+ = createIndexColumnsFreeList(tableView, partitionId,
rowVersionFreeList, pageMemory, meta);
- initNewVersionChainTree = true;
- }
-
- boolean initRowVersionFreeList = false;
-
- if (meta.rowVersionFreeListRootPageId() == 0) {
- meta.rowVersionFreeListRootPageId(checkpointId,
persistentPageMemory.allocatePage(grpId, partitionId, FLAG_AUX));
+ VersionChainTree versionChainTree =
createVersionChainTree(tableView, partitionId, rowVersionFreeList, pageMemory,
meta);
- initRowVersionFreeList = true;
- }
-
- RowVersionFreeList rowVersionFreeList = createRowVersionFreeList(
- tableView,
- partitionId,
- meta.rowVersionFreeListRootPageId(),
- initRowVersionFreeList
- );
-
- autoCloseables.add(rowVersionFreeList::close);
-
- VersionChainTree versionChainTree = createVersionChainTree(
- tableView,
- partitionId,
- rowVersionFreeList,
- meta.versionChainTreeRootPageId(),
- initNewVersionChainTree
- );
+ IndexMetaTree indexMetaTree = createIndexMetaTree(tableView,
partitionId, rowVersionFreeList, pageMemory, meta);
return new PersistentPageMemoryMvPartitionStorage(
this,
partitionId,
- tableView,
- dataRegion,
- checkpointManager,
meta,
rowVersionFreeList,
- versionChainTree
+ indexColumnsFreeList,
+ versionChainTree,
+ indexMetaTree
);
} catch (IgniteInternalCheckedException e) {
throw new StorageException(
@@ -224,29 +200,48 @@ public class PersistentPageMemoryTableStorage extends
AbstractPageMemoryTableSto
}
}
+ /**
+ * Returns id of the last started checkpoint, or {@code null} if no
checkpoints were started yet.
+ */
+ public @Nullable UUID lastCheckpointId() {
+ CheckpointProgress lastCeckpointProgress =
dataRegion.checkpointManager().lastCheckpointProgress();
+
+ return lastCeckpointProgress == null ? null :
lastCeckpointProgress.id();
+ }
+
/**
* Returns new {@link RowVersionFreeList} instance for partition.
*
* @param tableView Table configuration.
* @param partId Partition ID.
- * @param rootPageId Root page ID.
- * @param initNew {@code True} if new metadata should be initialized.
+ * @param pageMemory Persistent page memory instance.
+ * @param meta Partition metadata.
* @throws StorageException If failed.
*/
private RowVersionFreeList createRowVersionFreeList(
TableView tableView,
int partId,
- long rootPageId,
- boolean initNew
+ PersistentPageMemory pageMemory,
+ PartitionMeta meta
) throws StorageException {
try {
+ boolean initNew = false;
+
+ if (meta.rowVersionFreeListRootPageId() == 0) {
+ long rootPageId = pageMemory.allocatePage(tableView.tableId(),
partId, FLAG_AUX);
+
+ meta.rowVersionFreeListRootPageId(lastCheckpointId(),
rootPageId);
+
+ initNew = true;
+ }
+
return new RowVersionFreeList(
tableView.tableId(),
partId,
dataRegion.pageMemory(),
null,
PageLockListenerNoOp.INSTANCE,
- rootPageId,
+ meta.rowVersionFreeListRootPageId(),
initNew,
dataRegion.pageListCacheLimit(),
PageEvictionTrackerNoOp.INSTANCE,
@@ -260,36 +255,92 @@ public class PersistentPageMemoryTableStorage extends
AbstractPageMemoryTableSto
}
}
+ /**
+ * Returns new {@link IndexColumnsFreeList} instance for partition.
+ *
+ * @param tableView Table configuration.
+ * @param partitionId Partition ID.
+ * @param reuseList Reuse list.
+ * @param pageMemory Persistent page memory instance.
+ * @param meta Partition metadata.
+ * @throws StorageException If failed.
+ */
+ private IndexColumnsFreeList createIndexColumnsFreeList(
+ TableView tableView,
+ int partitionId,
+ ReuseList reuseList,
+ PersistentPageMemory pageMemory,
+ PartitionMeta meta
+ ) {
+ try {
+ boolean initNew = false;
+
+ if (meta.indexColumnsFreeListRootPageId() == 0L) {
+ long rootPageId = pageMemory.allocatePage(tableView.tableId(),
partitionId, FLAG_AUX);
+
+ meta.indexColumnsFreeListRootPageId(lastCheckpointId(),
rootPageId);
+
+ initNew = true;
+ }
+
+ return new IndexColumnsFreeList(
+ tableView.tableId(),
+ partitionId,
+ pageMemory,
+ reuseList,
+ PageLockListenerNoOp.INSTANCE,
+ meta.indexColumnsFreeListRootPageId(),
+ initNew,
+ new AtomicLong(),
+ PageEvictionTrackerNoOp.INSTANCE,
+ IoStatisticsHolderNoOp.INSTANCE
+ );
+ } catch (IgniteInternalCheckedException e) {
+ throw new StorageException(
+ String.format("Error creating IndexColumnsFreeList
[tableName=%s, partitionId=%s]", tableView.name(), partitionId),
+ e
+ );
+ }
+ }
+
/**
* Returns new {@link VersionChainTree} instance for partition.
*
* @param tableView Table configuration.
* @param partId Partition ID.
- * @param freeList {@link VersionChain} free list.
- * @param rootPageId Root page ID.
- * @param initNewTree {@code True} if new tree should be created.
+ * @param reuseList Reuse list.
+ * @param pageMemory Persistent page memory instance.
+ * @param meta Partition metadata.
* @throws StorageException If failed.
*/
private VersionChainTree createVersionChainTree(
TableView tableView,
int partId,
- ReuseList freeList,
- long rootPageId,
- boolean initNewTree
+ ReuseList reuseList,
+ PersistentPageMemory pageMemory,
+ PartitionMeta meta
) throws StorageException {
- int grpId = tableView.tableId();
-
try {
+ boolean initNew = false;
+
+ if (meta.versionChainTreeRootPageId() == 0) {
+ long rootPageId = pageMemory.allocatePage(tableView.tableId(),
partId, FLAG_AUX);
+
+ meta.versionChainTreeRootPageId(lastCheckpointId(),
rootPageId);
+
+ initNew = true;
+ }
+
return new VersionChainTree(
- grpId,
+ tableView.tableId(),
tableView.name(),
partId,
dataRegion.pageMemory(),
PageLockListenerNoOp.INSTANCE,
new AtomicLong(),
- rootPageId,
- freeList,
- initNewTree
+ meta.versionChainTreeRootPageId(),
+ reuseList,
+ initNew
);
} catch (IgniteInternalCheckedException e) {
throw new StorageException(
@@ -298,4 +349,51 @@ public class PersistentPageMemoryTableStorage extends
AbstractPageMemoryTableSto
);
}
}
+
+ /**
+ * Returns new {@link IndexMetaTree} instance for partition.
+ *
+ * @param tableView Table configuration.
+ * @param partitionId Partition ID.
+ * @param reuseList Reuse list.
+ * @param pageMemory Persistent page memory instance.
+ * @param meta Partition metadata.
+ * @throws StorageException If failed.
+ */
+ private IndexMetaTree createIndexMetaTree(
+ TableView tableView,
+ int partitionId,
+ ReuseList reuseList,
+ PersistentPageMemory pageMemory,
+ PartitionMeta meta
+ ) {
+ try {
+ boolean initNew = false;
+
+ if (meta.indexTreeMetaPageId() == 0) {
+ long rootPageId = pageMemory.allocatePage(tableView.tableId(),
partitionId, FLAG_AUX);
+
+ meta.indexTreeMetaPageId(lastCheckpointId(), rootPageId);
+
+ initNew = true;
+ }
+
+ return new IndexMetaTree(
+ tableView.tableId(),
+ tableView.name(),
+ partitionId,
+ dataRegion.pageMemory(),
+ PageLockListenerNoOp.INSTANCE,
+ new AtomicLong(),
+ meta.indexTreeMetaPageId(),
+ reuseList,
+ initNew
+ );
+ } catch (IgniteInternalCheckedException e) {
+ throw new StorageException(
+ String.format("Error creating IndexMetaTree [tableName=%s,
partitionId=%s]", tableView.name(), partitionId),
+ e
+ );
+ }
+ }
}
diff --git
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryDataRegion.java
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryDataRegion.java
index 26f7fd866b..19eaa17c03 100644
---
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryDataRegion.java
+++
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryDataRegion.java
@@ -30,9 +30,9 @@ import
org.apache.ignite.internal.pagememory.metric.IoStatisticsHolderNoOp;
import org.apache.ignite.internal.pagememory.reuse.ReuseList;
import org.apache.ignite.internal.pagememory.util.PageLockListenerNoOp;
import org.apache.ignite.internal.storage.StorageException;
+import
org.apache.ignite.internal.storage.pagememory.index.freelist.IndexColumnsFreeList;
import org.apache.ignite.internal.storage.pagememory.mv.RowVersionFreeList;
import org.apache.ignite.lang.IgniteInternalCheckedException;
-import org.jetbrains.annotations.Nullable;
/**
* Implementation of {@link DataRegion} for in-memory case.
@@ -52,6 +52,8 @@ public class VolatilePageMemoryDataRegion implements
DataRegion<VolatilePageMemo
private volatile RowVersionFreeList rowVersionFreeList;
+ private volatile IndexColumnsFreeList indexColumnsFreeList;
+
/**
* Constructor.
*
@@ -79,7 +81,9 @@ public class VolatilePageMemoryDataRegion implements
DataRegion<VolatilePageMemo
pageMemory.start();
try {
- rowVersionFreeList = createRowVersionFreeList(pageMemory, null);
+ rowVersionFreeList = createRowVersionFreeList(pageMemory);
+
+ indexColumnsFreeList = createIndexColumnsFreeList(pageMemory,
rowVersionFreeList);
} catch (IgniteInternalCheckedException e) {
throw new StorageException("Error creating a RowVersionFreeList",
e);
}
@@ -88,12 +92,30 @@ public class VolatilePageMemoryDataRegion implements
DataRegion<VolatilePageMemo
}
private static RowVersionFreeList createRowVersionFreeList(
- PageMemory pageMemory,
- @Nullable ReuseList reuseList
+ PageMemory pageMemory
) throws IgniteInternalCheckedException {
long metaPageId = pageMemory.allocatePage(FREE_LIST_GROUP_ID,
FREE_LIST_PARTITION_ID, FLAG_AUX);
return new RowVersionFreeList(
+ FREE_LIST_GROUP_ID,
+ FREE_LIST_PARTITION_ID,
+ pageMemory,
+ null,
+ PageLockListenerNoOp.INSTANCE,
+ metaPageId,
+ true,
+ // Because in memory.
+ null,
+ PageEvictionTrackerNoOp.INSTANCE,
+ IoStatisticsHolderNoOp.INSTANCE
+ );
+ }
+
+ private IndexColumnsFreeList createIndexColumnsFreeList(VolatilePageMemory
pageMemory, ReuseList reuseList)
+ throws IgniteInternalCheckedException {
+ long metaPageId = pageMemory.allocatePage(FREE_LIST_GROUP_ID,
FREE_LIST_PARTITION_ID, FLAG_AUX);
+
+ return new IndexColumnsFreeList(
FREE_LIST_GROUP_ID,
FREE_LIST_PARTITION_ID,
pageMemory,
@@ -126,6 +148,10 @@ public class VolatilePageMemoryDataRegion implements
DataRegion<VolatilePageMemo
return pageMemory;
}
+ public ReuseList reuseList() {
+ return rowVersionFreeList();
+ }
+
/**
* Returns version chain free list.
*
@@ -137,6 +163,10 @@ public class VolatilePageMemoryDataRegion implements
DataRegion<VolatilePageMemo
return rowVersionFreeList;
}
+ public IndexColumnsFreeList indexColumnsFreeList() {
+ return indexColumnsFreeList;
+ }
+
/**
* Checks that the data region has started.
*
diff --git
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryTableStorage.java
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryTableStorage.java
index f1f33a4632..3d5bb16c96 100644
---
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryTableStorage.java
+++
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryTableStorage.java
@@ -24,6 +24,7 @@ import
org.apache.ignite.configuration.schemas.table.TableConfiguration;
import org.apache.ignite.configuration.schemas.table.TableView;
import org.apache.ignite.internal.pagememory.util.PageLockListenerNoOp;
import org.apache.ignite.internal.storage.StorageException;
+import org.apache.ignite.internal.storage.pagememory.index.meta.IndexMetaTree;
import org.apache.ignite.internal.storage.pagememory.mv.VersionChainTree;
import
org.apache.ignite.internal.storage.pagememory.mv.VolatilePageMemoryMvPartitionStorage;
import org.apache.ignite.lang.IgniteInternalCheckedException;
@@ -32,7 +33,7 @@ import org.apache.ignite.lang.IgniteInternalCheckedException;
* Implementation of {@link AbstractPageMemoryTableStorage} for in-memory case.
*/
public class VolatilePageMemoryTableStorage extends
AbstractPageMemoryTableStorage {
- private VolatilePageMemoryDataRegion dataRegion;
+ private final VolatilePageMemoryDataRegion dataRegion;
/**
* Constructor.
@@ -46,20 +47,48 @@ public class VolatilePageMemoryTableStorage extends
AbstractPageMemoryTableStora
this.dataRegion = dataRegion;
}
+ @Override
+ public VolatilePageMemoryDataRegion dataRegion() {
+ return dataRegion;
+ }
+
/** {@inheritDoc} */
@Override
public VolatilePageMemoryMvPartitionStorage createMvPartitionStorage(int
partitionId) throws StorageException {
VersionChainTree versionChainTree =
createVersionChainTree(partitionId, tableCfg.value());
+ IndexMetaTree indexMetaTree = createIndexMetaTree(partitionId,
tableCfg.value());
+
return new VolatilePageMemoryMvPartitionStorage(
+ this,
partitionId,
- tableCfg.value(),
- dataRegion.pageMemory(),
- dataRegion.rowVersionFreeList(),
- versionChainTree
+ versionChainTree,
+ indexMetaTree
);
}
+ private IndexMetaTree createIndexMetaTree(int partitionId, TableView
tableCfgView) {
+ int grpId = tableCfgView.tableId();
+
+ long metaPageId = dataRegion.pageMemory().allocatePage(grpId,
partitionId, FLAG_AUX);
+
+ try {
+ return new IndexMetaTree(
+ grpId,
+ tableCfgView.name(),
+ partitionId,
+ dataRegion.pageMemory(),
+ PageLockListenerNoOp.INSTANCE,
+ new AtomicLong(),
+ metaPageId,
+ dataRegion.reuseList(),
+ true
+ );
+ } catch (IgniteInternalCheckedException e) {
+ throw new StorageException(e);
+ }
+ }
+
/** {@inheritDoc} */
@Override
public boolean isVolatile() {
@@ -83,6 +112,8 @@ public class VolatilePageMemoryTableStorage extends
AbstractPageMemoryTableStora
int grpId = tableView.tableId();
try {
+ long metaPageId = dataRegion.pageMemory().allocatePage(grpId,
partId, FLAG_AUX);
+
return new VersionChainTree(
grpId,
tableView.name(),
@@ -90,8 +121,8 @@ public class VolatilePageMemoryTableStorage extends
AbstractPageMemoryTableStora
dataRegion.pageMemory(),
PageLockListenerNoOp.INSTANCE,
new AtomicLong(),
- dataRegion.pageMemory().allocatePage(grpId, partId,
FLAG_AUX),
- dataRegion.rowVersionFreeList(),
+ metaPageId,
+ dataRegion.reuseList(),
true
);
} catch (IgniteInternalCheckedException e) {
diff --git
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/freelist/IndexColumnsFreeList.java
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/freelist/IndexColumnsFreeList.java
index b66373bcfc..713fa0330d 100644
---
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/freelist/IndexColumnsFreeList.java
+++
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/freelist/IndexColumnsFreeList.java
@@ -19,6 +19,7 @@ package
org.apache.ignite.internal.storage.pagememory.index.freelist;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.ignite.internal.logger.IgniteLogger;
+import org.apache.ignite.internal.logger.Loggers;
import org.apache.ignite.internal.pagememory.PageMemory;
import org.apache.ignite.internal.pagememory.evict.PageEvictionTracker;
import org.apache.ignite.internal.pagememory.freelist.AbstractFreeList;
@@ -32,6 +33,10 @@ import org.jetbrains.annotations.Nullable;
* Free list implementation to store {@link IndexColumns} values.
*/
public class IndexColumnsFreeList extends AbstractFreeList<IndexColumns> {
+ private static final IgniteLogger LOG =
Loggers.forClass(IndexColumnsFreeList.class);
+
+ private final IoStatisticsHolder statHolder;
+
/**
* Constructor.
*
@@ -40,7 +45,6 @@ public class IndexColumnsFreeList extends
AbstractFreeList<IndexColumns> {
* @param pageMem Page memory.
* @param reuseList Reuse list or {@code null} if this free list will be a
reuse list for itself.
* @param lockLsnr Page lock listener.
- * @param log Logger.
* @param metaPageId Metadata page ID.
* @param initNew {@code True} if new metadata should be initialized.
* @param pageListCacheLimit Page list cache limit.
@@ -53,7 +57,6 @@ public class IndexColumnsFreeList extends
AbstractFreeList<IndexColumns> {
PageMemory pageMem,
@Nullable ReuseList reuseList,
PageLockListener lockLsnr,
- IgniteLogger log,
long metaPageId,
boolean initNew,
@Nullable AtomicLong pageListCacheLimit,
@@ -67,11 +70,21 @@ public class IndexColumnsFreeList extends
AbstractFreeList<IndexColumns> {
pageMem,
reuseList,
lockLsnr,
- log,
+ LOG,
metaPageId,
initNew,
pageListCacheLimit,
evictionTracker
);
+ this.statHolder = statHolder;
+ }
+
+ /**
+ * Shortcut method for {@link #saveMetadata(IoStatisticsHolder)} with
statistics holder.
+ *
+ * @throws IgniteInternalCheckedException If failed.
+ */
+ public void saveMetadata() throws IgniteInternalCheckedException {
+ saveMetadata(statHolder);
}
}
diff --git
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/freelist/io/IndexColumnsDataIo.java
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/freelist/io/IndexColumnsDataIo.java
index 002c86b949..3e107fc4c5 100644
---
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/freelist/io/IndexColumnsDataIo.java
+++
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/freelist/io/IndexColumnsDataIo.java
@@ -19,6 +19,7 @@ package
org.apache.ignite.internal.storage.pagememory.index.freelist.io;
import static
org.apache.ignite.internal.pagememory.util.PageUtils.putByteBuffer;
import static org.apache.ignite.internal.pagememory.util.PageUtils.putInt;
+import static org.apache.ignite.internal.pagememory.util.PageUtils.putShort;
import java.nio.ByteBuffer;
import org.apache.ignite.internal.pagememory.io.AbstractDataPageIo;
@@ -48,6 +49,10 @@ public class IndexColumnsDataIo extends
AbstractDataPageIo<IndexColumns> {
protected void writeRowData(long pageAddr, int dataOff, int payloadSize,
IndexColumns row, boolean newRow) {
assertPageType(pageAddr);
+ putShort(pageAddr, dataOff, (short) payloadSize);
+
+ dataOff += Short.BYTES;
+
putInt(pageAddr, dataOff + IndexColumns.SIZE_OFFSET, row.valueSize());
putByteBuffer(pageAddr, dataOff + IndexColumns.VALUE_OFFSET,
row.valueBuffer());
diff --git
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/InsertHashIndexRowInvokeClosure.java
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/InsertHashIndexRowInvokeClosure.java
index c6099ead0a..f803e89e22 100644
---
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/InsertHashIndexRowInvokeClosure.java
+++
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/InsertHashIndexRowInvokeClosure.java
@@ -32,7 +32,7 @@ import org.jetbrains.annotations.Nullable;
* Insert closure that inserts corresponding {@link IndexColumns} into a
{@link IndexColumnsFreeList} before writing to the
* {@link HashIndexTree}.
*/
-public class InsertHashIndexRowInvokeClosure implements
InvokeClosure<HashIndexRow> {
+class InsertHashIndexRowInvokeClosure implements InvokeClosure<HashIndexRow> {
/** Hash index row instance for insertion. */
private final HashIndexRow hashIndexRow;
diff --git
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/PageMemoryHashIndexStorage.java
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/PageMemoryHashIndexStorage.java
new file mode 100644
index 0000000000..3a2ef1a6cb
--- /dev/null
+++
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/PageMemoryHashIndexStorage.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.storage.pagememory.index.hash;
+
+import org.apache.ignite.internal.pagememory.metric.IoStatisticsHolderNoOp;
+import org.apache.ignite.internal.schema.BinaryTuple;
+import org.apache.ignite.internal.storage.RowId;
+import org.apache.ignite.internal.storage.StorageException;
+import org.apache.ignite.internal.storage.index.HashIndexDescriptor;
+import org.apache.ignite.internal.storage.index.HashIndexStorage;
+import org.apache.ignite.internal.storage.index.IndexRow;
+import
org.apache.ignite.internal.storage.pagememory.index.freelist.IndexColumns;
+import
org.apache.ignite.internal.storage.pagememory.index.freelist.IndexColumnsFreeList;
+import org.apache.ignite.internal.storage.pagememory.util.TreeCursorAdapter;
+import org.apache.ignite.internal.util.Cursor;
+import org.apache.ignite.internal.util.IgniteCursor;
+import org.apache.ignite.lang.IgniteInternalCheckedException;
+
+/**
+ * Hash index storage implementation.
+ */
+public class PageMemoryHashIndexStorage implements HashIndexStorage {
+ /** Index descriptor. */
+ private final HashIndexDescriptor descriptor;
+
+ /** Free list to store index columns. */
+ private final IndexColumnsFreeList freeList;
+
+ /** Hash index tree instance. */
+ private final HashIndexTree hashIndexTree;
+
+ /** Partition id. */
+ private final int partitionId;
+
+ /** Lowest possible RowId according to signed long ordering. */
+ private final RowId lowestRowId;
+
+ /** Highest possible RowId according to signed long ordering. */
+ private final RowId highestRowId;
+
+ /**
+ * Constructor.
+ *
+ * @param descriptor Hash index descriptor.
+ * @param freeList Free list to store indx columns.
+ * @param hashIndexTree Hash index tree instance.
+ */
+ public PageMemoryHashIndexStorage(HashIndexDescriptor descriptor,
IndexColumnsFreeList freeList, HashIndexTree hashIndexTree) {
+ this.descriptor = descriptor;
+ this.freeList = freeList;
+ this.hashIndexTree = hashIndexTree;
+
+ partitionId = hashIndexTree.partitionId();
+
+ lowestRowId = new RowId(partitionId, Long.MIN_VALUE, Long.MIN_VALUE);
+
+ highestRowId = new RowId(partitionId, Long.MAX_VALUE, Long.MAX_VALUE);
+ }
+
+ @Override
+ public HashIndexDescriptor indexDescriptor() {
+ return descriptor;
+ }
+
+ @Override
+ public Cursor<RowId> get(BinaryTuple key) throws StorageException {
+ IndexColumns indexColumns = new IndexColumns(partitionId,
key.byteBuffer());
+
+ HashIndexRow lowerBound = new HashIndexRow(indexColumns, lowestRowId);
+ HashIndexRow upperBound = new HashIndexRow(indexColumns, highestRowId);
+
+ IgniteCursor<HashIndexRow> cursor;
+
+ try {
+ cursor = hashIndexTree.find(lowerBound, upperBound, null);
+ } catch (IgniteInternalCheckedException e) {
+ throw new StorageException("Failed to create scan cursor", e);
+ }
+
+ return Cursor.fromIterator(new TreeCursorAdapter<>(cursor,
HashIndexRow::rowId));
+ }
+
+ @Override
+ public void put(IndexRow row) throws StorageException {
+ IndexColumns indexColumns = new IndexColumns(partitionId,
row.indexColumns().byteBuffer());
+
+ try {
+ HashIndexRow hashIndexRow = new HashIndexRow(indexColumns,
row.rowId());
+
+ var insert = new InsertHashIndexRowInvokeClosure(hashIndexRow,
freeList, IoStatisticsHolderNoOp.INSTANCE);
+
+ hashIndexTree.invoke(hashIndexRow, null, insert);
+ } catch (IgniteInternalCheckedException e) {
+ throw new StorageException("Failed to put value into index", e);
+ }
+ }
+
+ @Override
+ public void remove(IndexRow row) throws StorageException {
+ IndexColumns indexColumns = new IndexColumns(partitionId,
row.indexColumns().byteBuffer());
+
+ try {
+ HashIndexRow hashIndexRow = new HashIndexRow(indexColumns,
row.rowId());
+
+ var remove = new RemoveHashIndexRowInvokeClosure(hashIndexRow,
freeList, IoStatisticsHolderNoOp.INSTANCE);
+
+ hashIndexTree.invoke(hashIndexRow, null, remove);
+
+ // Performs actual deletion from freeList if necessary.
+ remove.afterCompletion();
+ } catch (IgniteInternalCheckedException e) {
+ throw new StorageException("Failed to remove value from index", e);
+ }
+ }
+
+ @Override
+ public void destroy() throws StorageException {
+ //TODO IGNITE-17626 Implement.
+ }
+}
diff --git
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/RemoveHashIndexRowInvokeClosure.java
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/RemoveHashIndexRowInvokeClosure.java
index bdd342bc75..e4a9717315 100644
---
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/RemoveHashIndexRowInvokeClosure.java
+++
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/RemoveHashIndexRowInvokeClosure.java
@@ -33,7 +33,7 @@ import org.jetbrains.annotations.Nullable;
* Insert closure that removes corresponding {@link IndexColumns} from a
{@link IndexColumnsFreeList} after removing it from the
* {@link HashIndexTree}.
*/
-public class RemoveHashIndexRowInvokeClosure implements
InvokeClosure<HashIndexRow> {
+class RemoveHashIndexRowInvokeClosure implements InvokeClosure<HashIndexRow> {
/** Hash index row instance for removal. */
private final HashIndexRow hashIndexRow;
diff --git
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/IndexMeta.java
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/IndexMeta.java
index cdcc22d0e0..d3019d3665 100644
---
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/IndexMeta.java
+++
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/IndexMeta.java
@@ -18,27 +18,28 @@
package org.apache.ignite.internal.storage.pagememory.index.meta;
import java.util.UUID;
-import org.apache.ignite.internal.tostring.IgniteToStringInclude;
+import org.apache.ignite.internal.tostring.IgniteToStringExclude;
import org.apache.ignite.internal.tostring.S;
+import org.apache.ignite.internal.util.IgniteUtils;
/**
* Index tree meta information.
*/
public class IndexMeta {
- @IgniteToStringInclude
private final UUID id;
- private final long rootPageId;
+ @IgniteToStringExclude
+ private final long metaPageId;
/**
* Constructor.
*
* @param id Index ID.
- * @param rootPageId Index root page ID.
+ * @param metaPageId Index tree meta page ID.
*/
- public IndexMeta(UUID id, long rootPageId) {
+ public IndexMeta(UUID id, long metaPageId) {
this.id = id;
- this.rootPageId = rootPageId;
+ this.metaPageId = metaPageId;
}
/**
@@ -49,15 +50,15 @@ public class IndexMeta {
}
/**
- * Returns the index root page ID.
+ * Returns page ID of the index tree meta page.
*/
- public long rootPageId() {
- return rootPageId;
+ public long metaPageId() {
+ return metaPageId;
}
/** {@inheritDoc} */
@Override
public String toString() {
- return S.toString(IndexMeta.class, this);
+ return S.toString(IndexMeta.class, this, "metaPageId",
IgniteUtils.hexLong(metaPageId));
}
}
diff --git
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaIo.java
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaIo.java
index 61e8e95dd4..d7a582fa7c 100644
---
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaIo.java
+++
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaIo.java
@@ -41,8 +41,8 @@ public interface IndexMetaIo {
/** Offset of the {@link UUID#getLeastSignificantBits() least significant
bits} of the index ID (8 bytes). */
int INDEX_ID_LSB_OFFSET = INDEX_ID_MSB_OFFSET + Long.BYTES;
- /** Index root page ID offset - long (8 bytes). */
- int INDEX_ROOT_PAGE_ID_OFFSET = INDEX_ID_LSB_OFFSET + Long.BYTES;
+ /** Index tree meta page id offset - long (8 bytes). */
+ int INDEX_TREE_META_PAGE_ID_OFFSET = INDEX_ID_LSB_OFFSET + Long.BYTES;
/** Payload size in bytes. */
int SIZE_IN_BYTES = 2 * Long.BYTES /* Index ID - {@link UUID} (16 bytes)
*/ + Long.BYTES /* Index root page ID - long (8 bytes) */;
@@ -86,9 +86,9 @@ public interface IndexMetaIo {
long indexIdMsb = getLong(pageAddr, elementOffset +
INDEX_ID_MSB_OFFSET);
long indexIdLsb = getLong(pageAddr, elementOffset +
INDEX_ID_LSB_OFFSET);
- long indexRootPageId = getLong(pageAddr, elementOffset +
INDEX_ROOT_PAGE_ID_OFFSET);
+ long indexTreeMetaPageId = getLong(pageAddr, elementOffset +
INDEX_TREE_META_PAGE_ID_OFFSET);
- return new IndexMeta(new UUID(indexIdMsb, indexIdLsb),
indexRootPageId);
+ return new IndexMeta(new UUID(indexIdMsb, indexIdLsb),
indexTreeMetaPageId);
}
/**
@@ -112,6 +112,6 @@ public interface IndexMetaIo {
putLong(pageAddr, off + INDEX_ID_MSB_OFFSET,
row.id().getMostSignificantBits());
putLong(pageAddr, off + INDEX_ID_LSB_OFFSET,
row.id().getLeastSignificantBits());
- putLong(pageAddr, off + INDEX_ROOT_PAGE_ID_OFFSET, row.rootPageId());
+ putLong(pageAddr, off + INDEX_TREE_META_PAGE_ID_OFFSET,
row.metaPageId());
}
}
diff --git
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/AbstractPageMemoryMvPartitionStorage.java
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/AbstractPageMemoryMvPartitionStorage.java
index 5c89a17678..9deb69241f 100644
---
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/AbstractPageMemoryMvPartitionStorage.java
+++
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/AbstractPageMemoryMvPartitionStorage.java
@@ -17,24 +17,43 @@
package org.apache.ignite.internal.storage.pagememory.mv;
+import static
org.apache.ignite.internal.configuration.util.ConfigurationUtil.getByInternalId;
import static org.apache.ignite.internal.pagememory.util.PageIdUtils.NULL_LINK;
import java.nio.ByteBuffer;
import java.util.NoSuchElementException;
import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
+import org.apache.ignite.configuration.NamedListView;
+import org.apache.ignite.configuration.schemas.table.HashIndexView;
+import org.apache.ignite.configuration.schemas.table.SortedIndexView;
+import org.apache.ignite.configuration.schemas.table.TableIndexView;
import org.apache.ignite.configuration.schemas.table.TableView;
import org.apache.ignite.hlc.HybridTimestamp;
+import org.apache.ignite.internal.pagememory.PageIdAllocator;
import org.apache.ignite.internal.pagememory.PageMemory;
import org.apache.ignite.internal.pagememory.datapage.DataPageReader;
import org.apache.ignite.internal.pagememory.metric.IoStatisticsHolderNoOp;
+import org.apache.ignite.internal.pagememory.util.PageLockListenerNoOp;
import org.apache.ignite.internal.schema.BinaryRow;
import org.apache.ignite.internal.schema.ByteBufferRow;
import org.apache.ignite.internal.storage.MvPartitionStorage;
import org.apache.ignite.internal.storage.RowId;
import org.apache.ignite.internal.storage.StorageException;
import org.apache.ignite.internal.storage.TxIdMismatchException;
+import org.apache.ignite.internal.storage.index.HashIndexDescriptor;
+import org.apache.ignite.internal.storage.index.HashIndexStorage;
+import
org.apache.ignite.internal.storage.pagememory.AbstractPageMemoryTableStorage;
+import
org.apache.ignite.internal.storage.pagememory.index.freelist.IndexColumns;
+import
org.apache.ignite.internal.storage.pagememory.index.freelist.IndexColumnsFreeList;
+import org.apache.ignite.internal.storage.pagememory.index.hash.HashIndexTree;
+import
org.apache.ignite.internal.storage.pagememory.index.hash.PageMemoryHashIndexStorage;
+import org.apache.ignite.internal.storage.pagememory.index.meta.IndexMeta;
+import org.apache.ignite.internal.storage.pagememory.index.meta.IndexMetaTree;
import org.apache.ignite.internal.util.Cursor;
import org.apache.ignite.internal.util.IgniteCursor;
import org.apache.ignite.lang.IgniteInternalCheckedException;
@@ -52,39 +71,134 @@ public abstract class AbstractPageMemoryMvPartitionStorage
implements MvPartitio
private static final Predicate<HybridTimestamp> ALWAYS_LOAD_VALUE =
timestamp -> true;
- private final int partitionId;
- private final int groupId;
+ protected final int partitionId;
+
+ protected final int groupId;
+
+ protected final AbstractPageMemoryTableStorage tableStorage;
+
+ protected final VersionChainTree versionChainTree;
- private final VersionChainTree versionChainTree;
protected final RowVersionFreeList rowVersionFreeList;
- private final DataPageReader rowVersionDataPageReader;
+
+ protected final IndexColumnsFreeList indexFreeList;
+
+ protected final IndexMetaTree indexMetaTree;
+
+ protected final DataPageReader rowVersionDataPageReader;
+
+ protected final ConcurrentMap<UUID, HashIndexStorage> indexes = new
ConcurrentHashMap<>();
/**
* Constructor.
*
* @param partitionId Partition id.
- * @param tableView Table configuration.
- * @param pageMemory Page memory.
+ * @param tableStorage Table storage instance.
* @param rowVersionFreeList Free list for {@link RowVersion}.
+ * @param indexFreeList Free list fot {@link IndexColumns}.
* @param versionChainTree Table tree for {@link VersionChain}.
+ * @param indexMetaTree Tree that contains SQL indexes' metadata.
*/
protected AbstractPageMemoryMvPartitionStorage(
int partitionId,
- TableView tableView,
- PageMemory pageMemory,
+ AbstractPageMemoryTableStorage tableStorage,
RowVersionFreeList rowVersionFreeList,
- VersionChainTree versionChainTree
+ IndexColumnsFreeList indexFreeList,
+ VersionChainTree versionChainTree,
+ IndexMetaTree indexMetaTree
) {
this.partitionId = partitionId;
+ this.tableStorage = tableStorage;
this.rowVersionFreeList = rowVersionFreeList;
+ this.indexFreeList = indexFreeList;
+
this.versionChainTree = versionChainTree;
+ this.indexMetaTree = indexMetaTree;
+
+ PageMemory pageMemory = tableStorage.dataRegion().pageMemory();
- groupId = tableView.tableId();
+ groupId = tableStorage.configuration().value().tableId();
rowVersionDataPageReader = new DataPageReader(pageMemory, groupId,
IoStatisticsHolderNoOp.INSTANCE);
}
+ /**
+ * Starts a partition by initializing its internal structures.
+ */
+ public void start() {
+ try {
+ IgniteCursor<IndexMeta> cursor = indexMetaTree.find(null, null);
+
+ NamedListView<? extends TableIndexView> indicesCfgView =
tableStorage.configuration().value().indices();
+
+ while (cursor.next()) {
+ IndexMeta indexMeta = cursor.get();
+
+ TableIndexView indexCfgView = getByInternalId(indicesCfgView,
indexMeta.id());
+
+ if (indexCfgView instanceof HashIndexView) {
+ createOrRestoreHashIndex(indexMeta);
+ } else if (indexCfgView instanceof SortedIndexView) {
+ throw new UnsupportedOperationException("Not implemented
yet");
+ } else {
+ assert indexCfgView == null;
+
+ //TODO IGNITE-17626 Drop the index synchronously.
+ }
+ }
+ } catch (IgniteInternalCheckedException e) {
+ throw new StorageException("Failed to process SQL indexes during
the partition start", e);
+ }
+ }
+
+ /**
+ * Returns a hash index instance, creating index it if necessary.
+ *
+ * @param indexId Index UUID.
+ */
+ public HashIndexStorage getOrCreateHashIndex(UUID indexId) {
+ return indexes.computeIfAbsent(indexId, uuid ->
createOrRestoreHashIndex(new IndexMeta(indexId, 0L)));
+ }
+
+ private PageMemoryHashIndexStorage createOrRestoreHashIndex(IndexMeta
indexMeta) {
+ TableView tableView = tableStorage.configuration().value();
+
+ var indexDescriptor = new HashIndexDescriptor(indexMeta.id(),
tableView);
+
+ try {
+ PageMemory pageMemory = tableStorage.dataRegion().pageMemory();
+
+ boolean initNew = indexMeta.metaPageId() == 0L;
+
+ long metaPageId = initNew
+ ? pageMemory.allocatePage(groupId, partitionId,
PageIdAllocator.FLAG_AUX)
+ : indexMeta.metaPageId();
+
+ HashIndexTree hashIndexTree = new HashIndexTree(
+ groupId,
+ tableView.name(),
+ partitionId,
+ pageMemory,
+ PageLockListenerNoOp.INSTANCE,
+ new AtomicLong(),
+ metaPageId,
+ rowVersionFreeList,
+ initNew
+ );
+
+ if (initNew) {
+ boolean replaced = indexMetaTree.putx(new
IndexMeta(indexMeta.id(), metaPageId));
+
+ assert !replaced;
+ }
+
+ return new PageMemoryHashIndexStorage(indexDescriptor,
indexFreeList, hashIndexTree);
+ } catch (IgniteInternalCheckedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
/** {@inheritDoc} */
@Override
public @Nullable BinaryRow read(RowId rowId, UUID txId) throws
TxIdMismatchException, StorageException {
@@ -392,6 +506,8 @@ public abstract class AbstractPageMemoryMvPartitionStorage
implements MvPartitio
@Override
public void close() {
versionChainTree.close();
+
+ indexMetaTree.close();
}
/**
diff --git
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/PersistentPageMemoryMvPartitionStorage.java
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/PersistentPageMemoryMvPartitionStorage.java
index ab2cb51d48..5535c7e089 100644
---
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/PersistentPageMemoryMvPartitionStorage.java
+++
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/PersistentPageMemoryMvPartitionStorage.java
@@ -20,10 +20,7 @@ package org.apache.ignite.internal.storage.pagememory.mv;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
-import org.apache.ignite.configuration.schemas.table.TableView;
-import org.apache.ignite.internal.pagememory.DataRegion;
import org.apache.ignite.internal.pagememory.persistence.PartitionMeta;
-import org.apache.ignite.internal.pagememory.persistence.PersistentPageMemory;
import
org.apache.ignite.internal.pagememory.persistence.checkpoint.CheckpointListener;
import
org.apache.ignite.internal.pagememory.persistence.checkpoint.CheckpointManager;
import
org.apache.ignite.internal.pagememory.persistence.checkpoint.CheckpointProgress;
@@ -32,8 +29,12 @@ import
org.apache.ignite.internal.pagememory.persistence.checkpoint.CheckpointTi
import org.apache.ignite.internal.pagememory.tree.BplusTree;
import org.apache.ignite.internal.storage.MvPartitionStorage;
import org.apache.ignite.internal.storage.StorageException;
+import org.apache.ignite.internal.storage.index.HashIndexStorage;
import
org.apache.ignite.internal.storage.pagememory.PersistentPageMemoryTableStorage;
import
org.apache.ignite.internal.storage.pagememory.configuration.schema.PersistentPageMemoryStorageEngineView;
+import
org.apache.ignite.internal.storage.pagememory.index.freelist.IndexColumns;
+import
org.apache.ignite.internal.storage.pagememory.index.freelist.IndexColumnsFreeList;
+import org.apache.ignite.internal.storage.pagememory.index.meta.IndexMetaTree;
import org.apache.ignite.lang.IgniteInternalCheckedException;
import org.apache.ignite.lang.IgniteInternalException;
import org.jetbrains.annotations.Nullable;
@@ -42,9 +43,6 @@ import org.jetbrains.annotations.Nullable;
* Implementation of {@link MvPartitionStorage} based on a {@link BplusTree}
for persistent case.
*/
public class PersistentPageMemoryMvPartitionStorage extends
AbstractPageMemoryMvPartitionStorage {
- /** Table storage instance. */
- private final PersistentPageMemoryTableStorage tableStorage;
-
/** Checkpoint manager instance. */
private final CheckpointManager checkpointManager;
@@ -65,28 +63,24 @@ public class PersistentPageMemoryMvPartitionStorage extends
AbstractPageMemoryMv
*
* @param tableStorage Table storage.
* @param partitionId Partition id.
- * @param tableView Table configuration.
- * @param dataRegion Data region.
- * @param checkpointManager Checkpoint manager.
* @param meta Partition meta.
* @param rowVersionFreeList Free list for {@link RowVersion}.
+ * @param indexFreeList Free list fot {@link IndexColumns}.
* @param versionChainTree Table tree for {@link VersionChain}.
+ * @param indexMetaTree Tree that contains SQL indexes' metadata.
*/
public PersistentPageMemoryMvPartitionStorage(
PersistentPageMemoryTableStorage tableStorage,
int partitionId,
- TableView tableView,
- DataRegion<PersistentPageMemory> dataRegion,
- CheckpointManager checkpointManager,
PartitionMeta meta,
RowVersionFreeList rowVersionFreeList,
- VersionChainTree versionChainTree
+ IndexColumnsFreeList indexFreeList,
+ VersionChainTree versionChainTree,
+ IndexMetaTree indexMetaTree
) {
- super(partitionId, tableView, dataRegion.pageMemory(),
rowVersionFreeList, versionChainTree);
-
- this.tableStorage = tableStorage;
+ super(partitionId, tableStorage, rowVersionFreeList, indexFreeList,
versionChainTree, indexMetaTree);
- this.checkpointManager = checkpointManager;
+ checkpointManager = tableStorage.engine().checkpointManager();
checkpointTimeoutLock = checkpointManager.checkpointTimeoutLock();
checkpointManager.addCheckpointListener(checkpointListener = new
CheckpointListener() {
@@ -109,7 +103,7 @@ public class PersistentPageMemoryMvPartitionStorage extends
AbstractPageMemoryMv
public void afterCheckpointEnd(CheckpointProgress progress) {
persistedIndex =
meta.metaSnapshot(progress.id()).lastAppliedIndex();
}
- }, dataRegion);
+ }, tableStorage.dataRegion());
this.meta = meta;
}
@@ -136,7 +130,9 @@ public class PersistentPageMemoryMvPartitionStorage extends
AbstractPageMemoryMv
if (lastCheckpoint != null &&
meta.metaSnapshot(lastCheckpoint.id()).lastAppliedIndex() ==
meta.lastAppliedIndex()) {
scheduledCheckpoint = lastCheckpoint;
} else {
- PersistentPageMemoryStorageEngineView engineCfg =
tableStorage.engine().configuration().value();
+ var persistentTableStorage = (PersistentPageMemoryTableStorage)
tableStorage;
+
+ PersistentPageMemoryStorageEngineView engineCfg =
persistentTableStorage.engine().configuration().value();
int checkpointDelayMillis =
engineCfg.checkpoint().checkpointDelayMillis();
scheduledCheckpoint =
checkpointManager.scheduleCheckpoint(checkpointDelayMillis, "Triggered by
replicator");
@@ -169,10 +165,18 @@ public class PersistentPageMemoryMvPartitionStorage
extends AbstractPageMemoryMv
return persistedIndex;
}
+ @Override
+ public HashIndexStorage getOrCreateHashIndex(UUID indexId) {
+ return runConsistently(() -> super.getOrCreateHashIndex(indexId));
+ }
+
/** {@inheritDoc} */
@Override
public void close() {
checkpointManager.removeCheckpointListener(checkpointListener);
+
+ rowVersionFreeList.close();
+ indexFreeList.close();
}
/**
@@ -184,6 +188,8 @@ public class PersistentPageMemoryMvPartitionStorage extends
AbstractPageMemoryMv
private void syncMetadataOnCheckpoint(@Nullable Executor executor) throws
IgniteInternalCheckedException {
if (executor == null) {
rowVersionFreeList.saveMetadata();
+
+ indexFreeList.saveMetadata();
} else {
executor.execute(() -> {
try {
@@ -192,6 +198,14 @@ public class PersistentPageMemoryMvPartitionStorage
extends AbstractPageMemoryMv
throw new IgniteInternalException("Failed to save
RowVersionFreeList metadata", e);
}
});
+
+ executor.execute(() -> {
+ try {
+ indexFreeList.saveMetadata();
+ } catch (IgniteInternalCheckedException e) {
+ throw new IgniteInternalException("Failed to save
IndexColumnsFreeList metadata", e);
+ }
+ });
}
}
}
diff --git
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/VolatilePageMemoryMvPartitionStorage.java
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/VolatilePageMemoryMvPartitionStorage.java
index dbcbd7c4a8..dc90fc9f37 100644
---
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/VolatilePageMemoryMvPartitionStorage.java
+++
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/VolatilePageMemoryMvPartitionStorage.java
@@ -18,11 +18,11 @@
package org.apache.ignite.internal.storage.pagememory.mv;
import java.util.concurrent.CompletableFuture;
-import org.apache.ignite.configuration.schemas.table.TableView;
-import org.apache.ignite.internal.pagememory.inmemory.VolatilePageMemory;
import org.apache.ignite.internal.pagememory.tree.BplusTree;
import org.apache.ignite.internal.storage.MvPartitionStorage;
import org.apache.ignite.internal.storage.StorageException;
+import
org.apache.ignite.internal.storage.pagememory.VolatilePageMemoryTableStorage;
+import org.apache.ignite.internal.storage.pagememory.index.meta.IndexMetaTree;
/**
* Implementation of {@link MvPartitionStorage} based on a {@link BplusTree}
for in-memory case.
@@ -34,20 +34,25 @@ public class VolatilePageMemoryMvPartitionStorage extends
AbstractPageMemoryMvPa
/**
* Constructor.
*
- * @param partId Partition id.
- * @param tableView Table configuration.
- * @param pageMemory Page memory.
- * @param rowVersionFreeList Free list for {@link RowVersion}.
+ * @param tableStorage Table storage instance.
+ * @param partitionId Partition id.
* @param versionChainTree Table tree for {@link VersionChain}.
+ * @param indexMetaTree Tree that contains SQL indexes' metadata.
*/
public VolatilePageMemoryMvPartitionStorage(
- int partId,
- TableView tableView,
- VolatilePageMemory pageMemory,
- RowVersionFreeList rowVersionFreeList,
- VersionChainTree versionChainTree
+ VolatilePageMemoryTableStorage tableStorage,
+ int partitionId,
+ VersionChainTree versionChainTree,
+ IndexMetaTree indexMetaTree
) {
- super(partId, tableView, pageMemory, rowVersionFreeList,
versionChainTree);
+ super(
+ partitionId,
+ tableStorage,
+ tableStorage.dataRegion().rowVersionFreeList(),
+ tableStorage.dataRegion().indexColumnsFreeList(),
+ versionChainTree,
+ indexMetaTree
+ );
}
/** {@inheritDoc} */
diff --git
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/util/TreeCursorAdapter.java
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/util/TreeCursorAdapter.java
new file mode 100644
index 0000000000..2d7c7abd5a
--- /dev/null
+++
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/util/TreeCursorAdapter.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.storage.pagememory.util;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.function.Function;
+import org.apache.ignite.internal.storage.StorageException;
+import org.apache.ignite.internal.util.IgniteCursor;
+import org.apache.ignite.lang.IgniteInternalCheckedException;
+
+/**
+ * Wraps {@link IgniteCursor} into a {@link Iterator}.
+ *
+ * @param <TREE_ROWT> Type of elements in a tree cursor.
+ * @param <CURSOR_ROWT> Type of elements in a resulting iterator.
+ */
+public class TreeCursorAdapter<TREE_ROWT, CURSOR_ROWT> implements
Iterator<CURSOR_ROWT> {
+ /** Cursor instance from the tree. */
+ private final IgniteCursor<TREE_ROWT> cursor;
+
+ /** Value mapper to transform the data. */
+ private final Function<TREE_ROWT, CURSOR_ROWT> mapper;
+
+ /** Cached {@link IgniteCursor#next()} value. */
+ private Boolean hasNext;
+
+ public TreeCursorAdapter(IgniteCursor<TREE_ROWT> cursor,
Function<TREE_ROWT, CURSOR_ROWT> mapper) {
+ this.cursor = cursor;
+ this.mapper = mapper;
+ }
+
+ @Override
+ public boolean hasNext() throws StorageException {
+ try {
+ if (hasNext == null) {
+ hasNext = cursor.next();
+ }
+
+ return hasNext;
+ } catch (IgniteInternalCheckedException e) {
+ throw new StorageException("Failed to read next element from the
tree", e);
+ }
+ }
+
+ @Override
+ public CURSOR_ROWT next() throws NoSuchElementException, StorageException {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+
+ try {
+ TREE_ROWT treeRow = cursor.get();
+
+ hasNext = null;
+
+ return mapper.apply(treeRow);
+ } catch (IgniteInternalCheckedException e) {
+ throw new StorageException("Failed to read next element from the
tree", e);
+ }
+ }
+}
diff --git
a/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/index/PersistentPageMemoryHashIndexStorageTest.java
b/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/index/PersistentPageMemoryHashIndexStorageTest.java
new file mode 100644
index 0000000000..86774dba9c
--- /dev/null
+++
b/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/index/PersistentPageMemoryHashIndexStorageTest.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.storage.pagememory.index;
+
+import java.nio.file.Path;
+import
org.apache.ignite.configuration.schemas.table.ConstantValueDefaultConfigurationSchema;
+import
org.apache.ignite.configuration.schemas.table.EntryCountBudgetConfigurationSchema;
+import
org.apache.ignite.configuration.schemas.table.FunctionCallDefaultConfigurationSchema;
+import
org.apache.ignite.configuration.schemas.table.HashIndexConfigurationSchema;
+import
org.apache.ignite.configuration.schemas.table.NullValueDefaultConfigurationSchema;
+import org.apache.ignite.configuration.schemas.table.TableConfiguration;
+import
org.apache.ignite.configuration.schemas.table.UnlimitedBudgetConfigurationSchema;
+import
org.apache.ignite.internal.configuration.testframework.ConfigurationExtension;
+import
org.apache.ignite.internal.configuration.testframework.InjectConfiguration;
+import
org.apache.ignite.internal.pagememory.configuration.schema.UnsafeMemoryAllocatorConfigurationSchema;
+import org.apache.ignite.internal.pagememory.io.PageIoRegistry;
+import org.apache.ignite.internal.storage.index.AbstractHashIndexStorageTest;
+import
org.apache.ignite.internal.storage.pagememory.PersistentPageMemoryStorageEngine;
+import
org.apache.ignite.internal.storage.pagememory.PersistentPageMemoryTableStorage;
+import
org.apache.ignite.internal.storage.pagememory.configuration.schema.PersistentPageMemoryDataStorageConfigurationSchema;
+import
org.apache.ignite.internal.storage.pagememory.configuration.schema.PersistentPageMemoryStorageEngineConfiguration;
+import org.apache.ignite.internal.testframework.WorkDirectory;
+import org.apache.ignite.internal.testframework.WorkDirectoryExtension;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+/**
+ * Hash index test implementation for persistent page memory storage.
+ */
+@ExtendWith({ConfigurationExtension.class, WorkDirectoryExtension.class})
+class PersistentPageMemoryHashIndexStorageTest extends
AbstractHashIndexStorageTest {
+ @WorkDirectory
+ private Path workDir;
+
+ @InjectConfiguration(polymorphicExtensions =
UnsafeMemoryAllocatorConfigurationSchema.class)
+ private PersistentPageMemoryStorageEngineConfiguration engineConfig;
+
+ @InjectConfiguration(
+ name = "table",
+ value = "mock.dataStorage.name = " +
PersistentPageMemoryStorageEngine.ENGINE_NAME,
+ polymorphicExtensions = {
+ HashIndexConfigurationSchema.class,
+ PersistentPageMemoryDataStorageConfigurationSchema.class,
+ ConstantValueDefaultConfigurationSchema.class,
+ FunctionCallDefaultConfigurationSchema.class,
+ NullValueDefaultConfigurationSchema.class,
+ UnlimitedBudgetConfigurationSchema.class,
+ EntryCountBudgetConfigurationSchema.class
+ }
+ )
+ private TableConfiguration tableCfg;
+
+ private PersistentPageMemoryStorageEngine engine;
+
+ private PersistentPageMemoryTableStorage table;
+
+ @BeforeEach
+ void setUp() {
+ PageIoRegistry ioRegistry = new PageIoRegistry();
+
+ ioRegistry.loadFromServiceLoader();
+
+ engine = new PersistentPageMemoryStorageEngine("test", engineConfig,
ioRegistry, workDir, null);
+
+ engine.start();
+
+ table = engine.createMvTable(tableCfg);
+
+ table.start();
+
+ initialize(table);
+ }
+
+ @AfterEach
+ void tearDown() throws Exception {
+ IgniteUtils.closeAll(
+ table == null ? null : table::stop,
+ engine == null ? null : engine::stop
+ );
+ }
+
+ //TODO IGNITE-17626 Enable the test.
+ @Disabled
+ @Override
+ public void testDestroy() {
+ }
+}
diff --git
a/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/index/VolatilePageMemoryHashIndexStorageTest.java
b/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/index/VolatilePageMemoryHashIndexStorageTest.java
new file mode 100644
index 0000000000..a81df0c5d6
--- /dev/null
+++
b/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/index/VolatilePageMemoryHashIndexStorageTest.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.storage.pagememory.index;
+
+import
org.apache.ignite.configuration.schemas.table.ConstantValueDefaultConfigurationSchema;
+import
org.apache.ignite.configuration.schemas.table.EntryCountBudgetConfigurationSchema;
+import
org.apache.ignite.configuration.schemas.table.FunctionCallDefaultConfigurationSchema;
+import
org.apache.ignite.configuration.schemas.table.HashIndexConfigurationSchema;
+import
org.apache.ignite.configuration.schemas.table.NullValueDefaultConfigurationSchema;
+import org.apache.ignite.configuration.schemas.table.TableConfiguration;
+import
org.apache.ignite.configuration.schemas.table.UnlimitedBudgetConfigurationSchema;
+import
org.apache.ignite.internal.configuration.testframework.ConfigurationExtension;
+import
org.apache.ignite.internal.configuration.testframework.InjectConfiguration;
+import
org.apache.ignite.internal.pagememory.configuration.schema.UnsafeMemoryAllocatorConfigurationSchema;
+import org.apache.ignite.internal.pagememory.io.PageIoRegistry;
+import org.apache.ignite.internal.storage.index.AbstractHashIndexStorageTest;
+import
org.apache.ignite.internal.storage.pagememory.VolatilePageMemoryStorageEngine;
+import
org.apache.ignite.internal.storage.pagememory.VolatilePageMemoryTableStorage;
+import
org.apache.ignite.internal.storage.pagememory.configuration.schema.VolatilePageMemoryDataStorageConfigurationSchema;
+import
org.apache.ignite.internal.storage.pagememory.configuration.schema.VolatilePageMemoryStorageEngineConfiguration;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+/**
+ * Hash index test implementation for volatile page memory storage.
+ */
+@ExtendWith(ConfigurationExtension.class)
+class VolatilePageMemoryHashIndexStorageTest extends
AbstractHashIndexStorageTest {
+ @InjectConfiguration(polymorphicExtensions =
UnsafeMemoryAllocatorConfigurationSchema.class)
+ private VolatilePageMemoryStorageEngineConfiguration engineConfig;
+
+ @InjectConfiguration(
+ name = "table",
+ value = "mock.dataStorage.name = " +
VolatilePageMemoryStorageEngine.ENGINE_NAME,
+ polymorphicExtensions = {
+ HashIndexConfigurationSchema.class,
+ VolatilePageMemoryDataStorageConfigurationSchema.class,
+ ConstantValueDefaultConfigurationSchema.class,
+ FunctionCallDefaultConfigurationSchema.class,
+ NullValueDefaultConfigurationSchema.class,
+ UnlimitedBudgetConfigurationSchema.class,
+ EntryCountBudgetConfigurationSchema.class
+ }
+ )
+ private TableConfiguration tableCfg;
+
+ private VolatilePageMemoryStorageEngine engine;
+
+ private VolatilePageMemoryTableStorage table;
+
+ @BeforeEach
+ void setUp() {
+ PageIoRegistry ioRegistry = new PageIoRegistry();
+
+ ioRegistry.loadFromServiceLoader();
+
+ engine = new VolatilePageMemoryStorageEngine(engineConfig, ioRegistry);
+
+ engine.start();
+
+ table = engine.createMvTable(tableCfg);
+
+ table.start();
+
+ initialize(table);
+ }
+
+ @AfterEach
+ void tearDown() throws Exception {
+ IgniteUtils.closeAll(
+ table == null ? null : table::stop,
+ engine == null ? null : engine::stop
+ );
+ }
+
+ //TODO IGNITE-17626 Enable the test.
+ @Disabled
+ @Override
+ public void testDestroy() {
+ }
+}
diff --git
a/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/mv/AbstractPageMemoryMvPartitionStorageTest.java
b/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/mv/AbstractPageMemoryMvPartitionStorageTest.java
index 1fb6f8ad7c..fb594309e1 100644
---
a/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/mv/AbstractPageMemoryMvPartitionStorageTest.java
+++
b/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/mv/AbstractPageMemoryMvPartitionStorageTest.java
@@ -35,8 +35,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
/**
* Base test for MV partition storages based on PageMemory.
*/
-@ExtendWith(ConfigurationExtension.class)
-@ExtendWith(WorkDirectoryExtension.class)
+@ExtendWith({ConfigurationExtension.class, WorkDirectoryExtension.class})
abstract class AbstractPageMemoryMvPartitionStorageTest extends
AbstractMvPartitionStorageTest {
protected final PageIoRegistry ioRegistry = new PageIoRegistry();
diff --git
a/modules/storage-rocksdb/src/main/java/org/apache/ignite/internal/storage/rocksdb/RocksDbTableStorage.java
b/modules/storage-rocksdb/src/main/java/org/apache/ignite/internal/storage/rocksdb/RocksDbTableStorage.java
index ea0dab45e7..5b3d98d323 100644
---
a/modules/storage-rocksdb/src/main/java/org/apache/ignite/internal/storage/rocksdb/RocksDbTableStorage.java
+++
b/modules/storage-rocksdb/src/main/java/org/apache/ignite/internal/storage/rocksdb/RocksDbTableStorage.java
@@ -425,6 +425,7 @@ public class RocksDbTableStorage implements MvTableStorage {
return CompletableFuture.completedFuture(null);
}
+ //TODO IGNITE-17626 Destroy indexes as well...
mvPartition.destroy();
// Wait for the data to actually be removed from the disk and close
the storage.