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

sdanilov 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 28ef32f723 IGNITE-19225 Generate beginTs on a coordinator and send it 
to all tx participants (#1973)
28ef32f723 is described below

commit 28ef32f723e12992ecd05bcdcfe9566ad379b659
Author: Roman Puchkovskiy <[email protected]>
AuthorDate: Tue Apr 25 14:38:12 2023 +0400

    IGNITE-19225 Generate beginTs on a coordinator and send it to all tx 
participants (#1973)
---
 .../storage/ItRebalanceDistributedTest.java        |   3 +-
 .../runner/app/ItIgniteNodeRestartTest.java        |   3 +-
 .../org/apache/ignite/internal/app/IgniteImpl.java |   4 +-
 .../exec/rel/TableScanNodeExecutionTest.java       |   3 +-
 .../ignite/distributed/ItTablePersistenceTest.java |   5 +-
 .../distributed/ItTxDistributedTestSingleNode.java |   5 +-
 .../ignite/internal/table/ItColocationTest.java    |  16 +-
 .../apache/ignite/internal/table/TxLocalTest.java  |   3 +-
 .../PartitionRaftCommandsSerializationTest.java    |  14 +-
 .../raft/PartitionCommandListenerTest.java         |  18 +-
 .../PartitionReplicaListenerIndexLockingTest.java  |   8 +-
 .../replication/PartitionReplicaListenerTest.java  |  54 +++---
 .../table/impl/DummyInternalTableImpl.java         |   5 +-
 .../apache/ignite/internal/tx/TransactionIds.java  |  47 +++++
 .../ignite/internal/tx/impl/NodeIdSupplier.java    |  32 ++++
 .../internal/tx/impl/TransactionIdGenerator.java   |  48 ++++++
 .../ignite/internal/tx/impl/TxManagerImpl.java     |  18 +-
 .../internal/tx/AbstractLockManagerTest.java       | 189 +++++++++++----------
 .../ignite/internal/tx/AbstractLockingTest.java    |   3 +-
 .../ignite/internal/tx/TransactionIdsTest.java     |  39 +++++
 .../apache/ignite/internal/tx/TxManagerTest.java   |  12 +-
 .../internal/tx/test/TestTransactionIds.java       |  46 +++++
 22 files changed, 409 insertions(+), 166 deletions(-)

diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/configuration/storage/ItRebalanceDistributedTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/configuration/storage/ItRebalanceDistributedTest.java
index f43bb61d9c..0172a9c54d 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/configuration/storage/ItRebalanceDistributedTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/configuration/storage/ItRebalanceDistributedTest.java
@@ -141,6 +141,7 @@ import 
org.apache.ignite.internal.testframework.WorkDirectoryExtension;
 import org.apache.ignite.internal.tx.LockManager;
 import org.apache.ignite.internal.tx.TxManager;
 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.tx.message.TxMessageGroup;
 import org.apache.ignite.internal.tx.storage.state.TxStateTableStorage;
@@ -633,7 +634,7 @@ public class ItRebalanceDistributedTest {
                     hybridClock
             );
 
-            txManager = new TxManagerImpl(replicaSvc, lockManager, 
hybridClock);
+            txManager = new TxManagerImpl(replicaSvc, lockManager, 
hybridClock, new TransactionIdGenerator(addr.port()));
 
             var clusterStateStorage = new TestClusterStateStorage();
             var logicalTopology = new LogicalTopologyImpl(clusterStateStorage);
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItIgniteNodeRestartTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItIgniteNodeRestartTest.java
index 8b72d9a462..1fcc58cb61 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItIgniteNodeRestartTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItIgniteNodeRestartTest.java
@@ -111,6 +111,7 @@ import 
org.apache.ignite.internal.testframework.IgniteAbstractTest;
 import org.apache.ignite.internal.testframework.TestIgnitionManager;
 import org.apache.ignite.internal.testframework.WithSystemProperty;
 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.tx.message.TxMessageGroup;
 import org.apache.ignite.internal.util.IgniteUtils;
@@ -294,7 +295,7 @@ public class ItIgniteNodeRestartTest extends 
IgniteAbstractTest {
 
         ReplicaService replicaSvc = new 
ReplicaService(clusterSvc.messagingService(), hybridClock);
 
-        var txManager = new TxManagerImpl(replicaService, lockManager, 
hybridClock);
+        var txManager = new TxManagerImpl(replicaService, lockManager, 
hybridClock, new TransactionIdGenerator(idx));
 
         var clusterStateStorage = new 
RocksDbClusterStateStorage(dir.resolve("cmg"));
 
diff --git 
a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java 
b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
index 3ba125f858..b5a19f80a9 100644
--- 
a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
+++ 
b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
@@ -120,6 +120,7 @@ import org.apache.ignite.internal.tx.LockManager;
 import org.apache.ignite.internal.tx.TxManager;
 import org.apache.ignite.internal.tx.impl.HeapLockManager;
 import org.apache.ignite.internal.tx.impl.IgniteTransactionsImpl;
+import org.apache.ignite.internal.tx.impl.TransactionIdGenerator;
 import org.apache.ignite.internal.tx.impl.TxManagerImpl;
 import org.apache.ignite.internal.tx.message.TxMessageGroup;
 import org.apache.ignite.internal.vault.VaultManager;
@@ -352,7 +353,8 @@ public class IgniteImpl implements Ignite {
 
         ReplicaService replicaSvc = new 
ReplicaService(clusterSvc.messagingService(), clock);
 
-        txManager = new TxManagerImpl(replicaSvc, lockMgr, clock);
+        // TODO: IGNITE-19344 - use nodeId that is validated on join (and 
probably generated differently).
+        txManager = new TxManagerImpl(replicaSvc, lockMgr, clock, new 
TransactionIdGenerator(() -> clusterSvc.nodeName().hashCode()));
 
         // TODO: IGNITE-16841 - use common RocksDB instance to store cluster 
state as well.
         clusterStateStorage = new 
RocksDbClusterStateStorage(workDir.resolve(CMG_DB_PATH));
diff --git 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/rel/TableScanNodeExecutionTest.java
 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/rel/TableScanNodeExecutionTest.java
index ab09a436c7..a7679278f1 100644
--- 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/rel/TableScanNodeExecutionTest.java
+++ 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/rel/TableScanNodeExecutionTest.java
@@ -52,6 +52,7 @@ import 
org.apache.ignite.internal.storage.engine.MvTableStorage;
 import org.apache.ignite.internal.table.InternalTable;
 import org.apache.ignite.internal.table.distributed.storage.InternalTableImpl;
 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.tx.storage.state.TxStateTableStorage;
 import org.apache.ignite.network.ClusterNode;
@@ -153,7 +154,7 @@ public class TableScanNodeExecutionTest extends 
AbstractExecutionTest {
                     Int2ObjectMaps.singleton(0, mock(RaftGroupService.class)),
                     PART_CNT,
                     addr -> mock(ClusterNode.class),
-                    new TxManagerImpl(replicaSvc, new HeapLockManager(), new 
HybridClockImpl()),
+                    new TxManagerImpl(replicaSvc, new HeapLockManager(), new 
HybridClockImpl(), new TransactionIdGenerator(0xdeadbeef)),
                     mock(MvTableStorage.class),
                     mock(TxStateTableStorage.class),
                     replicaSvc,
diff --git 
a/modules/table/src/integrationTest/java/org/apache/ignite/distributed/ItTablePersistenceTest.java
 
b/modules/table/src/integrationTest/java/org/apache/ignite/distributed/ItTablePersistenceTest.java
index 49d6a3cdb8..bc35f24156 100644
--- 
a/modules/table/src/integrationTest/java/org/apache/ignite/distributed/ItTablePersistenceTest.java
+++ 
b/modules/table/src/integrationTest/java/org/apache/ignite/distributed/ItTablePersistenceTest.java
@@ -86,6 +86,7 @@ import 
org.apache.ignite.internal.table.impl.DummyInternalTableImpl;
 import org.apache.ignite.internal.testframework.WorkDirectoryExtension;
 import org.apache.ignite.internal.tx.TxManager;
 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.tx.message.TxFinishReplicaRequest;
 import org.apache.ignite.internal.tx.storage.state.test.TestTxStateStorage;
@@ -181,12 +182,12 @@ public class ItTablePersistenceTest extends 
ItAbstractListenerSnapshotTest<Parti
                 .thenAnswer(invocationOnMock -> 
partitionReplicaListener.invoke(invocationOnMock.getArgument(1)));
 
         for (int i = 0; i < nodes(); i++) {
-            TxManager txManager = new TxManagerImpl(replicaService, new 
HeapLockManager(), hybridClock);
+            TxManager txManager = new TxManagerImpl(replicaService, new 
HeapLockManager(), hybridClock, new TransactionIdGenerator(i));
             txManagers.put(i, txManager);
             closeables.add(txManager::stop);
         }
 
-        TxManager txManager = new TxManagerImpl(replicaService, new 
HeapLockManager(), hybridClock);
+        TxManager txManager = new TxManagerImpl(replicaService, new 
HeapLockManager(), hybridClock, new TransactionIdGenerator(-1));
         closeables.add(txManager::stop);
 
         table = new InternalTableImpl(
diff --git 
a/modules/table/src/integrationTest/java/org/apache/ignite/distributed/ItTxDistributedTestSingleNode.java
 
b/modules/table/src/integrationTest/java/org/apache/ignite/distributed/ItTxDistributedTestSingleNode.java
index bd9a8462fd..933dd1d29d 100644
--- 
a/modules/table/src/integrationTest/java/org/apache/ignite/distributed/ItTxDistributedTestSingleNode.java
+++ 
b/modules/table/src/integrationTest/java/org/apache/ignite/distributed/ItTxDistributedTestSingleNode.java
@@ -97,6 +97,7 @@ import org.apache.ignite.internal.tx.InternalTransaction;
 import org.apache.ignite.internal.tx.TxManager;
 import org.apache.ignite.internal.tx.impl.HeapLockManager;
 import org.apache.ignite.internal.tx.impl.IgniteTransactionsImpl;
+import org.apache.ignite.internal.tx.impl.TransactionIdGenerator;
 import org.apache.ignite.internal.tx.impl.TxManagerImpl;
 import org.apache.ignite.internal.tx.message.TxMessageGroup;
 import org.apache.ignite.internal.tx.storage.state.TxStateStorage;
@@ -316,7 +317,7 @@ public class ItTxDistributedTestSingleNode extends 
TxAbstractTest {
 
             replicaServices.put(node.name(), replicaSvc);
 
-            TxManagerImpl txMgr = new TxManagerImpl(replicaSvc, new 
HeapLockManager(), clock);
+            TxManagerImpl txMgr = new TxManagerImpl(replicaSvc, new 
HeapLockManager(), clock, new TransactionIdGenerator(i));
 
             txMgr.start();
 
@@ -341,7 +342,7 @@ public class ItTxDistributedTestSingleNode extends 
TxAbstractTest {
         String localNodeName = 
accRaftClients.get(0).clusterService().topologyService().localMember().name();
 
         if (startClient()) {
-            clientTxManager = new TxManagerImpl(clientReplicaSvc, new 
HeapLockManager(), clientClock);
+            clientTxManager = new TxManagerImpl(clientReplicaSvc, new 
HeapLockManager(), clientClock, new TransactionIdGenerator(-1));
         } else {
             // Collocated mode.
             clientTxManager = txManagers.get(localNodeName);
diff --git 
a/modules/table/src/integrationTest/java/org/apache/ignite/internal/table/ItColocationTest.java
 
b/modules/table/src/integrationTest/java/org/apache/ignite/internal/table/ItColocationTest.java
index c660493e2a..a8946d4c44 100644
--- 
a/modules/table/src/integrationTest/java/org/apache/ignite/internal/table/ItColocationTest.java
+++ 
b/modules/table/src/integrationTest/java/org/apache/ignite/internal/table/ItColocationTest.java
@@ -83,11 +83,12 @@ import 
org.apache.ignite.internal.table.distributed.replicator.TablePartitionId;
 import org.apache.ignite.internal.table.distributed.storage.InternalTableImpl;
 import org.apache.ignite.internal.table.impl.DummyInternalTableImpl;
 import org.apache.ignite.internal.table.impl.DummySchemaManagerImpl;
-import org.apache.ignite.internal.tx.Timestamp;
 import org.apache.ignite.internal.tx.TxManager;
 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.tx.storage.state.test.TestTxStateTableStorage;
+import org.apache.ignite.internal.tx.test.TestTransactionIds;
 import org.apache.ignite.internal.util.CollectionUtils;
 import org.apache.ignite.lang.IgniteBiTuple;
 import org.apache.ignite.network.ClusterNode;
@@ -135,7 +136,12 @@ public class ItColocationTest {
 
         ReplicaService replicaService = Mockito.mock(ReplicaService.class, 
RETURNS_DEEP_STUBS);
 
-        TxManager txManager = new TxManagerImpl(replicaService,  new 
HeapLockManager(), new HybridClockImpl()) {
+        TxManager txManager = new TxManagerImpl(
+                replicaService,
+                new HeapLockManager(),
+                new HybridClockImpl(),
+                new TransactionIdGenerator(0xdeadbeef)
+        ) {
             @Override
             public CompletableFuture<Void> finish(
                     ReplicationGroupId commitPartition,
@@ -192,7 +198,7 @@ public class ItColocationTest {
             if (request instanceof ReadWriteMultiRowReplicaRequest) {
                 Map<UUID, ByteBuffer> rows = 
((ReadWriteMultiRowReplicaRequest) request).binaryRows()
                         .stream()
-                        .collect(toMap(row -> 
Timestamp.nextVersion().toUuid(), BinaryRow::byteBuffer));
+                        .collect(toMap(row -> 
TestTransactionIds.newTransactionId(), BinaryRow::byteBuffer));
 
                 return r.run(MSG_FACTORY.updateAllCommand()
                                 
.tablePartitionId(MSG_FACTORY.tablePartitionIdMessage()
@@ -213,9 +219,9 @@ public class ItColocationTest {
                                         
.partitionId(commitPartId.partitionId())
                                         .build()
                         )
-                        .rowUuid(Timestamp.nextVersion().toUuid())
+                        .rowUuid(UUID.randomUUID())
                         .rowBuffer(((ReadWriteSingleRowReplicaRequest) 
request).binaryRow().byteBuffer())
-                        .txId(UUID.randomUUID())
+                        .txId(TestTransactionIds.newTransactionId())
                         .build());
             }
         });
diff --git 
a/modules/table/src/test/java/org/apache/ignite/internal/table/TxLocalTest.java 
b/modules/table/src/test/java/org/apache/ignite/internal/table/TxLocalTest.java
index 42dc2d44a8..6c08f536cf 100644
--- 
a/modules/table/src/test/java/org/apache/ignite/internal/table/TxLocalTest.java
+++ 
b/modules/table/src/test/java/org/apache/ignite/internal/table/TxLocalTest.java
@@ -39,6 +39,7 @@ import org.apache.ignite.internal.tx.LockManager;
 import org.apache.ignite.internal.tx.TxManager;
 import org.apache.ignite.internal.tx.impl.HeapLockManager;
 import org.apache.ignite.internal.tx.impl.IgniteTransactionsImpl;
+import org.apache.ignite.internal.tx.impl.TransactionIdGenerator;
 import org.apache.ignite.internal.tx.impl.TxManagerImpl;
 import org.apache.ignite.internal.tx.message.TxStateReplicaRequest;
 import org.apache.ignite.network.ClusterNode;
@@ -88,7 +89,7 @@ public class TxLocalTest extends TxAbstractTest {
                     
tables.get(request.groupId()).txStateStorage().getTxStateStorage(0).get(request.txId()));
         }).when(placementDriver).sendMetaRequest(any(), any());
 
-        txManager = new TxManagerImpl(replicaSvc, lockManager, new 
HybridClockImpl());
+        txManager = new TxManagerImpl(replicaSvc, lockManager, new 
HybridClockImpl(), new TransactionIdGenerator(0xdeadbeef));
 
         igniteTransactions = new IgniteTransactionsImpl(txManager);
 
diff --git 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/command/PartitionRaftCommandsSerializationTest.java
 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/command/PartitionRaftCommandsSerializationTest.java
index 5eab41ea95..235bb2df65 100644
--- 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/command/PartitionRaftCommandsSerializationTest.java
+++ 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/command/PartitionRaftCommandsSerializationTest.java
@@ -45,7 +45,7 @@ import 
org.apache.ignite.internal.table.distributed.TableMessagesFactory;
 import org.apache.ignite.internal.testframework.IgniteAbstractTest;
 import org.apache.ignite.internal.tostring.IgniteToStringInclude;
 import org.apache.ignite.internal.tostring.S;
-import org.apache.ignite.internal.tx.Timestamp;
+import org.apache.ignite.internal.tx.test.TestTransactionIds;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 
@@ -85,9 +85,9 @@ public class PartitionRaftCommandsSerializationTest extends 
IgniteAbstractTest {
                         .partitionId(1)
                         .build()
                 )
-                .rowUuid(Timestamp.nextVersion().toUuid())
+                .rowUuid(UUID.randomUUID())
                 .rowBuffer(byteBufferFromBinaryRow(1))
-                .txId(UUID.randomUUID())
+                .txId(TestTransactionIds.newTransactionId())
                 .build();
 
         UpdateCommand readCmd = copyCommand(cmd);
@@ -105,8 +105,8 @@ public class PartitionRaftCommandsSerializationTest extends 
IgniteAbstractTest {
                         .partitionId(1)
                         .build()
                 )
-                .rowUuid(Timestamp.nextVersion().toUuid())
-                .txId(UUID.randomUUID())
+                .rowUuid(UUID.randomUUID())
+                .txId(TestTransactionIds.newTransactionId())
                 .build();
 
         UpdateCommand readCmd = copyCommand(cmd);
@@ -121,7 +121,7 @@ public class PartitionRaftCommandsSerializationTest extends 
IgniteAbstractTest {
         Map<UUID, ByteBuffer> rowsToUpdate = new HashMap<>();
 
         for (int i = 0; i < 10; i++) {
-            rowsToUpdate.put(Timestamp.nextVersion().toUuid(), 
byteBufferFromBinaryRow(i));
+            rowsToUpdate.put(TestTransactionIds.newTransactionId(), 
byteBufferFromBinaryRow(i));
         }
 
         var cmd = msgFactory.updateAllCommand()
@@ -153,7 +153,7 @@ public class PartitionRaftCommandsSerializationTest extends 
IgniteAbstractTest {
         Map<UUID, ByteBuffer> rowsToRemove = new HashMap<>();
 
         for (int i = 0; i < 10; i++) {
-            rowsToRemove.put(Timestamp.nextVersion().toUuid(), null);
+            rowsToRemove.put(TestTransactionIds.newTransactionId(), null);
         }
 
         var cmd = msgFactory.updateAllCommand()
diff --git 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/raft/PartitionCommandListenerTest.java
 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/raft/PartitionCommandListenerTest.java
index 216dee1119..c6fce10e63 100644
--- 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/raft/PartitionCommandListenerTest.java
+++ 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/raft/PartitionCommandListenerTest.java
@@ -92,11 +92,11 @@ import 
org.apache.ignite.internal.table.distributed.replicator.TablePartitionId;
 import org.apache.ignite.internal.table.impl.DummyInternalTableImpl;
 import org.apache.ignite.internal.testframework.WorkDirectory;
 import org.apache.ignite.internal.testframework.WorkDirectoryExtension;
-import org.apache.ignite.internal.tx.Timestamp;
 import org.apache.ignite.internal.tx.TxMeta;
 import org.apache.ignite.internal.tx.TxState;
 import org.apache.ignite.internal.tx.storage.state.TxStateStorage;
 import org.apache.ignite.internal.tx.storage.state.test.TestTxStateStorage;
+import org.apache.ignite.internal.tx.test.TestTransactionIds;
 import org.apache.ignite.internal.util.Cursor;
 import org.apache.ignite.internal.util.PendingComparableValuesTracker;
 import org.apache.ignite.network.ClusterService;
@@ -608,13 +608,13 @@ public class PartitionCommandListenerTest {
      */
     private void insertAll() {
         Map<UUID, ByteBuffer> rows = new HashMap<>(KEY_COUNT);
-        UUID txId = Timestamp.nextVersion().toUuid();
+        UUID txId = TestTransactionIds.newTransactionId();
         var commitPartId = new TablePartitionId(txId, PARTITION_ID);
 
         for (int i = 0; i < KEY_COUNT; i++) {
             Row row = getTestRow(i, i);
 
-            rows.put(Timestamp.nextVersion().toUuid(), row.byteBuffer());
+            rows.put(TestTransactionIds.newTransactionId(), row.byteBuffer());
         }
 
         HybridTimestamp commitTimestamp = hybridClock.now();
@@ -643,7 +643,7 @@ public class PartitionCommandListenerTest {
      * @param keyValueMapper Mep a value to update to the iter number.
      */
     private void updateAll(Function<Integer, Integer> keyValueMapper) {
-        UUID txId = Timestamp.nextVersion().toUuid();
+        UUID txId = TestTransactionIds.newTransactionId();
         var commitPartId = new TablePartitionId(txId, PARTITION_ID);
         Map<UUID, ByteBuffer> rows = new HashMap<>(KEY_COUNT);
 
@@ -677,7 +677,7 @@ public class PartitionCommandListenerTest {
      * Deletes all rows.
      */
     private void deleteAll() {
-        UUID txId = Timestamp.nextVersion().toUuid();
+        UUID txId = TestTransactionIds.newTransactionId();
         var commitPartId = new TablePartitionId(txId, PARTITION_ID);
         Map<UUID, ByteBuffer> keyRows = new HashMap<>(KEY_COUNT);
 
@@ -716,7 +716,7 @@ public class PartitionCommandListenerTest {
         List<UUID> txIds = new ArrayList<>();
 
         commandListener.onWrite(iterator((i, clo) -> {
-            UUID txId = Timestamp.nextVersion().toUuid();
+            UUID txId = TestTransactionIds.newTransactionId();
             Row row = getTestRow(i, keyValueMapper.apply(i));
             RowId rowId = readRow(row);
 
@@ -761,7 +761,7 @@ public class PartitionCommandListenerTest {
         List<UUID> txIds = new ArrayList<>();
 
         commandListener.onWrite(iterator((i, clo) -> {
-            UUID txId = Timestamp.nextVersion().toUuid();
+            UUID txId = TestTransactionIds.newTransactionId();
             Row row = getTestRow(i, i);
             RowId rowId = readRow(row);
 
@@ -839,7 +839,7 @@ public class PartitionCommandListenerTest {
         List<UUID> txIds = new ArrayList<>();
 
         commandListener.onWrite(iterator((i, clo) -> {
-            UUID txId = Timestamp.nextVersion().toUuid();
+            UUID txId = TestTransactionIds.newTransactionId();
             Row row = getTestRow(i, i);
             txIds.add(txId);
 
@@ -850,7 +850,7 @@ public class PartitionCommandListenerTest {
                             
.tablePartitionId(msgFactory.tablePartitionIdMessage()
                                     .tableId(txId)
                                     .partitionId(PARTITION_ID).build())
-                            .rowUuid(Timestamp.nextVersion().toUuid())
+                            .rowUuid(UUID.randomUUID())
                             .rowBuffer(row.byteBuffer())
                             .txId(txId)
                             .safeTime(hybridTimestamp(hybridClock.now()))
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 99f7a34063..9b53b6a251 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
@@ -75,10 +75,10 @@ import 
org.apache.ignite.internal.testframework.IgniteAbstractTest;
 import org.apache.ignite.internal.tx.Lock;
 import org.apache.ignite.internal.tx.LockManager;
 import org.apache.ignite.internal.tx.LockMode;
-import org.apache.ignite.internal.tx.Timestamp;
 import org.apache.ignite.internal.tx.TxManager;
 import org.apache.ignite.internal.tx.impl.HeapLockManager;
 import org.apache.ignite.internal.tx.storage.state.test.TestTxStateStorage;
+import org.apache.ignite.internal.tx.test.TestTransactionIds;
 import org.apache.ignite.internal.util.Lazy;
 import org.apache.ignite.internal.util.Pair;
 import org.apache.ignite.internal.util.PendingComparableValuesTracker;
@@ -99,7 +99,7 @@ public class PartitionReplicaListenerIndexLockingTest extends 
IgniteAbstractTest
     private static final UUID PK_INDEX_ID = new UUID(0L, 1L);
     private static final UUID HASH_INDEX_ID = new UUID(0L, 2L);
     private static final UUID SORTED_INDEX_ID = new UUID(0L, 3L);
-    private static final UUID TRANSACTION_ID = 
Timestamp.nextVersion().toUuid();
+    private static final UUID TRANSACTION_ID = 
TestTransactionIds.newTransactionId();
     private static final HybridClock CLOCK = new HybridClockImpl();
     private static final LockManager LOCK_MANAGER = new HeapLockManager();
     private static final TablePartitionId PARTITION_ID = new 
TablePartitionId(TABLE_ID, PART_ID);
@@ -216,7 +216,7 @@ public class PartitionReplicaListenerIndexLockingTest 
extends IgniteAbstractTest
 
         if (arg.type != RequestType.RW_INSERT) {
             var rowId = new RowId(PART_ID);
-            insertRows(List.of(new Pair<>(testBinaryRow, rowId)), 
Timestamp.nextVersion().toUuid());
+            insertRows(List.of(new Pair<>(testBinaryRow, rowId)), 
TestTransactionIds.newTransactionId());
         }
 
         CompletableFuture<?> fut = 
partitionReplicaListener.invoke(TABLE_MESSAGES_FACTORY.readWriteSingleRowReplicaRequest()
@@ -261,7 +261,7 @@ public class PartitionReplicaListenerIndexLockingTest 
extends IgniteAbstractTest
         if (arg.type != RequestType.RW_INSERT_ALL) {
             for (BinaryRow row : rows) {
                 var rowId = new RowId(PART_ID);
-                insertRows(List.of(new Pair<>(row, rowId)), 
Timestamp.nextVersion().toUuid());
+                insertRows(List.of(new Pair<>(row, rowId)), 
TestTransactionIds.newTransactionId());
             }
         }
 
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 ec6b5bc7f2..84cf06b4b8 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
@@ -109,13 +109,13 @@ import 
org.apache.ignite.internal.testframework.IgniteAbstractTest;
 import org.apache.ignite.internal.tostring.IgniteToStringInclude;
 import org.apache.ignite.internal.tostring.S;
 import org.apache.ignite.internal.tx.LockManager;
-import org.apache.ignite.internal.tx.Timestamp;
 import org.apache.ignite.internal.tx.TxManager;
 import org.apache.ignite.internal.tx.TxMeta;
 import org.apache.ignite.internal.tx.TxState;
 import org.apache.ignite.internal.tx.impl.HeapLockManager;
 import org.apache.ignite.internal.tx.message.TxMessagesFactory;
 import org.apache.ignite.internal.tx.storage.state.test.TestTxStateStorage;
+import org.apache.ignite.internal.tx.test.TestTransactionIds;
 import org.apache.ignite.internal.util.Cursor;
 import org.apache.ignite.internal.util.Lazy;
 import org.apache.ignite.internal.util.PendingComparableValuesTracker;
@@ -368,7 +368,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
         CompletableFuture<?> fut = 
partitionReplicaListener.invoke(TX_MESSAGES_FACTORY.txStateReplicaRequest()
                 .groupId(grpId)
                 .readTimestamp(clock.now())
-                .txId(Timestamp.nextVersion().toUuid())
+                .txId(TestTransactionIds.newTransactionId())
                 .build());
 
         LeaderOrTxState tuple = (LeaderOrTxState) fut.get(1, TimeUnit.SECONDS);
@@ -379,7 +379,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
 
     @Test
     public void testTxStateReplicaRequestCommitState() throws Exception {
-        UUID txId = Timestamp.nextVersion().toUuid();
+        UUID txId = TestTransactionIds.newTransactionId();
 
         txStateStorage.put(txId, new TxMeta(TxState.COMMITED, 
Collections.singletonList(grpId), clock.now()));
 
@@ -405,7 +405,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
         CompletableFuture<?> fut = 
partitionReplicaListener.invoke(TX_MESSAGES_FACTORY.txStateReplicaRequest()
                 .groupId(grpId)
                 .readTimestamp(clock.now())
-                .txId(Timestamp.nextVersion().toUuid())
+                .txId(TestTransactionIds.newTransactionId())
                 .build());
 
         LeaderOrTxState tuple = (LeaderOrTxState) fut.get(1, TimeUnit.SECONDS);
@@ -432,7 +432,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
 
     @Test
     public void testReadOnlySingleRowReplicaRequestCommittedResult() throws 
Exception {
-        UUID txId = Timestamp.nextVersion().toUuid();
+        UUID txId = TestTransactionIds.newTransactionId();
         BinaryRow testBinaryKey = nextBinaryKey();
         BinaryRow testBinaryRow = binaryRow(key(testBinaryKey), new 
TestValue(1, "v1"));
         var rowId = new RowId(partId);
@@ -455,7 +455,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
 
     @Test
     public void 
testReadOnlySingleRowReplicaRequestResolveWriteIntentCommitted() throws 
Exception {
-        UUID txId = Timestamp.nextVersion().toUuid();
+        UUID txId = TestTransactionIds.newTransactionId();
         BinaryRow testBinaryKey = nextBinaryKey();
         BinaryRow testBinaryRow = binaryRow(key(testBinaryKey), new 
TestValue(1, "v1"));
         var rowId = new RowId(partId);
@@ -478,7 +478,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
 
     @Test
     public void testReadOnlySingleRowReplicaRequestResolveWriteIntentPending() 
throws Exception {
-        UUID txId = Timestamp.nextVersion().toUuid();
+        UUID txId = TestTransactionIds.newTransactionId();
         BinaryRow testBinaryKey = nextBinaryKey();
         BinaryRow testBinaryRow = binaryRow(key(testBinaryKey), new 
TestValue(1, "v1"));
         var rowId = new RowId(partId);
@@ -500,7 +500,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
 
     @Test
     public void testReadOnlySingleRowReplicaRequestResolveWriteIntentAborted() 
throws Exception {
-        UUID txId = Timestamp.nextVersion().toUuid();
+        UUID txId = TestTransactionIds.newTransactionId();
         BinaryRow testBinaryKey = nextBinaryKey();
         BinaryRow testBinaryRow = binaryRow(key(testBinaryKey), new 
TestValue(1, "v1"));
         var rowId = new RowId(partId);
@@ -523,7 +523,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
 
     @Test
     public void testWriteScanRetriveBatchReplicaRequestWithSortedIndex() 
throws Exception {
-        UUID txId = Timestamp.nextVersion().toUuid();
+        UUID txId = TestTransactionIds.newTransactionId();
         UUID sortedIndexId = sortedIndexStorage.id();
 
         IntStream.range(0, 6).forEach(i -> {
@@ -540,7 +540,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
             testMvPartitionStorage.commitWrite(rowId, clock.now());
         });
 
-        UUID scanTxId = Timestamp.nextVersion().toUuid();
+        UUID scanTxId = TestTransactionIds.newTransactionId();
 
         // Request first batch
         CompletableFuture<?> fut = 
partitionReplicaListener.invoke(TABLE_MESSAGES_FACTORY.readWriteScanRetrieveBatchReplicaRequest()
@@ -577,7 +577,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
         // Request bounded.
         fut = 
partitionReplicaListener.invoke(TABLE_MESSAGES_FACTORY.readWriteScanRetrieveBatchReplicaRequest()
                 .groupId(grpId)
-                .transactionId(Timestamp.nextVersion().toUuid())
+                .transactionId(TestTransactionIds.newTransactionId())
                 .timestamp(clock.now())
                 .term(1L)
                 .scanId(2L)
@@ -596,7 +596,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
         // Empty result.
         fut = 
partitionReplicaListener.invoke(TABLE_MESSAGES_FACTORY.readWriteScanRetrieveBatchReplicaRequest()
                 .groupId(grpId)
-                .transactionId(Timestamp.nextVersion().toUuid())
+                .transactionId(TestTransactionIds.newTransactionId())
                 .timestamp(clock.now())
                 .term(1L)
                 .scanId(2L)
@@ -613,7 +613,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
         // Lookup.
         fut = 
partitionReplicaListener.invoke(TABLE_MESSAGES_FACTORY.readWriteScanRetrieveBatchReplicaRequest()
                 .groupId(grpId)
-                .transactionId(Timestamp.nextVersion().toUuid())
+                .transactionId(TestTransactionIds.newTransactionId())
                 .timestamp(clock.now())
                 .term(1L)
                 .scanId(2L)
@@ -630,7 +630,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
 
     @Test
     public void testReadOnlyScanRetriveBatchReplicaRequestSortedIndex() throws 
Exception {
-        UUID txId = Timestamp.nextVersion().toUuid();
+        UUID txId = TestTransactionIds.newTransactionId();
         UUID sortedIndexId = sortedIndexStorage.id();
 
         IntStream.range(0, 6).forEach(i -> {
@@ -647,7 +647,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
             testMvPartitionStorage.commitWrite(rowId, clock.now());
         });
 
-        UUID scanTxId = Timestamp.nextVersion().toUuid();
+        UUID scanTxId = TestTransactionIds.newTransactionId();
 
         // Request first batch
         CompletableFuture<?> fut = 
partitionReplicaListener.invoke(TABLE_MESSAGES_FACTORY.readOnlyScanRetrieveBatchReplicaRequest()
@@ -682,7 +682,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
         // Request bounded.
         fut = 
partitionReplicaListener.invoke(TABLE_MESSAGES_FACTORY.readOnlyScanRetrieveBatchReplicaRequest()
                 .groupId(grpId)
-                .transactionId(Timestamp.nextVersion().toUuid())
+                .transactionId(TestTransactionIds.newTransactionId())
                 .readTimestamp(clock.now())
                 .scanId(2L)
                 .indexToUse(sortedIndexId)
@@ -700,7 +700,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
         // Empty result.
         fut = 
partitionReplicaListener.invoke(TABLE_MESSAGES_FACTORY.readOnlyScanRetrieveBatchReplicaRequest()
                 .groupId(grpId)
-                .transactionId(Timestamp.nextVersion().toUuid())
+                .transactionId(TestTransactionIds.newTransactionId())
                 .readTimestamp(clock.now())
                 .scanId(2L)
                 .indexToUse(sortedIndexId)
@@ -716,7 +716,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
         // Lookup.
         fut = 
partitionReplicaListener.invoke(TABLE_MESSAGES_FACTORY.readOnlyScanRetrieveBatchReplicaRequest()
                 .groupId(grpId)
-                .transactionId(Timestamp.nextVersion().toUuid())
+                .transactionId(TestTransactionIds.newTransactionId())
                 .readTimestamp(clock.now())
                 .scanId(2L)
                 .indexToUse(sortedIndexId)
@@ -732,7 +732,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
 
     @Test
     public void testReadOnlyScanRetriveBatchReplicaRequstHashIndex() throws 
Exception {
-        UUID txId = Timestamp.nextVersion().toUuid();
+        UUID txId = TestTransactionIds.newTransactionId();
         UUID hashIndexId = hashIndexStorage.id();
 
         IntStream.range(0, 7).forEach(i -> {
@@ -749,7 +749,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
             testMvPartitionStorage.commitWrite(rowId, clock.now());
         });
 
-        UUID scanTxId = Timestamp.nextVersion().toUuid();
+        UUID scanTxId = TestTransactionIds.newTransactionId();
 
         // Request first batch
         CompletableFuture<?> fut = 
partitionReplicaListener.invoke(TABLE_MESSAGES_FACTORY.readOnlyScanRetrieveBatchReplicaRequest()
@@ -786,7 +786,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
         // Empty result.
         fut = 
partitionReplicaListener.invoke(TABLE_MESSAGES_FACTORY.readOnlyScanRetrieveBatchReplicaRequest()
                 .groupId(grpId)
-                .transactionId(Timestamp.nextVersion().toUuid())
+                .transactionId(TestTransactionIds.newTransactionId())
                 .readTimestamp(clock.now())
                 .scanId(2L)
                 .indexToUse(hashIndexId)
@@ -802,7 +802,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
         // Lookup.
         fut = 
partitionReplicaListener.invoke(TABLE_MESSAGES_FACTORY.readOnlyScanRetrieveBatchReplicaRequest()
                 .groupId(grpId)
-                .transactionId(Timestamp.nextVersion().toUuid())
+                .transactionId(TestTransactionIds.newTransactionId())
                 .readTimestamp(clock.now())
                 .scanId(2L)
                 .indexToUse(hashIndexId)
@@ -818,7 +818,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
 
     @Test
     public void testWriteIntentOnPrimaryReplicaInsertUpdateDelete() {
-        UUID txId = Timestamp.nextVersion().toUuid();
+        UUID txId = TestTransactionIds.newTransactionId();
 
         doSingleRowRequest(txId, binaryRow(0), RequestType.RW_INSERT);
         checkRowInMvStorage(binaryRow(0), true);
@@ -854,7 +854,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
 
     @Test
     public void testWriteIntentOnPrimaryReplicaMultiRowOps() {
-        UUID txId = Timestamp.nextVersion().toUuid();
+        UUID txId = TestTransactionIds.newTransactionId();
         BinaryRow row0 = binaryRow(0);
         BinaryRow row1 = binaryRow(1);
         Collection<BinaryRow> rows = asList(row0, row1);
@@ -912,7 +912,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
 
     @Test
     public void testWriteIntentOnPrimaryReplicaSingleUpdate() {
-        UUID txId = Timestamp.nextVersion().toUuid();
+        UUID txId = TestTransactionIds.newTransactionId();
         AtomicInteger counter = new AtomicInteger();
 
         testWriteIntentOnPrimaryReplica(
@@ -936,7 +936,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
 
     @Test
     public void testWriteIntentOnPrimaryReplicaUpdateAll() {
-        UUID txId = Timestamp.nextVersion().toUuid();
+        UUID txId = TestTransactionIds.newTransactionId();
         AtomicInteger counter = new AtomicInteger();
 
         testWriteIntentOnPrimaryReplica(
@@ -1155,7 +1155,7 @@ public class PartitionReplicaListenerTest extends 
IgniteAbstractTest {
     }
 
     private UUID beginTx() {
-        return Timestamp.nextVersion().toUuid();
+        return TestTransactionIds.newTransactionId();
     }
 
     private void upsert(UUID txId, BinaryRow row) {
diff --git 
a/modules/table/src/testFixtures/java/org/apache/ignite/internal/table/impl/DummyInternalTableImpl.java
 
b/modules/table/src/testFixtures/java/org/apache/ignite/internal/table/impl/DummyInternalTableImpl.java
index 6c482ade7b..b05940b7a4 100644
--- 
a/modules/table/src/testFixtures/java/org/apache/ignite/internal/table/impl/DummyInternalTableImpl.java
+++ 
b/modules/table/src/testFixtures/java/org/apache/ignite/internal/table/impl/DummyInternalTableImpl.java
@@ -73,6 +73,7 @@ import 
org.apache.ignite.internal.table.distributed.storage.InternalTableImpl;
 import org.apache.ignite.internal.tx.InternalTransaction;
 import org.apache.ignite.internal.tx.TxManager;
 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.tx.storage.state.test.TestTxStateTableStorage;
 import org.apache.ignite.internal.util.Lazy;
@@ -182,7 +183,9 @@ public class DummyInternalTableImpl extends 
InternalTableImpl {
                 Int2ObjectMaps.singleton(PART_ID, 
mock(RaftGroupService.class)),
                 1,
                 name -> mock(ClusterNode.class),
-                txManager == null ? new TxManagerImpl(replicaSvc, new 
HeapLockManager(), CLOCK) : txManager,
+                txManager == null
+                        ? new TxManagerImpl(replicaSvc, new HeapLockManager(), 
CLOCK, new TransactionIdGenerator(0xdeadbeef))
+                        : txManager,
                 mock(MvTableStorage.class),
                 new TestTxStateTableStorage(),
                 replicaSvc,
diff --git 
a/modules/transactions/src/main/java/org/apache/ignite/internal/tx/TransactionIds.java
 
b/modules/transactions/src/main/java/org/apache/ignite/internal/tx/TransactionIds.java
new file mode 100644
index 0000000000..15288062d0
--- /dev/null
+++ 
b/modules/transactions/src/main/java/org/apache/ignite/internal/tx/TransactionIds.java
@@ -0,0 +1,47 @@
+/*
+ * 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.tx;
+
+import java.util.UUID;
+import org.apache.ignite.internal.hlc.HybridTimestamp;
+
+/**
+ * Collection of utils to generate and pick apart transaction IDs.
+ */
+public class TransactionIds {
+    /**
+     * Creates a transaction ID from the given begin timestamp and nodeId.
+     *
+     * @param beginTimestamp Transaction begin timestamp.
+     * @param nodeId Unique ID of the current node used to make generated 
transaction IDs globally unique.
+     * @return Transaction ID corresponding to the provided values.
+     */
+    public static UUID transactionId(HybridTimestamp beginTimestamp, int 
nodeId) {
+        return new UUID(beginTimestamp.getPhysical(), (((long) 
beginTimestamp.getLogical()) << Integer.SIZE) | (nodeId & 0xFFFFFFFFL));
+    }
+
+    /**
+     * Extracts begin timestamp from the provided transaction ID.
+     *
+     * @param transactionId Transaction ID.
+     * @return Begin timestamp of the transaction.
+     */
+    public static HybridTimestamp beginTimestamp(UUID transactionId) {
+        return new HybridTimestamp(transactionId.getMostSignificantBits(), 
(int) (transactionId.getLeastSignificantBits() >> Integer.SIZE));
+    }
+}
diff --git 
a/modules/transactions/src/main/java/org/apache/ignite/internal/tx/impl/NodeIdSupplier.java
 
b/modules/transactions/src/main/java/org/apache/ignite/internal/tx/impl/NodeIdSupplier.java
new file mode 100644
index 0000000000..3664221577
--- /dev/null
+++ 
b/modules/transactions/src/main/java/org/apache/ignite/internal/tx/impl/NodeIdSupplier.java
@@ -0,0 +1,32 @@
+/*
+ * 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.tx.impl;
+
+/**
+ * Knows how to obtain a 32-bit nodeId needed for transactionId generation. 
Must return the same value for all invocations
+ * run in the same Ignite instance.
+ */
+@FunctionalInterface
+public interface NodeIdSupplier {
+    /**
+     * Returns the node ID.
+     *
+     * @return Node ID.
+     */
+    int nodeId();
+}
diff --git 
a/modules/transactions/src/main/java/org/apache/ignite/internal/tx/impl/TransactionIdGenerator.java
 
b/modules/transactions/src/main/java/org/apache/ignite/internal/tx/impl/TransactionIdGenerator.java
new file mode 100644
index 0000000000..23e8d4332e
--- /dev/null
+++ 
b/modules/transactions/src/main/java/org/apache/ignite/internal/tx/impl/TransactionIdGenerator.java
@@ -0,0 +1,48 @@
+/*
+ * 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.tx.impl;
+
+import java.util.UUID;
+import org.apache.ignite.internal.hlc.HybridTimestamp;
+import org.apache.ignite.internal.tx.TransactionIds;
+
+/**
+ * Generates transaction IDs.
+ */
+public class TransactionIdGenerator {
+    /** Supplies nodeId for transactionId generation. */
+    private final NodeIdSupplier nodeIdSupplier;
+
+    public TransactionIdGenerator(NodeIdSupplier nodeIdSupplier) {
+        this.nodeIdSupplier = nodeIdSupplier;
+    }
+
+    public TransactionIdGenerator(int nodeId) {
+        this(() -> nodeId);
+    }
+
+    /**
+     * Creates a transaction ID with the given begin timestamp.
+     *
+     * @param beginTimestamp Transaction begin timestamp.
+     * @return Transaction ID.
+     */
+    public UUID transactionIdFor(HybridTimestamp beginTimestamp) {
+        return TransactionIds.transactionId(beginTimestamp, 
nodeIdSupplier.nodeId());
+    }
+}
diff --git 
a/modules/transactions/src/main/java/org/apache/ignite/internal/tx/impl/TxManagerImpl.java
 
b/modules/transactions/src/main/java/org/apache/ignite/internal/tx/impl/TxManagerImpl.java
index 2152e25c20..6c2846d5c6 100644
--- 
a/modules/transactions/src/main/java/org/apache/ignite/internal/tx/impl/TxManagerImpl.java
+++ 
b/modules/transactions/src/main/java/org/apache/ignite/internal/tx/impl/TxManagerImpl.java
@@ -37,7 +37,6 @@ import org.apache.ignite.internal.replicator.ReplicaService;
 import org.apache.ignite.internal.replicator.ReplicationGroupId;
 import org.apache.ignite.internal.tx.InternalTransaction;
 import org.apache.ignite.internal.tx.LockManager;
-import org.apache.ignite.internal.tx.Timestamp;
 import org.apache.ignite.internal.tx.TxManager;
 import org.apache.ignite.internal.tx.TxState;
 import org.apache.ignite.internal.tx.message.TxFinishReplicaRequest;
@@ -64,6 +63,9 @@ public class TxManagerImpl implements TxManager {
     /** A hybrid logical clock. */
     private final HybridClock clock;
 
+    /** Generates transaction IDs. */
+    private final TransactionIdGenerator transactionIdGenerator;
+
     // TODO: IGNITE-17638 Consider using Txn state map instead of states.
     /** The storage for tx states. */
     @TestOnly
@@ -89,11 +91,18 @@ public class TxManagerImpl implements TxManager {
      * @param replicaService Replica service.
      * @param lockManager Lock manager.
      * @param clock A hybrid logical clock.
+     * @param transactionIdGenerator Used to generate transaction IDs.
      */
-    public TxManagerImpl(ReplicaService replicaService, LockManager 
lockManager, HybridClock clock) {
+    public TxManagerImpl(
+            ReplicaService replicaService,
+            LockManager lockManager,
+            HybridClock clock,
+            TransactionIdGenerator transactionIdGenerator
+    ) {
         this.replicaService = replicaService;
         this.lockManager = lockManager;
         this.clock = clock;
+        this.transactionIdGenerator = transactionIdGenerator;
     }
 
     @Override
@@ -103,13 +112,14 @@ public class TxManagerImpl implements TxManager {
 
     @Override
     public InternalTransaction begin(boolean readOnly) {
-        UUID txId = Timestamp.nextVersion().toUuid();
+        HybridTimestamp beginTimestamp = clock.now();
+        UUID txId = transactionIdGenerator.transactionIdFor(beginTimestamp);
 
         if (!readOnly) {
             return new ReadWriteTransactionImpl(this, txId);
         }
 
-        HybridTimestamp readTimestamp = clock.now();
+        HybridTimestamp readTimestamp = beginTimestamp;
 
         lowWatermarkReadWriteLock.readLock().lock();
 
diff --git 
a/modules/transactions/src/test/java/org/apache/ignite/internal/tx/AbstractLockManagerTest.java
 
b/modules/transactions/src/test/java/org/apache/ignite/internal/tx/AbstractLockManagerTest.java
index 7151370ecc..94a9d3d456 100644
--- 
a/modules/transactions/src/test/java/org/apache/ignite/internal/tx/AbstractLockManagerTest.java
+++ 
b/modules/transactions/src/test/java/org/apache/ignite/internal/tx/AbstractLockManagerTest.java
@@ -44,6 +44,7 @@ import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.atomic.LongAdder;
 import org.apache.ignite.internal.testframework.IgniteAbstractTest;
 import org.apache.ignite.internal.testframework.IgniteTestUtils;
+import org.apache.ignite.internal.tx.test.TestTransactionIds;
 import org.apache.ignite.lang.IgniteBiTuple;
 import org.apache.ignite.lang.IgniteException;
 import org.junit.jupiter.api.BeforeEach;
@@ -64,7 +65,7 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
 
     @Test
     public void testSingleKeyWrite() {
-        UUID txId1 = Timestamp.nextVersion().toUuid();
+        UUID txId1 = TestTransactionIds.newTransactionId();
 
         LockKey key = new LockKey("test");
 
@@ -84,9 +85,9 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     }
 
     @Test
-    public void testSingleKeyWriteLock() throws LockException {
-        UUID txId1 = Timestamp.nextVersion().toUuid();
-        UUID txId2 = Timestamp.nextVersion().toUuid();
+    public void testSingleKeyWriteLock() {
+        UUID txId1 = TestTransactionIds.newTransactionId();
+        UUID txId2 = TestTransactionIds.newTransactionId();
 
         LockKey key = new LockKey("test");
 
@@ -117,10 +118,10 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     }
 
     @Test
-    public void downgradeLockOutOfTurnTest() throws Exception {
-        UUID txId0 = Timestamp.nextVersion().toUuid();
-        UUID txId1 = Timestamp.nextVersion().toUuid();
-        UUID txId2 = Timestamp.nextVersion().toUuid();
+    public void downgradeLockOutOfTurnTest() {
+        UUID txId0 = TestTransactionIds.newTransactionId();
+        UUID txId1 = TestTransactionIds.newTransactionId();
+        UUID txId2 = TestTransactionIds.newTransactionId();
 
         LockKey key = new LockKey("test");
 
@@ -143,10 +144,10 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     }
 
     @Test
-    public void upgradeLockImmediatelyTest() throws LockException {
-        UUID txId0 = Timestamp.nextVersion().toUuid();
-        UUID txId1 = Timestamp.nextVersion().toUuid();
-        UUID txId2 = Timestamp.nextVersion().toUuid();
+    public void upgradeLockImmediatelyTest() {
+        UUID txId0 = TestTransactionIds.newTransactionId();
+        UUID txId1 = TestTransactionIds.newTransactionId();
+        UUID txId2 = TestTransactionIds.newTransactionId();
 
         LockKey key = new LockKey("test");
 
@@ -166,11 +167,11 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     }
 
     @Test
-    public void testSingleKeyReadWriteLock() throws LockException {
-        UUID txId0 = Timestamp.nextVersion().toUuid();
-        UUID txId1 = Timestamp.nextVersion().toUuid();
-        UUID txId2 = Timestamp.nextVersion().toUuid();
-        UUID txId3 = Timestamp.nextVersion().toUuid();
+    public void testSingleKeyReadWriteLock() {
+        UUID txId0 = TestTransactionIds.newTransactionId();
+        UUID txId1 = TestTransactionIds.newTransactionId();
+        UUID txId2 = TestTransactionIds.newTransactionId();
+        UUID txId3 = TestTransactionIds.newTransactionId();
         assertTrue(txId3.compareTo(txId2) > 0);
         assertTrue(txId2.compareTo(txId1) > 0);
         assertTrue(txId1.compareTo(txId0) > 0);
@@ -216,9 +217,9 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     }
 
     @Test
-    public void testSingleKeyReadWriteConflict() throws LockException {
-        UUID txId0 = Timestamp.nextVersion().toUuid();
-        UUID txId1 = Timestamp.nextVersion().toUuid();
+    public void testSingleKeyReadWriteConflict() {
+        UUID txId0 = TestTransactionIds.newTransactionId();
+        UUID txId1 = TestTransactionIds.newTransactionId();
         LockKey key = new LockKey("test");
 
         // Lock in order
@@ -249,7 +250,7 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     }
 
     @Test
-    public void testSingleKeyReadWriteConflict2() throws LockException {
+    public void testSingleKeyReadWriteConflict2() {
         UUID[] txId = generate(3);
         LockKey key = new LockKey("test");
 
@@ -270,10 +271,10 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     }
 
     @Test
-    public void testSingleKeyReadWriteConflict3() throws LockException {
-        UUID txId0 = Timestamp.nextVersion().toUuid();
-        UUID txId1 = Timestamp.nextVersion().toUuid();
-        UUID txId2 = Timestamp.nextVersion().toUuid();
+    public void testSingleKeyReadWriteConflict3() {
+        UUID txId0 = TestTransactionIds.newTransactionId();
+        UUID txId1 = TestTransactionIds.newTransactionId();
+        UUID txId2 = TestTransactionIds.newTransactionId();
         LockKey key = new LockKey("test");
 
         // Lock in order
@@ -295,11 +296,11 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     }
 
     @Test
-    public void testSingleKeyReadWriteConflict4() throws LockException {
-        UUID txId1 = Timestamp.nextVersion().toUuid();
-        final UUID txId2 = Timestamp.nextVersion().toUuid();
-        UUID txId3 = Timestamp.nextVersion().toUuid();
-        UUID txId4 = Timestamp.nextVersion().toUuid();
+    public void testSingleKeyReadWriteConflict4() {
+        UUID txId1 = TestTransactionIds.newTransactionId();
+        final UUID txId2 = TestTransactionIds.newTransactionId();
+        UUID txId3 = TestTransactionIds.newTransactionId();
+        UUID txId4 = TestTransactionIds.newTransactionId();
         LockKey key = new LockKey("test");
 
         CompletableFuture<Lock> fut4 = lockManager.acquire(txId4, key, S);
@@ -316,9 +317,9 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     }
 
     @Test
-    public void testSingleKeyReadWriteConflict5() throws LockException {
-        UUID txId0 = Timestamp.nextVersion().toUuid();
-        UUID txId1 = Timestamp.nextVersion().toUuid();
+    public void testSingleKeyReadWriteConflict5() {
+        UUID txId0 = TestTransactionIds.newTransactionId();
+        UUID txId1 = TestTransactionIds.newTransactionId();
         LockKey key = new LockKey("test");
 
         lockManager.acquire(txId0, key, X).join();
@@ -327,9 +328,9 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     }
 
     @Test
-    public void testConflicts() throws Exception {
-        UUID txId0 = Timestamp.nextVersion().toUuid();
-        UUID txId1 = Timestamp.nextVersion().toUuid();
+    public void testConflicts() {
+        UUID txId0 = TestTransactionIds.newTransactionId();
+        UUID txId1 = TestTransactionIds.newTransactionId();
 
         LockKey key = new LockKey("test");
 
@@ -370,10 +371,10 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     }
 
     @Test
-    public void testSingleKeyWriteWriteConflict() throws LockException {
-        UUID txId0 = Timestamp.nextVersion().toUuid();
-        UUID txId1 = Timestamp.nextVersion().toUuid();
-        UUID txId2 = Timestamp.nextVersion().toUuid();
+    public void testSingleKeyWriteWriteConflict() {
+        UUID txId0 = TestTransactionIds.newTransactionId();
+        UUID txId1 = TestTransactionIds.newTransactionId();
+        UUID txId2 = TestTransactionIds.newTransactionId();
         LockKey key = new LockKey("test");
 
         // Lock in order
@@ -393,10 +394,10 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     }
 
     @Test
-    public void testSingleKeyWriteWriteConflict2() throws LockException {
-        UUID txId0 = Timestamp.nextVersion().toUuid();
-        UUID txId1 = Timestamp.nextVersion().toUuid();
-        UUID txId2 = Timestamp.nextVersion().toUuid();
+    public void testSingleKeyWriteWriteConflict2() {
+        UUID txId0 = TestTransactionIds.newTransactionId();
+        UUID txId1 = TestTransactionIds.newTransactionId();
+        UUID txId2 = TestTransactionIds.newTransactionId();
         LockKey key = new LockKey("test");
 
         // Lock in order
@@ -443,9 +444,9 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     }
 
     @Test
-    public void testLockUpgrade() throws LockException {
-        UUID txId0 = Timestamp.nextVersion().toUuid();
-        UUID txId1 = Timestamp.nextVersion().toUuid();
+    public void testLockUpgrade() {
+        UUID txId0 = TestTransactionIds.newTransactionId();
+        UUID txId1 = TestTransactionIds.newTransactionId();
         LockKey key = new LockKey("test");
 
         lockManager.acquire(txId0, key, S).join();
@@ -465,9 +466,9 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     }
 
     @Test
-    public void testLockUpgrade2() throws LockException {
-        UUID txId0 = Timestamp.nextVersion().toUuid();
-        UUID txId1 = Timestamp.nextVersion().toUuid();
+    public void testLockUpgrade2() {
+        UUID txId0 = TestTransactionIds.newTransactionId();
+        UUID txId1 = TestTransactionIds.newTransactionId();
         LockKey key = new LockKey("test");
 
         lockManager.acquire(txId0, key, S).join();
@@ -478,10 +479,10 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     }
 
     @Test
-    public void testLockUpgrade3() throws LockException {
-        UUID txId0 = Timestamp.nextVersion().toUuid();
-        UUID txId1 = Timestamp.nextVersion().toUuid();
-        UUID txId2 = Timestamp.nextVersion().toUuid();
+    public void testLockUpgrade3() {
+        UUID txId0 = TestTransactionIds.newTransactionId();
+        UUID txId1 = TestTransactionIds.newTransactionId();
+        UUID txId2 = TestTransactionIds.newTransactionId();
         LockKey key = new LockKey("test");
 
         lockManager.acquire(txId1, key, S).join();
@@ -500,9 +501,9 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     }
 
     @Test
-    public void testLockUpgrade4() throws LockException {
-        UUID txId0 = Timestamp.nextVersion().toUuid();
-        UUID txId1 = Timestamp.nextVersion().toUuid();
+    public void testLockUpgrade4() {
+        UUID txId0 = TestTransactionIds.newTransactionId();
+        UUID txId1 = TestTransactionIds.newTransactionId();
         LockKey key = new LockKey("test");
 
         lockManager.acquire(txId0, key, S).join();
@@ -522,7 +523,7 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
 
     @Test
     public void testLockUpgrade5() {
-        UUID txId0 = Timestamp.nextVersion().toUuid();
+        UUID txId0 = TestTransactionIds.newTransactionId();
 
         LockKey key = new LockKey("test");
 
@@ -558,8 +559,8 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     }
 
     @Test
-    public void testReenter() throws LockException {
-        UUID txId = Timestamp.nextVersion().toUuid();
+    public void testReenter() {
+        UUID txId = TestTransactionIds.newTransactionId();
         LockKey key = new LockKey("test");
 
         CompletableFuture<Lock> fut = lockManager.acquire(txId, key, X);
@@ -589,8 +590,8 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
 
     @Test
     public void testAcquireReleasedLock() {
-        UUID txId0 = Timestamp.nextVersion().toUuid();
-        UUID txId1 = Timestamp.nextVersion().toUuid();
+        UUID txId0 = TestTransactionIds.newTransactionId();
+        UUID txId1 = TestTransactionIds.newTransactionId();
 
         LockKey key = new LockKey("test");
 
@@ -634,8 +635,8 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
 
     @Test
     public void testCompatibleLockModes() {
-        UUID txId0 = Timestamp.nextVersion().toUuid();
-        UUID txId1 = Timestamp.nextVersion().toUuid();
+        UUID txId0 = TestTransactionIds.newTransactionId();
+        UUID txId1 = TestTransactionIds.newTransactionId();
 
         LockKey key = new LockKey("test");
 
@@ -670,7 +671,7 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
 
     @Test
     public void testPossibleDowngradeLockModes() {
-        UUID txId0 = Timestamp.nextVersion().toUuid();
+        UUID txId0 = TestTransactionIds.newTransactionId();
 
         LockKey key = new LockKey("test");
 
@@ -701,7 +702,7 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
 
     @Test
     public void testAcquireRelease() {
-        UUID txId = Timestamp.nextVersion().toUuid();
+        UUID txId = TestTransactionIds.newTransactionId();
         LockKey key = new LockKey("test");
 
         for (LockMode lockMode : LockMode.values()) {
@@ -716,7 +717,7 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
 
     @Test
     public void testAcquireReleaseWhenHoldOther() {
-        UUID txId = Timestamp.nextVersion().toUuid();
+        UUID txId = TestTransactionIds.newTransactionId();
         LockKey key = new LockKey("test");
 
         for (LockMode holdLockMode : LockMode.values()) {
@@ -745,8 +746,8 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     public void testReleaseThenReleaseWeakerInHierarchy() {
         LockKey key = new LockKey("test");
 
-        UUID txId1 = Timestamp.nextVersion().toUuid();
-        UUID txId2 = Timestamp.nextVersion().toUuid();
+        UUID txId1 = TestTransactionIds.newTransactionId();
+        UUID txId2 = TestTransactionIds.newTransactionId();
 
         var tx1SharedLock = lockManager.acquire(txId2, key, S);
 
@@ -775,8 +776,8 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     public void testReleaseThenNoReleaseWeakerInHierarchy() {
         LockKey key = new LockKey("test");
 
-        UUID txId1 = Timestamp.nextVersion().toUuid();
-        UUID txId2 = Timestamp.nextVersion().toUuid();
+        UUID txId1 = TestTransactionIds.newTransactionId();
+        UUID txId2 = TestTransactionIds.newTransactionId();
 
         var tx1SharedLock = lockManager.acquire(txId2, key, S);
 
@@ -805,8 +806,8 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     public void testLockingOverloadAndUpgrade() {
         LockKey key = new LockKey("test");
 
-        UUID tx1 = Timestamp.nextVersion().toUuid();
-        UUID tx2 = Timestamp.nextVersion().toUuid();
+        UUID tx1 = TestTransactionIds.newTransactionId();
+        UUID tx2 = TestTransactionIds.newTransactionId();
 
         var tx1Lock = lockManager.acquire(tx2, key, X);
 
@@ -830,8 +831,8 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     public void testLockingOverload() {
         LockKey key = new LockKey("test");
 
-        UUID tx1 = Timestamp.nextVersion().toUuid();
-        UUID tx2 = Timestamp.nextVersion().toUuid();
+        UUID tx1 = TestTransactionIds.newTransactionId();
+        UUID tx2 = TestTransactionIds.newTransactionId();
 
         var tx1Lock = lockManager.acquire(tx2, key, X);
 
@@ -858,9 +859,9 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     public void testFailUpgrade() {
         LockKey key = new LockKey("test");
 
-        UUID tx1 = Timestamp.nextVersion().toUuid();
-        UUID tx2 = Timestamp.nextVersion().toUuid();
-        UUID tx3 = Timestamp.nextVersion().toUuid();
+        UUID tx1 = TestTransactionIds.newTransactionId();
+        UUID tx2 = TestTransactionIds.newTransactionId();
+        UUID tx3 = TestTransactionIds.newTransactionId();
 
         var tx1Lock = lockManager.acquire(tx1, key, S);
         var tx2Lock = lockManager.acquire(tx2, key, S);
@@ -892,8 +893,8 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     public void testDowngradeTargetLock() {
         LockKey key = new LockKey("test");
 
-        UUID tx1 = Timestamp.nextVersion().toUuid();
-        UUID tx2 = Timestamp.nextVersion().toUuid();
+        UUID tx1 = TestTransactionIds.newTransactionId();
+        UUID tx2 = TestTransactionIds.newTransactionId();
 
         var tx1Lock = lockManager.acquire(tx1, key, S);
         var tx2Lock = lockManager.acquire(tx2, key, S);
@@ -921,9 +922,9 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     public void testFailWait() {
         LockKey key = new LockKey("test");
 
-        UUID tx1 = Timestamp.nextVersion().toUuid();
-        UUID tx2 = Timestamp.nextVersion().toUuid();
-        UUID tx3 = Timestamp.nextVersion().toUuid();
+        UUID tx1 = TestTransactionIds.newTransactionId();
+        UUID tx2 = TestTransactionIds.newTransactionId();
+        UUID tx3 = TestTransactionIds.newTransactionId();
 
         var tx3Lock = lockManager.acquire(tx3, key, S);
 
@@ -948,9 +949,9 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     public void testWaitInOrder() {
         LockKey key = new LockKey("test");
 
-        UUID tx1 = Timestamp.nextVersion().toUuid();
-        UUID tx2 = Timestamp.nextVersion().toUuid();
-        UUID tx3 = Timestamp.nextVersion().toUuid();
+        UUID tx1 = TestTransactionIds.newTransactionId();
+        UUID tx2 = TestTransactionIds.newTransactionId();
+        UUID tx3 = TestTransactionIds.newTransactionId();
 
         var tx3IxLock = lockManager.acquire(tx3, key, IX);
         var tx3Lock = lockManager.acquire(tx3, key, S);
@@ -980,9 +981,9 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     public void testWaitNotInOrder() {
         LockKey key = new LockKey("test");
 
-        UUID tx1 = Timestamp.nextVersion().toUuid();
-        UUID tx2 = Timestamp.nextVersion().toUuid();
-        UUID tx3 = Timestamp.nextVersion().toUuid();
+        UUID tx1 = TestTransactionIds.newTransactionId();
+        UUID tx2 = TestTransactionIds.newTransactionId();
+        UUID tx3 = TestTransactionIds.newTransactionId();
 
         var tx3IxLock = lockManager.acquire(tx3, key, IX);
         var tx3Lock = lockManager.acquire(tx3, key, S);
@@ -1012,9 +1013,9 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
     public void testWaitFailNotInOrder() {
         LockKey key = new LockKey("test");
 
-        UUID tx1 = Timestamp.nextVersion().toUuid();
-        UUID tx2 = Timestamp.nextVersion().toUuid();
-        UUID tx3 = Timestamp.nextVersion().toUuid();
+        UUID tx1 = TestTransactionIds.newTransactionId();
+        UUID tx2 = TestTransactionIds.newTransactionId();
+        UUID tx3 = TestTransactionIds.newTransactionId();
 
         var tx3IxLock = lockManager.acquire(tx3, key, IX);
         var tx3Lock = lockManager.acquire(tx3, key, S);
@@ -1079,7 +1080,7 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
                     }
 
                     while (!stop.get() && firstErr.get() == null) {
-                        UUID txId = Timestamp.nextVersion().toUuid();
+                        UUID txId = TestTransactionIds.newTransactionId();
 
                         if (mode == 0 ? false : mode == 1 ? true : 
r.nextBoolean()) {
                             Lock lock;
@@ -1149,7 +1150,7 @@ public abstract class AbstractLockManagerTest extends 
IgniteAbstractTest {
         UUID[] tmp = new UUID[num];
 
         for (int i = 0; i < tmp.length; i++) {
-            tmp[i] = Timestamp.nextVersion().toUuid();
+            tmp[i] = TestTransactionIds.newTransactionId();
         }
 
         for (int i = 1; i < tmp.length; i++) {
diff --git 
a/modules/transactions/src/test/java/org/apache/ignite/internal/tx/AbstractLockingTest.java
 
b/modules/transactions/src/test/java/org/apache/ignite/internal/tx/AbstractLockingTest.java
index fde11382ce..3220c25797 100644
--- 
a/modules/transactions/src/test/java/org/apache/ignite/internal/tx/AbstractLockingTest.java
+++ 
b/modules/transactions/src/test/java/org/apache/ignite/internal/tx/AbstractLockingTest.java
@@ -28,6 +28,7 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
+import org.apache.ignite.internal.tx.test.TestTransactionIds;
 import org.apache.ignite.lang.IgniteBiTuple;
 
 /**
@@ -40,7 +41,7 @@ public abstract class AbstractLockingTest {
     protected abstract LockManager lockManager();
 
     protected UUID beginTx() {
-        return Timestamp.nextVersion().toUuid();
+        return TestTransactionIds.newTransactionId();
     }
 
     protected LockKey key(Object key) {
diff --git 
a/modules/transactions/src/test/java/org/apache/ignite/internal/tx/TransactionIdsTest.java
 
b/modules/transactions/src/test/java/org/apache/ignite/internal/tx/TransactionIdsTest.java
new file mode 100644
index 0000000000..6e731ad88e
--- /dev/null
+++ 
b/modules/transactions/src/test/java/org/apache/ignite/internal/tx/TransactionIdsTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.tx;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+import java.util.UUID;
+import org.apache.ignite.internal.hlc.HybridTimestamp;
+import org.junit.jupiter.api.Test;
+
+class TransactionIdsTest {
+    @Test
+    void transactionIdIsBuiltCorrectly() {
+        HybridTimestamp beginTs = new HybridTimestamp(123L, 456);
+
+        UUID txId = TransactionIds.transactionId(beginTs, 0xdeadbeef);
+
+        HybridTimestamp extractedTs = TransactionIds.beginTimestamp(txId);
+
+        assertThat(extractedTs, is(beginTs));
+        assertThat((int) txId.getLeastSignificantBits(), is(0xdeadbeef));
+    }
+}
diff --git 
a/modules/transactions/src/test/java/org/apache/ignite/internal/tx/TxManagerTest.java
 
b/modules/transactions/src/test/java/org/apache/ignite/internal/tx/TxManagerTest.java
index 4da2592d33..4db2218ad8 100644
--- 
a/modules/transactions/src/test/java/org/apache/ignite/internal/tx/TxManagerTest.java
+++ 
b/modules/transactions/src/test/java/org/apache/ignite/internal/tx/TxManagerTest.java
@@ -40,7 +40,9 @@ import 
org.apache.ignite.internal.replicator.ReplicationGroupId;
 import org.apache.ignite.internal.replicator.TestReplicationGroupId;
 import org.apache.ignite.internal.testframework.IgniteAbstractTest;
 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.tx.test.TestTransactionIds;
 import org.apache.ignite.lang.ErrorGroups.Transactions;
 import org.apache.ignite.lang.IgniteBiTuple;
 import org.apache.ignite.lang.IgniteInternalException;
@@ -79,7 +81,7 @@ public class TxManagerTest extends IgniteAbstractTest {
 
         replicaService = mock(ReplicaService.class, RETURNS_DEEP_STUBS);
 
-        txManager = new TxManagerImpl(replicaService, new HeapLockManager(), 
clock);
+        txManager = new TxManagerImpl(replicaService, new HeapLockManager(), 
clock, new TransactionIdGenerator(0xdeadbeef));
     }
 
     @Test
@@ -112,13 +114,13 @@ public class TxManagerTest extends IgniteAbstractTest {
 
     @Test
     public void testId() throws Exception {
-        UUID txId1 = Timestamp.nextVersion().toUuid();
-        UUID txId2 = Timestamp.nextVersion().toUuid();
-        UUID txId3 = Timestamp.nextVersion().toUuid();
+        UUID txId1 = TestTransactionIds.newTransactionId();
+        UUID txId2 = TestTransactionIds.newTransactionId();
+        UUID txId3 = TestTransactionIds.newTransactionId();
 
         Thread.sleep(1);
 
-        UUID txId4 = Timestamp.nextVersion().toUuid();
+        UUID txId4 = TestTransactionIds.newTransactionId();
 
         assertTrue(txId2.compareTo(txId1) > 0);
         assertTrue(txId3.compareTo(txId2) > 0);
diff --git 
a/modules/transactions/src/testFixtures/java/org/apache/ignite/internal/tx/test/TestTransactionIds.java
 
b/modules/transactions/src/testFixtures/java/org/apache/ignite/internal/tx/test/TestTransactionIds.java
new file mode 100644
index 0000000000..66e4a6814b
--- /dev/null
+++ 
b/modules/transactions/src/testFixtures/java/org/apache/ignite/internal/tx/test/TestTransactionIds.java
@@ -0,0 +1,46 @@
+/*
+ * 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.tx.test;
+
+import java.util.UUID;
+import org.apache.ignite.internal.hlc.HybridClock;
+import org.apache.ignite.internal.hlc.HybridClockImpl;
+import org.apache.ignite.internal.tx.impl.TransactionIdGenerator;
+
+/**
+ * Contains methods to generate transaction IDs for the cases when the clock 
and nodeId might be hard-coded
+ * (just for tests).
+ */
+public class TestTransactionIds {
+    /** Global clock instance. */
+    private static final HybridClock GLOBAL_CLOCK = new HybridClockImpl();
+
+    /** Hard-coded node ID. */
+    private static final int SOLE_NODE_ID = 0xdeadbeef;
+
+    private static final TransactionIdGenerator TRANSACTION_ID_GENERATOR = new 
TransactionIdGenerator(SOLE_NODE_ID);
+
+    /**
+     * Generates new transaction ID using the global clock and hard-coded node 
ID.
+     *
+     * @return New transaction ID.
+     */
+    public static UUID newTransactionId() {
+        return TRANSACTION_ID_GENERATOR.transactionIdFor(GLOBAL_CLOCK.now());
+    }
+}

Reply via email to