diff --git a/modules/core/src/main/java/org/apache/ignite/internal/cache/query/index/sorted/inline/InlineIndexImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/cache/query/index/sorted/inline/InlineIndexImpl.java index a31a9cf8b713f..ade4c4d10a74d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/cache/query/index/sorted/inline/InlineIndexImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/cache/query/index/sorted/inline/InlineIndexImpl.java @@ -109,7 +109,7 @@ public InlineIndexImpl(GridCacheContext cctx, SortedIndexDefinition def, I try { // If it is known that only one row will be returned an optimization is employed if (isSingleRowLookup(lower, upper)) { - IndexRowImpl row = segments[segment].findOne(lower, closure, null); + IndexRowImpl row = segments[segment].findOne(lower, closure, null, null); if (row == null || isExpired(row)) return IndexValueCursor.EMPTY; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java index 47671d01a462c..52c470d3dfbf0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java @@ -1783,24 +1783,18 @@ private void clearPendingEntries(GridCacheContext cctx, CacheDataRow oldRow) int cacheId = grp.sharedGroup() ? cctx.cacheId() : CU.UNDEFINED_CACHE_ID; - CacheDataRow row = dataTree.findOne(new SearchRow(cacheId, key), CacheDataRowAdapter.RowData.NO_KEY); - - afterRowFound(row, key); - - return row; - } - - /** - * @param row Row. - * @param key Key. - * @throws IgniteCheckedException If failed. - */ - private void afterRowFound(@Nullable CacheDataRow row, KeyCacheObject key) throws IgniteCheckedException { - if (row != null) { - row.key(key); - - grp.dataRegion().evictionTracker().touchPage(row.link()); - } + return dataTree.findOne( + new SearchRow(cacheId, key), + null, + CacheDataRowAdapter.RowData.NO_KEY, + (pageId, row) -> { + if (row != null) { + grp.dataRegion().evictionTracker().touchPage(row.link()); + + ((CacheDataRow)row).key(key); + } + } + ); } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/FairFifoPageEvictionTracker.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/FairFifoPageEvictionTracker.java index 84fd0188de32f..4678df41eedfe 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/FairFifoPageEvictionTracker.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/FairFifoPageEvictionTracker.java @@ -55,7 +55,7 @@ public FairFifoPageEvictionTracker( } /** {@inheritDoc} */ - @Override public synchronized void touchPage(long pageId) throws IgniteCheckedException { + @Override public synchronized void touchPage(long pageId) { pageUsageList.addLast(PageIdUtils.pageIndex(pageId)); } @@ -65,7 +65,7 @@ public FairFifoPageEvictionTracker( } /** {@inheritDoc} */ - @Override public synchronized void forgetPage(long pageId) throws IgniteCheckedException { + @Override public synchronized void forgetPage(long pageId) { // No-op. } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/NoOpPageEvictionTracker.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/NoOpPageEvictionTracker.java index d212fcec88b5a..4409e35e7446b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/NoOpPageEvictionTracker.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/NoOpPageEvictionTracker.java @@ -16,7 +16,6 @@ */ package org.apache.ignite.internal.processors.cache.persistence.evict; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteException; /** @@ -34,17 +33,17 @@ public class NoOpPageEvictionTracker implements PageEvictionTracker { } /** {@inheritDoc} */ - @Override public void touchPage(long pageId) throws IgniteCheckedException { + @Override public void touchPage(long pageId) { // No-op. } /** {@inheritDoc} */ - @Override public void evictDataPage() throws IgniteCheckedException { + @Override public void evictDataPage() { // No-op. } /** {@inheritDoc} */ - @Override public void forgetPage(long pageId) throws IgniteCheckedException { + @Override public void forgetPage(long pageId) { // No-op. } @@ -54,7 +53,7 @@ public class NoOpPageEvictionTracker implements PageEvictionTracker { } /** {@inheritDoc} */ - @Override public void trackFragmentPage(long pageId, long prevPageId, boolean isHeadPage) throws IgniteCheckedException { + @Override public void trackFragmentPage(long pageId, long prevPageId, boolean isHeadPage) { // No-op. } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/PageAbstractEvictionTracker.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/PageAbstractEvictionTracker.java index 07a97e8e4fbbd..e5795a80f1e1c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/PageAbstractEvictionTracker.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/PageAbstractEvictionTracker.java @@ -185,7 +185,7 @@ int pageIdx(int trackingIdx) { } /** {@inheritDoc} */ - @Override public void trackFragmentPage(long pageId, long prevPageId, boolean isHeadPage) throws IgniteCheckedException { + @Override public void trackFragmentPage(long pageId, long prevPageId, boolean isHeadPage) { // Do nothing if called for tail page. if (prevPageId == 0) return; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/PageEvictionTracker.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/PageEvictionTracker.java index 5954137fc40a7..82970fb52521c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/PageEvictionTracker.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/PageEvictionTracker.java @@ -28,9 +28,8 @@ public interface PageEvictionTracker extends LifecycleAware { * Call this method when data page is accessed. * * @param pageId Page id. - * @throws IgniteCheckedException In case of page memory error. */ - public void touchPage(long pageId) throws IgniteCheckedException; + public void touchPage(long pageId); /** * Check if page eviction is required according to the configured policy. @@ -53,9 +52,8 @@ public interface PageEvictionTracker extends LifecycleAware { * Call this method when last entry is removed from data page. * * @param pageId Page id. - * @throws IgniteCheckedException In case of page memory error. */ - public void forgetPage(long pageId) throws IgniteCheckedException; + public void forgetPage(long pageId); /** * Call this method when data page containing fragment of row is written. @@ -63,7 +61,6 @@ public interface PageEvictionTracker extends LifecycleAware { * @param pageId Page id. * @param prevPageId Page id of previous fragment. 0 if called for the tail fragment (written first). * @param isHeadPage True if head fragment (written last) of row is written, False otherwise. - * @throws IgniteCheckedException In case of page memory error. */ - public void trackFragmentPage(long pageId, long prevPageId, boolean isHeadPage) throws IgniteCheckedException; + public void trackFragmentPage(long pageId, long prevPageId, boolean isHeadPage); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/Random2LruPageEvictionTracker.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/Random2LruPageEvictionTracker.java index 80634ed878f5a..47cc49702cfac 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/Random2LruPageEvictionTracker.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/Random2LruPageEvictionTracker.java @@ -80,7 +80,7 @@ public Random2LruPageEvictionTracker( } /** {@inheritDoc} */ - @Override public void touchPage(long pageId) throws IgniteCheckedException { + @Override public void touchPage(long pageId) { int pageIdx = PageIdUtils.pageIndex(pageId); long latestTs = compactTimestamp(U.currentTimeMillis()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/RandomLruPageEvictionTracker.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/RandomLruPageEvictionTracker.java index cd690e0af7314..bc4f3de6bc470 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/RandomLruPageEvictionTracker.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/RandomLruPageEvictionTracker.java @@ -82,7 +82,7 @@ public RandomLruPageEvictionTracker( } /** {@inheritDoc} */ - @Override public void touchPage(long pageId) throws IgniteCheckedException { + @Override public void touchPage(long pageId) { int pageIdx = PageIdUtils.pageIndex(pageId); long res = compactTimestamp(U.currentTimeMillis()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/BPlusTree.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/BPlusTree.java index 782724dd5f414..1ac799c57d116 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/BPlusTree.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/BPlusTree.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.BiConsumer; import java.util.function.Supplier; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteSystemProperties; @@ -1533,27 +1534,24 @@ public T findLast(final TreeRowClosure c) throws IgniteCheckedException { /** * @param row Lookup row for exact match. + * @param c Filter closure. * @param x Implementation specific argument, {@code null} always means that we need to return full detached data row. - * @return Found result or {@code null} - * @throws IgniteCheckedException If failed. - */ - public final R findOne(L row, Object x) throws IgniteCheckedException { - return findOne(row, null, x); - } - - /** - * @param row Lookup row for exact match. - * @param x Implementation specific argument, {@code null} always means that we need to return full detached data row. + * @param foundLsnr Found row listener. If not {@code null}, is called when a row is found under a page-read-lock. * @return Found result or {@code null}. * @throws IgniteCheckedException If failed. */ - public final R findOne(L row, TreeRowClosure c, Object x) throws IgniteCheckedException { + public final R findOne( + L row, + @Nullable TreeRowClosure c, + Object x, + @Nullable BiConsumer foundLsnr + ) throws IgniteCheckedException { checkDestroyed(); GetOne g = new GetOne(row, c, x, false); try { - doFind(g); + doFind(g, foundLsnr); return (R)g.row; } @@ -1577,7 +1575,7 @@ public final R findOne(L row, TreeRowClosure c, Object x) throws Ignit * @throws IgniteCheckedException If failed. */ @Override public final T findOne(L row) throws IgniteCheckedException { - return findOne(row, null, null); + return findOne(row, null, null, null); } /** @@ -1585,12 +1583,21 @@ public final R findOne(L row, TreeRowClosure c, Object x) throws Ignit * @throws IgniteCheckedException If failed. */ private void doFind(Get g) throws IgniteCheckedException { + doFind(g, null); + } + + /** + * @param g Get. + * @param foundLsnr Found row listener. If not {@code null}, is called when a row is found under a page-read-lock. + * @throws IgniteCheckedException If failed. + */ + private void doFind(Get g, @Nullable BiConsumer foundLsnr) throws IgniteCheckedException { assert !sequentialWriteOptsEnabled; for (;;) { // Go down with retries. g.init(); - switch (findDown(g, g.rootId, 0L, g.rootLvl)) { + switch (findDown(g, g.rootId, 0L, g.rootLvl, foundLsnr)) { case RETRY: case RETRY_ROOT: checkDestroyed(); @@ -1609,10 +1616,11 @@ private void doFind(Get g) throws IgniteCheckedException { * @param pageId Page ID. * @param fwdId Expected forward page ID. * @param lvl Level. + * @param foundLsnr Found row listener. If not {@code null}, is called when a row is found under a page-read-lock. * @return Result code. * @throws IgniteCheckedException If failed. */ - private Result findDown(final Get g, final long pageId, final long fwdId, final int lvl) + private Result findDown(Get g, long pageId, long fwdId, int lvl, @Nullable BiConsumer foundLsnr) throws IgniteCheckedException { long page = acquirePage(pageId); @@ -1633,7 +1641,7 @@ private Result findDown(final Get g, final long pageId, final long fwdId, final assert g.fwdId != fwdId || fwdId == 0; // Go down recursively. - res = findDown(g, g.pageId, g.fwdId, lvl - 1); + res = findDown(g, g.pageId, g.fwdId, lvl - 1, foundLsnr); switch (res) { case RETRY: @@ -1652,6 +1660,12 @@ private Result findDown(final Get g, final long pageId, final long fwdId, final return res; + case FOUND: + if (foundLsnr != null) + foundLsnr.accept(pageId, g.row); + + return res; + default: return res; } diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractFieldsQuerySelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractFieldsQuerySelfTest.java index 400d24d993ca7..24ba05017a40f 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractFieldsQuerySelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractFieldsQuerySelfTest.java @@ -30,6 +30,7 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.Callable; +import java.util.function.BiConsumer; import javax.cache.CacheException; import com.google.common.collect.ImmutableMap; import org.apache.ignite.IgniteCache; @@ -782,7 +783,8 @@ public void testEmptyResult() throws Exception { /** * Verifies that exactly one record is found when we have equality comparison in where clause (which is supposed - * to use {@link BPlusTree#findOne(Object, Object)} instead of {@link BPlusTree#find(Object, Object, Object)}. + * to use {@link BPlusTree#findOne(Object, BPlusTree.TreeRowClosure, Object, BiConsumer)} instead of + * {@link BPlusTree#find(Object, Object, Object)}. * * @throws Exception If failed. */ @@ -801,8 +803,8 @@ public void testSingleResultUsesFindOne() throws Exception { /** * Verifies that zero records are found when we have equality comparison in where clause (which is supposed - * to use {@link BPlusTree#findOne(Object, Object)} instead of {@link BPlusTree#find(Object, Object, Object)} - * and the key is not in the cache. + * to use {@link BPlusTree#findOne(Object, BPlusTree.TreeRowClosure, Object, BiConsumer)} instead of + * {@link BPlusTree#find(Object, Object, Object)} and the key is not in the cache. * * @throws Exception If failed. */