This is an automated email from the ASF dual-hosted git repository. ascherbakov pushed a commit to branch tx_deadlock_recovery_hang in repository https://gitbox.apache.org/repos/asf/ignite-3.git
commit e7f3ff5fa9f1f6fd3c8a39843677035a85be5bb8 Author: Alexey Scherbakov <alexey.scherbak...@gmail.com> AuthorDate: Fri Dec 8 18:40:59 2023 +0300 Hang on commit --- .../apache/ignite/distributed/ItLockTableTest.java | 203 +++++++++++++++++++++ 1 file changed, 203 insertions(+) diff --git a/modules/table/src/integrationTest/java/org/apache/ignite/distributed/ItLockTableTest.java b/modules/table/src/integrationTest/java/org/apache/ignite/distributed/ItLockTableTest.java new file mode 100644 index 0000000000..dfe256571b --- /dev/null +++ b/modules/table/src/integrationTest/java/org/apache/ignite/distributed/ItLockTableTest.java @@ -0,0 +1,203 @@ +/* + * 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.distributed; + +import static org.apache.ignite.internal.replicator.ReplicaManager.DEFAULT_IDLE_SAFE_TIME_PROPAGATION_PERIOD_MILLISECONDS; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.apache.ignite.internal.configuration.testframework.ConfigurationExtension; +import org.apache.ignite.internal.configuration.testframework.InjectConfiguration; +import org.apache.ignite.internal.hlc.HybridClock; +import org.apache.ignite.internal.logger.IgniteLogger; +import org.apache.ignite.internal.logger.Loggers; +import org.apache.ignite.internal.placementdriver.PlacementDriver; +import org.apache.ignite.internal.raft.configuration.RaftConfiguration; +import org.apache.ignite.internal.replicator.ReplicaService; +import org.apache.ignite.internal.schema.Column; +import org.apache.ignite.internal.schema.SchemaDescriptor; +import org.apache.ignite.internal.schema.configuration.GcConfiguration; +import org.apache.ignite.internal.table.TableViewInternal; +import org.apache.ignite.internal.testframework.IgniteAbstractTest; +import org.apache.ignite.internal.tx.DeadlockPreventionPolicy; +import org.apache.ignite.internal.tx.HybridTimestampTracker; +import org.apache.ignite.internal.tx.InternalTransaction; +import org.apache.ignite.internal.tx.configuration.TransactionConfiguration; +import org.apache.ignite.internal.tx.impl.HeapLockManager; +import org.apache.ignite.internal.tx.impl.TransactionIdGenerator; +import org.apache.ignite.internal.tx.impl.TxManagerImpl; +import org.apache.ignite.internal.type.NativeTypes; +import org.apache.ignite.network.ClusterNode; +import org.apache.ignite.network.ClusterService; +import org.apache.ignite.table.RecordView; +import org.apache.ignite.table.Tuple; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.api.extension.ExtendWith; + +/** + * Test lock table. + */ +@ExtendWith(ConfigurationExtension.class) +public class ItLockTableTest extends IgniteAbstractTest { + private static final IgniteLogger LOG = Loggers.forClass(ItLockTableTest.class); + + private static int EMP_TABLE_ID = 2; + + private static final int CACHE_SIZE = 10; + + private static final String TABLE_NAME = "test"; + + private static SchemaDescriptor TABLE_SCHEMA = new SchemaDescriptor( + 1, + new Column[]{new Column("id".toUpperCase(), NativeTypes.INT32, false)}, + new Column[]{ + new Column("name".toUpperCase(), NativeTypes.STRING, true), + new Column("salary".toUpperCase(), NativeTypes.DOUBLE, true) + } + ); + + protected TableViewInternal testTable; + + protected final TestInfo testInfo; + + //TODO fsync can be turned on again after https://issues.apache.org/jira/browse/IGNITE-20195 + @InjectConfiguration("mock: { fsync: false }") + protected static RaftConfiguration raftConfiguration; + + @InjectConfiguration + protected static GcConfiguration gcConfig; + + @InjectConfiguration + protected static TransactionConfiguration txConfiguration; + + private ItTxTestCluster txTestCluster; + + private HybridTimestampTracker timestampTracker = new HybridTimestampTracker(); + + /** + * The constructor. + * + * @param testInfo Test info. + */ + public ItLockTableTest(TestInfo testInfo) { + this.testInfo = testInfo; + } + + @BeforeEach + public void before() throws Exception { + txTestCluster = new ItTxTestCluster( + testInfo, + raftConfiguration, + txConfiguration, + workDir, + 1, + 1, + false, + timestampTracker + ) { + @Override + protected TxManagerImpl newTxManager( + ClusterService clusterService, + ReplicaService replicaSvc, + HybridClock clock, + TransactionIdGenerator generator, + ClusterNode node, + PlacementDriver placementDriver + ) { + return new TxManagerImpl( + txConfiguration, + clusterService, + replicaSvc, + new HeapLockManager( + new DeadlockPreventionPolicy() {}), + clock, + generator, + placementDriver, + () -> DEFAULT_IDLE_SAFE_TIME_PROPAGATION_PERIOD_MILLISECONDS + ); + } + }; + txTestCluster.prepareCluster(); + + testTable = txTestCluster.startTable(TABLE_NAME, EMP_TABLE_ID, TABLE_SCHEMA); + + log.info("Tables have been started"); + } + + @AfterEach + public void after() throws Exception { + txTestCluster.shutdownCluster(); + } + + @Test + public void testDeadlockRecovery() throws InterruptedException { + RecordView<Tuple> view = testTable.recordView(); + Tuple t1 = tuple(0, "0"); + assertTrue(view.insert(null, t1)); + + Tuple t2 = tuple(1, "1"); + assertTrue(view.insert(null, t2)); + + InternalTransaction tx1 = (InternalTransaction) txTestCluster.igniteTransactions().begin(); + InternalTransaction tx2 = (InternalTransaction) txTestCluster.igniteTransactions().begin(); + + LOG.info("id1={}", tx1.id()); + LOG.info("id2={}", tx2.id()); + + assertTrue(tx2.id().compareTo(tx1.id()) > 0); + + Tuple t10 = view.get(tx1, keyTuple(0)); + Tuple t21 = view.get(tx2, keyTuple(1)); + + assertEquals(t1.stringValue("name"), t10.stringValue("name")); + assertEquals(t2.stringValue("name"), t21.stringValue("name")); + + view.upsertAsync(tx1, tuple(1, "11")); + view.upsertAsync(tx2, tuple(0, "00")); + + Thread.sleep(500); + +// assertTrue(TestUtils.waitForCondition(() -> { +// int total = 0; +// HeapLockManager lockManager = (HeapLockManager) txTestCluster.txManagers.get(txTestCluster.localNodeName).lockManager(); +// for (int j = 0; j < lockManager.getSlots().length; j++) { +// LockState slot = lockManager.getSlots()[j]; +// +// total += slot.waitersCount(); +// } +// +// return total == 8; +// }, 10_000), "Some lockers are missing"); + + tx1.commit(); + } + + private static Tuple tuple(int id, String name) { + return Tuple.create() + .set("id", id) + .set("name", name); + } + + private static Tuple keyTuple(int id) { + return Tuple.create() + .set("id", id); + } +}