Inline offheap indexes (simple types + String).
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/8f836cb0 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/8f836cb0 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/8f836cb0 Branch: refs/heads/ignite-4652 Commit: 8f836cb0efbda3805672788be911131d46dde9b6 Parents: 7663c22 Author: Konstantin Dudkov <kdud...@ya.ru> Authored: Thu Feb 16 14:18:05 2017 +0300 Committer: Konstantin Dudkov <kdud...@ya.ru> Committed: Thu Feb 16 14:25:32 2017 +0300 ---------------------------------------------------------------------- .../benchmarks/jmh/tree/BPlusTreeBenchmark.java | 13 +- .../apache/ignite/IgniteSystemProperties.java | 7 + .../org/apache/ignite/cache/QueryIndex.java | 21 ++ .../configuration/CacheConfiguration.java | 35 ++- .../internal/pagemem/wal/record/WALRecord.java | 5 +- .../delta/MetaPageInitRootInlineRecord.java | 62 +++++ .../record/delta/MetaPageInitRootRecord.java | 3 +- .../cache/database/MetadataStorage.java | 15 +- .../cache/database/tree/BPlusTree.java | 72 ++++- .../cache/database/tree/io/BPlusIO.java | 3 +- .../cache/database/tree/io/BPlusInnerIO.java | 24 +- .../cache/database/tree/io/BPlusLeafIO.java | 9 +- .../cache/database/tree/io/BPlusMetaIO.java | 45 ++- .../cache/database/tree/io/DataPageIO.java | 4 +- .../cache/database/tree/io/DataPagePayload.java | 2 +- .../cache/database/tree/io/PageIO.java | 60 ++++ .../query/GridQueryIndexDescriptor.java | 7 + .../processors/query/GridQueryProcessor.java | 47 +++- .../processors/query/h2/IgniteH2Indexing.java | 23 +- .../processors/query/h2/database/H2Tree.java | 57 +++- .../query/h2/database/H2TreeIndex.java | 236 +++++++++++++++- .../query/h2/database/InlineIndexHelper.java | 279 +++++++++++++++++++ .../query/h2/database/io/H2ExtrasInnerIO.java | 135 +++++++++ .../query/h2/database/io/H2ExtrasLeafIO.java | 132 +++++++++ .../processors/query/h2/opt/GridH2Row.java | 2 +- .../processors/query/h2/opt/GridH2Table.java | 3 +- .../h2/GridIndexingSpiAbstractSelfTest.java | 5 + .../query/h2/database/H2TreeIndexTest.java | 59 ++++ .../h2/database/InlineIndexHelperTest.java | 46 +++ 29 files changed, 1314 insertions(+), 97 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/tree/BPlusTreeBenchmark.java ---------------------------------------------------------------------- diff --git a/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/tree/BPlusTreeBenchmark.java b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/tree/BPlusTreeBenchmark.java index d1bca73..7355850 100644 --- a/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/tree/BPlusTreeBenchmark.java +++ b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/tree/BPlusTreeBenchmark.java @@ -17,7 +17,6 @@ package org.apache.ignite.internal.benchmarks.jmh.tree; -import java.nio.ByteBuffer; import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicLong; @@ -269,12 +268,7 @@ public class BPlusTreeBenchmark extends JmhAbstractBenchmark { throws IgniteCheckedException { Long row = srcIo.getLookupRow(null, src, srcIdx); - store(dst, dstIdx, row, null); - } - - /** {@inheritDoc} */ - @Override public void storeByOffset(ByteBuffer buf, int off, Long row) throws IgniteCheckedException { - throw new UnsupportedOperationException(); + store(dst, dstIdx, row, null, false); } /** {@inheritDoc} */ @@ -308,11 +302,6 @@ public class BPlusTreeBenchmark extends JmhAbstractBenchmark { } /** {@inheritDoc} */ - @Override public void storeByOffset(ByteBuffer buf, int off, Long row) throws IgniteCheckedException { - throw new UnsupportedOperationException(); - } - - /** {@inheritDoc} */ @Override public void storeByOffset(long pageAddr, int off, Long row) { PageUtils.putLong(pageAddr, off, row); } http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java index b229729..504b589 100644 --- a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java +++ b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java @@ -540,6 +540,13 @@ public final class IgniteSystemProperties { public static final String IGNITE_UNWRAP_BINARY_FOR_INDEXING_SPI = "IGNITE_UNWRAP_BINARY_FOR_INDEXING_SPI"; /** + * System property to specify maximum payload size in bytes for {@code H2TreeIndex}. + * <p> + * Defaults to {@code 0}, meaning that inline index store is disabled. + */ + public static final String IGNITE_MAX_INDEX_PAYLOAD_SIZE = "IGNITE_MAX_INDEX_PAYLOAD_SIZE"; + + /** * Enforces singleton. */ private IgniteSystemProperties() { http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/core/src/main/java/org/apache/ignite/cache/QueryIndex.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/QueryIndex.java b/modules/core/src/main/java/org/apache/ignite/cache/QueryIndex.java index af11999..bbe2872 100644 --- a/modules/core/src/main/java/org/apache/ignite/cache/QueryIndex.java +++ b/modules/core/src/main/java/org/apache/ignite/cache/QueryIndex.java @@ -40,6 +40,9 @@ public class QueryIndex implements Serializable { /** */ private QueryIndexType type; + /** */ + private int inlineSize = -1; + /** * Creates an empty index. Should be populated via setters. */ @@ -224,4 +227,22 @@ public class QueryIndex implements Serializable { public void setIndexType(QueryIndexType type) { this.type = type; } + + /** + * Gets inline size. + * + * @return inline size. + */ + public int getInlineSize() { + return inlineSize; + } + + /** + * Sets inline size. + * + * @param inlineSize Inline size. + */ + public void setInlineSize(int inlineSize) { + this.inlineSize = inlineSize; + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java b/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java index b3be1cf..6c56fc5 100644 --- a/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java +++ b/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java @@ -2456,10 +2456,11 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> { * * @param idxName Index name. * @param type Index type. + * @param inlineSize Inline size. * @return Index descriptor. */ - public IndexDescriptor addIndex(String idxName, GridQueryIndexType type) { - IndexDescriptor idx = new IndexDescriptor(type); + public IndexDescriptor addIndex(String idxName, GridQueryIndexType type, int inlineSize) { + IndexDescriptor idx = new IndexDescriptor(type, inlineSize); if (indexes.put(idxName, idx) != null) throw new CacheException("Index with name '" + idxName + "' already exists."); @@ -2468,6 +2469,17 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> { } /** + * Adds index. + * + * @param idxName Index name. + * @param type Index type. + * @return Index descriptor. + */ + public IndexDescriptor addIndex(String idxName, GridQueryIndexType type) { + return addIndex(idxName, type, -1); + } + + /** * Adds field to index. * * @param idxName Index name. @@ -2594,13 +2606,25 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> { /** */ private final GridQueryIndexType type; + /** */ + private final int inlineSize; + /** * @param type Type. + * @param inlineSize Inline size. */ - private IndexDescriptor(GridQueryIndexType type) { + private IndexDescriptor(GridQueryIndexType type, int inlineSize) { assert type != null; this.type = type; + this.inlineSize = inlineSize; + } + + /** + * @param type Type. + */ + private IndexDescriptor(GridQueryIndexType type) { + this(type, -1); } /** {@inheritDoc} */ @@ -2642,6 +2666,11 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> { } /** {@inheritDoc} */ + @Override public int inlineSize() { + return inlineSize; + } + + /** {@inheritDoc} */ @Override public String toString() { return S.toString(IndexDescriptor.class, this); } http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java index f761f68..9c2c88a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java @@ -157,7 +157,10 @@ public abstract class WALRecord { SWITCH_SEGMENT_RECORD, /** */ - DATA_PAGE_UPDATE_RECORD + DATA_PAGE_UPDATE_RECORD, + + /** init */ + BTREE_META_PAGE_INIT_ROOT2 ; /** */ http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootInlineRecord.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootInlineRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootInlineRecord.java new file mode 100644 index 0000000..212f5b9 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootInlineRecord.java @@ -0,0 +1,62 @@ +/* + * 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.pagemem.wal.record.delta; + +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.pagemem.PageMemory; +import org.apache.ignite.internal.processors.cache.database.tree.io.BPlusMetaIO; + +/** + * + */ +public class MetaPageInitRootInlineRecord extends MetaPageInitRootRecord { + + /** */ + private final int inlineSize; + + /** + * @param cacheId + * @param pageId Meta page ID. + * @param rootId + * @param inlineSize Inline size. + */ + public MetaPageInitRootInlineRecord(int cacheId, long pageId, long rootId, int inlineSize) { + super(cacheId, pageId, rootId); + this.inlineSize = inlineSize; + } + + /** + * @return Inline size. + */ + public int inlineSize() { + return inlineSize; + } + + /** {@inheritDoc} */ + @Override public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException { + BPlusMetaIO io = BPlusMetaIO.VERSIONS.forPage(pageAddr); + + io.initRoot(pageAddr, rootId, pageMem.pageSize()); + io.setInlineSize(pageAddr, inlineSize); + } + + /** {@inheritDoc} */ + @Override public RecordType type() { + return RecordType.BTREE_META_PAGE_INIT_ROOT2; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootRecord.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootRecord.java index 4d56db0..280310f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootRecord.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootRecord.java @@ -26,7 +26,7 @@ import org.apache.ignite.internal.processors.cache.database.tree.io.BPlusMetaIO; */ public class MetaPageInitRootRecord extends PageDeltaRecord { /** */ - private long rootId; + protected long rootId; /** * @param pageId Meta page ID. @@ -44,6 +44,7 @@ public class MetaPageInitRootRecord extends PageDeltaRecord { BPlusMetaIO io = BPlusMetaIO.VERSIONS.forPage(pageAddr); io.initRoot(pageAddr, rootId, pageMem.pageSize()); + io.setInlineSize(pageAddr, 0); } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/MetadataStorage.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/MetadataStorage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/MetadataStorage.java index faf7608..47c3254 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/MetadataStorage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/MetadataStorage.java @@ -192,7 +192,7 @@ public class MetadataStorage implements MetaStore { /** {@inheritDoc} */ @Override protected int compare(final BPlusIO<IndexItem> io, final long pageAddr, final int idx, final IndexItem row) throws IgniteCheckedException { - final int off = ((IndexIO)io).getOffset(idx); + final int off = ((IndexIO)io).getOffset(pageAddr, idx); int shift = 0; @@ -214,7 +214,7 @@ public class MetadataStorage implements MetaStore { /** {@inheritDoc} */ @Override protected IndexItem getRow(final BPlusIO<IndexItem> io, final long pageAddr, final int idx) throws IgniteCheckedException { - return readRow(pageAddr, ((IndexIO)io).getOffset(idx)); + return readRow(pageAddr, ((IndexIO)io).getOffset(pageAddr, idx)); } } @@ -323,10 +323,11 @@ public class MetadataStorage implements MetaStore { */ private interface IndexIO { /** + * @param pageAddr Page address. * @param idx Index. * @return Offset in buffer according to {@code idx}. */ - int getOffset(int idx); + int getOffset(long pageAddr, int idx); } /** @@ -355,7 +356,7 @@ public class MetadataStorage implements MetaStore { @Override public void store(final long dstPageAddr, final int dstIdx, final BPlusIO<IndexItem> srcIo, final long srcPageAddr, final int srcIdx) throws IgniteCheckedException { - storeRow(dstPageAddr, offset(dstIdx), srcPageAddr, ((IndexIO)srcIo).getOffset(srcIdx)); + storeRow(dstPageAddr, offset(dstIdx), srcPageAddr, ((IndexIO)srcIo).getOffset(srcPageAddr, srcIdx)); } /** {@inheritDoc} */ @@ -365,7 +366,7 @@ public class MetadataStorage implements MetaStore { } /** {@inheritDoc} */ - @Override public int getOffset(final int idx) { + @Override public int getOffset(long pageAddr, final int idx) { return offset(idx); } } @@ -398,7 +399,7 @@ public class MetadataStorage implements MetaStore { final BPlusIO<IndexItem> srcIo, final long srcPageAddr, final int srcIdx) throws IgniteCheckedException { - storeRow(dstPageAddr, offset(dstIdx), srcPageAddr, ((IndexIO)srcIo).getOffset(srcIdx)); + storeRow(dstPageAddr, offset(dstIdx), srcPageAddr, ((IndexIO)srcIo).getOffset(srcPageAddr, srcIdx)); } /** {@inheritDoc} */ @@ -409,7 +410,7 @@ public class MetadataStorage implements MetaStore { } /** {@inheritDoc} */ - @Override public int getOffset(final int idx) { + @Override public int getOffset(long pageAddr, final int idx) { return offset(idx); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/BPlusTree.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/BPlusTree.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/BPlusTree.java index 518d0d8..aa61fbd 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/BPlusTree.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/BPlusTree.java @@ -38,7 +38,7 @@ import org.apache.ignite.internal.pagemem.wal.record.delta.FixRemoveId; import org.apache.ignite.internal.pagemem.wal.record.delta.InsertRecord; import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageAddRootRecord; import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageCutRootRecord; -import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageInitRootRecord; +import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageInitRootInlineRecord; import org.apache.ignite.internal.pagemem.wal.record.delta.NewRootInitRecord; import org.apache.ignite.internal.pagemem.wal.record.delta.RecycleRecord; import org.apache.ignite.internal.pagemem.wal.record.delta.RemoveRecord; @@ -103,16 +103,16 @@ public abstract class BPlusTree<L, T extends L> extends DataStructure implements private final float maxFill; /** */ - private final long metaPageId; + protected final long metaPageId; /** */ - private final boolean canGetRowFromInner; + private boolean canGetRowFromInner; /** */ - private final IOVersions<? extends BPlusInnerIO<L>> innerIos; + private IOVersions<? extends BPlusInnerIO<L>> innerIos; /** */ - private final IOVersions<? extends BPlusLeafIO<L>> leafIos; + private IOVersions<? extends BPlusLeafIO<L>> leafIos; /** */ private final AtomicLong globalRmvId; @@ -661,7 +661,7 @@ public abstract class BPlusTree<L, T extends L> extends DataStructure implements */ private class InitRoot extends PageHandler<Long, Bool> { /** {@inheritDoc} */ - @Override public Bool run(Page meta, PageIO iox, long pageAddr, Long rootId, int lvl) + @Override public Bool run(Page meta, PageIO iox, long pageAddr, Long rootId, int inlineSize) throws IgniteCheckedException { assert rootId != null; @@ -669,9 +669,10 @@ public abstract class BPlusTree<L, T extends L> extends DataStructure implements BPlusMetaIO io = (BPlusMetaIO)iox; io.initRoot(pageAddr, rootId, pageSize()); + io.setInlineSize(pageAddr, inlineSize); if (needWalDeltaRecord(meta)) - wal.log(new MetaPageInitRootRecord(cacheId, meta.id(), rootId)); + wal.log(new MetaPageInitRootInlineRecord(cacheId, meta.id(), rootId, inlineSize)); assert io.getRootLevel(pageAddr) == 0; assert io.getFirstPageId(pageAddr, 0) == rootId; @@ -694,7 +695,7 @@ public abstract class BPlusTree<L, T extends L> extends DataStructure implements * @param leafIos Leaf IO versions. * @throws IgniteCheckedException If failed. */ - public BPlusTree( + protected BPlusTree( String name, int cacheId, PageMemory pageMem, @@ -705,6 +706,29 @@ public abstract class BPlusTree<L, T extends L> extends DataStructure implements IOVersions<? extends BPlusInnerIO<L>> innerIos, IOVersions<? extends BPlusLeafIO<L>> leafIos ) throws IgniteCheckedException { + this(name, cacheId, pageMem, wal, globalRmvId, metaPageId, reuseList); + setIos(innerIos, leafIos); + } + + /** + * @param name Tree name. + * @param cacheId Cache ID. + * @param pageMem Page memory. + * @param wal Write ahead log manager. + * @param globalRmvId Remove ID. + * @param metaPageId Meta page ID. + * @param reuseList Reuse list. + * @throws IgniteCheckedException If failed. + */ + protected BPlusTree( + String name, + int cacheId, + PageMemory pageMem, + IgniteWriteAheadLogManager wal, + AtomicLong globalRmvId, + long metaPageId, + ReuseList reuseList + ) throws IgniteCheckedException { super(cacheId, pageMem, wal); assert !F.isEmpty(name); @@ -713,13 +737,8 @@ public abstract class BPlusTree<L, T extends L> extends DataStructure implements minFill = 0f; // Testing worst case when merge happens only on empty page. maxFill = 0f; // Avoiding random effects on testing. - assert innerIos != null; - assert leafIos != null; assert metaPageId != 0L; - this.canGetRowFromInner = innerIos.latest().canGetRow(); // TODO refactor - this.innerIos = innerIos; - this.leafIos = leafIos; this.metaPageId = metaPageId; this.name = name; this.reuseList = reuseList; @@ -727,6 +746,20 @@ public abstract class BPlusTree<L, T extends L> extends DataStructure implements } /** + * @param innerIos Inner IO versions. + * @param leafIos Leaf IO versions. + */ + protected void setIos(IOVersions<? extends BPlusInnerIO<L>> innerIos, + IOVersions<? extends BPlusLeafIO<L>> leafIos) { + assert innerIos != null; + assert leafIos != null; + + this.canGetRowFromInner = innerIos.latest().canGetRow(); // TODO refactor + this.innerIos = innerIos; + this.leafIos = leafIos; + } + + /** * @return Tree name. */ public final String getName() { @@ -748,6 +781,17 @@ public abstract class BPlusTree<L, T extends L> extends DataStructure implements * @throws IgniteCheckedException If failed. */ protected final void initTree(boolean initNew) throws IgniteCheckedException { + initTree(initNew, 0); + } + + /** + * Initialize new tree. + * + * @param initNew {@code True} if new tree should be created. + * @param inlineSize Inline size. + * @throws IgniteCheckedException If failed. + */ + protected final void initTree(boolean initNew, int inlineSize) throws IgniteCheckedException { if (initNew) { // Allocate the first leaf page, it will be our root. long rootId = allocatePage(null); @@ -758,7 +802,7 @@ public abstract class BPlusTree<L, T extends L> extends DataStructure implements // Initialize meta page with new root page. try (Page meta = page(metaPageId)) { - Bool res = writePage(pageMem, meta, this, initRoot, BPlusMetaIO.VERSIONS.latest(), wal, rootId, 0, FALSE); + Bool res = writePage(pageMem, meta, this, initRoot, BPlusMetaIO.VERSIONS.latest(), wal, rootId, inlineSize, FALSE); assert res == TRUE: res; } http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/BPlusIO.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/BPlusIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/BPlusIO.java index 5186808..bcf2908 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/BPlusIO.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/BPlusIO.java @@ -51,7 +51,6 @@ public abstract class BPlusIO<L> extends PageIO { * @param ver Page format version. * @param leaf If this is a leaf IO. * @param canGetRow If we can get full row from this page. - * @param itemSize Single item size on page. */ protected BPlusIO(int type, int ver, boolean leaf, boolean canGetRow, int itemSize) { super(type, ver); @@ -194,7 +193,7 @@ public abstract class BPlusIO<L> extends PageIO { * @param idx Index of element. * @return Offset from byte buffer begin in bytes. */ - protected abstract int offset(int idx); + public abstract int offset(int idx); /** * Store the needed info about the row in the page. Leaf and inner pages can store different info. http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/BPlusInnerIO.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/BPlusInnerIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/BPlusInnerIO.java index b15c2dc..60fd24c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/BPlusInnerIO.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/BPlusInnerIO.java @@ -49,7 +49,7 @@ public abstract class BPlusInnerIO<L> extends BPlusIO<L> { // The structure of the page is the following: // |ITEMS_OFF|w|A|x|B|y|C|z| // where capital letters are data items, lowercase letters are 8 byte page references. - return (pageSize - ITEMS_OFF - 8) / (itemSize + 8); + return (pageSize - ITEMS_OFF - 8) / (getItemSize() + 8); } /** @@ -58,7 +58,7 @@ public abstract class BPlusInnerIO<L> extends BPlusIO<L> { * @return Page ID. */ public final long getLeft(long pageAddr, int idx) { - return PageUtils.getLong(pageAddr, (offset(idx, SHIFT_LEFT))); + return PageUtils.getLong(pageAddr, (offset0(idx, SHIFT_LEFT))); } /** @@ -67,7 +67,7 @@ public abstract class BPlusInnerIO<L> extends BPlusIO<L> { * @param pageId Page ID. */ public final void setLeft(long pageAddr, int idx, long pageId) { - PageUtils.putLong(pageAddr, offset(idx, SHIFT_LEFT), pageId); + PageUtils.putLong(pageAddr, offset0(idx, SHIFT_LEFT), pageId); assert pageId == getLeft(pageAddr, idx); } @@ -78,7 +78,7 @@ public abstract class BPlusInnerIO<L> extends BPlusIO<L> { * @return Page ID. */ public final long getRight(long pageAddr, int idx) { - return PageUtils.getLong(pageAddr, offset(idx, SHIFT_RIGHT)); + return PageUtils.getLong(pageAddr, offset0(idx, SHIFT_RIGHT)); } /** @@ -87,7 +87,7 @@ public abstract class BPlusInnerIO<L> extends BPlusIO<L> { * @param pageId Page ID. */ private void setRight(long pageAddr, int idx, long pageId) { - PageUtils.putLong(pageAddr, offset(idx, SHIFT_RIGHT), pageId); + PageUtils.putLong(pageAddr, offset0(idx, SHIFT_RIGHT), pageId); assert pageId == getRight(pageAddr, idx); } @@ -97,17 +97,17 @@ public abstract class BPlusInnerIO<L> extends BPlusIO<L> { boolean cpLeft) throws IgniteCheckedException { assert srcIdx != dstIdx || srcPageAddr != dstPageAddr; - cnt *= itemSize + 8; // From items to bytes. + cnt *= getItemSize() + 8; // From items to bytes. if (dstIdx > srcIdx) { PageHandler.copyMemory(srcPageAddr, dstPageAddr, offset(srcIdx), offset(dstIdx), cnt); if (cpLeft) - PageUtils.putLong(dstPageAddr, offset(dstIdx, SHIFT_LEFT), PageUtils.getLong(srcPageAddr, (offset(srcIdx, SHIFT_LEFT)))); + PageUtils.putLong(dstPageAddr, offset0(dstIdx, SHIFT_LEFT), PageUtils.getLong(srcPageAddr, (offset0(srcIdx, SHIFT_LEFT)))); } else { if (cpLeft) - PageUtils.putLong(dstPageAddr, offset(dstIdx, SHIFT_LEFT), PageUtils.getLong(srcPageAddr, (offset(srcIdx, SHIFT_LEFT)))); + PageUtils.putLong(dstPageAddr, offset0(dstIdx, SHIFT_LEFT), PageUtils.getLong(srcPageAddr, (offset0(srcIdx, SHIFT_LEFT)))); PageHandler.copyMemory(srcPageAddr, dstPageAddr, offset(srcIdx), offset(dstIdx), cnt); } @@ -118,13 +118,13 @@ public abstract class BPlusInnerIO<L> extends BPlusIO<L> { * @param shift It can be either link itself or left or right page ID. * @return Offset from byte buffer begin in bytes. */ - private int offset(int idx, int shift) { - return shift + (8 + itemSize) * idx; + private int offset0(int idx, int shift) { + return shift + (8 + getItemSize()) * idx; } /** {@inheritDoc} */ - @Override protected final int offset(int idx) { - return offset(idx, SHIFT_LINK); + @Override public final int offset(int idx) { + return offset0(idx, SHIFT_LINK); } // Methods for B+Tree logic. http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/BPlusLeafIO.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/BPlusLeafIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/BPlusLeafIO.java index f3dccee..f6011b3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/BPlusLeafIO.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/BPlusLeafIO.java @@ -35,7 +35,7 @@ public abstract class BPlusLeafIO<L> extends BPlusIO<L> { /** {@inheritDoc} */ @Override public int getMaxCount(long pageAddr, int pageSize) { - return (pageSize - ITEMS_OFF) / itemSize; + return (pageSize - ITEMS_OFF) / getItemSize(); } /** {@inheritDoc} */ @@ -43,13 +43,14 @@ public abstract class BPlusLeafIO<L> extends BPlusIO<L> { boolean cpLeft) throws IgniteCheckedException { assert srcIdx != dstIdx || srcPageAddr != dstPageAddr; - PageHandler.copyMemory(srcPageAddr, dstPageAddr, offset(srcIdx), offset(dstIdx), cnt * itemSize); + PageHandler.copyMemory(srcPageAddr, dstPageAddr, offset(srcIdx), offset(dstIdx), + cnt * getItemSize()); } /** {@inheritDoc} */ - @Override protected final int offset(int idx) { + @Override public final int offset(int idx) { assert idx >= 0: idx; - return ITEMS_OFF + idx * itemSize; + return ITEMS_OFF + idx * getItemSize(); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/BPlusMetaIO.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/BPlusMetaIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/BPlusMetaIO.java index 8850863..6755820 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/BPlusMetaIO.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/BPlusMetaIO.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal.processors.cache.database.tree.io; +import org.apache.ignite.IgniteException; import org.apache.ignite.internal.pagemem.PageUtils; /** @@ -25,20 +26,38 @@ import org.apache.ignite.internal.pagemem.PageUtils; public class BPlusMetaIO extends PageIO { /** */ public static final IOVersions<BPlusMetaIO> VERSIONS = new IOVersions<>( - new BPlusMetaIO(1) + new BPlusMetaIO(1), new BPlusMetaIO(2) ); /** */ private static final int LVLS_OFF = COMMON_HEADER_END; /** */ - private static final int REFS_OFF = LVLS_OFF + 1; + private final int refsOff; + + /** */ + private final int inlineSizeOff; /** * @param ver Page format version. */ private BPlusMetaIO(int ver) { super(T_BPLUS_META, ver); + + switch (ver) { + case 1: + inlineSizeOff = -1; + refsOff = LVLS_OFF + 1; + break; + + case 2: + inlineSizeOff = LVLS_OFF + 1; + refsOff = inlineSizeOff + 2; + break; + + default: + throw new IgniteException("invalid IO version: " + ver); + } } /** @@ -65,7 +84,7 @@ public class BPlusMetaIO extends PageIO { * @return Max levels possible for this page size. */ private int getMaxLevels(long pageAddr, int pageSize) { - return (pageSize - REFS_OFF) / 8; + return (pageSize - refsOff) / 8; } /** @@ -85,8 +104,8 @@ public class BPlusMetaIO extends PageIO { * @param lvl Level. * @return Offset for page reference. */ - private static int offset(int lvl) { - return lvl * 8 + REFS_OFF; + private int offset(int lvl) { + return lvl * 8 + refsOff; } /** @@ -144,4 +163,20 @@ public class BPlusMetaIO extends PageIO { setLevelsCount(pageAddr, lvl, pageSize); // Decrease tree height. } + + /** + * @param pageAddr Page address. + * @param size Offset size. + */ + public void setInlineSize(long pageAddr, int size) { + if (getVersion() > 1) + PageUtils.putShort(pageAddr, inlineSizeOff, (short)size); + } + + /** + * @param pageAddr Page address. + */ + public int getInlineSize(long pageAddr) { + return getVersion() > 1 ? PageUtils.getShort(pageAddr, inlineSizeOff) : 0; + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/DataPageIO.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/DataPageIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/DataPageIO.java index 945f4dc..190349a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/DataPageIO.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/DataPageIO.java @@ -452,10 +452,12 @@ public class DataPageIO extends PageIO { } /** + * Sets position to start of actual fragment data and limit to it's end. + * * @param pageAddr Page address. * @param itemId Item to position on. * @param pageSize Page size. - * @return Size and offset of actual fragment data, and link to the next fragment if data is fragmented. + * @return {@link DataPagePayload} object. */ public DataPagePayload readPayload(final long pageAddr, final int itemId, final int pageSize) { int dataOff = getDataOffset(pageAddr, itemId, pageSize); http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/DataPagePayload.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/DataPagePayload.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/DataPagePayload.java index 7dedc00..277bdc7 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/DataPagePayload.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/DataPagePayload.java @@ -56,7 +56,7 @@ public class DataPagePayload { } /** - * @return Next link. + * @return Link to the next fragment or {@code 0} if it is the last fragment or the data row is not fragmented. */ public long nextLink() { return nextLink; http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/PageIO.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/PageIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/PageIO.java index f6ac905..6f50bf7 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/PageIO.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/database/tree/io/PageIO.java @@ -18,6 +18,8 @@ package org.apache.ignite.internal.processors.cache.database.tree.io; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.pagemem.Page; import org.apache.ignite.internal.pagemem.PageMemory; @@ -76,6 +78,15 @@ public abstract class PageIO { /** */ private static IOVersions<? extends BPlusLeafIO<?>> h2LeafIOs; + /** Maximum payload size. */ + public static final short MAX_PAYLOAD_SIZE = 2048; + + /** */ + private static List<IOVersions<? extends BPlusInnerIO<?>>> h2ExtraInnerIOs = new ArrayList<>(MAX_PAYLOAD_SIZE); + + /** */ + private static List<IOVersions<? extends BPlusLeafIO<?>>> h2ExtraLeafIOs = new ArrayList<>(MAX_PAYLOAD_SIZE); + /** */ public static final int TYPE_OFF = 0; @@ -147,6 +158,14 @@ public abstract class PageIO { /** */ public static final short T_PAGE_UPDATE_TRACKING = 15; + /** Index for payload == 1. */ + public static final short T_H2_EX_REF_LEAF_START = 10000; + public static final short T_H2_EX_REF_LEAF_END = T_H2_EX_REF_LEAF_START + MAX_PAYLOAD_SIZE - 1; + + /** */ + public static final short T_H2_EX_REF_INNER_START = 20000; + public static final short T_H2_EX_REF_INNER_END = T_H2_EX_REF_INNER_START + MAX_PAYLOAD_SIZE - 1; + /** */ private final int ver; @@ -290,6 +309,40 @@ public abstract class PageIO { } /** + * Registers extra inner IO versions. + */ + public static void registerH2ExtraInner( + IOVersions<? extends BPlusInnerIO<?>> innerExtIOs + ) { + h2ExtraInnerIOs.add(innerExtIOs); + } + + /** + * Registers extra inner IO versions. + */ + public static void registerH2ExtraLeaf( + IOVersions<? extends BPlusLeafIO<?>> leafExtIOs + ) { + h2ExtraLeafIOs.add(leafExtIOs); + } + + /** + * @param idx Index. + * @return IOVersions for given idx. + */ + public static IOVersions<? extends BPlusInnerIO<?>> getInnerVersions(int idx) { + return h2ExtraInnerIOs.get(idx); + } + + /** + * @param idx Index. + * @return IOVersions for given idx. + */ + public static IOVersions<? extends BPlusLeafIO<?>> getLeafVersions(int idx) { + return h2ExtraLeafIOs.get(idx); + } + + /** * Registers IOs for testing. * * @param innerIO Inner IO. @@ -402,6 +455,13 @@ public abstract class PageIO { */ @SuppressWarnings("unchecked") public static <Q extends BPlusIO<?>> Q getBPlusIO(int type, int ver) throws IgniteCheckedException { + + if (type >= T_H2_EX_REF_LEAF_START && type <= T_H2_EX_REF_LEAF_END) + return (Q)h2ExtraLeafIOs.get(type - T_H2_EX_REF_LEAF_START).forVersion(ver); + + if (type >= T_H2_EX_REF_INNER_START && type <= T_H2_EX_REF_INNER_END) + return (Q)h2ExtraInnerIOs.get(type - T_H2_EX_REF_INNER_START).forVersion(ver); + switch (type) { case T_H2_REF_INNER: if (h2InnerIOs == null) http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexDescriptor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexDescriptor.java index fe58112..bed2ffe 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexDescriptor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexDescriptor.java @@ -47,4 +47,11 @@ public interface GridQueryIndexDescriptor { * @return Type. */ public GridQueryIndexType type(); + + /** + * Gets inline size for SORTED index. + * + * @return Inline size. + */ + public int inlineSize(); } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java index cf85a52..03a6f9b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java @@ -17,12 +17,11 @@ package org.apache.ignite.internal.processors.query; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.concurrent.TimeUnit; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.math.BigDecimal; +import java.sql.PreparedStatement; +import java.sql.SQLException; import java.sql.Time; import java.sql.Timestamp; import java.util.ArrayList; @@ -40,6 +39,7 @@ import java.util.TreeSet; import java.util.UUID; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; import javax.cache.Cache; import javax.cache.CacheException; import org.apache.ignite.IgniteCheckedException; @@ -71,9 +71,9 @@ import org.apache.ignite.internal.processors.cache.CacheEntryImpl; import org.apache.ignite.internal.processors.cache.CacheObject; import org.apache.ignite.internal.processors.cache.CacheObjectContext; import org.apache.ignite.internal.processors.cache.GridCacheContext; -import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.GridCacheDefaultAffinityKeyMapper; import org.apache.ignite.internal.processors.cache.IgniteCacheProxy; +import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.QueryCursorImpl; import org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl; import org.apache.ignite.internal.processors.cache.query.CacheQueryFuture; @@ -1700,7 +1700,7 @@ public class GridQueryProcessor extends GridProcessorAdapter { idxName = QueryEntity.defaultIndexName(idx); if (idx.getIndexType() == QueryIndexType.SORTED || idx.getIndexType() == QueryIndexType.GEOSPATIAL) { - d.addIndex(idxName, idx.getIndexType() == QueryIndexType.SORTED ? SORTED : GEO_SPATIAL); + d.addIndex(idxName, idx.getIndexType() == QueryIndexType.SORTED ? SORTED : GEO_SPATIAL, idx.getInlineSize()); int i = 0; @@ -2453,11 +2453,13 @@ public class GridQueryProcessor extends GridProcessorAdapter { * * @param idxName Index name. * @param type Index type. + * @param inlineSize Inline size. * @return Index descriptor. * @throws IgniteCheckedException In case of error. */ - public IndexDescriptor addIndex(String idxName, GridQueryIndexType type) throws IgniteCheckedException { - IndexDescriptor idx = new IndexDescriptor(type); + public IndexDescriptor addIndex(String idxName, GridQueryIndexType type, + int inlineSize) throws IgniteCheckedException { + IndexDescriptor idx = new IndexDescriptor(type, inlineSize); if (indexes.put(idxName, idx) != null) throw new IgniteCheckedException("Index with name '" + idxName + "' already exists."); @@ -2466,6 +2468,18 @@ public class GridQueryProcessor extends GridProcessorAdapter { } /** + * Adds index. + * + * @param idxName Index name. + * @param type Index type. + * @return Index descriptor. + * @throws IgniteCheckedException In case of error. + */ + public IndexDescriptor addIndex(String idxName, GridQueryIndexType type) throws IgniteCheckedException { + return addIndex(idxName, type, 0); + } + + /** * Adds field to index. * * @param idxName Index name. @@ -2653,13 +2667,25 @@ public class GridQueryProcessor extends GridProcessorAdapter { /** */ private final GridQueryIndexType type; + /** */ + private int inlineSize; + /** * @param type Type. + * @param inlineSize Inline size. */ - private IndexDescriptor(GridQueryIndexType type) { + private IndexDescriptor(GridQueryIndexType type, int inlineSize) { assert type != null; this.type = type; + this.inlineSize = inlineSize; + } + + /** + * @param type Type. + */ + private IndexDescriptor(GridQueryIndexType type) { + this(type, 0); } /** {@inheritDoc} */ @@ -2701,6 +2727,11 @@ public class GridQueryProcessor extends GridProcessorAdapter { } /** {@inheritDoc} */ + @Override public int inlineSize() { + return inlineSize; + } + + /** {@inheritDoc} */ @Override public String toString() { return S.toString(IndexDescriptor.class, this); } http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index 98b5b7f..b0e7956 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -85,8 +85,8 @@ import org.apache.ignite.internal.processors.cache.database.tree.io.PageIO; import org.apache.ignite.internal.processors.cache.query.GridCacheQueryMarshallable; import org.apache.ignite.internal.processors.cache.query.GridCacheTwoStepQuery; import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode; -import org.apache.ignite.internal.processors.query.GridQueryCancel; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; +import org.apache.ignite.internal.processors.query.GridQueryCancel; import org.apache.ignite.internal.processors.query.GridQueryFieldMetadata; import org.apache.ignite.internal.processors.query.GridQueryFieldsResult; import org.apache.ignite.internal.processors.query.GridQueryFieldsResultAdapter; @@ -96,11 +96,13 @@ import org.apache.ignite.internal.processors.query.GridQueryProperty; import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor; import org.apache.ignite.internal.processors.query.IgniteSQLException; import org.apache.ignite.internal.processors.query.h2.database.H2PkHashIndex; -import org.apache.ignite.internal.processors.query.h2.opt.GridH2DefaultTableEngine; import org.apache.ignite.internal.processors.query.h2.database.H2RowFactory; import org.apache.ignite.internal.processors.query.h2.database.H2TreeIndex; +import org.apache.ignite.internal.processors.query.h2.database.io.H2ExtrasInnerIO; +import org.apache.ignite.internal.processors.query.h2.database.io.H2ExtrasLeafIO; import org.apache.ignite.internal.processors.query.h2.database.io.H2InnerIO; import org.apache.ignite.internal.processors.query.h2.database.io.H2LeafIO; +import org.apache.ignite.internal.processors.query.h2.opt.GridH2DefaultTableEngine; import org.apache.ignite.internal.processors.query.h2.opt.GridH2KeyValueRowOffheap; import org.apache.ignite.internal.processors.query.h2.opt.GridH2KeyValueRowOnheap; import org.apache.ignite.internal.processors.query.h2.opt.GridH2QueryContext; @@ -209,13 +211,16 @@ import static org.apache.ignite.internal.processors.query.h2.opt.GridH2QueryType */ @SuppressWarnings({"UnnecessaryFullyQualifiedName", "NonFinalStaticVariableUsedInClassInitialization"}) public class IgniteH2Indexing implements GridQueryIndexing { + /** * Register IO for indexes. */ static { PageIO.registerH2(H2InnerIO.VERSIONS, H2LeafIO.VERSIONS); + H2ExtrasInnerIO.register(); + H2ExtrasLeafIO.register(); } - + /** Default DB options. */ private static final String DB_OPTIONS = ";LOCK_MODE=3;MULTI_THREADED=1;DB_CLOSE_ON_EXIT=FALSE" + ";DEFAULT_LOCK_TIMEOUT=10000;FUNCTIONS_IN_SCHEMA=true;OPTIMIZE_REUSE_RESULTS=0;QUERY_CACHE_SIZE=0" + @@ -2596,7 +2601,8 @@ public class IgniteH2Indexing implements GridQueryIndexing { "_key_PK", tbl, true, - treeIndexColumns(new ArrayList<IndexColumn>(2), keyCol, affCol))); + treeIndexColumns(new ArrayList<IndexColumn>(2), keyCol, affCol), + -1)); if (type().valueClass() == String.class) { try { @@ -2641,7 +2647,7 @@ public class IgniteH2Indexing implements GridQueryIndexing { cols = treeIndexColumns(cols, keyCol, affCol); - idxs.add(createSortedIndex(cacheId, name, tbl, false, cols)); + idxs.add(createSortedIndex(cacheId, name, tbl, false, cols, idx.inlineSize())); } else if (idx.type() == GEO_SPATIAL) idxs.add(createH2SpatialIndex(tbl, name, cols.toArray(new IndexColumn[cols.size()]))); @@ -2653,7 +2659,7 @@ public class IgniteH2Indexing implements GridQueryIndexing { // Add explicit affinity key index if nothing alike was found. if (affCol != null && !affIdxFound) { idxs.add(createSortedIndex(cacheId, "AFFINITY_KEY", tbl, false, - treeIndexColumns(new ArrayList<IndexColumn>(2), affCol, keyCol))); + treeIndexColumns(new ArrayList<IndexColumn>(2), affCol, keyCol), -1)); } return idxs; @@ -2672,7 +2678,8 @@ public class IgniteH2Indexing implements GridQueryIndexing { String name, GridH2Table tbl, boolean pk, - List<IndexColumn> cols + List<IndexColumn> cols, + int inlineSize ) { try { GridCacheSharedContext<Object, Object> scctx = ctx.cache().context(); @@ -2682,7 +2689,7 @@ public class IgniteH2Indexing implements GridQueryIndexing { if (log.isInfoEnabled()) log.info("Creating cache index [cacheId=" + cctx.cacheId() + ", idxName=" + name + ']'); - return new H2TreeIndex(cctx, tbl, name, pk, cols); + return new H2TreeIndex(cctx, tbl, name, pk, cols, inlineSize); } catch (IgniteCheckedException e) { throw new IgniteException(e); http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java index 19e05ed..dd37492 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java @@ -19,14 +19,17 @@ package org.apache.ignite.internal.processors.query.h2.database; import java.util.concurrent.atomic.AtomicLong; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.pagemem.Page; import org.apache.ignite.internal.pagemem.PageMemory; import org.apache.ignite.internal.pagemem.wal.IgniteWriteAheadLogManager; import org.apache.ignite.internal.processors.cache.database.tree.BPlusTree; import org.apache.ignite.internal.processors.cache.database.tree.io.BPlusIO; +import org.apache.ignite.internal.processors.cache.database.tree.io.BPlusMetaIO; import org.apache.ignite.internal.processors.cache.database.tree.reuse.ReuseList; -import org.apache.ignite.internal.processors.query.h2.database.io.H2InnerIO; -import org.apache.ignite.internal.processors.query.h2.database.io.H2LeafIO; +import org.apache.ignite.internal.processors.query.h2.database.io.H2ExtrasInnerIO; +import org.apache.ignite.internal.processors.query.h2.database.io.H2ExtrasLeafIO; import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row; +import org.apache.ignite.internal.util.typedef.internal.U; import org.h2.result.SearchRow; /** @@ -35,6 +38,9 @@ public abstract class H2Tree extends BPlusTree<SearchRow, GridH2Row> { /** */ private final H2RowFactory rowStore; + /** */ + private final int inlineSize; + /** * @param name Tree name. * @param reuseList Reuse list. @@ -46,7 +52,7 @@ public abstract class H2Tree extends BPlusTree<SearchRow, GridH2Row> { * @param initNew Initialize new index. * @throws IgniteCheckedException If failed. */ - public H2Tree( + protected H2Tree( String name, ReuseList reuseList, int cacheId, @@ -55,15 +61,25 @@ public abstract class H2Tree extends BPlusTree<SearchRow, GridH2Row> { AtomicLong globalRmvId, H2RowFactory rowStore, long metaPageId, - boolean initNew + boolean initNew, + int inlineSize ) throws IgniteCheckedException { - super(name, cacheId, pageMem, wal, globalRmvId, metaPageId, reuseList, H2InnerIO.VERSIONS, H2LeafIO.VERSIONS); + super(name, cacheId, pageMem, wal, globalRmvId, metaPageId, reuseList); + + if (!initNew) { + // Page is ready - read inline size from it. + inlineSize = getMetaInlineSize(); + } + + this.inlineSize = inlineSize; assert rowStore != null; this.rowStore = rowStore; - initTree(initNew); + setIos(H2ExtrasInnerIO.getVersions(inlineSize), H2ExtrasLeafIO.getVersions(inlineSize)); + + initTree(initNew, inlineSize); } /** @@ -78,6 +94,35 @@ public abstract class H2Tree extends BPlusTree<SearchRow, GridH2Row> { throws IgniteCheckedException { return (GridH2Row)io.getLookupRow(this, pageAddr, idx); } + + /** + * @return Inline size. + */ + public int inlineSize() { + return inlineSize; + } + + /** + * @return Inline size. + * @throws IgniteCheckedException + */ + private int getMetaInlineSize() throws IgniteCheckedException { + try (Page meta = page(metaPageId)) { + long pageAddr = readLock(meta); // Meta can't be removed. + + assert pageAddr != 0 : "Failed to read lock meta page [page=" + meta + ", metaPageId=" + + U.hexLong(metaPageId) + ']'; + + try { + BPlusMetaIO io = BPlusMetaIO.VERSIONS.forPage(pageAddr); + + return io.getInlineSize(pageAddr); + } + finally { + readUnlock(meta, pageAddr); + } + } + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java index 9bcdab5..be5be0a 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java @@ -17,18 +17,24 @@ package org.apache.ignite.internal.processors.query.h2.database; +import java.util.ArrayList; import java.util.List; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteException; +import org.apache.ignite.IgniteSystemProperties; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.database.IgniteCacheDatabaseSharedManager; import org.apache.ignite.internal.processors.cache.database.RootPage; import org.apache.ignite.internal.processors.cache.database.tree.BPlusTree; import org.apache.ignite.internal.processors.cache.database.tree.io.BPlusIO; -import org.apache.ignite.internal.processors.query.h2.*; -import org.apache.ignite.internal.processors.query.h2.opt.*; -import org.apache.ignite.internal.util.*; -import org.apache.ignite.internal.util.lang.*; +import org.apache.ignite.internal.processors.cache.database.tree.io.PageIO; +import org.apache.ignite.internal.processors.query.h2.H2Cursor; +import org.apache.ignite.internal.processors.query.h2.opt.GridH2IndexBase; +import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row; +import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table; +import org.apache.ignite.internal.util.IgniteTree; +import org.apache.ignite.internal.util.lang.GridCursor; +import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.lang.IgniteBiPredicate; import org.apache.ignite.spi.indexing.IndexingQueryFilter; import org.h2.engine.Session; @@ -39,15 +45,25 @@ import org.h2.result.SearchRow; import org.h2.result.SortOrder; import org.h2.table.IndexColumn; import org.h2.table.TableFilter; +import org.h2.value.Value; import org.jetbrains.annotations.Nullable; /** * H2 Index over {@link BPlusTree}. */ public class H2TreeIndex extends GridH2IndexBase { + /** Default value for {@code IGNITE_MAX_INDEX_PAYLOAD_SIZE} */ + public static final int IGNITE_MAX_INDEX_PAYLOAD_SIZE_DEFAULT = 0; + + /** PageContext for use in IO's */ + private static final ThreadLocal<H2TreeIndex> currentIndex = new ThreadLocal<>(); + /** */ private final H2Tree tree; + /** */ + private final List<InlineIndexHelper> inlineIdxs; + /** Cache context. */ private GridCacheContext<?, ?> cctx; @@ -57,14 +73,16 @@ public class H2TreeIndex extends GridH2IndexBase { * @param name Index name. * @param pk Primary key. * @param colsList Index columns. + * @param inlineSize Inline size. * @throws IgniteCheckedException If failed. */ public H2TreeIndex( - GridCacheContext<?,?> cctx, + GridCacheContext<?, ?> cctx, GridH2Table tbl, String name, boolean pk, - List<IndexColumn> colsList + List<IndexColumn> colsList, + int inlineSize ) throws IgniteCheckedException { this.cctx = cctx; IndexColumn[] cols = colsList.toArray(new IndexColumn[colsList.size()]); @@ -83,34 +101,151 @@ public class H2TreeIndex extends GridH2IndexBase { RootPage page = cctx.offheap().rootPageForIndex(name); + inlineIdxs = getAvailableInlineColumns(cols); + tree = new H2Tree(name, cctx.offheap().reuseListForIndex(name), cctx.cacheId(), dbMgr.pageMemory(), cctx.shared().wal(), cctx.offheap().globalRemoveId(), - tbl.rowFactory(), page.pageId().pageId(), page.isAllocated()) { + tbl.rowFactory(), page.pageId().pageId(), page.isAllocated(), computeInlineSize(inlineIdxs, inlineSize)) { @Override protected int compare(BPlusIO<SearchRow> io, long pageAddr, int idx, SearchRow row) throws IgniteCheckedException { - return compareRows(getRow(io, pageAddr, idx), row); + + if (inlineSize() == 0) + return compareRows(getRow(io, pageAddr, idx), row); + else { + int off = io.offset(idx); + + int fieldOff = 0; + + int lastIdxUsed = 0; + + for (int i = 0; i < inlineIdxs.size(); i++) { + InlineIndexHelper inlineIdx = inlineIdxs.get(i); + + Value v2 = row.getValue(inlineIdx.columnIndex()); + + if (v2 == null) + return 0; + + Value v1 = inlineIdx.get(pageAddr, off + fieldOff, inlineSize() - fieldOff); + + if (v1 == null) + break; + + int c = compareValues(v1, v2, inlineIdx.sortType()); + + if (!canRelyOnCompare(c, v1, v2, inlineIdx)) + break; + + lastIdxUsed++; + + if (c != 0) + return c; + + fieldOff += inlineIdx.fullSize(pageAddr, off + fieldOff); + + if (fieldOff > inlineSize()) + break; + } + + SearchRow rowData = getRow(io, pageAddr, idx); + + for (int i = lastIdxUsed, len = indexColumns.length; i < len; i++) { + int idx0 = columnIds[i]; + + Value v2 = row.getValue(idx0); + if (v2 == null) { + // Can't compare further. + return 0; + } + + Value v1 = rowData.getValue(idx0); + + int c = compareValues(v1, v2, indexColumns[i].sortType); + if (c != 0) + return c; + } + + return 0; + } } }; } - else + else { // We need indexes on the client node, but index will not contain any data. tree = null; + inlineIdxs = null; + } initDistributedJoinMessaging(tbl); } /** + * @param cols Columns array. + * @return List of {@link InlineIndexHelper} objects. + */ + private List<InlineIndexHelper> getAvailableInlineColumns(IndexColumn[] cols) { + + // todo: null + List<InlineIndexHelper> res = new ArrayList<>(); + + for (int i = 0; i < cols.length; i++) { + IndexColumn col = cols[i]; + + if (!InlineIndexHelper.AVAILABLE_TYPES.contains(col.column.getType())) + break; + + InlineIndexHelper idx = new InlineIndexHelper(col.column.getType(), col.column.getColumnId(), col.sortType); + + res.add(idx); + } + + return res; + } + + /** + * @return Tree updated in current thread. + */ + public static H2TreeIndex getCurrentIndex() { + return currentIndex.get(); + } + + /** + * @param a First value. + * @param b Second Value. + * @param sortType Sort type. + * @return Compare result. + */ + private int compareValues(Value a, Value b, int sortType) { + if (a == b) + return 0; + + int comp = table.compareTypeSafe(a, b); + + if ((sortType & SortOrder.DESCENDING) != 0) + comp = -comp; + + return comp; + } + + /** * @return Tree. */ public H2Tree tree() { return tree; } + /** + * @return InlineIndexHelper list. + */ + public List<InlineIndexHelper> inlineIndexes() { + return inlineIdxs; + } + /** {@inheritDoc} */ @Override public Cursor find(Session ses, SearchRow lower, SearchRow upper) { try { IndexingQueryFilter f = threadLocalFilter(); - IgniteBiPredicate<Object,Object> p = null; + IgniteBiPredicate<Object, Object> p = null; if (f != null) { String spaceName = getTable().spaceName(); @@ -138,41 +273,59 @@ public class H2TreeIndex extends GridH2IndexBase { /** {@inheritDoc} */ @Override public GridH2Row put(GridH2Row row) { try { + currentIndex.set(this); + return tree.put(row); } catch (IgniteCheckedException e) { throw DbException.convert(e); } + finally { + currentIndex.remove(); + } } /** {@inheritDoc} */ @Override public boolean putx(GridH2Row row) { try { + currentIndex.set(this); + return tree.putx(row); } catch (IgniteCheckedException e) { throw DbException.convert(e); } + finally { + currentIndex.remove(); + } } /** {@inheritDoc} */ @Override public GridH2Row remove(SearchRow row) { try { + currentIndex.set(this); return tree.remove(row); } catch (IgniteCheckedException e) { throw DbException.convert(e); } + finally { + currentIndex.remove(); + } } /** {@inheritDoc} */ @Override public void removex(SearchRow row) { try { + currentIndex.set(this); tree.removex(row); } catch (IgniteCheckedException e) { throw DbException.convert(e); } + finally { + currentIndex.remove(); + } } /** {@inheritDoc} */ @@ -262,4 +415,67 @@ public class H2TreeIndex extends GridH2IndexBase { throw DbException.convert(e); } } + + /** + * @param inlineIdxs Inline index helpers. + * @param cfgInlineSize Inline size from cache config. + * @return Inline size. + */ + private int computeInlineSize(List<InlineIndexHelper> inlineIdxs, int cfgInlineSize) { + int maxSize = PageIO.MAX_PAYLOAD_SIZE; + + int propSize = IgniteSystemProperties.getInteger(IgniteSystemProperties.IGNITE_MAX_INDEX_PAYLOAD_SIZE, + IGNITE_MAX_INDEX_PAYLOAD_SIZE_DEFAULT); + + if (cfgInlineSize == 0) + return 0; + + if (F.isEmpty(inlineIdxs)) + return 0; + + if (cfgInlineSize == -1) { + if (propSize == 0) + return 0; + + int size = 0; + + for (int i = 0; i < inlineIdxs.size(); i++) { + InlineIndexHelper idxHelper = inlineIdxs.get(i); + if (idxHelper.size() <= 0) { + size = propSize; + break; + } + // 1 byte type + size + size += idxHelper.size() + 1; + } + + return Math.min(maxSize, size); + } + else + return Math.min(maxSize, cfgInlineSize); + } + + /** + * @param c Compare result. + * @param shortVal Short value. + * @param v2 Second value; + * @param inlineIdx Index helper. + * @return {@code true} if we can rely on compare result. + */ + protected static boolean canRelyOnCompare(int c, Value shortVal, Value v2, InlineIndexHelper inlineIdx) { + if (inlineIdx.type() == Value.STRING) { + if (c == 0 && shortVal.getType() != Value.NULL && v2.getType() != Value.NULL) + return false; + + if (shortVal.getType() != Value.NULL + && v2.getType() != Value.NULL + && ((c < 0 && inlineIdx.sortType() == SortOrder.ASCENDING) || (c > 0 && inlineIdx.sortType() == SortOrder.DESCENDING)) + && shortVal.getString().length() <= v2.getString().length()) { + // Can't rely on compare, should use full string. + return false; + } + } + + return true; + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelper.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelper.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelper.java new file mode 100644 index 0000000..ff44df5 --- /dev/null +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelper.java @@ -0,0 +1,279 @@ +/* + * 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.processors.query.h2.database; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.List; +import org.apache.ignite.internal.pagemem.PageUtils; +import org.h2.table.IndexColumn; +import org.h2.value.Value; +import org.h2.value.ValueBoolean; +import org.h2.value.ValueByte; +import org.h2.value.ValueInt; +import org.h2.value.ValueLong; +import org.h2.value.ValueNull; +import org.h2.value.ValueString; + +/** + * Helper class for in-page indexes. + */ +public class InlineIndexHelper { + private static final Charset CHARSET = StandardCharsets.UTF_8; + + /** */ + public static final List<Integer> AVAILABLE_TYPES = Arrays.asList( + Value.BOOLEAN, + Value.BYTE, + Value.SHORT, + Value.INT, + Value.LONG, + Value.STRING + ); + + /** */ + private final int type; + + /** */ + private final int colIdx; + + /** */ + private final int sortType; + + /** + * @param type Index type (see {@link Value}). + * @param colIdx Index column index. + * @param sortType Column sort type (see {@link IndexColumn#sortType}). + */ + public InlineIndexHelper(int type, int colIdx, int sortType) { + this.type = type; + this.colIdx = colIdx; + this.sortType = sortType; + } + + /** + * @return Index type. + */ + public int type() { + return type; + } + + /** + * @return Column index. + */ + public int columnIndex() { + return colIdx; + } + + /** + * @return Sort type. + */ + public int sortType() { + return sortType; + } + + /** + * @return Value size. + */ + public short size() { + switch (type) { + case Value.BOOLEAN: + case Value.BYTE: + return 1; + + case Value.SHORT: + return 2; + + case Value.INT: + return 4; + + case Value.LONG: + return 8; + + case Value.STRING: + return -1; + + default: + throw new UnsupportedOperationException("no get operation for fast index type " + type); + } + } + + /** + * @param pageAddr Page address. + * @param off Offset. + * @return Full size in page. + */ + public int fullSize(long pageAddr, int off) { + int type = PageUtils.getByte(pageAddr, off); + + if (type == Value.NULL) + return 1; + + switch (type) { + case Value.BOOLEAN: + case Value.BYTE: + case Value.INT: + case Value.SHORT: + case Value.LONG: + return size() + 1; + + case Value.STRING: + return PageUtils.getShort(pageAddr, off + 1) + 3; + + default: + throw new UnsupportedOperationException("no get operation for fast index type " + type); + } + } + + /** + * @param pageAddr Page address. + * @param off Offset. + * @return Value. + */ + public Value get(long pageAddr, int off, int maxSize) { + if (size() > 0 && size() + 1 > maxSize) + return null; + + int type = PageUtils.getByte(pageAddr, off); + + if (type == Value.UNKNOWN) + return null; + + if (type == Value.NULL) + return ValueNull.INSTANCE; + + if (this.type != type) + throw new UnsupportedOperationException("invalid fast index type " + type); + + switch (this.type) { + case Value.BOOLEAN: + return ValueBoolean.get(PageUtils.getByte(pageAddr, off + 1) != 0); + + case Value.BYTE: + return ValueByte.get(PageUtils.getByte(pageAddr, off + 1)); + + case Value.SHORT: + return ValueInt.get(PageUtils.getShort(pageAddr, off + 1)); + + case Value.INT: + return ValueInt.get(PageUtils.getInt(pageAddr, off + 1)); + + case Value.LONG: + return ValueLong.get(PageUtils.getLong(pageAddr, off + 1)); + + case Value.STRING: + short size = PageUtils.getShort(pageAddr, off + 1); + return ValueString.get(new String(PageUtils.getBytes(pageAddr, off + 3, size), CHARSET)); + + default: + throw new UnsupportedOperationException("no get operation for fast index type " + type); + } + } + + /** + * @param pageAddr Page address. + * @param off Offset. + * @param val Value. + * @return NUmber of bytes saved. + */ + public int put(long pageAddr, int off, Value val, int maxSize) { + if (size() > 0 && size() + 1 > maxSize) + return 0; + + if (val.getType() == Value.NULL) { + PageUtils.putByte(pageAddr, off, (byte)Value.NULL); + return 1; + } + + if (val.getType() != type) + throw new UnsupportedOperationException("value type doesn't match"); + + switch (type) { + case Value.BOOLEAN: + PageUtils.putByte(pageAddr, off, (byte)val.getType()); + PageUtils.putByte(pageAddr, off + 1, (byte)(val.getBoolean() ? 1 : 0)); + return size() + 1; + + case Value.BYTE: + PageUtils.putByte(pageAddr, off, (byte)val.getType()); + PageUtils.putByte(pageAddr, off + 1, val.getByte()); + return size() + 1; + + case Value.SHORT: + PageUtils.putByte(pageAddr, off, (byte)val.getType()); + PageUtils.putShort(pageAddr, off + 1, val.getShort()); + return size() + 1; + + case Value.INT: + PageUtils.putByte(pageAddr, off, (byte)val.getType()); + PageUtils.putInt(pageAddr, off + 1, val.getInt()); + return size() + 1; + + case Value.LONG: + PageUtils.putByte(pageAddr, off, (byte)val.getType()); + PageUtils.putLong(pageAddr, off + 1, val.getLong()); + return size() + 1; + + case Value.STRING: + byte[] s; + if (val.getString().getBytes(CHARSET).length + 3 <= maxSize) + s = val.getString().getBytes(CHARSET); + else + s = toBytes(val.getString(), maxSize - 3); + + if (s == null) { + // Can't fit anything to + PageUtils.putByte(pageAddr, off, (byte)Value.UNKNOWN); + return 0; + } + else { + PageUtils.putByte(pageAddr, off, (byte)val.getType()); + PageUtils.putShort(pageAddr, off + 1, (short)s.length); + PageUtils.putBytes(pageAddr, off + 3, s); + return s.length + 3; + } + + default: + throw new UnsupportedOperationException("no get operation for fast index type " + type); + } + } + + /** + * Convert String to byte[] with size limit, according to UTF-8 encoding. + * + * @param s String. + * @param limit Size limit. + * @return byte[]. + */ + public static byte[] toBytes(String s, int limit) { + byte[] bytes = s.getBytes(CHARSET); + if (bytes.length <= limit) + return bytes; + + for (int i = bytes.length - 1; i > 0; i--) { + if ((bytes[i] & 0xc0) != 0x80 && i <= limit) { + byte[] res = new byte[i]; + System.arraycopy(bytes, 0, res, 0, i); + return res; + } + } + + return null; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/8f836cb0/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2ExtrasInnerIO.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2ExtrasInnerIO.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2ExtrasInnerIO.java new file mode 100644 index 0000000..5a8a681 --- /dev/null +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/io/H2ExtrasInnerIO.java @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.processors.query.h2.database.io; + +import java.util.List; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.pagemem.PageUtils; +import org.apache.ignite.internal.processors.cache.database.tree.BPlusTree; +import org.apache.ignite.internal.processors.cache.database.tree.io.BPlusIO; +import org.apache.ignite.internal.processors.cache.database.tree.io.BPlusInnerIO; +import org.apache.ignite.internal.processors.cache.database.tree.io.IOVersions; +import org.apache.ignite.internal.processors.cache.database.tree.io.PageIO; +import org.apache.ignite.internal.processors.query.h2.database.H2Tree; +import org.apache.ignite.internal.processors.query.h2.database.H2TreeIndex; +import org.apache.ignite.internal.processors.query.h2.database.InlineIndexHelper; +import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row; +import org.h2.result.SearchRow; + +/** + * Inner page for H2 row references. + */ +public class H2ExtrasInnerIO extends BPlusInnerIO<SearchRow> { + /** Payload size. */ + private final int payloadSize; + + /** */ + public static void register() { + for (short payload = 1; payload <= PageIO.MAX_PAYLOAD_SIZE; payload++) + PageIO.registerH2ExtraInner(getVersions((short)(PageIO.T_H2_EX_REF_INNER_START + payload - 1), payload)); + } + + /** + * @param payload Payload size. + * @return IOVersions for given payload. + */ + public static IOVersions<? extends BPlusInnerIO<SearchRow>> getVersions(int payload) { + assert payload >= 0 && payload <= PageIO.MAX_PAYLOAD_SIZE; + + if (payload == 0) + return H2InnerIO.VERSIONS; + else + return (IOVersions<BPlusInnerIO<SearchRow>>)PageIO.getInnerVersions((short)(payload - 1)); + } + + /** */ + private static IOVersions<H2ExtrasInnerIO> getVersions(short type, short payload) { + return new IOVersions<>(new H2ExtrasInnerIO(type, 1, payload)); + } + + /** + * @param type Page type. + * @param ver Page format version. + * @param payloadSize Payload size. + */ + private H2ExtrasInnerIO(short type, int ver, int payloadSize) { + super(type, ver, true, 8 + payloadSize); + this.payloadSize = payloadSize; + } + + /** {@inheritDoc} */ + @Override public void storeByOffset(long pageAddr, int off, SearchRow row) { + GridH2Row row0 = (GridH2Row)row; + + assert row0.link != 0 : row0; + + H2TreeIndex currentIdx = H2TreeIndex.getCurrentIndex(); + assert currentIdx != null; + List<InlineIndexHelper> inlineIdx = currentIdx.inlineIndexes(); + + assert inlineIdx != null; + + int fieldOff = 0; + + for (int i = 0; i < inlineIdx.size(); i++) { + InlineIndexHelper idx = inlineIdx.get(i); + int size = idx.put(pageAddr, off + fieldOff, row.getValue(idx.columnIndex()), payloadSize - fieldOff); + if (size == 0) + break; + fieldOff += size; + } + + PageUtils.putLong(pageAddr, off + payloadSize, row0.link); + } + + /** {@inheritDoc} */ + @Override public SearchRow getLookupRow(BPlusTree<SearchRow, ?> tree, long pageAddr, int idx) + throws IgniteCheckedException { + long link = getLink(pageAddr, idx); + + assert link != 0; + + GridH2Row r0 = ((H2Tree)tree).getRowFactory().getRow(link); + + return r0; + } + + /** {@inheritDoc} */ + @Override public void store(long dstPageAddr, int dstIdx, BPlusIO<SearchRow> srcIo, long srcPageAddr, int srcIdx) { + int srcOff = srcIo.offset(srcIdx); + + byte[] payload = PageUtils.getBytes(srcPageAddr, srcOff, payloadSize); + long link = PageUtils.getLong(srcPageAddr, srcOff + payloadSize); + + assert link != 0; + + int dstOff = offset(dstIdx); + + PageUtils.putBytes(dstPageAddr, dstOff, payload); + PageUtils.putLong(dstPageAddr, dstOff + payloadSize, link); + } + + /** + * @param pageAddr Page address. + * @param idx Index. + * @return Link to row. + */ + private long getLink(long pageAddr, int idx) { + return PageUtils.getLong(pageAddr, offset(idx) + payloadSize); + } +}