nizhikov commented on code in PR #11438:
URL: https://github.com/apache/ignite/pull/11438#discussion_r1759729196


##########
modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/CacheIndexImpl.java:
##########
@@ -153,60 +164,133 @@ public Index queryIndex() {
 
     /** {@inheritDoc} */
     @Override public long count(ExecutionContext<?> ectx, ColocationGroup grp, 
boolean notNull) {
+        if (idx == null || !grp.nodeIds().contains(ectx.localNodeId()))
+            return 0L;
+
+        int[] locParts = grp.partitions(ectx.localNodeId());
+
+        IndexingQueryFilter filter = new 
IndexingQueryFilterImpl(tbl.descriptor().cacheContext().kernalContext(),
+            ectx.topologyVersion(), locParts);
+
+        InlineIndex iidx = idx.unwrap(InlineIndex.class);
+
+        TreeRowClosure<IndexRow, IndexRow> rowFilter = countRowFilter(notNull, 
iidx);
+
         long cnt = 0;
 
-        if (idx != null && grp.nodeIds().contains(ectx.localNodeId())) {
-            IndexingQueryFilter filter = new 
IndexingQueryFilterImpl(tbl.descriptor().cacheContext().kernalContext(),
-                ectx.topologyVersion(), grp.partitions(ectx.localNodeId()));
+        if (!F.isEmpty(ectx.getTxWriteEntries())) {
+            IgniteBiTuple<Set<KeyCacheObject>, List<CacheDataRow>> txChanges = 
transactionData(
+                ectx.getTxWriteEntries(),
+                iidx.indexDefinition().cacheInfo().cacheId(),
+                locParts,
+                Function.identity()
+            );
 
-            InlineIndex iidx = idx.unwrap(InlineIndex.class);
+            if (!txChanges.get1().isEmpty()) {
+                // This call will change `txChanges.get1()` content.
+                // Removing found key from set more efficient so we break some 
rules here.
+                rowFilter = transactionAwareCountRowFilter(rowFilter, 
txChanges.get1());
 
-            BPlusTree.TreeRowClosure<IndexRow, IndexRow> rowFilter = null;
+                cnt = countTransactionRows(iidx, txChanges.get2());
+            }
+        }
 
-            boolean checkExpired = 
!tbl.descriptor().cacheContext().config().isEagerTtl();
+        try {
+            for (int i = 0; i < iidx.segmentsCount(); ++i)
+                cnt += iidx.count(i, new IndexQueryContext(filter, rowFilter));
 
-            if (notNull) {
-                boolean nullsFirst = 
collation.getFieldCollations().get(0).nullDirection ==
-                    RelFieldCollation.NullDirection.FIRST;
+            return cnt;
+        }
+        catch (IgniteCheckedException e) {
+            throw new IgniteException("Unable to count index records.", e);
+        }
+    }
 
-                BPlusTree.TreeRowClosure<IndexRow, IndexRow> notNullRowFilter =
-                    IndexScan.createNotNullRowFilter(iidx, checkExpired);
+    /** */
+    private @Nullable TreeRowClosure<IndexRow, IndexRow> 
countRowFilter(boolean notNull, InlineIndex iidx) {
+        boolean checkExpired = 
!tbl.descriptor().cacheContext().config().isEagerTtl();
+
+        if (notNull) {
+            boolean nullsFirst = 
collation.getFieldCollations().get(0).nullDirection == 
RelFieldCollation.NullDirection.FIRST;
+
+            TreeRowClosure<IndexRow, IndexRow> notNullRowFilter = 
IndexScan.createNotNullRowFilter(iidx, checkExpired);
+
+            return new TreeRowClosure<IndexRow, IndexRow>() {
+                private boolean skipCheck;
+
+                @Override public boolean apply(
+                    BPlusTree<IndexRow, IndexRow> tree,
+                    BPlusIO<IndexRow> io,
+                    long pageAddr,
+                    int idx
+                ) throws IgniteCheckedException {
+                    // If we have NULLS-FIRST collation, all values after 
first not-null value will be not-null,
+                    // don't need to check it with notNullRowFilter.
+                    // In case of NULL-LAST collation, all values after first 
null value will be null,
+                    // don't need to check it too.
+                    if (skipCheck && !checkExpired)
+                        return nullsFirst;
+
+                    boolean res = notNullRowFilter.apply(tree, io, pageAddr, 
idx);
+
+                    if (res == nullsFirst)
+                        skipCheck = true;
+
+                    return res;
+                }
+
+                @Override public IndexRow lastRow() {
+                    return (skipCheck && !checkExpired)
+                        ? null
+                        : notNullRowFilter.lastRow();
+                }
+            };
+        }
+        else if (checkExpired)
+            return IndexScan.createNotExpiredRowFilter();
 
-                AtomicBoolean skipCheck = new AtomicBoolean();
+        return null;
+    }
 
-                rowFilter = new BPlusTree.TreeRowClosure<IndexRow, IndexRow>() 
{
-                    @Override public boolean apply(
-                        BPlusTree<IndexRow, IndexRow> tree,
-                        BPlusIO<IndexRow> io,
-                        long pageAddr,
-                        int idx
-                    ) throws IgniteCheckedException {
-                        // If we have NULLS-FIRST collation, all values after 
first not-null value will be not-null,
-                        // don't need to check it with notNullRowFilter.
-                        // In case of NULL-LAST collation, all values after 
first null value will be null,
-                        // don't need to check it too.
-                        if (skipCheck.get() && !checkExpired)
-                            return nullsFirst;
+    /** */
+    private static @NotNull TreeRowClosure<IndexRow, IndexRow> 
transactionAwareCountRowFilter(
+        TreeRowClosure<IndexRow, IndexRow> rowFilter,
+        Set<KeyCacheObject> skipKeys
+    ) {
+        return new TreeRowClosure<IndexRow, IndexRow>() {
+            @Override public boolean apply(
+                BPlusTree<IndexRow, IndexRow> tree,
+                BPlusIO<IndexRow> io,
+                long pageAddr,
+                int idx
+            ) throws IgniteCheckedException {
+                if (rowFilter != null && !rowFilter.apply(tree, io, pageAddr, 
idx))
+                    return false;
 
-                        boolean res = notNullRowFilter.apply(tree, io, 
pageAddr, idx);
+                if (skipKeys.isEmpty())
+                    return true;
 
-                        if (res == nullsFirst)
-                            skipCheck.set(true);
+                IndexRow row = rowFilter == null ? null : rowFilter.lastRow();
 
-                        return res;
-                    }
-                };
-            }
-            else if (checkExpired)
-                rowFilter = IndexScan.createNotExpiredRowFilter();
+                if (row == null)
+                    row = tree.getRow(io, pageAddr, idx);
 
-            try {
-                for (int i = 0; i < iidx.segmentsCount(); ++i)
-                    cnt += iidx.count(i, new IndexQueryContext(filter, 
rowFilter));
-            }
-            catch (IgniteCheckedException e) {
-                throw new IgniteException("Unable to count index records.", e);
+                return !skipKeys.remove(row.cacheDataRow().key());
             }
+        };
+    }
+
+    /** */
+    private static long countTransactionRows(InlineIndex iidx, 
List<CacheDataRow> changedRows) {
+        InlineIndexRowHandler rowHnd = iidx.segment(0).rowHandler();
+
+        long cnt = 0;
+
+        for (CacheDataRow txRow : changedRows) {
+            if (rowHnd.indexKey(0, txRow) == NullIndexKey.INSTANCE)

Review Comment:
   Fixed.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@ignite.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to