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 c6761344e6 IGNITE-17535 Implemented a hash index B+Tree (#1021) c6761344e6 is described below commit c6761344e635b7c7798a2fd3bcb9316d932936be Author: Kirill Tkalenko <tkalkir...@yandex.ru> AuthorDate: Wed Aug 31 13:18:48 2022 +0300 IGNITE-17535 Implemented a hash index B+Tree (#1021) --- .../pagememory/datastructure/DataStructure.java | 4 +- .../pagememory/freelist/AbstractFreeList.java | 2 +- .../internal/pagememory/freelist/PagesList.java | 10 +- .../internal/pagememory/io/AbstractDataPageIo.java | 114 ++++--------- .../pagememory/persistence/PageStoreWriter.java | 1 - .../replacement/DelayedDirtyPageWrite.java | 1 - .../persistence/store/AbstractFilePageStoreIo.java | 2 +- .../internal/pagememory/util/PageIdUtils.java | 70 ++++---- .../pagememory/util}/PartitionlessLinks.java | 17 +- .../pagememory/freelist/TestDataPageIo.java | 6 +- .../internal/pagememory/util/PageIdUtilsTest.java | 4 +- .../pagememory/index/IndexPageIoModule.java | 12 +- .../storage/pagememory/index/IndexPageTypes.java | 44 +++++ .../pagememory/index/freelist/IndexColumns.java | 120 +++++++++++++ .../index/freelist/IndexColumnsFreeList.java | 77 +++++++++ .../ReadIndexColumnsValue.java} | 32 ++-- .../index/freelist/io/IndexColumnsDataIo.java | 83 +++++++++ .../pagememory/index/hash/HashIndexRow.java | 61 +++++++ .../pagememory/index/hash/HashIndexRowKey.java | 55 ++++++ .../IndexMetaTree.java => hash/HashIndexTree.java} | 66 ++++---- .../hash/InsertHashIndexRowInvokeClosure.java | 83 +++++++++ .../hash/RemoveHashIndexRowInvokeClosure.java | 99 +++++++++++ .../index/hash/io/HashIndexTreeInnerIo.java | 61 +++++++ .../pagememory/index/hash/io/HashIndexTreeIo.java | 188 +++++++++++++++++++++ .../index/hash/io/HashIndexTreeLeafIo.java | 61 +++++++ .../io/HashIndexTreeMetaIo.java} | 18 +- .../pagememory/index/meta/IndexMetaTree.java | 16 +- .../pagememory/index/meta/io/IndexMetaInnerIo.java | 6 +- .../pagememory/index/meta/io/IndexMetaIo.java | 3 +- .../pagememory/index/meta/io/IndexMetaLeafIo.java | 6 +- .../index/meta/io/IndexMetaTreeMetaIo.java | 6 +- .../mv/AbstractPageMemoryMvPartitionStorage.java | 8 +- .../storage/pagememory/mv/ReadRowVersion.java | 2 +- .../internal/storage/pagememory/mv/RowVersion.java | 5 +- .../storage/pagememory/mv/RowVersionFreeList.java | 3 - .../pagememory/mv/ScanVersionChainByTimestamp.java | 5 +- .../storage/pagememory/mv/VersionChain.java | 4 +- .../storage/pagememory/mv/io/RowVersionDataIo.java | 35 ++-- .../storage/pagememory/mv/io/VersionChainIo.java | 6 +- 39 files changed, 1125 insertions(+), 271 deletions(-) diff --git a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/datastructure/DataStructure.java b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/datastructure/DataStructure.java index 355ec47a09..16d0559ff7 100644 --- a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/datastructure/DataStructure.java +++ b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/datastructure/DataStructure.java @@ -19,7 +19,7 @@ package org.apache.ignite.internal.pagememory.datastructure; import static org.apache.ignite.internal.pagememory.PageIdAllocator.FLAG_DATA; import static org.apache.ignite.internal.pagememory.PageIdAllocator.MAX_PARTITION_ID; -import static org.apache.ignite.internal.pagememory.util.PageIdUtils.MAX_ITEMID_NUM; +import static org.apache.ignite.internal.pagememory.util.PageIdUtils.MAX_ITEM_ID_NUM; import static org.apache.ignite.internal.pagememory.util.PageIdUtils.flag; import static org.apache.ignite.internal.pagememory.util.PageIdUtils.itemId; import static org.apache.ignite.internal.pagememory.util.PageIdUtils.partitionId; @@ -453,7 +453,7 @@ public abstract class DataStructure { recycled = PageIdUtils.rotatePageId(pageId); } - assert itemId(recycled) > 0 && itemId(recycled) <= MAX_ITEMID_NUM : IgniteUtils.hexLong(recycled); + assert itemId(recycled) > 0 && itemId(recycled) <= MAX_ITEM_ID_NUM : IgniteUtils.hexLong(recycled); PageIo.setPageId(pageAddr, recycled); 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 287caa5ff7..9c104cd9a0 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 @@ -81,7 +81,7 @@ public abstract class AbstractFreeList<T extends Storable> extends PagesList imp private final @Nullable AtomicLong pageListCacheLimit; /** Page eviction tracker. */ - private final PageEvictionTracker evictionTracker; + protected final PageEvictionTracker evictionTracker; private final PageHandler<T, Boolean> updateRow = new UpdateRowHandler(); diff --git a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/freelist/PagesList.java b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/freelist/PagesList.java index 11b54485d3..724396b9f9 100644 --- a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/freelist/PagesList.java +++ b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/freelist/PagesList.java @@ -25,8 +25,8 @@ import static org.apache.ignite.internal.pagememory.PageIdAllocator.FLAG_DATA; import static org.apache.ignite.internal.pagememory.freelist.io.PagesListNodeIo.T_PAGE_LIST_NODE; import static org.apache.ignite.internal.pagememory.io.PageIo.getPageId; import static org.apache.ignite.internal.pagememory.io.PageIo.getType; -import static org.apache.ignite.internal.pagememory.util.PageIdUtils.MAX_ITEMID_NUM; -import static org.apache.ignite.internal.pagememory.util.PageIdUtils.changeType; +import static org.apache.ignite.internal.pagememory.util.PageIdUtils.MAX_ITEM_ID_NUM; +import static org.apache.ignite.internal.pagememory.util.PageIdUtils.changeFlag; import static org.apache.ignite.internal.pagememory.util.PageIdUtils.itemId; import static org.apache.ignite.internal.pagememory.util.PageIdUtils.pageId; import static org.apache.ignite.internal.pagememory.util.PageIdUtils.partitionId; @@ -988,7 +988,7 @@ public abstract class PagesList extends DataStructure { assert dataIo.isEmpty(dataAddr); // We can put only empty data pages to reuse bucket. // Change page type to index and add it as next node page to this list. - long newDataId = changeType(dataId, FLAG_AUX); + long newDataId = changeFlag(dataId, FLAG_AUX); setupNextPage(io, pageId, pageAddr, newDataId, dataAddr); @@ -1065,7 +1065,7 @@ public abstract class PagesList extends DataStructure { try { while ((nextId = bag.pollFreePage()) != 0L) { - assert itemId(nextId) > 0 && itemId(nextId) <= MAX_ITEMID_NUM : hexLong(nextId); + assert itemId(nextId) > 0 && itemId(nextId) <= MAX_ITEM_ID_NUM : hexLong(nextId); int idx = io.addPage(prevAddr, nextId, pageSize()); @@ -1266,7 +1266,7 @@ public abstract class PagesList extends DataStructure { dirty = true; - if (isReuseBucket(bucket) && !(itemId(pageId) > 0 && itemId(pageId) <= MAX_ITEMID_NUM)) { + if (isReuseBucket(bucket) && !(itemId(pageId) > 0 && itemId(pageId) <= MAX_ITEM_ID_NUM)) { throw corruptedFreeListException("Incorrectly recycled pageId in reuse bucket: " + hexLong(pageId), pageId); } 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 c63fac03e0..ac7b967b7f 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 @@ -1235,99 +1235,32 @@ public abstract class AbstractDataPageIo<T extends Storable> extends PageIo { ) throws IgniteInternalCheckedException { assertPageType(pageAddr); - return addRowFragment(pageMem, pageId, pageAddr, written, rowSize, row.link(), row, null, pageSize); - } - - /** - * Adds this payload as a fragment to this data page. - * - * @param pageId Page ID to use to construct a link. - * @param pageAddr Page address. - * @param payload Payload bytes. - * @param lastLink Link to the previous written fragment (link to the tail). - * @param pageSize Page size. - * @throws IgniteInternalCheckedException If failed. - */ - public void addRowFragment( - long pageId, - long pageAddr, - byte[] payload, - long lastLink, - int pageSize - ) throws IgniteInternalCheckedException { - assertPageType(pageAddr); + assert row != null; - addRowFragment(null, pageId, pageAddr, 0, 0, lastLink, null, payload, pageSize); - } - - /** - * Adds maximum possible fragment of the given row to this data page and sets respective link to the row. - * - * @param pageMem Page memory. - * @param pageId Page ID to use to construct a link. - * @param pageAddr Page address. - * @param written Number of bytes of row size that was already written. - * @param rowSize Row size. - * @param lastLink Link to the previous written fragment (link to the tail). - * @param row Row. - * @param payload Payload bytes. - * @param pageSize Page size. - * @return Written payload size. - * @throws IgniteInternalCheckedException If failed. - */ - private int addRowFragment( - PageMemory pageMem, - long pageId, - long pageAddr, - int written, - int rowSize, - long lastLink, - T row, - byte[] payload, - int pageSize - ) throws IgniteInternalCheckedException { - assert payload == null ^ row == null; + long lastLink = row.link(); int directCnt = getDirectCount(pageAddr); int indirectCnt = getIndirectCount(pageAddr); - int payloadSize = payload != null ? payload.length : - Math.min(rowSize - written, getFreeSpace(pageAddr)); + int payloadSize = Math.min(rowSize - written, getFreeSpace(pageAddr)); - if (row != null) { - int remain = rowSize - written - payloadSize; - int hdrSize = row.headerSize(); - - // We need page header (i.e. MVCC info) is located entirely on the very first page in chain. - // So we force moving it to the next page if it could not fit entirely on this page. - if (remain > 0 && remain < hdrSize) { - payloadSize -= hdrSize - remain; - } - } + assert payloadSize >= row.headerSize() || written >= row.headerSize(); int fullEntrySize = getPageEntrySize(payloadSize, SHOW_PAYLOAD_LEN | SHOW_LINK | SHOW_ITEM); int dataOff = getDataOffsetForWrite(pageAddr, fullEntrySize, directCnt, indirectCnt, pageSize); - if (payload == null) { - ByteBuffer buf = pageMem.pageBuffer(pageAddr); - - buf.position(dataOff); + ByteBuffer buf = pageMem.pageBuffer(pageAddr); - short p = (short) (payloadSize | FRAGMENTED_FLAG); + buf.position(dataOff); - buf.putShort(p); - buf.putLong(lastLink); + short fragmentSize = (short) (payloadSize | FRAGMENTED_FLAG); - int rowOff = rowSize - written - payloadSize; + buf.putShort(fragmentSize); + buf.putLong(lastLink); - writeFragmentData(row, buf, rowOff, payloadSize); - } else { - PageUtils.putShort(pageAddr, dataOff, (short) (payloadSize | FRAGMENTED_FLAG)); + int rowOff = rowSize - written - payloadSize; - PageUtils.putLong(pageAddr, dataOff + 2, lastLink); - - PageUtils.putBytes(pageAddr, dataOff + 10, payload); - } + writeFragmentData(row, buf, rowOff, payloadSize); int itemId = addItem(pageAddr, fullEntrySize, directCnt, indirectCnt, dataOff, pageSize); @@ -1353,18 +1286,39 @@ public abstract class AbstractDataPageIo<T extends Storable> extends PageIo { * Writes row data fragment. * * @param row Row. - * @param buf Byte buffer. + * @param pageBuf Byte buffer. * @param rowOff Offset in row data bytes. * @param payloadSize Data length that should be written in a fragment. * @throws IgniteInternalCheckedException If failed. */ protected abstract void writeFragmentData( final T row, - final ByteBuffer buf, + final ByteBuffer pageBuf, final int rowOff, final int payloadSize ) throws IgniteInternalCheckedException; + /** + * Writes a content of a byte buffer into a page. + * + * @param pageBuffer Direct page buffer. + * @param valueBuffer Byte buffer with value bytes. + * @param offset Offset within the value buffer. + * @param payloadSize Number of bytes to write. + */ + protected void putValueBufferIntoPage(ByteBuffer pageBuffer, ByteBuffer valueBuffer, int offset, int payloadSize) { + int oldPosition = valueBuffer.position(); + int oldLimit = valueBuffer.limit(); + + valueBuffer.position(offset); + valueBuffer.limit(offset + payloadSize); + + pageBuffer.put(valueBuffer); + + valueBuffer.position(oldPosition); + valueBuffer.limit(oldLimit); + } + /** * Inserts an item. * diff --git a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageStoreWriter.java b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageStoreWriter.java index 8aeb212f8c..519ce986f7 100644 --- a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageStoreWriter.java +++ b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageStoreWriter.java @@ -26,7 +26,6 @@ import org.apache.ignite.lang.IgniteInternalCheckedException; /** * Interface for write page to {@link PageStore}. */ -// TODO: IGNITE-15818 Maybe refactor. public interface PageStoreWriter { /** * Callback for write page. {@link PersistentPageMemory} will copy page content to buffer before call. diff --git a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/replacement/DelayedDirtyPageWrite.java b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/replacement/DelayedDirtyPageWrite.java index 8e4bd74d24..97b3469633 100644 --- a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/replacement/DelayedDirtyPageWrite.java +++ b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/replacement/DelayedDirtyPageWrite.java @@ -32,7 +32,6 @@ import org.jetbrains.annotations.Nullable; * segment lock. Page data is copied into temp buffer during {@link #write(PersistentPageMemory, FullPageId, ByteBuffer)} and then sent to * real implementation by {@link #finishReplacement}. */ -// TODO: IGNITE-15818 Maybe refactor. public class DelayedDirtyPageWrite implements WriteDirtyPage { /** Real flush dirty page implementation. */ private final WriteDirtyPage flushDirtyPage; diff --git a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/store/AbstractFilePageStoreIo.java b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/store/AbstractFilePageStoreIo.java index 7043f90abf..dbe36c50dd 100644 --- a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/store/AbstractFilePageStoreIo.java +++ b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/store/AbstractFilePageStoreIo.java @@ -54,7 +54,7 @@ public abstract class AbstractFilePageStoreIo implements Closeable { private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); /** Skip CRC calculation flag. */ - // TODO: IGNITE-17011 Move to config + // TODO: IGNITE-16350 Move to config private final boolean skipCrc = getBoolean("IGNITE_PDS_SKIP_CRC"); private volatile Path filePath; diff --git a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/util/PageIdUtils.java b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/util/PageIdUtils.java index 9712ad3cc1..67eaac3766 100644 --- a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/util/PageIdUtils.java +++ b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/util/PageIdUtils.java @@ -17,6 +17,8 @@ package org.apache.ignite.internal.pagememory.util; +import static org.apache.ignite.internal.pagememory.PageIdAllocator.FLAG_DATA; + import org.apache.ignite.internal.pagememory.FullPageId; import org.apache.ignite.internal.pagememory.PageIdAllocator; import org.apache.ignite.internal.util.IgniteUtils; @@ -27,6 +29,9 @@ import org.apache.ignite.internal.util.IgniteUtils; * @see FullPageId */ public final class PageIdUtils { + /** Represents an absent or missing link. */ + public static final long NULL_LINK = 0; + /** Size of the page index portion. */ public static final int PAGE_IDX_SIZE = Integer.SIZE; @@ -40,7 +45,7 @@ public final class PageIdUtils { public static final int OFFSET_SIZE = Byte.SIZE; /** Size of a tag portion. */ - public static final int TAG_SIZE = 2 * Byte.SIZE; + public static final int TAG_SIZE = Short.SIZE; /** Page index mask. */ public static final long PAGE_IDX_MASK = ~(-1L << PAGE_IDX_SIZE); @@ -54,74 +59,64 @@ public final class PageIdUtils { /** Page Index is a monotonically growing number within each partition. */ public static final long PART_ID_MASK = ~(-1L << PART_ID_SIZE); - /** Flags mask. Flags consists of a number of reserved bits, and page type (data/index page). */ + /** Flag mask {@link PageIdAllocator#FLAG_DATA} of {@link PageIdAllocator#FLAG_AUX}. */ public static final long FLAG_MASK = ~(-1L << FLAG_SIZE); /** Effective page ID mask. */ private static final long EFFECTIVE_PAGE_ID_MASK = ~(-1L << (PAGE_IDX_SIZE + PART_ID_SIZE)); - /** - * Offset of a Rotation ID inside a Page ID. - */ + /** Offset of a rotation ID inside a Page ID. */ private static final long ROTATION_ID_OFFSET = PAGE_IDX_SIZE + PART_ID_SIZE + FLAG_SIZE; /** Page ID mask that excludes link. */ private static final long PAGE_ID_MASK = ~(-1L << ROTATION_ID_OFFSET); - /** Max itemid number. */ - public static final int MAX_ITEMID_NUM = 0xFE; + /** Max item ID number. */ + public static final int MAX_ITEM_ID_NUM = 0xFE; /** Maximum page number. */ public static final long MAX_PAGE_NUM = (1L << PAGE_IDX_SIZE) - 1; - /** Maximum page number. */ + /** Maximum partition ID. */ public static final int MAX_PART_ID = (1 << PART_ID_SIZE) - 1; - /** Private constructor. */ - private PageIdUtils() { - // No-op. - } - /** * Constructs a page link by the given page ID and 8-byte words within the page. * * @param pageId Page ID. * @param itemId Item ID. - * @return Page link. */ public static long link(long pageId, int itemId) { - assert itemId >= 0 && itemId <= MAX_ITEMID_NUM : itemId; + assert itemId >= 0 && itemId <= MAX_ITEM_ID_NUM : itemId; assert (pageId >> ROTATION_ID_OFFSET) == 0 : IgniteUtils.hexLong(pageId); return pageId | (((long) itemId) << ROTATION_ID_OFFSET); } /** - * Extracts a page index from the given page ID. + * Extracts a page index from the page ID. * * @param pageId Page ID. - * @return Page index. */ public static int pageIndex(long pageId) { return (int) (pageId & PAGE_IDX_MASK); // 4 bytes } /** - * Extracts a page ID from the given page link. + * Extracts a page ID from the page link. * * @param link Page link. - * @return Page ID. */ public static long pageId(long link) { - return flag(link) == PageIdAllocator.FLAG_DATA ? link & PAGE_ID_MASK : link; + return flag(link) == FLAG_DATA ? link & PAGE_ID_MASK : link; } /** * Creates page ID from its components. * * @param partitionId Partition ID. - * @param flag Flags (a number of reserved bits, and page type (data/index page)) - * @param pageIdx Page index, monotonically growing number within each partition + * @param flag Flag: {@link PageIdAllocator#FLAG_DATA} of {@link PageIdAllocator#FLAG_AUX}. + * @param pageIdx Page index, monotonically growing number within each partition. * @return Page ID constructed from the given pageIdx and partition ID, see {@link FullPageId} */ public static long pageId(int partitionId, byte flag, int pageIdx) { @@ -134,10 +129,9 @@ public final class PageIdUtils { } /** - * Converts link into an effective page ID: pageId with only pageIdx and partitionId. + * Converts page link into an effective page ID: page ID with only page index and partition ID. * * @param link Page link. - * @return Effective page id. */ public static long effectivePageId(long link) { return link & EFFECTIVE_PAGE_ID_MASK; @@ -147,37 +141,33 @@ public final class PageIdUtils { * Checks whether page ID matches effective page ID. * * @param pageId Page id. - * @return {@code True} if page id is equal to effective page id. */ public static boolean isEffectivePageId(long pageId) { return (pageId & ~EFFECTIVE_PAGE_ID_MASK) == 0; } /** - * Index of the item inside of data page. + * Extracts item id (Offset in 8-byte words) from the page link. * * @param link Page link. - * @return Offset in 8-byte words. */ public static int itemId(long link) { return (int) ((link >> ROTATION_ID_OFFSET) & OFFSET_MASK); } /** - * Tag of pageId. + * Extracts tag (item id + flag) from the page link. * * @param link Page link. - * @return tag - item id + flags */ public static int tag(long link) { return (int) ((link >> (PAGE_IDX_SIZE + PART_ID_SIZE)) & TAG_MASK); } /** - * Extracts flags byte from the page ID. + * Extracts flag ({@link PageIdAllocator#FLAG_DATA} of {@link PageIdAllocator#FLAG_AUX}) from the page ID. * * @param pageId Page ID. - * @return Flag. */ public static byte flag(long pageId) { return (byte) ((pageId >>> (PART_ID_SIZE + PAGE_IDX_SIZE)) & FLAG_MASK); @@ -187,14 +177,15 @@ public final class PageIdUtils { * Extracts partition ID from the page ID. * * @param pageId Page ID. - * @return Partition ID. */ public static int partitionId(long pageId) { return (int) ((pageId >>> PAGE_IDX_SIZE) & PART_ID_MASK); } /** - * Returns the Rotation ID of a page identified by the given ID. + * Extracts rotation ID from the page ID. + * + * @param pageId Page ID. */ public static long rotationId(long pageId) { return pageId >>> ROTATION_ID_OFFSET; @@ -209,7 +200,7 @@ public final class PageIdUtils { public static long rotatePageId(long pageId) { long updatedRotationId = rotationId(pageId) + 1; - if (updatedRotationId > MAX_ITEMID_NUM) { + if (updatedRotationId > MAX_ITEM_ID_NUM) { updatedRotationId = 1; // We always want non-zero updatedRotationId } @@ -227,14 +218,14 @@ public final class PageIdUtils { } /** - * Change page type. + * Change page flag. * * @param pageId Old page ID. - * @param type New page type. + * @param flag New page flag: {@link PageIdAllocator#FLAG_AUX} or {@link PageIdAllocator#FLAG_DATA}. * @return Changed page ID. */ - public static long changeType(long pageId, byte type) { - return pageId(partitionId(pageId), type, pageIndex(pageId)); + public static long changeFlag(long pageId, byte flag) { + return pageId(partitionId(pageId), flag, pageIndex(pageId)); } /** @@ -254,8 +245,9 @@ public final class PageIdUtils { /** * Replaces partition ID in the page ID. * - * @param pageId Page ID. + * @param pageId Page ID. * @param partitionId Partition ID. + * @return Changed page ID. */ public static long changePartitionId(long pageId, int partitionId) { byte flag = flag(pageId); diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/PartitionlessLinks.java b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/util/PartitionlessLinks.java similarity index 86% rename from modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/PartitionlessLinks.java rename to modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/util/PartitionlessLinks.java index 26bb54a421..996d8db58e 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/PartitionlessLinks.java +++ b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/util/PartitionlessLinks.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.ignite.internal.storage.pagememory.mv; +package org.apache.ignite.internal.pagememory.util; import static org.apache.ignite.internal.pagememory.util.PageIdUtils.link; import static org.apache.ignite.internal.pagememory.util.PageIdUtils.pageId; @@ -27,23 +27,22 @@ 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.util.PageIdUtils; /** - * Handling of <em>partitionless links</em>, that is, page memory links from which partition ID is removed. They are used to spare storage - * space in cases when we know the partition ID from the context. + * Handling of <em>partitionless links</em>, that is, page memory links from which partition ID is removed. + * + * <p>They are used to save storage space in cases when we know the partition ID from the context. * * @see PageIdUtils#link(long, int) */ public class PartitionlessLinks { - /** - * Number of bytes a partitionless link takes in storage. - */ + /** Number of bytes a partitionless link takes in storage. */ public static final int PARTITIONLESS_LINK_SIZE_BYTES = 6; /** * Reads a partitionless link from the memory. * + * @param partitionId Partition ID. * @param pageAddr Page address. * @param offset Data offset. * @return Partitionless link. @@ -52,11 +51,11 @@ public class PartitionlessLinks { int tag = getShort(pageAddr, offset) & 0xFFFF; int pageIdx = getInt(pageAddr, offset + Short.BYTES); - // Links to metapages are impossible. For the sake of simplicity, NULL_LINK is returned in this case. + // NULL_LINK is stored as zeroes. This is fine, because no real link can be like this. Page with index 0 is never a data page. if (pageIdx == 0) { assert tag == 0 : tag; - return RowVersion.NULL_LINK; + return PageIdUtils.NULL_LINK; } byte flags = (byte) tag; diff --git a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/freelist/TestDataPageIo.java b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/freelist/TestDataPageIo.java index 336fe16032..0a9567b1b5 100644 --- a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/freelist/TestDataPageIo.java +++ b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/freelist/TestDataPageIo.java @@ -57,11 +57,11 @@ class TestDataPageIo extends AbstractDataPageIo<TestDataRow> { /** {@inheritDoc} */ @Override - protected void writeFragmentData(TestDataRow row, ByteBuffer buf, int rowOff, int payloadSize) { - assertPageType(buf); + protected void writeFragmentData(TestDataRow row, ByteBuffer pageBuf, int rowOff, int payloadSize) { + assertPageType(pageBuf); if (payloadSize > 0) { - buf.put(row.bytes, rowOff, payloadSize); + pageBuf.put(row.bytes, rowOff, payloadSize); } } diff --git a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/util/PageIdUtilsTest.java b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/util/PageIdUtilsTest.java index 7760e22d0e..10ad125185 100644 --- a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/util/PageIdUtilsTest.java +++ b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/util/PageIdUtilsTest.java @@ -121,11 +121,11 @@ public class PageIdUtilsTest { } @Test - public void testRandomIds() throws Exception { + public void testRandomIds() { Random rnd = new Random(); for (int i = 0; i < 50_000; i++) { - int off = rnd.nextInt(PageIdUtils.MAX_ITEMID_NUM + 1); + int off = rnd.nextInt(PageIdUtils.MAX_ITEM_ID_NUM + 1); int partId = rnd.nextInt(PageIdUtils.MAX_PART_ID + 1); int pageNum = rnd.nextInt(); diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/IndexPageIoModule.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/IndexPageIoModule.java index d463333673..a00368d279 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/IndexPageIoModule.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/IndexPageIoModule.java @@ -22,6 +22,10 @@ import java.util.List; import org.apache.ignite.internal.pagememory.PageMemory; import org.apache.ignite.internal.pagememory.io.IoVersions; import org.apache.ignite.internal.pagememory.io.PageIoModule; +import org.apache.ignite.internal.storage.pagememory.index.freelist.io.IndexColumnsDataIo; +import org.apache.ignite.internal.storage.pagememory.index.hash.io.HashIndexTreeInnerIo; +import org.apache.ignite.internal.storage.pagememory.index.hash.io.HashIndexTreeLeafIo; +import org.apache.ignite.internal.storage.pagememory.index.hash.io.HashIndexTreeMetaIo; import org.apache.ignite.internal.storage.pagememory.index.meta.io.IndexMetaInnerIo; import org.apache.ignite.internal.storage.pagememory.index.meta.io.IndexMetaLeafIo; import org.apache.ignite.internal.storage.pagememory.index.meta.io.IndexMetaTreeMetaIo; @@ -34,9 +38,15 @@ public class IndexPageIoModule implements PageIoModule { @Override public Collection<IoVersions<?>> ioVersions() { return List.of( + IndexColumnsDataIo.VERSIONS, + // Meta tree IO. IndexMetaTreeMetaIo.VERSIONS, IndexMetaInnerIo.VERSIONS, - IndexMetaLeafIo.VERSIONS + IndexMetaLeafIo.VERSIONS, + // Hash index IO. + HashIndexTreeMetaIo.VERSIONS, + HashIndexTreeInnerIo.VERSIONS, + HashIndexTreeLeafIo.VERSIONS ); } } diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/IndexPageTypes.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/IndexPageTypes.java new file mode 100644 index 0000000000..1621b2af26 --- /dev/null +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/IndexPageTypes.java @@ -0,0 +1,44 @@ +/* + * 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; + +/** + * Collection of all page types that relate to indexes. + */ +public interface IndexPageTypes { + /** Page IO type. */ + short T_VALUE_VERSION_DATA_IO = 100; + + /** Index meta tree meta IO type. */ + short T_INDEX_META_TREE_META_IO = 101; + + /** Index meta tree inner IO type. */ + short T_INDEX_META_INNER_IO = 102; + + /** Index meta tree leaf IO type. */ + short T_INDEX_META_LEAF_IO = 103; + + /** Hash index tree meta IO type. */ + short T_HASH_INDEX_META_IO = 10_000; + + /** Hash index tree inner IO type. */ + short T_HASH_INDEX_INNER_IO = 10_001; + + /** Hash index tree meta IO type. */ + short T_HASH_INDEX_LEAF_IO = 10_002; +} diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/freelist/IndexColumns.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/freelist/IndexColumns.java new file mode 100644 index 0000000000..803bb9940c --- /dev/null +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/freelist/IndexColumns.java @@ -0,0 +1,120 @@ +/* + * 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.freelist; + +import static org.apache.ignite.internal.pagememory.util.PageIdUtils.NULL_LINK; + +import java.nio.ByteBuffer; +import org.apache.ignite.internal.pagememory.Storable; +import org.apache.ignite.internal.pagememory.io.AbstractDataPageIo; +import org.apache.ignite.internal.pagememory.io.IoVersions; +import org.apache.ignite.internal.storage.pagememory.index.freelist.io.IndexColumnsDataIo; +import org.apache.ignite.lang.IgniteInternalCheckedException; +import org.jetbrains.annotations.Nullable; + +/** + * Index columns to store in free list. + */ +public class IndexColumns implements Storable { + /** Size offset. */ + public static final int SIZE_OFFSET = 0; + + /** Value offset. Value goes right after the size. */ + public static final int VALUE_OFFSET = SIZE_OFFSET + Integer.BYTES; + + /** Partition ID. */ + private final int partitionId; + + /** Link value. */ + private long link = NULL_LINK; + + /** Byte buffer with binary tuple data. */ + private final @Nullable ByteBuffer valueBuffer; + + /** + * Constructor. + * + * @param partitionId Partition ID. + * @param valueBuffer Value buffer. + */ + + public IndexColumns(int partitionId, @Nullable ByteBuffer valueBuffer) { + this.partitionId = partitionId; + this.valueBuffer = valueBuffer; + } + + /** + * Constructor. + * + * @param partitionId Partition ID. + * @param link Link. + * @param valueBuffer Value buffer. + */ + public IndexColumns(int partitionId, long link, @Nullable ByteBuffer valueBuffer) { + this.partitionId = partitionId; + this.link = link; + this.valueBuffer = valueBuffer; + } + + /** + * Returns the size of binary tuple. + */ + public int valueSize() { + assert valueBuffer != null; + + return valueBuffer.limit(); + } + + /** + * Returns a byte buffer that contains binary tuple data. + */ + public ByteBuffer valueBuffer() { + return valueBuffer; + } + + @Override + public void link(long link) { + this.link = link; + } + + @Override + public long link() { + return link; + } + + @Override + public int partition() { + return partitionId; + } + + @Override + public int size() throws IgniteInternalCheckedException { + return VALUE_OFFSET + valueSize(); + } + + @Override + public int headerSize() { + // Size of the tuple and its header. For further use in future optimizations. + return VALUE_OFFSET + Byte.BYTES; + } + + @Override + public IoVersions<? extends AbstractDataPageIo<?>> ioVersions() { + return IndexColumnsDataIo.VERSIONS; + } +} 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 new file mode 100644 index 0000000000..b66373bcfc --- /dev/null +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/freelist/IndexColumnsFreeList.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.index.freelist; + +import java.util.concurrent.atomic.AtomicLong; +import org.apache.ignite.internal.logger.IgniteLogger; +import org.apache.ignite.internal.pagememory.PageMemory; +import org.apache.ignite.internal.pagememory.evict.PageEvictionTracker; +import org.apache.ignite.internal.pagememory.freelist.AbstractFreeList; +import org.apache.ignite.internal.pagememory.metric.IoStatisticsHolder; +import org.apache.ignite.internal.pagememory.reuse.ReuseList; +import org.apache.ignite.internal.pagememory.util.PageLockListener; +import org.apache.ignite.lang.IgniteInternalCheckedException; +import org.jetbrains.annotations.Nullable; + +/** + * Free list implementation to store {@link IndexColumns} values. + */ +public class IndexColumnsFreeList extends AbstractFreeList<IndexColumns> { + /** + * Constructor. + * + * @param grpId Group ID. + * @param partId Partition ID. + * @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. + * @param evictionTracker Page eviction tracker. + * @throws IgniteInternalCheckedException If failed. + */ + public IndexColumnsFreeList( + int grpId, + int partId, + PageMemory pageMem, + @Nullable ReuseList reuseList, + PageLockListener lockLsnr, + IgniteLogger log, + long metaPageId, + boolean initNew, + @Nullable AtomicLong pageListCacheLimit, + PageEvictionTracker evictionTracker, + IoStatisticsHolder statHolder + ) throws IgniteInternalCheckedException { + super( + grpId, + partId, + "IndexColumnsFreeList_" + grpId, + pageMem, + reuseList, + lockLsnr, + log, + metaPageId, + initNew, + pageListCacheLimit, + evictionTracker + ); + } +} diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaTreeMetaIo.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/freelist/ReadIndexColumnsValue.java similarity index 51% copy from modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaTreeMetaIo.java copy to modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/freelist/ReadIndexColumnsValue.java index 9e8d229c15..9c30911e0a 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaTreeMetaIo.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/freelist/ReadIndexColumnsValue.java @@ -15,28 +15,24 @@ * limitations under the License. */ -package org.apache.ignite.internal.storage.pagememory.index.meta.io; +package org.apache.ignite.internal.storage.pagememory.index.freelist; -import org.apache.ignite.internal.pagememory.io.IoVersions; -import org.apache.ignite.internal.pagememory.tree.io.BplusMetaIo; -import org.apache.ignite.internal.storage.pagememory.index.meta.IndexMetaTree; +import org.apache.ignite.internal.pagememory.datapage.ReadPageMemoryRowValue; +import org.apache.ignite.internal.storage.pagememory.mv.RowVersion; /** - * IO routines for {@link IndexMetaTree} meta pages. + * Reads {@link RowVersion#value()} from page-memory. */ -public class IndexMetaTreeMetaIo extends BplusMetaIo { - /** Page IO type. */ - public static final short T_INDEX_META_TREE_META_IO = 13; - - /** I/O versions. */ - public static final IoVersions<IndexMetaTreeMetaIo> VERSIONS = new IoVersions<>(new IndexMetaTreeMetaIo(1)); +public class ReadIndexColumnsValue extends ReadPageMemoryRowValue { + /** {@inheritDoc} */ + @Override + protected int valueSizeOffsetInFirstSlot() { + return IndexColumns.SIZE_OFFSET; + } - /** - * Constructor. - * - * @param ver Page format version. - */ - protected IndexMetaTreeMetaIo(int ver) { - super(T_INDEX_META_TREE_META_IO, ver); + /** {@inheritDoc} */ + @Override + protected int valueOffsetInFirstSlot() { + return IndexColumns.VALUE_OFFSET; } } 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 new file mode 100644 index 0000000000..002c86b949 --- /dev/null +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/freelist/io/IndexColumnsDataIo.java @@ -0,0 +1,83 @@ +/* + * 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.freelist.io; + +import static org.apache.ignite.internal.pagememory.util.PageUtils.putByteBuffer; +import static org.apache.ignite.internal.pagememory.util.PageUtils.putInt; + +import java.nio.ByteBuffer; +import org.apache.ignite.internal.pagememory.io.AbstractDataPageIo; +import org.apache.ignite.internal.pagememory.io.IoVersions; +import org.apache.ignite.internal.storage.pagememory.index.IndexPageTypes; +import org.apache.ignite.internal.storage.pagememory.index.freelist.IndexColumns; +import org.apache.ignite.lang.IgniteStringBuilder; + +/** + * Data pages IO for {@link IndexColumns}. + */ +public class IndexColumnsDataIo extends AbstractDataPageIo<IndexColumns> { + /** I/O versions. */ + public static final IoVersions<IndexColumnsDataIo> VERSIONS = new IoVersions<>(new IndexColumnsDataIo(1)); + + /** + * Constructor. + * + * @param ver Page format version. + */ + protected IndexColumnsDataIo(int ver) { + super(IndexPageTypes.T_VALUE_VERSION_DATA_IO, ver); + } + + /** {@inheritDoc} */ + @Override + protected void writeRowData(long pageAddr, int dataOff, int payloadSize, IndexColumns row, boolean newRow) { + assertPageType(pageAddr); + + putInt(pageAddr, dataOff + IndexColumns.SIZE_OFFSET, row.valueSize()); + + putByteBuffer(pageAddr, dataOff + IndexColumns.VALUE_OFFSET, row.valueBuffer()); + } + + /** {@inheritDoc} */ + @Override + protected void writeFragmentData(IndexColumns row, ByteBuffer pageBuf, int rowOff, int payloadSize) { + assertPageType(pageBuf); + + if (rowOff == 0) { + // First fragment. + assert row.headerSize() <= payloadSize; + + pageBuf.putInt(row.valueSize()); + + putValueBufferIntoPage(pageBuf, row.valueBuffer(), 0, payloadSize - IndexColumns.VALUE_OFFSET); + } else { + // Not a first fragment. + assert rowOff >= row.headerSize(); + + putValueBufferIntoPage(pageBuf, row.valueBuffer(), rowOff - IndexColumns.VALUE_OFFSET, payloadSize); + } + } + + /** {@inheritDoc} */ + @Override + protected void printPage(long addr, int pageSize, IgniteStringBuilder sb) { + sb.app("IndexColumnsDataIo [\n"); + printPageLayout(addr, pageSize, sb); + sb.app("\n]"); + } +} diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/HashIndexRow.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/HashIndexRow.java new file mode 100644 index 0000000000..320a4033e1 --- /dev/null +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/HashIndexRow.java @@ -0,0 +1,61 @@ +/* + * 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.storage.RowId; +import org.apache.ignite.internal.storage.index.IndexRow; +import org.apache.ignite.internal.storage.pagememory.index.freelist.IndexColumns; +import org.apache.ignite.internal.util.HashUtils; + +/** + * {@link IndexRow} implementation used in the {@link HashIndexTree}. + */ +public class HashIndexRow extends HashIndexRowKey { + /** Row id. */ + private final RowId rowId; + + /** + * Constructor. + * + * @param indexColumns Index columns. + * @param rowId Row id. + */ + public HashIndexRow(IndexColumns indexColumns, RowId rowId) { + this(HashUtils.hash32(indexColumns.valueBuffer()), indexColumns, rowId); + } + + /** + * Constructor. + * + * @param indexColumnsHash Hash of the index columns. + * @param indexColumns Index columns. + * @param rowId Row id. + */ + public HashIndexRow(int indexColumnsHash, IndexColumns indexColumns, RowId rowId) { + super(indexColumnsHash, indexColumns); + + this.rowId = rowId; + } + + /** + * Returns a row id of the row. + */ + public RowId rowId() { + return rowId; + } +} diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/HashIndexRowKey.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/HashIndexRowKey.java new file mode 100644 index 0000000000..62e520fd56 --- /dev/null +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/HashIndexRowKey.java @@ -0,0 +1,55 @@ +/* + * 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.storage.pagememory.index.freelist.IndexColumns; + +/** + * Key to search for a {@link HashIndexRow} in the {@link HashIndexTree}. + */ +public class HashIndexRowKey { + private final int indexColumnsHash; + + private final IndexColumns indexColumns; + + /** + * Constructor. + * + * @param indexColumnsHash Hash of the index columns. + * @param indexColumns Index columns. + */ + public HashIndexRowKey(int indexColumnsHash, IndexColumns indexColumns) { + this.indexColumnsHash = indexColumnsHash; + + this.indexColumns = indexColumns; + } + + /** + * Returns the hash of the index columns. + */ + public int indexColumnsHash() { + return indexColumnsHash; + } + + /** + * Returns an indexed columns value. + */ + public IndexColumns indexColumns() { + return indexColumns; + } +} diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/IndexMetaTree.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/HashIndexTree.java similarity index 51% copy from modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/IndexMetaTree.java copy to modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/HashIndexTree.java index e3d55bb0d6..d9ebdc48d2 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/IndexMetaTree.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/HashIndexTree.java @@ -15,25 +15,29 @@ * limitations under the License. */ -package org.apache.ignite.internal.storage.pagememory.index.meta; +package org.apache.ignite.internal.storage.pagememory.index.hash; import java.util.concurrent.atomic.AtomicLong; import org.apache.ignite.internal.pagememory.PageMemory; +import org.apache.ignite.internal.pagememory.datapage.DataPageReader; import org.apache.ignite.internal.pagememory.reuse.ReuseList; import org.apache.ignite.internal.pagememory.tree.BplusTree; import org.apache.ignite.internal.pagememory.tree.io.BplusIo; import org.apache.ignite.internal.pagememory.util.PageLockListener; -import org.apache.ignite.internal.storage.pagememory.index.meta.io.IndexMetaInnerIo; -import org.apache.ignite.internal.storage.pagememory.index.meta.io.IndexMetaIo; -import org.apache.ignite.internal.storage.pagememory.index.meta.io.IndexMetaLeafIo; -import org.apache.ignite.internal.storage.pagememory.index.meta.io.IndexMetaTreeMetaIo; +import org.apache.ignite.internal.storage.pagememory.index.hash.io.HashIndexTreeInnerIo; +import org.apache.ignite.internal.storage.pagememory.index.hash.io.HashIndexTreeIo; +import org.apache.ignite.internal.storage.pagememory.index.hash.io.HashIndexTreeLeafIo; +import org.apache.ignite.internal.storage.pagememory.index.hash.io.HashIndexTreeMetaIo; import org.apache.ignite.lang.IgniteInternalCheckedException; import org.jetbrains.annotations.Nullable; /** - * Tree for storing index meta-information, such as the root of an index tree. + * {@link BplusTree} implementation for storing {@link HashIndexRow}. */ -public class IndexMetaTree extends BplusTree<IndexMeta, IndexMeta> { +public class HashIndexTree extends BplusTree<HashIndexRowKey, HashIndexRow> { + /** Data page reader instance to read payload from data pages. */ + private final DataPageReader dataPageReader; + /** * Constructor. * @@ -48,9 +52,9 @@ public class IndexMetaTree extends BplusTree<IndexMeta, IndexMeta> { * @param initNew {@code True} if new tree should be created. * @throws IgniteInternalCheckedException If failed. */ - public IndexMetaTree( + public HashIndexTree( int grpId, - String grpName, + @Nullable String grpName, int partId, PageMemory pageMem, PageLockListener lockLsnr, @@ -59,36 +63,40 @@ public class IndexMetaTree extends BplusTree<IndexMeta, IndexMeta> { @Nullable ReuseList reuseList, boolean initNew ) throws IgniteInternalCheckedException { - super( - "IndexMetaTree_" + grpId, - grpId, - grpName, - partId, - pageMem, - lockLsnr, - globalRmvId, - metaPageId, - reuseList - ); + super("HashIndexTree_" + grpId, grpId, grpName, partId, pageMem, lockLsnr, globalRmvId, metaPageId, reuseList); + + setIos(HashIndexTreeInnerIo.VERSIONS, HashIndexTreeLeafIo.VERSIONS, HashIndexTreeMetaIo.VERSIONS); - setIos(IndexMetaInnerIo.VERSIONS, IndexMetaLeafIo.VERSIONS, IndexMetaTreeMetaIo.VERSIONS); + dataPageReader = new DataPageReader(pageMem, grpId, statisticsHolder()); initTree(initNew); } - /** {@inheritDoc} */ + /** + * Returns a partition id. + */ + public int partitionId() { + return partId; + } + + /** + * Returns a data page reader instance to read payload from data pages. + */ + public DataPageReader dataPageReader() { + return dataPageReader; + } + @Override - protected int compare(BplusIo<IndexMeta> io, long pageAddr, int idx, IndexMeta row) { - IndexMetaIo indexMetaIo = (IndexMetaIo) io; + protected int compare(BplusIo<HashIndexRowKey> io, long pageAddr, int idx, HashIndexRowKey row) throws IgniteInternalCheckedException { + HashIndexTreeIo hashIndexTreeIo = (HashIndexTreeIo) io; - return indexMetaIo.compare(pageAddr, idx, row); + return hashIndexTreeIo.compare(dataPageReader, partId, pageAddr, idx, row); } - /** {@inheritDoc} */ @Override - public IndexMeta getRow(BplusIo<IndexMeta> io, long pageAddr, int idx, Object x) { - IndexMetaIo indexMetaIo = (IndexMetaIo) io; + public HashIndexRow getRow(BplusIo<HashIndexRowKey> io, long pageAddr, int idx, Object x) throws IgniteInternalCheckedException { + HashIndexTreeIo hashIndexTreeIo = (HashIndexTreeIo) io; - return indexMetaIo.getRow(pageAddr, idx); + return hashIndexTreeIo.getRow(dataPageReader, partId, pageAddr, idx); } } 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 new file mode 100644 index 0000000000..c6099ead0a --- /dev/null +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/InsertHashIndexRowInvokeClosure.java @@ -0,0 +1,83 @@ +/* + * 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 static org.apache.ignite.internal.pagememory.util.PageIdUtils.NULL_LINK; + +import org.apache.ignite.internal.pagememory.metric.IoStatisticsHolder; +import org.apache.ignite.internal.pagememory.tree.IgniteTree.InvokeClosure; +import org.apache.ignite.internal.pagememory.tree.IgniteTree.OperationType; +import org.apache.ignite.internal.storage.pagememory.index.freelist.IndexColumns; +import org.apache.ignite.internal.storage.pagememory.index.freelist.IndexColumnsFreeList; +import org.apache.ignite.lang.IgniteInternalCheckedException; +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> { + /** Hash index row instance for insertion. */ + private final HashIndexRow hashIndexRow; + + /** Free list to insert data into in case of necessity. */ + private final IndexColumnsFreeList freeList; + + /** Statistics holder to track IO operations. */ + private final IoStatisticsHolder statHolder; + + /** Operation type, either {@link OperationType#PUT} or {@link OperationType#NOOP} depending on the tree state. */ + private OperationType operationType = OperationType.PUT; + + /** + * Constructor. + * + * @param hashIndexRow Hash index row instance for insertion. + * @param freeList Free list to insert data into in case of necessity. + * @param statHolder Statistics holder to track IO operations. + */ + public InsertHashIndexRowInvokeClosure(HashIndexRow hashIndexRow, IndexColumnsFreeList freeList, IoStatisticsHolder statHolder) { + assert hashIndexRow.indexColumns().link() == NULL_LINK; + + this.hashIndexRow = hashIndexRow; + this.freeList = freeList; + this.statHolder = statHolder; + } + + @Override + public void call(@Nullable HashIndexRow oldRow) throws IgniteInternalCheckedException { + if (oldRow != null) { + operationType = OperationType.NOOP; + + return; + } + + freeList.insertDataRow(hashIndexRow.indexColumns(), statHolder); + } + + @Override + public @Nullable HashIndexRow newRow() { + return hashIndexRow; + } + + @Override + public OperationType operationType() { + return operationType; + } +} 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 new file mode 100644 index 0000000000..bdd342bc75 --- /dev/null +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/RemoveHashIndexRowInvokeClosure.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.hash; + + +import static org.apache.ignite.internal.pagememory.util.PageIdUtils.NULL_LINK; + +import org.apache.ignite.internal.pagememory.metric.IoStatisticsHolder; +import org.apache.ignite.internal.pagememory.tree.BplusTree; +import org.apache.ignite.internal.pagememory.tree.IgniteTree.InvokeClosure; +import org.apache.ignite.internal.pagememory.tree.IgniteTree.OperationType; +import org.apache.ignite.internal.storage.pagememory.index.freelist.IndexColumns; +import org.apache.ignite.internal.storage.pagememory.index.freelist.IndexColumnsFreeList; +import org.apache.ignite.lang.IgniteInternalCheckedException; +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> { + /** Hash index row instance for removal. */ + private final HashIndexRow hashIndexRow; + + /** Free list to insert data into in case of necessity. */ + private final IndexColumnsFreeList freeList; + + /** Statistics holder to track IO operations. */ + private final IoStatisticsHolder statHolder; + + /** Operation type, either {@link OperationType#REMOVE} or {@link OperationType#NOOP} if row is missing. */ + private OperationType operationType = OperationType.REMOVE; + + /** + * Constructor. + * + * @param hashIndexRow Hash index row instance for removal. + * @param freeList Free list to insert data into in case of necessity. + * @param statHolder Statistics holder to track IO operations. + */ + public RemoveHashIndexRowInvokeClosure(HashIndexRow hashIndexRow, IndexColumnsFreeList freeList, IoStatisticsHolder statHolder) { + assert hashIndexRow.indexColumns().link() == 0L; + + this.hashIndexRow = hashIndexRow; + this.freeList = freeList; + this.statHolder = statHolder; + } + + @Override + public void call(@Nullable HashIndexRow oldRow) { + if (oldRow == null) { + operationType = OperationType.NOOP; + } else { + hashIndexRow.indexColumns().link(oldRow.indexColumns().link()); + } + } + + @Override + public @Nullable HashIndexRow newRow() { + return null; + } + + @Override + public OperationType operationType() { + return operationType; + } + + /** + * Method to call after {@link BplusTree#invoke(Object, Object, InvokeClosure)} has completed. + * + * @throws IgniteInternalCheckedException If failed to remove data from the free list. + */ + public void afterCompletion() throws IgniteInternalCheckedException { + IndexColumns indexColumns = hashIndexRow.indexColumns(); + + if (indexColumns.link() != NULL_LINK) { + assert operationType == OperationType.REMOVE; + + freeList.removeDataRowByLink(indexColumns.link(), statHolder); + + indexColumns.link(NULL_LINK); + } + } +} diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/io/HashIndexTreeInnerIo.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/io/HashIndexTreeInnerIo.java new file mode 100644 index 0000000000..ffd3fe93b1 --- /dev/null +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/io/HashIndexTreeInnerIo.java @@ -0,0 +1,61 @@ +/* + * 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.io; + +import org.apache.ignite.internal.pagememory.io.IoVersions; +import org.apache.ignite.internal.pagememory.tree.BplusTree; +import org.apache.ignite.internal.pagememory.tree.io.BplusInnerIo; +import org.apache.ignite.internal.pagememory.tree.io.BplusIo; +import org.apache.ignite.internal.storage.pagememory.index.IndexPageTypes; +import org.apache.ignite.internal.storage.pagememory.index.hash.HashIndexRowKey; +import org.apache.ignite.internal.storage.pagememory.index.hash.HashIndexTree; +import org.apache.ignite.lang.IgniteInternalCheckedException; + +/** + * {@link BplusInnerIo} implementation for {@link HashIndexTree}. + */ +public class HashIndexTreeInnerIo extends BplusInnerIo<HashIndexRowKey> implements HashIndexTreeIo { + /** I/O versions. */ + public static final IoVersions<HashIndexTreeInnerIo> VERSIONS = new IoVersions<>(new HashIndexTreeInnerIo(1)); + + /** + * Constructor. + * + * @param ver Page format version. + */ + protected HashIndexTreeInnerIo(int ver) { + super(IndexPageTypes.T_HASH_INDEX_INNER_IO, ver, true, SIZE_IN_BYTES); + } + + @Override + public void store(long dstPageAddr, int dstIdx, BplusIo<HashIndexRowKey> srcIo, long srcPageAddr, int srcIdx) { + HashIndexTreeIo.super.store(dstPageAddr, dstIdx, srcIo, srcPageAddr, srcIdx); + } + + @Override + public void storeByOffset(long pageAddr, int off, HashIndexRowKey row) { + HashIndexTreeIo.super.storeByOffset(pageAddr, off, row); + } + + @Override + public HashIndexRowKey getLookupRow(BplusTree<HashIndexRowKey, ?> tree, long pageAddr, int idx) throws IgniteInternalCheckedException { + HashIndexTree hashIndexTree = (HashIndexTree) tree; + + return getRow(hashIndexTree.dataPageReader(), hashIndexTree.partitionId(), pageAddr, idx); + } +} diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/io/HashIndexTreeIo.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/io/HashIndexTreeIo.java new file mode 100644 index 0000000000..395bbb3f05 --- /dev/null +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/io/HashIndexTreeIo.java @@ -0,0 +1,188 @@ +/* + * 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.io; + +import static org.apache.ignite.internal.pagememory.util.PageUtils.getInt; +import static org.apache.ignite.internal.pagememory.util.PageUtils.getLong; +import static org.apache.ignite.internal.pagememory.util.PageUtils.putInt; +import static org.apache.ignite.internal.pagememory.util.PageUtils.putLong; +import static org.apache.ignite.internal.pagememory.util.PartitionlessLinks.PARTITIONLESS_LINK_SIZE_BYTES; +import static org.apache.ignite.internal.pagememory.util.PartitionlessLinks.readPartitionlessLink; +import static org.apache.ignite.internal.pagememory.util.PartitionlessLinks.writePartitionlessLink; + +import java.nio.ByteBuffer; +import java.util.UUID; +import org.apache.ignite.internal.pagememory.datapage.DataPageReader; +import org.apache.ignite.internal.pagememory.tree.io.BplusIo; +import org.apache.ignite.internal.pagememory.util.PageUtils; +import org.apache.ignite.internal.storage.RowId; +import org.apache.ignite.internal.storage.pagememory.index.freelist.IndexColumns; +import org.apache.ignite.internal.storage.pagememory.index.freelist.ReadIndexColumnsValue; +import org.apache.ignite.internal.storage.pagememory.index.hash.HashIndexRow; +import org.apache.ignite.internal.storage.pagememory.index.hash.HashIndexRowKey; +import org.apache.ignite.internal.storage.pagememory.index.meta.IndexMeta; +import org.apache.ignite.lang.IgniteInternalCheckedException; + +/** + * Interface for {@link IndexMeta} B+Tree-related IO. + * + * <p>Defines a following data layout: + * <ul> + * <li>Index ID - {@link UUID} (16 bytes);</li> + * <li>Index root page ID - long (8 bytes).</li> + * </ul> + */ +public interface HashIndexTreeIo { + /** Offset of the index columns hash (4 bytes). */ + int INDEX_COLUMNS_HASH_OFFSET = 0; + + /** Offset of the index column link (6 bytes). */ + int INDEX_COLUMNS_LINK_OFFSET = INDEX_COLUMNS_HASH_OFFSET + Integer.BYTES; + + /** Offset of rowId's most significant bits, 8 bytes. */ + int ROW_ID_MSB_OFFSET = INDEX_COLUMNS_LINK_OFFSET + PARTITIONLESS_LINK_SIZE_BYTES; + + /** Offset of rowId's least significant bits, 8 bytes. */ + int ROW_ID_LSB_OFFSET = ROW_ID_MSB_OFFSET + Long.BYTES; + + /** Payload size in bytes. */ + int SIZE_IN_BYTES = ROW_ID_LSB_OFFSET + Long.BYTES; + + /** + * Returns an offset of the element inside the page. + * + * @see BplusIo#offset(int) + */ + int offset(int idx); + + /** + * Stores a hash index row, copied from another page. + * + * @see BplusIo#store(long, int, BplusIo, long, int) + */ + default void store(long dstPageAddr, int dstIdx, BplusIo<HashIndexRowKey> srcIo, long srcPageAddr, int srcIdx) { + int dstOffset = offset(dstIdx); + int srcOffset = offset(srcIdx); + + PageUtils.copyMemory(srcPageAddr, srcOffset, dstPageAddr, dstOffset, SIZE_IN_BYTES); + } + + /** + * Stores a hash index row in the page. + * + * @see BplusIo#storeByOffset(long, int, Object) + */ + default void storeByOffset(long pageAddr, int off, HashIndexRowKey rowKey) { + assert rowKey instanceof HashIndexRow; + + HashIndexRow hashIndexRow = (HashIndexRow) rowKey; + + putInt(pageAddr, off + INDEX_COLUMNS_HASH_OFFSET, hashIndexRow.indexColumnsHash()); + + writePartitionlessLink(pageAddr + off + INDEX_COLUMNS_LINK_OFFSET, hashIndexRow.indexColumns().link()); + + RowId rowId = hashIndexRow.rowId(); + + putLong(pageAddr, off + ROW_ID_MSB_OFFSET, rowId.mostSignificantBits()); + putLong(pageAddr, off + ROW_ID_LSB_OFFSET, rowId.leastSignificantBits()); + } + + /** + * Compare the {@link HashIndexRowKey} from the page with passed {@link HashIndexRowKey}. + * + * @param pageAddr Page address. + * @param idx Element's index. + * @param rowKey Lookup index row key. + * @return Comparison result. + */ + default int compare(DataPageReader dataPageReader, int partitionId, long pageAddr, int idx, HashIndexRowKey rowKey) + throws IgniteInternalCheckedException { + assert rowKey instanceof HashIndexRow; + + HashIndexRow hashIndexRow = (HashIndexRow) rowKey; + + int off = offset(idx); + + int cmp = Integer.compare(getInt(pageAddr, off + INDEX_COLUMNS_HASH_OFFSET), hashIndexRow.indexColumnsHash()); + + if (cmp != 0) { + return cmp; + } + + long link = readPartitionlessLink(partitionId, pageAddr, off + INDEX_COLUMNS_LINK_OFFSET); + + //TODO Add in-place compare in IGNITE-17536 + ReadIndexColumnsValue indexColumnsTraversal = new ReadIndexColumnsValue(); + + dataPageReader.traverse(link, indexColumnsTraversal, null); + + ByteBuffer indexColumnsBuffer = ByteBuffer.wrap(indexColumnsTraversal.result()); + + cmp = indexColumnsBuffer.compareTo(hashIndexRow.indexColumns().valueBuffer()); + + if (cmp != 0) { + return cmp; + } + + long rowIdMsb = getLong(pageAddr, off + ROW_ID_MSB_OFFSET); + + cmp = Long.compare(rowIdMsb, hashIndexRow.rowId().mostSignificantBits()); + + if (cmp != 0) { + return cmp; + } + + long rowIdLsb = getLong(pageAddr, off + ROW_ID_LSB_OFFSET); + + return Long.compare(rowIdLsb, hashIndexRow.rowId().leastSignificantBits()); + } + + /** + * Reads a hash index row value. + * + * @param dataPageReader Data page reader instance to read payload from data pages. + * @param partitionId Partition id. + * @param pageAddr Page address. + * @param idx Element's index. + * @return Hash index row. + * @throws IgniteInternalCheckedException If failed to read payload from data pages. + */ + default HashIndexRow getRow(DataPageReader dataPageReader, int partitionId, long pageAddr, int idx) + throws IgniteInternalCheckedException { + int off = offset(idx); + + int hash = getInt(pageAddr, off + INDEX_COLUMNS_HASH_OFFSET); + + long link = readPartitionlessLink(partitionId, pageAddr, off + INDEX_COLUMNS_LINK_OFFSET); + + ReadIndexColumnsValue indexColumnsTraversal = new ReadIndexColumnsValue(); + + dataPageReader.traverse(link, indexColumnsTraversal, null); + + ByteBuffer indexColumnsBuffer = ByteBuffer.wrap(indexColumnsTraversal.result()); + + IndexColumns indexColumns = new IndexColumns(partitionId, link, indexColumnsBuffer); + + long rowIdMsb = getLong(pageAddr, off + ROW_ID_MSB_OFFSET); + long rowIdLsb = getLong(pageAddr, off + ROW_ID_LSB_OFFSET); + + RowId rowId = new RowId(partitionId, rowIdMsb, rowIdLsb); + + return new HashIndexRow(hash, indexColumns, rowId); + } +} diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/io/HashIndexTreeLeafIo.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/io/HashIndexTreeLeafIo.java new file mode 100644 index 0000000000..02affe53ec --- /dev/null +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/io/HashIndexTreeLeafIo.java @@ -0,0 +1,61 @@ +/* + * 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.io; + +import org.apache.ignite.internal.pagememory.io.IoVersions; +import org.apache.ignite.internal.pagememory.tree.BplusTree; +import org.apache.ignite.internal.pagememory.tree.io.BplusIo; +import org.apache.ignite.internal.pagememory.tree.io.BplusLeafIo; +import org.apache.ignite.internal.storage.pagememory.index.IndexPageTypes; +import org.apache.ignite.internal.storage.pagememory.index.hash.HashIndexRowKey; +import org.apache.ignite.internal.storage.pagememory.index.hash.HashIndexTree; +import org.apache.ignite.lang.IgniteInternalCheckedException; + +/** + * {@link BplusLeafIo} implementation for {@link HashIndexTree}. + */ +public class HashIndexTreeLeafIo extends BplusLeafIo<HashIndexRowKey> implements HashIndexTreeIo { + /** I/O versions. */ + public static final IoVersions<HashIndexTreeLeafIo> VERSIONS = new IoVersions<>(new HashIndexTreeLeafIo(1)); + + /** + * Constructor. + * + * @param ver Page format version. + */ + protected HashIndexTreeLeafIo(int ver) { + super(IndexPageTypes.T_HASH_INDEX_LEAF_IO, ver, SIZE_IN_BYTES); + } + + @Override + public void store(long dstPageAddr, int dstIdx, BplusIo<HashIndexRowKey> srcIo, long srcPageAddr, int srcIdx) { + HashIndexTreeIo.super.store(dstPageAddr, dstIdx, srcIo, srcPageAddr, srcIdx); + } + + @Override + public void storeByOffset(long pageAddr, int off, HashIndexRowKey row) { + HashIndexTreeIo.super.storeByOffset(pageAddr, off, row); + } + + @Override + public HashIndexRowKey getLookupRow(BplusTree<HashIndexRowKey, ?> tree, long pageAddr, int idx) throws IgniteInternalCheckedException { + HashIndexTree hashIndexTree = (HashIndexTree) tree; + + return getRow(hashIndexTree.dataPageReader(), hashIndexTree.partitionId(), pageAddr, idx); + } +} diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaTreeMetaIo.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/io/HashIndexTreeMetaIo.java similarity index 66% copy from modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaTreeMetaIo.java copy to modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/io/HashIndexTreeMetaIo.java index 9e8d229c15..46a7ad0760 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaTreeMetaIo.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/hash/io/HashIndexTreeMetaIo.java @@ -15,28 +15,26 @@ * limitations under the License. */ -package org.apache.ignite.internal.storage.pagememory.index.meta.io; +package org.apache.ignite.internal.storage.pagememory.index.hash.io; import org.apache.ignite.internal.pagememory.io.IoVersions; import org.apache.ignite.internal.pagememory.tree.io.BplusMetaIo; -import org.apache.ignite.internal.storage.pagememory.index.meta.IndexMetaTree; +import org.apache.ignite.internal.storage.pagememory.index.IndexPageTypes; +import org.apache.ignite.internal.storage.pagememory.index.hash.HashIndexTree; /** - * IO routines for {@link IndexMetaTree} meta pages. + * IO routines for {@link HashIndexTree} meta pages. */ -public class IndexMetaTreeMetaIo extends BplusMetaIo { - /** Page IO type. */ - public static final short T_INDEX_META_TREE_META_IO = 13; - +public class HashIndexTreeMetaIo extends BplusMetaIo { /** I/O versions. */ - public static final IoVersions<IndexMetaTreeMetaIo> VERSIONS = new IoVersions<>(new IndexMetaTreeMetaIo(1)); + public static final IoVersions<HashIndexTreeMetaIo> VERSIONS = new IoVersions<>(new HashIndexTreeMetaIo(1)); /** * Constructor. * * @param ver Page format version. */ - protected IndexMetaTreeMetaIo(int ver) { - super(T_INDEX_META_TREE_META_IO, ver); + protected HashIndexTreeMetaIo(int ver) { + super(IndexPageTypes.T_HASH_INDEX_META_IO, ver); } } diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/IndexMetaTree.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/IndexMetaTree.java index e3d55bb0d6..99daf6b7ef 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/IndexMetaTree.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/IndexMetaTree.java @@ -31,7 +31,7 @@ import org.apache.ignite.lang.IgniteInternalCheckedException; import org.jetbrains.annotations.Nullable; /** - * Tree for storing index meta-information, such as the root of an index tree. + * {@link BplusTree} implementation for storing {@link IndexMeta}. */ public class IndexMetaTree extends BplusTree<IndexMeta, IndexMeta> { /** @@ -59,24 +59,13 @@ public class IndexMetaTree extends BplusTree<IndexMeta, IndexMeta> { @Nullable ReuseList reuseList, boolean initNew ) throws IgniteInternalCheckedException { - super( - "IndexMetaTree_" + grpId, - grpId, - grpName, - partId, - pageMem, - lockLsnr, - globalRmvId, - metaPageId, - reuseList - ); + super("IndexMetaTree_" + grpId, grpId, grpName, partId, pageMem, lockLsnr, globalRmvId, metaPageId, reuseList); setIos(IndexMetaInnerIo.VERSIONS, IndexMetaLeafIo.VERSIONS, IndexMetaTreeMetaIo.VERSIONS); initTree(initNew); } - /** {@inheritDoc} */ @Override protected int compare(BplusIo<IndexMeta> io, long pageAddr, int idx, IndexMeta row) { IndexMetaIo indexMetaIo = (IndexMetaIo) io; @@ -84,7 +73,6 @@ public class IndexMetaTree extends BplusTree<IndexMeta, IndexMeta> { return indexMetaIo.compare(pageAddr, idx, row); } - /** {@inheritDoc} */ @Override public IndexMeta getRow(BplusIo<IndexMeta> io, long pageAddr, int idx, Object x) { IndexMetaIo indexMetaIo = (IndexMetaIo) io; diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaInnerIo.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaInnerIo.java index 0dca86a381..18507991c9 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaInnerIo.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaInnerIo.java @@ -21,6 +21,7 @@ import org.apache.ignite.internal.pagememory.io.IoVersions; import org.apache.ignite.internal.pagememory.tree.BplusTree; import org.apache.ignite.internal.pagememory.tree.io.BplusInnerIo; import org.apache.ignite.internal.pagememory.tree.io.BplusIo; +import org.apache.ignite.internal.storage.pagememory.index.IndexPageTypes; import org.apache.ignite.internal.storage.pagememory.index.meta.IndexMeta; import org.apache.ignite.internal.storage.pagememory.index.meta.IndexMetaTree; @@ -28,9 +29,6 @@ import org.apache.ignite.internal.storage.pagememory.index.meta.IndexMetaTree; * IO routines for {@link IndexMetaTree} inner pages. */ public class IndexMetaInnerIo extends BplusInnerIo<IndexMeta> implements IndexMetaIo { - /** Page IO type. */ - public static final short T_INDEX_META_INNER_IO = 15; - /** I/O versions. */ public static final IoVersions<IndexMetaInnerIo> VERSIONS = new IoVersions<>(new IndexMetaInnerIo(1)); @@ -40,7 +38,7 @@ public class IndexMetaInnerIo extends BplusInnerIo<IndexMeta> implements IndexMe * @param ver Page format version. */ private IndexMetaInnerIo(int ver) { - super(T_INDEX_META_INNER_IO, ver, true, SIZE_IN_BYTES); + super(IndexPageTypes.T_INDEX_META_INNER_IO, ver, true, SIZE_IN_BYTES); } /** {@inheritDoc} */ 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 92b5996912..61e8e95dd4 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 @@ -24,7 +24,6 @@ import java.util.UUID; import org.apache.ignite.internal.pagememory.tree.io.BplusIo; import org.apache.ignite.internal.pagememory.util.PageUtils; import org.apache.ignite.internal.storage.pagememory.index.meta.IndexMeta; -import org.apache.ignite.internal.storage.pagememory.index.meta.IndexMetaTree; /** * Interface for {@link IndexMeta} B+Tree-related IO. @@ -56,7 +55,7 @@ public interface IndexMetaIo { int offset(int idx); /** - * Compare the index meta from the page with passed index meta, thus defining the order of element in the {@link IndexMetaTree}. + * Compare the {@link IndexMeta} from the page with passed {@link IndexMeta}. * * @param pageAddr Page address. * @param idx Element's index. diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaLeafIo.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaLeafIo.java index c5d938d786..5314020808 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaLeafIo.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaLeafIo.java @@ -21,6 +21,7 @@ import org.apache.ignite.internal.pagememory.io.IoVersions; import org.apache.ignite.internal.pagememory.tree.BplusTree; import org.apache.ignite.internal.pagememory.tree.io.BplusIo; import org.apache.ignite.internal.pagememory.tree.io.BplusLeafIo; +import org.apache.ignite.internal.storage.pagememory.index.IndexPageTypes; import org.apache.ignite.internal.storage.pagememory.index.meta.IndexMeta; import org.apache.ignite.internal.storage.pagememory.index.meta.IndexMetaTree; @@ -28,9 +29,6 @@ import org.apache.ignite.internal.storage.pagememory.index.meta.IndexMetaTree; * IO routines for {@link IndexMetaTree} leaf pages. */ public class IndexMetaLeafIo extends BplusLeafIo<IndexMeta> implements IndexMetaIo { - /** Page IO type. */ - public static final short T_INDEX_META_LEAF_IO = 14; - /** I/O versions. */ public static final IoVersions<IndexMetaLeafIo> VERSIONS = new IoVersions<>(new IndexMetaLeafIo(1)); @@ -40,7 +38,7 @@ public class IndexMetaLeafIo extends BplusLeafIo<IndexMeta> implements IndexMeta * @param ver Page format version. */ private IndexMetaLeafIo(int ver) { - super(T_INDEX_META_LEAF_IO, ver, SIZE_IN_BYTES); + super(IndexPageTypes.T_INDEX_META_LEAF_IO, ver, SIZE_IN_BYTES); } /** {@inheritDoc} */ diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaTreeMetaIo.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaTreeMetaIo.java index 9e8d229c15..9b67160131 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaTreeMetaIo.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/index/meta/io/IndexMetaTreeMetaIo.java @@ -19,15 +19,13 @@ package org.apache.ignite.internal.storage.pagememory.index.meta.io; import org.apache.ignite.internal.pagememory.io.IoVersions; import org.apache.ignite.internal.pagememory.tree.io.BplusMetaIo; +import org.apache.ignite.internal.storage.pagememory.index.IndexPageTypes; import org.apache.ignite.internal.storage.pagememory.index.meta.IndexMetaTree; /** * IO routines for {@link IndexMetaTree} meta pages. */ public class IndexMetaTreeMetaIo extends BplusMetaIo { - /** Page IO type. */ - public static final short T_INDEX_META_TREE_META_IO = 13; - /** I/O versions. */ public static final IoVersions<IndexMetaTreeMetaIo> VERSIONS = new IoVersions<>(new IndexMetaTreeMetaIo(1)); @@ -37,6 +35,6 @@ public class IndexMetaTreeMetaIo extends BplusMetaIo { * @param ver Page format version. */ protected IndexMetaTreeMetaIo(int ver) { - super(T_INDEX_META_TREE_META_IO, ver); + super(IndexPageTypes.T_INDEX_META_TREE_META_IO, ver); } } 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 0261dde770..5c89a17678 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,6 +17,8 @@ package org.apache.ignite.internal.storage.pagememory.mv; +import static org.apache.ignite.internal.pagememory.util.PageIdUtils.NULL_LINK; + import java.nio.ByteBuffer; import java.util.NoSuchElementException; import java.util.UUID; @@ -226,9 +228,9 @@ public abstract class AbstractPageMemoryMvPartitionStorage implements MvPartitio VersionChain currentChain = findVersionChain(rowId); if (currentChain == null) { - RowVersion newVersion = insertRowVersion(row, RowVersion.NULL_LINK); + RowVersion newVersion = insertRowVersion(row, NULL_LINK); - VersionChain versionChain = new VersionChain(rowId, txId, newVersion.link(), RowVersion.NULL_LINK); + VersionChain versionChain = new VersionChain(rowId, txId, newVersion.link(), NULL_LINK); updateVersionChain(versionChain); @@ -277,7 +279,7 @@ public abstract class AbstractPageMemoryMvPartitionStorage implements MvPartitio // Next can be safely replaced with any value (like 0), because this field is only used when there // is some uncommitted value, but when we add an uncommitted value, we 'fix' such placeholder value // (like 0) by replacing it with a valid value. - VersionChain versionChainReplacement = new VersionChain(rowId, null, latestVersion.nextLink(), RowVersion.NULL_LINK); + VersionChain versionChainReplacement = new VersionChain(rowId, null, latestVersion.nextLink(), NULL_LINK); updateVersionChain(versionChainReplacement); } else { diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/ReadRowVersion.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/ReadRowVersion.java index 3441318ef6..20f5988449 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/ReadRowVersion.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/ReadRowVersion.java @@ -17,7 +17,7 @@ package org.apache.ignite.internal.storage.pagememory.mv; -import static org.apache.ignite.internal.storage.pagememory.mv.PartitionlessLinks.readPartitionlessLink; +import static org.apache.ignite.internal.pagememory.util.PartitionlessLinks.readPartitionlessLink; import java.nio.ByteBuffer; import java.util.function.Predicate; diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/RowVersion.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/RowVersion.java index 2b13ab7ccd..60425a0402 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/RowVersion.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/RowVersion.java @@ -18,6 +18,7 @@ package org.apache.ignite.internal.storage.pagememory.mv; import static org.apache.ignite.hlc.HybridTimestamp.HYBRID_TIMESTAMP_SIZE; +import static org.apache.ignite.internal.pagememory.util.PageIdUtils.NULL_LINK; import java.nio.ByteBuffer; import java.util.Objects; @@ -25,6 +26,7 @@ import org.apache.ignite.hlc.HybridTimestamp; import org.apache.ignite.internal.pagememory.Storable; import org.apache.ignite.internal.pagememory.io.AbstractDataPageIo; import org.apache.ignite.internal.pagememory.io.IoVersions; +import org.apache.ignite.internal.pagememory.util.PartitionlessLinks; import org.apache.ignite.internal.storage.pagememory.mv.io.RowVersionDataIo; import org.apache.ignite.internal.tostring.IgniteToStringExclude; import org.apache.ignite.internal.tostring.S; @@ -34,9 +36,6 @@ import org.jetbrains.annotations.Nullable; * Represents row version inside row version chain. */ public final class RowVersion implements Storable { - /** Represents an absent partitionless link. */ - public static final long NULL_LINK = 0; - private static final int NEXT_LINK_STORE_SIZE_BYTES = PartitionlessLinks.PARTITIONLESS_LINK_SIZE_BYTES; private static final int VALUE_SIZE_STORE_SIZE_BYTES = Integer.BYTES; diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/RowVersionFreeList.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/RowVersionFreeList.java index a3a20abb06..c853b4da95 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/RowVersionFreeList.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/RowVersionFreeList.java @@ -39,8 +39,6 @@ import org.jetbrains.annotations.Nullable; public class RowVersionFreeList extends AbstractFreeList<RowVersion> { private static final IgniteLogger LOG = Loggers.forClass(RowVersionFreeList.class); - private final PageEvictionTracker evictionTracker; - private final IoStatisticsHolder statHolder; private final UpdateTimestampHandler updateTimestampHandler = new UpdateTimestampHandler(); @@ -87,7 +85,6 @@ public class RowVersionFreeList extends AbstractFreeList<RowVersion> { evictionTracker ); - this.evictionTracker = evictionTracker; this.statHolder = statHolder; } diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/ScanVersionChainByTimestamp.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/ScanVersionChainByTimestamp.java index 569c2086aa..7d5fd1616e 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/ScanVersionChainByTimestamp.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/ScanVersionChainByTimestamp.java @@ -17,7 +17,8 @@ package org.apache.ignite.internal.storage.pagememory.mv; -import static org.apache.ignite.internal.storage.pagememory.mv.PartitionlessLinks.readPartitionlessLink; +import static org.apache.ignite.internal.pagememory.util.PageIdUtils.NULL_LINK; +import static org.apache.ignite.internal.pagememory.util.PartitionlessLinks.readPartitionlessLink; import org.apache.ignite.hlc.HybridTimestamp; import org.apache.ignite.internal.pagememory.datapage.PageMemoryTraversal; @@ -80,7 +81,7 @@ class ScanVersionChainByTimestamp implements PageMemoryTraversal<HybridTimestamp private long advanceToNextVersion(long pageAddr, DataPagePayload payload) { long nextLink = readPartitionlessLink(partitionId, pageAddr, payload.offset() + RowVersion.NEXT_LINK_OFFSET); - if (nextLink == RowVersion.NULL_LINK) { + if (nextLink == NULL_LINK) { return STOP_TRAVERSAL; } diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/VersionChain.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/VersionChain.java index 022c1cf94a..c650bed4dc 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/VersionChain.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/VersionChain.java @@ -17,6 +17,8 @@ package org.apache.ignite.internal.storage.pagememory.mv; +import static org.apache.ignite.internal.pagememory.util.PageIdUtils.NULL_LINK; + import java.util.UUID; import org.apache.ignite.internal.storage.RowId; import org.apache.ignite.internal.tostring.S; @@ -91,7 +93,7 @@ public class VersionChain extends VersionChainKey { * Returns {@code true} if this version chain has at least one committed version. */ public boolean hasCommittedVersions() { - return newestCommittedLink() != RowVersion.NULL_LINK; + return newestCommittedLink() != NULL_LINK; } /** {@inheritDoc} */ diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/RowVersionDataIo.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/RowVersionDataIo.java index c7d8846112..23c6b17988 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/RowVersionDataIo.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/RowVersionDataIo.java @@ -20,14 +20,14 @@ package org.apache.ignite.internal.storage.pagememory.mv.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 static org.apache.ignite.internal.storage.pagememory.mv.PartitionlessLinks.writePartitionlessLink; +import static org.apache.ignite.internal.pagememory.util.PartitionlessLinks.writePartitionlessLink; import java.nio.ByteBuffer; import org.apache.ignite.hlc.HybridTimestamp; import org.apache.ignite.internal.pagememory.io.AbstractDataPageIo; import org.apache.ignite.internal.pagememory.io.IoVersions; +import org.apache.ignite.internal.pagememory.util.PartitionlessLinks; import org.apache.ignite.internal.storage.pagememory.mv.HybridTimestamps; -import org.apache.ignite.internal.storage.pagememory.mv.PartitionlessLinks; import org.apache.ignite.internal.storage.pagememory.mv.RowVersion; import org.apache.ignite.lang.IgniteStringBuilder; import org.jetbrains.annotations.Nullable; @@ -73,44 +73,29 @@ public class RowVersionDataIo extends AbstractDataPageIo<RowVersion> { /** {@inheritDoc} */ @Override - protected void writeFragmentData(RowVersion row, ByteBuffer buf, int rowOff, int payloadSize) { - assertPageType(buf); + protected void writeFragmentData(RowVersion row, ByteBuffer pageBuf, int rowOff, int payloadSize) { + assertPageType(pageBuf); if (rowOff == 0) { // first fragment assert row.headerSize() <= payloadSize : "Header must entirely fit in the first fragment, but header size is " + row.headerSize() + " and payload size is " + payloadSize; - HybridTimestamps.writeTimestampToBuffer(buf, row.timestamp()); + HybridTimestamps.writeTimestampToBuffer(pageBuf, row.timestamp()); - PartitionlessLinks.writeToBuffer(buf, row.nextLink()); + PartitionlessLinks.writeToBuffer(pageBuf, row.nextLink()); - buf.putInt(row.valueSize()); + pageBuf.putInt(row.valueSize()); - int valueBytesToWrite = payloadSize - row.headerSize(); - putValueFragmentToBuffer(row, buf, 0, valueBytesToWrite); + putValueBufferIntoPage(pageBuf, row.value(), 0, payloadSize - row.headerSize()); } else { // non-first fragment - assert rowOff > row.headerSize(); + assert rowOff >= row.headerSize(); - putValueFragmentToBuffer(row, buf, rowOff - row.headerSize(), payloadSize); + putValueBufferIntoPage(pageBuf, row.value(), rowOff - row.headerSize(), payloadSize); } } - private void putValueFragmentToBuffer(RowVersion row, ByteBuffer buf, int readBufferPosition, int valueBytesToWrite) { - ByteBuffer valueBuffer = row.value(); - - int oldLimit = valueBuffer.limit(); - int oldPosition = valueBuffer.position(); - - valueBuffer.position(readBufferPosition); - valueBuffer.limit(valueBuffer.position() + valueBytesToWrite); - buf.put(valueBuffer); - - valueBuffer.position(oldPosition); - valueBuffer.limit(oldLimit); - } - /** * Updates timestamp leaving the rest untouched. * diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/VersionChainIo.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/VersionChainIo.java index 63461d1257..7e5fcbe202 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/VersionChainIo.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/VersionChainIo.java @@ -19,9 +19,9 @@ package org.apache.ignite.internal.storage.pagememory.mv.io; import static org.apache.ignite.internal.pagememory.util.PageUtils.getLong; import static org.apache.ignite.internal.pagememory.util.PageUtils.putLong; -import static org.apache.ignite.internal.storage.pagememory.mv.PartitionlessLinks.PARTITIONLESS_LINK_SIZE_BYTES; -import static org.apache.ignite.internal.storage.pagememory.mv.PartitionlessLinks.readPartitionlessLink; -import static org.apache.ignite.internal.storage.pagememory.mv.PartitionlessLinks.writePartitionlessLink; +import static org.apache.ignite.internal.pagememory.util.PartitionlessLinks.PARTITIONLESS_LINK_SIZE_BYTES; +import static org.apache.ignite.internal.pagememory.util.PartitionlessLinks.readPartitionlessLink; +import static org.apache.ignite.internal.pagememory.util.PartitionlessLinks.writePartitionlessLink; import static org.apache.ignite.internal.storage.pagememory.mv.VersionChain.NULL_UUID_COMPONENT; import java.util.UUID;