This is an automated email from the ASF dual-hosted git repository.

vpyatkov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new cd5720b790 IGNITE-19329 Tx. POSITIVE_INF inside SortedIndexLocker is 
not unique across partitions (#2074)
cd5720b790 is described below

commit cd5720b790e4cd767e374b01977cdccb229d7360
Author: Vladislav Pyatkov <[email protected]>
AuthorDate: Wed May 17 12:09:22 2023 +0400

    IGNITE-19329 Tx. POSITIVE_INF inside SortedIndexLocker is not unique across 
partitions (#2074)
---
 .../ignite/internal/sql/engine/ItDmlTest.java      | 18 ++++++++
 .../apache/ignite/internal/table/TableImpl.java    |  1 +
 .../table/distributed/SortedIndexLocker.java       | 49 ++++++++++++++++++----
 .../PartitionReplicaListenerIndexLockingTest.java  |  1 +
 .../replication/PartitionReplicaListenerTest.java  |  2 +-
 5 files changed, 61 insertions(+), 10 deletions(-)

diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDmlTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDmlTest.java
index f0ce4c9335..7203ab60b2 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDmlTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDmlTest.java
@@ -136,6 +136,24 @@ public class ItDmlTest extends 
ClusterPerClassIntegrationTest {
                 .check();
     }
 
+    /**
+     * Test ensures inserts are possible after read lock on a range.
+     */
+    @Test
+    public void rangeReadAndExclusiveInsert() {
+        sql("CREATE TABLE test (id INT, aff_key INT, val INT, PRIMARY KEY (id, 
aff_key)) COLOCATE BY (aff_key) ");
+        sql("CREATE INDEX test_val_asc_idx ON test (val ASC)");
+        sql("INSERT INTO test VALUES (1, 1, 1), (2, 1, 2), (3, 1, 3)");
+
+        log.info("Data was loaded.");
+
+        Transaction tx = CLUSTER_NODES.get(0).transactions().begin();
+
+        sql(tx, "SELECT * FROM test WHERE val <= 1 ORDER BY val");
+
+        sql("INSERT INTO test VALUES (4, 1, 4)"); // <-- this INSERT uses 
implicit transaction
+    }
+
     /**
      * Test ensures that big insert although being split to several chunks 
will share the same implicit transaction.
      */
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/table/TableImpl.java 
b/modules/table/src/main/java/org/apache/ignite/internal/table/TableImpl.java
index 1e406f54c6..c1200dc027 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/table/TableImpl.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/TableImpl.java
@@ -326,6 +326,7 @@ public class TableImpl implements Table {
                 indexId,
                 partitionId -> new SortedIndexLocker(
                         indexId,
+                        partitionId,
                         lockManager,
                         tbl.storage().getOrCreateSortedIndex(partitionId, 
indexId),
                         searchRowResolver
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/SortedIndexLocker.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/SortedIndexLocker.java
index 804e922fab..e82347efbb 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/SortedIndexLocker.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/SortedIndexLocker.java
@@ -25,7 +25,9 @@ import org.apache.ignite.internal.schema.BinaryRow;
 import org.apache.ignite.internal.schema.BinaryTuple;
 import org.apache.ignite.internal.schema.BinaryTuplePrefix;
 import org.apache.ignite.internal.schema.BinaryTupleSchema;
-import org.apache.ignite.internal.schema.BinaryTupleSchema.Element;
+import org.apache.ignite.internal.schema.Column;
+import org.apache.ignite.internal.schema.NativeTypes;
+import org.apache.ignite.internal.schema.SchemaDescriptor;
 import org.apache.ignite.internal.storage.RowId;
 import org.apache.ignite.internal.storage.index.IndexRow;
 import org.apache.ignite.internal.storage.index.PeekCursor;
@@ -43,12 +45,19 @@ import org.jetbrains.annotations.Nullable;
  * <p>Simply acquires lock on a given row for lookup and remove, acquires lock 
on a next key for insert.
  */
 public class SortedIndexLocker implements IndexLocker {
-    /** Index INF+ value object. */
-    private static final BinaryTuple POSITIVE_INF = new BinaryTuple(
-            BinaryTupleSchema.create(new Element[0]),
-            new BinaryTupleBuilder(0, false).build()
+
+    private static final SchemaDescriptor INFINITY_TUPLE_SCHEMA = new 
SchemaDescriptor(
+            1,
+            new Column[]{
+                    new Column("indexId", NativeTypes.UUID, false),
+                    new Column("partId", NativeTypes.INT32, false)
+            },
+            new Column[0]
     );
 
+    /** Index INF+ value object. */
+    private final BinaryTuple positiveInf;
+
     private final UUID indexId;
     private final LockManager lockManager;
 
@@ -62,16 +71,38 @@ public class SortedIndexLocker implements IndexLocker {
      * Constructs the object.
      *
      * @param indexId An identifier of the index this locker is created for.
+     * @param partId Partition number.
      * @param lockManager A lock manager to acquire locks in.
      * @param storage A storage of an index this locker is created for.
      * @param indexRowResolver A convertor which derives an index key from 
given table row.
      */
-    public SortedIndexLocker(UUID indexId, LockManager lockManager, 
SortedIndexStorage storage,
+    public SortedIndexLocker(UUID indexId, int partId, LockManager 
lockManager, SortedIndexStorage storage,
             Function<BinaryRow, BinaryTuple> indexRowResolver) {
         this.indexId = indexId;
         this.lockManager = lockManager;
         this.storage = storage;
         this.indexRowResolver = indexRowResolver;
+
+        this.positiveInf = createInfiniteBoundary(partId, indexId);
+    }
+
+    /**
+     * Creates a tuple for positive infinity boundary.
+     *
+     * @param partId Partition id.
+     * @param indexId Index id.
+     * @return Infinity binary tuple.
+     */
+    private static BinaryTuple createInfiniteBoundary(int partId, UUID 
indexId) {
+        var binarySchema = 
BinaryTupleSchema.createSchema(INFINITY_TUPLE_SCHEMA, new int[]{
+                INFINITY_TUPLE_SCHEMA.column("indexId").schemaIndex(),
+                INFINITY_TUPLE_SCHEMA.column("partId").schemaIndex()
+        });
+
+        return new BinaryTuple(
+                binarySchema,
+                new BinaryTupleBuilder(binarySchema.elementCount(), 
false).appendUuid(indexId).appendInt(partId).build()
+        );
     }
 
     /** {@inheritDoc} */
@@ -143,8 +174,8 @@ public class SortedIndexLocker implements IndexLocker {
         return row0 == row1 || row0.rowId().equals(row1.rowId());
     }
 
-    private static BinaryTuple indexKey(@Nullable IndexRow indexRow) {
-        return (indexRow == null) ? POSITIVE_INF : indexRow.indexColumns();
+    private BinaryTuple indexKey(@Nullable IndexRow indexRow) {
+        return (indexRow == null) ? positiveInf : indexRow.indexColumns();
     }
 
     /** {@inheritDoc} */
@@ -161,7 +192,7 @@ public class SortedIndexLocker implements IndexLocker {
         if (cursor.hasNext()) {
             nextKey = cursor.next().indexColumns();
         } else { // Otherwise INF.
-            nextKey = POSITIVE_INF;
+            nextKey = positiveInf;
         }
 
         var nextLockKey = new LockKey(indexId, nextKey.byteBuffer());
diff --git 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerIndexLockingTest.java
 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerIndexLockingTest.java
index 44a8fbc65c..fd9c72973c 100644
--- 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerIndexLockingTest.java
+++ 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerIndexLockingTest.java
@@ -161,6 +161,7 @@ public class PartitionReplicaListenerIndexLockingTest 
extends IgniteAbstractTest
 
         IndexLocker sortedIndexLocker = new SortedIndexLocker(
                 SORTED_INDEX_ID,
+                PART_ID,
                 LOCK_MANAGER,
                 (SortedIndexStorage) sortedIndexStorage.storage(),
                 row2SortKeyConverter
diff --git 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerTest.java
 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerTest.java
index 5079324369..cbf3f6b19b 100644
--- 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerTest.java
+++ 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerTest.java
@@ -351,7 +351,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
         );
 
         IndexLocker pkLocker = new HashIndexLocker(pkIndexId, true, 
lockManager, row2Tuple);
-        IndexLocker sortedIndexLocker = new SortedIndexLocker(sortedIndexId, 
lockManager, indexStorage, row2Tuple);
+        IndexLocker sortedIndexLocker = new SortedIndexLocker(sortedIndexId, 
partId, lockManager, indexStorage, row2Tuple);
         IndexLocker hashIndexLocker = new HashIndexLocker(hashIndexId, false, 
lockManager, row2Tuple);
 
         DummySchemaManagerImpl schemaManager = new 
DummySchemaManagerImpl(schemaDescriptor);

Reply via email to