From 2b73fba9cd60dc132ecdd35d6ef3ff5e306f12a1 Mon Sep 17 00:00:00 2001 From: Aleksey Plekhanov Date: Mon, 29 Jun 2026 19:31:22 +0300 Subject: [PATCH 1/2] IGNITE-28833 Add system views for cache locks --- .../monitoring-metrics/system-views.adoc | 34 ++ .../ignite/internal/binary/BinaryUtils.java | 4 +- .../cache/GridCacheExplicitLockSpan.java | 16 + .../cache/GridCacheMvccCandidate.java | 16 + .../cache/GridCacheMvccManager.java | 44 ++ .../view/CacheExplicitLockView.java | 73 ++++ .../spi/systemview/view/CacheKeyLockView.java | 115 ++++++ .../spi/systemview/view/TransactionView.java | 10 +- .../internal/metric/SystemViewLocksTest.java | 387 ++++++++++++++++++ .../testsuites/IgniteCacheTestSuite13.java | 2 + .../query/SqlSystemViewsSelfTest.java | 55 +++ 11 files changed, 753 insertions(+), 3 deletions(-) create mode 100644 modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CacheExplicitLockView.java create mode 100644 modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CacheKeyLockView.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewLocksTest.java diff --git a/docs/_docs/monitoring-metrics/system-views.adoc b/docs/_docs/monitoring-metrics/system-views.adoc index d7426347a0f6b..61a519e02c9b0 100644 --- a/docs/_docs/monitoring-metrics/system-views.adoc +++ b/docs/_docs/monitoring-metrics/system-views.adoc @@ -275,6 +275,7 @@ Each row in this view represents a transaction object on the node where the view |ORIGINATING_NODE_ID | UUID | ID of the node that initiated the current transaction object. For a transaction object mapped to a primary partition, this is the transaction initiator node; for a transaction object mapped to a backup partition, this is the node that owns the primary partition |STATE | string | Current transaction state |XID | UUID | Unique transaction identifier +|ORIGINATING_XID | UUID | Ttransaction ID on originating node |LABEL | string | Transaction label |START_TIME | long | Start time of the transaction on this node |ISOLATION | string | Transaction isolation level @@ -299,6 +300,39 @@ Each row in this view represents a transaction object on the node where the view |TOP_VER | string | Topology version assigned to the transaction. If not assigned explicitly, it is a topology version of the latest partition exchange. |=== +== CACHE_EXPLICIT_LOCKS + +This view exposes information about explicit locks acquired on the current node. +Explicit locks are acquired using the `Cache.lock(key)` API. + +[{table_opts}] +|=== +|NAME | TYPE | DESCRIPTION +|CACHE_ID | int | Cache ID +|KEY | string | Locked key +|THREAD_ID | long | ID of the thread that acquired the lock +|XID | UUID | Lock ID (unique identifier) +|=== + +== CACHE_KEY_LOCKS + +This view exposes information about all locks (both explicit and transactional) requested for keys hosted on the current node. +This includes locks from remote nodes trying to access primary keys on this node. + +[{table_opts}] +|=== +|NAME | TYPE | DESCRIPTION +|CACHE_ID | int | Cache ID +|KEY | string | Locked key +|NODE_ID | UUID | ID of the node where the lock is hosted +|ORIGINATING_NODE_ID | UUID | ID of the node that initiated the lock request +|IS_OWNER | boolean | `True` if the lock is currently owned +|IS_TX | boolean | `True` if the lock is part of a transaction +|FLAGS | string | All flags for the lock +|XID | UUID | Current transaction ID (or explicit lock ID) +|ORIGINATING_XID | UUID | Originating transaction ID (or explicit lock ID) +|=== + == NODES diff --git a/modules/binary/api/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java b/modules/binary/api/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java index fcbd74fe0c550..14a97520c8175 100644 --- a/modules/binary/api/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java +++ b/modules/binary/api/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java @@ -3291,7 +3291,7 @@ public void clearAllListener() { * @param ver Cache version. * @return Version represented as {@code IgniteUuid}. */ - public static IgniteUuid asIgniteUuid(GridCacheVersion ver) { - return new IgniteUuid(new UUID(ver.topologyVersion(), ver.nodeOrderAndDrIdRaw()), ver.order()); + public static @Nullable IgniteUuid asIgniteUuid(@Nullable GridCacheVersion ver) { + return ver == null ? null : new IgniteUuid(new UUID(ver.topologyVersion(), ver.nodeOrderAndDrIdRaw()), ver.order()); } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheExplicitLockSpan.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheExplicitLockSpan.java index e0c6d9b42406a..53c8ad6f5774d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheExplicitLockSpan.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheExplicitLockSpan.java @@ -17,6 +17,8 @@ package org.apache.ignite.internal.processors.cache; +import java.util.ArrayList; +import java.util.Collection; import java.util.Deque; import java.util.HashMap; import java.util.Iterator; @@ -216,6 +218,20 @@ public boolean isEmpty() { } } + /** + * @return Lock candidates. + */ + public Collection candidates() { + lock(); + + try { + return new ArrayList<>(F.flatCollections(cands.values())); + } + finally { + unlock(); + } + } + /** * Marks all candidates added for given key as owned. * diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccCandidate.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccCandidate.java index d0e624f94bb0d..4a6e96e4b8287 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccCandidate.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccCandidate.java @@ -607,6 +607,22 @@ public IgniteTxKey key() { return parent0.txKey(); } + /** */ + public String enabledFlags() { + SB sb = new SB(); + + for (Mask m : Mask.MASKS) { + if (m.bit(flags) != 0) { + if (sb.length() != 0) + sb.a(" | "); + + sb.a(m.name()); + } + } + + return sb.toString(); + } + /** {@inheritDoc} */ @Override public GridCacheMvccCandidate candidate(int idx) { assert idx == 0 : idx; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccManager.java index 9ca503678031b..be2dc5bba5240 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccManager.java @@ -20,6 +20,7 @@ import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Deque; import java.util.HashMap; import java.util.HashSet; @@ -49,6 +50,8 @@ import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx; import org.apache.ignite.internal.processors.cache.transactions.IgniteTxKey; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; +import org.apache.ignite.internal.systemview.CacheExplicitLockViewWalker; +import org.apache.ignite.internal.systemview.CacheKeyLockViewWalker; import org.apache.ignite.internal.util.GridBoundedConcurrentLinkedHashSet; import org.apache.ignite.internal.util.GridConcurrentFactory; import org.apache.ignite.internal.util.GridConcurrentHashSet; @@ -67,6 +70,8 @@ import org.apache.ignite.lang.IgniteFuture; import org.apache.ignite.lang.IgnitePredicate; import org.apache.ignite.lang.IgniteUuid; +import org.apache.ignite.spi.systemview.view.CacheExplicitLockView; +import org.apache.ignite.spi.systemview.view.CacheKeyLockView; import org.apache.ignite.util.deque.FastSizeDeque; import org.jetbrains.annotations.Nullable; @@ -94,6 +99,18 @@ public class GridCacheMvccManager extends GridCacheSharedManagerAdapter { private static final int MAX_NESTED_LSNR_CALLS = getInteger(IGNITE_MAX_NESTED_LISTENER_CALLS, DFLT_MAX_NESTED_LISTENER_CALLS); + /** System view name for cache explicit locks. */ + public static final String CACHE_EXPLICIT_LOCKS_VIEW = "cacheExplicitLocks"; + + /** System view description for cache explicit locks. */ + public static final String CACHE_EXPLICIT_LOCKS_VIEW_DESC = "Explicit locks on cache keys"; + + /** System view name for cache locks. */ + public static final String CACHE_KEY_LOCKS_VIEW = "cacheKeyLocks"; + + /** System view description for cache keys locks. */ + public static final String CACHE_KEY_LOCKS_VIEW_DESC = "Held and queued locks on cache keys"; + /** Pending locks per thread. */ private final ThreadLocal> pending = new ThreadLocal<>(); @@ -282,6 +299,33 @@ else if (log.isDebugEnabled()) pendingExplicit = GridConcurrentFactory.newMap(); cctx.gridEvents().addLocalEventListener(discoLsnr, EVT_NODE_FAILED, EVT_NODE_LEFT); + + cctx.kernalContext().systemView().registerInnerCollectionView( + CACHE_EXPLICIT_LOCKS_VIEW, + CACHE_EXPLICIT_LOCKS_VIEW_DESC, + new CacheExplicitLockViewWalker(), + pendingExplicit.values(), + GridCacheExplicitLockSpan::candidates, + (threadId, lock) -> new CacheExplicitLockView(lock) + ); + + cctx.kernalContext().systemView().registerInnerCollectionView( + CACHE_KEY_LOCKS_VIEW, + CACHE_KEY_LOCKS_VIEW_DESC, + new CacheKeyLockViewWalker(), + locked.values(), + entry -> { + entry.lockEntry(); + try { + GridCacheMvcc mvcc = entry.mvccExtras(); + return mvcc != null ? mvcc.localCandidates() : Collections.emptyList(); + } + finally { + entry.unlockEntry(); + } + }, + (entry, cand) -> new CacheKeyLockView(cand) + ); } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CacheExplicitLockView.java b/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CacheExplicitLockView.java new file mode 100644 index 0000000000000..8d2a36d6703ba --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CacheExplicitLockView.java @@ -0,0 +1,73 @@ +/* + * 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.spi.systemview.view; + +import org.apache.ignite.internal.binary.BinaryUtils; +import org.apache.ignite.internal.processors.cache.GridCacheMvccCandidate; +import org.apache.ignite.internal.systemview.Order; +import org.apache.ignite.internal.systemview.SystemViewDescriptor; +import org.apache.ignite.lang.IgniteUuid; + +/** + * Cache explicit lock representation for a {@link SystemView}. + * Shows locks acquired on current node (not hosted by current node). + */ +@SystemViewDescriptor +public class CacheExplicitLockView { + /** */ + private final GridCacheMvccCandidate cand; + + /** + * @param cand Lock candidate + */ + public CacheExplicitLockView(GridCacheMvccCandidate cand) { + this.cand = cand; + } + + /** + * @return Cache ID. + */ + @Order + public int cacheId() { + return cand.key().cacheId(); + } + + /** + * @return Key. + */ + @Order(1) + public String key() { + return cand.key().key().toString(); + } + + /** + * @return Thread ID. + */ + @Order(2) + public long threadId() { + return cand.threadId(); + } + + /** + * @return Version. + */ + @Order(3) + public IgniteUuid xid() { + return BinaryUtils.asIgniteUuid(cand.version()); + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CacheKeyLockView.java b/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CacheKeyLockView.java new file mode 100644 index 0000000000000..4209b038da582 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CacheKeyLockView.java @@ -0,0 +1,115 @@ +/* + * 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.spi.systemview.view; + +import java.util.UUID; +import org.apache.ignite.internal.binary.BinaryUtils; +import org.apache.ignite.internal.processors.cache.GridCacheMvccCandidate; +import org.apache.ignite.internal.systemview.Order; +import org.apache.ignite.internal.systemview.SystemViewDescriptor; +import org.apache.ignite.lang.IgniteUuid; + +/** + * Cache key lock representation for a {@link SystemView}. + * Shows held cache key locks and queued cache key locks hosted on current node, + * including explicit locks and transactional locks. + */ +@SystemViewDescriptor +public class CacheKeyLockView { + /** Lock candidate. */ + private final GridCacheMvccCandidate cand; + + /** + * @param cand Lock candidate + */ + public CacheKeyLockView(GridCacheMvccCandidate cand) { + this.cand = cand; + } + + /** + * @return Cache ID. + */ + @Order + public int cacheId() { + return cand.key().cacheId(); + } + + /** + * @return Key. + */ + @Order(1) + public String key() { + return cand.key().key().toString(); + } + + /** + * @return Node ID. + */ + @Order(2) + public UUID nodeId() { + return cand.nodeId(); + } + + /** + * @return Originating node ID. + */ + @Order(3) + public UUID originatingNodeId() { + return cand.otherNodeId(); + } + + /** + * @return "OWNER" flag. + */ + @Order(4) + public boolean isOwner() { + return cand.owner(); + } + + /** + * @return "TX" flag. + */ + @Order(5) + public boolean isTx() { + return cand.tx(); + } + + /** + * @return All enabled flags. + */ + @Order(6) + public String flags() { + return cand.enabledFlags(); + } + + /** + * @return Transaction ID. + */ + @Order(7) + public IgniteUuid xid() { + return BinaryUtils.asIgniteUuid(cand.version()); + } + + /** + * @return Originating transaction ID. + */ + @Order(8) + public IgniteUuid originatingXid() { + return BinaryUtils.asIgniteUuid(cand.otherVersion()); + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/TransactionView.java b/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/TransactionView.java index bc09a478c99b7..547715fee2cf7 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/TransactionView.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/TransactionView.java @@ -20,6 +20,7 @@ import java.util.Collection; import java.util.Objects; import java.util.UUID; +import org.apache.ignite.internal.binary.BinaryUtils; import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx; import org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry; import org.apache.ignite.internal.processors.cache.transactions.IgniteTxState; @@ -125,6 +126,14 @@ public IgniteUuid xid() { return tx.xid(); } + /** + * @return Near transaction ID. + * @see IgniteInternalTx#nearXidVersion() () + */ + public IgniteUuid originatingXid() { + return BinaryUtils.asIgniteUuid(tx.nearXidVersion()); + } + /** * @return {@code True} if transaction is started for system cache. * @see IgniteInternalTx#system() @@ -284,6 +293,5 @@ public String cacheIds() { catch (Throwable e) { return null; } - } } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewLocksTest.java b/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewLocksTest.java new file mode 100644 index 0000000000000..8830dbb36c21d --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewLocksTest.java @@ -0,0 +1,387 @@ +/* + * 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.metric; + +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.locks.Lock; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.IgniteInternalFuture; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.spi.systemview.view.CacheExplicitLockView; +import org.apache.ignite.spi.systemview.view.CacheKeyLockView; +import org.apache.ignite.spi.systemview.view.SystemView; +import org.apache.ignite.spi.systemview.view.TransactionView; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.transactions.Transaction; +import org.junit.Test; + +import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL; +import static org.apache.ignite.cache.CacheMode.PARTITIONED; +import static org.apache.ignite.internal.processors.cache.GridCacheMvccManager.CACHE_EXPLICIT_LOCKS_VIEW; +import static org.apache.ignite.internal.processors.cache.GridCacheMvccManager.CACHE_KEY_LOCKS_VIEW; +import static org.apache.ignite.internal.processors.cache.transactions.IgniteTxManager.TXS_MON_LIST; +import static org.apache.ignite.testframework.GridTestUtils.waitForCondition; +import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC; +import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ; + +/** Tests for {@link SystemView} for locks. */ +public class SystemViewLocksTest extends SystemViewAbstractTest { + /** {@inheritDoc} */ + @Override protected void beforeTest() throws Exception { + super.beforeTest(); + + IgniteEx ignite = startGrids(3); + + ignite.getOrCreateCache( + new CacheConfiguration(DEFAULT_CACHE_NAME) + .setAtomicityMode(TRANSACTIONAL) + .setCacheMode(PARTITIONED) + .setBackups(1) + ); + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + stopAllGrids(); + + super.afterTest(); + } + + /** */ + @Test + public void testExplicitLocks() throws Exception { + IgniteEx ignite0 = grid(0); + IgniteEx ignite1 = grid(1); + IgniteEx ignite2 = grid(2); + + CountDownLatch finishLatch = new CountDownLatch(1); + + try { + Integer key0 = primaryKey(ignite0.cache(DEFAULT_CACHE_NAME)); + Integer key1 = primaryKey(ignite1.cache(DEFAULT_CACHE_NAME)); + Integer key2 = primaryKey(ignite2.cache(DEFAULT_CACHE_NAME)); + + CountDownLatch firstNodeLatch = new CountDownLatch(1); + + // Block key0 and key1 from node0. + Runnable task0 = explicitLockTask(ignite0, () -> { + firstNodeLatch.countDown(); + U.awaitQuiet(finishLatch); + }, key0, key1); + + // Block key2 and wait for key0 from node1. + Runnable task1 = explicitLockTask(ignite1, () -> {}, key2, key0); + + // Wait for key0 from node2. + Runnable task2a = explicitLockTask(ignite2, () -> {}, key0); + + // Wait for key1 from node2. + Runnable task2b = explicitLockTask(ignite2, () -> {}, key1); + + IgniteInternalFuture fut0 = GridTestUtils.runAsync(task0); + firstNodeLatch.await(); + IgniteInternalFuture fut1 = GridTestUtils.runAsync(task1); + IgniteInternalFuture fut2a = GridTestUtils.runAsync(task2a); + IgniteInternalFuture fut2b = GridTestUtils.runAsync(task2b); + + List explicitLocks0 = viewContent(ignite0, CACHE_EXPLICIT_LOCKS_VIEW, 2); + List explicitLocks1 = viewContent(ignite1, CACHE_EXPLICIT_LOCKS_VIEW, 2); + List explicitLocks2 = viewContent(ignite2, CACHE_EXPLICIT_LOCKS_VIEW, 2); + + List keyLocks0 = viewContent(ignite0, CACHE_KEY_LOCKS_VIEW, 3); + List keyLocks1 = viewContent(ignite1, CACHE_KEY_LOCKS_VIEW, 2); + List keyLocks2 = viewContent(ignite2, CACHE_KEY_LOCKS_VIEW, 1); + + // Check threads. + assertEquals(explicitLocks0.get(0).threadId(), explicitLocks0.get(1).threadId()); + assertEquals(explicitLocks1.get(0).threadId(), explicitLocks1.get(1).threadId()); + assertNotSame(explicitLocks2.get(0).threadId(), explicitLocks2.get(1).threadId()); + + // Check lock owners. + CacheKeyLockView owner0 = F.find(keyLocks0, null, CacheKeyLockView::isOwner); + CacheKeyLockView owner1 = F.find(keyLocks1, null, CacheKeyLockView::isOwner); + CacheKeyLockView owner2 = F.find(keyLocks2, null, CacheKeyLockView::isOwner); + + assertNotNull(owner0); + assertNotNull(owner1); + assertNotNull(owner2); + + assertEquals(owner0.originatingNodeId(), ignite0.localNode().id()); + assertEquals(1, F.size(explicitLocks0, l -> l.xid().equals(owner0.originatingXid()))); + + assertEquals(owner1.originatingNodeId(), ignite0.localNode().id()); + assertEquals(1, F.size(explicitLocks0, l -> l.xid().equals(owner1.originatingXid()))); + + assertEquals(owner2.originatingNodeId(), ignite1.localNode().id()); + assertEquals(1, F.size(explicitLocks1, l -> l.xid().equals(owner2.originatingXid()))); + + // Check waiting locks. + assertEquals(1, F.size(keyLocks0, + l -> !l.isOwner() && l.originatingNodeId().equals(ignite1.localNode().id()))); + assertEquals(1, F.size(keyLocks0, + l -> !l.isOwner() && l.originatingNodeId().equals(ignite2.localNode().id()))); + assertEquals(1, F.size(keyLocks1, + l -> !l.isOwner() && l.originatingNodeId().equals(ignite2.localNode().id()))); + + finishLatch.countDown(); + + fut0.get(); + fut1.get(); + fut2a.get(); + fut2b.get(); + } + finally { + finishLatch.countDown(); + } + } + + /** */ + @Test + public void testTxLocks() throws Exception { + IgniteEx ignite0 = grid(0); + IgniteEx ignite1 = grid(1); + IgniteEx ignite2 = grid(2); + + CountDownLatch finishLatch = new CountDownLatch(1); + + try { + Integer key0 = primaryKey(ignite0.cache(DEFAULT_CACHE_NAME)); + Integer key1 = primaryKey(ignite1.cache(DEFAULT_CACHE_NAME)); + Integer key2 = primaryKey(ignite2.cache(DEFAULT_CACHE_NAME)); + + CountDownLatch firstNodeLatch = new CountDownLatch(1); + + // Block key0 and key1 from node0. + Runnable task0 = txLockTask(ignite0, () -> { + firstNodeLatch.countDown(); + U.awaitQuiet(finishLatch); + }, key0, key1); + + // Block key2 and wait for key0 from node1. + Runnable task1 = txLockTask(ignite1, () -> {}, key2, key0); + + // Wait for key0 from node2. + Runnable task2a = txLockTask(ignite2, () -> {}, key0); + + // Wait for key1 from node2. + Runnable task2b = txLockTask(ignite2, () -> {}, key1); + + IgniteInternalFuture fut0 = GridTestUtils.runAsync(task0); + firstNodeLatch.await(); + IgniteInternalFuture fut1 = GridTestUtils.runAsync(task1); + IgniteInternalFuture fut2a = GridTestUtils.runAsync(task2a); + IgniteInternalFuture fut2b = GridTestUtils.runAsync(task2b); + + List txs0 = viewContent(ignite0, TXS_MON_LIST, 3); // 1 near + 2 dht. + List txs1 = viewContent(ignite1, TXS_MON_LIST, 3); // 1 near + 2 dht + List txs2 = viewContent(ignite2, TXS_MON_LIST, 3); // 2 near + 1 dht + + List keyLocks0 = viewContent(ignite0, CACHE_KEY_LOCKS_VIEW, 3); + List keyLocks1 = viewContent(ignite1, CACHE_KEY_LOCKS_VIEW, 2); + List keyLocks2 = viewContent(ignite2, CACHE_KEY_LOCKS_VIEW, 1); + + // Check lock owners. + CacheKeyLockView owner0 = F.find(keyLocks0, null, CacheKeyLockView::isOwner); + CacheKeyLockView owner1 = F.find(keyLocks1, null, CacheKeyLockView::isOwner); + CacheKeyLockView owner2 = F.find(keyLocks2, null, CacheKeyLockView::isOwner); + + assertNotNull(owner0); + assertNotNull(owner1); + assertNotNull(owner2); + + assertEquals(owner0.originatingNodeId(), ignite0.localNode().id()); + assertEquals(1, F.size(txs0, l -> l.xid().equals(owner0.originatingXid()) && l.xid().equals(owner0.xid()))); + + assertEquals(owner1.originatingNodeId(), ignite0.localNode().id()); + assertEquals(1, F.size(txs0, l -> l.xid().equals(owner1.originatingXid()))); // Near. + assertEquals(1, F.size(txs1, l -> l.xid().equals(owner1.xid()))); // Dht. + + assertEquals(owner2.originatingNodeId(), ignite1.localNode().id()); + assertEquals(1, F.size(txs1, l -> l.xid().equals(owner2.originatingXid()))); // Near. + assertEquals(1, F.size(txs2, l -> l.xid().equals(owner2.xid()))); // Dht. + + // Check waiting locks. + CacheKeyLockView waiting1on0 = F.find(keyLocks0, null, + l -> !l.isOwner() && l.originatingNodeId().equals(ignite1.localNode().id())); + CacheKeyLockView waiting2on0 = F.find(keyLocks0, null, + l -> !l.isOwner() && l.originatingNodeId().equals(ignite2.localNode().id())); + CacheKeyLockView waiting2on1 = F.find(keyLocks1, null, + l -> !l.isOwner() && l.originatingNodeId().equals(ignite2.localNode().id())); + + assertNotNull(waiting1on0); + assertNotNull(waiting2on0); + assertNotNull(waiting2on1); + + assertEquals(1, F.size(txs1, l -> l.xid().equals(waiting1on0.originatingXid()))); // Near. + assertEquals(1, F.size(txs0, l -> l.xid().equals(waiting1on0.xid()))); // Dht. + + assertEquals(1, F.size(txs2, l -> l.xid().equals(waiting2on0.originatingXid()))); // Near. + assertEquals(1, F.size(txs0, l -> l.xid().equals(waiting2on0.xid()))); // Dht. + + assertEquals(1, F.size(txs2, l -> l.xid().equals(waiting2on1.originatingXid()))); // Near. + assertEquals(1, F.size(txs1, l -> l.xid().equals(waiting2on1.xid()))); // Dht. + + finishLatch.countDown(); + + fut0.get(); + fut1.get(); + fut2a.get(); + fut2b.get(); + } + finally { + finishLatch.countDown(); + } + } + + /** */ + @Test + public void testMixedExplicitTxLocks() throws Exception { + IgniteEx ignite0 = grid(0); + IgniteEx ignite1 = grid(1); + IgniteEx ignite2 = grid(2); + + CountDownLatch finishLatch = new CountDownLatch(1); + + try { + Integer key1 = primaryKey(ignite1.cache(DEFAULT_CACHE_NAME)); + Integer key2 = primaryKey(ignite2.cache(DEFAULT_CACHE_NAME)); + + CountDownLatch firstNodeLatch = new CountDownLatch(1); + CountDownLatch secondNodeLatch = new CountDownLatch(1); + + // Block key1 from node0. + Runnable task0 = explicitLockTask(ignite0, () -> { + firstNodeLatch.countDown(); + U.awaitQuiet(finishLatch); + }, key1); + + // Block key2 from node1. + Runnable task1 = txLockTask(ignite1, () -> { + secondNodeLatch.countDown(); + U.awaitQuiet(finishLatch); + }, key2); + + // Wait for key2 from node2. + Runnable task2a = explicitLockTask(ignite2, () -> {}, key2); + + // Wait for key1 from node2. + Runnable task2b = txLockTask(ignite2, () -> {}, key1); + + IgniteInternalFuture fut0 = GridTestUtils.runAsync(task0); + firstNodeLatch.await(); + IgniteInternalFuture fut1 = GridTestUtils.runAsync(task1); + secondNodeLatch.await(); + IgniteInternalFuture fut2a = GridTestUtils.runAsync(task2a); + IgniteInternalFuture fut2b = GridTestUtils.runAsync(task2b); + + List explicitLocks0 = viewContent(ignite0, CACHE_EXPLICIT_LOCKS_VIEW, 1); + List explicitLocks2 = viewContent(ignite2, CACHE_EXPLICIT_LOCKS_VIEW, 1); + List txs1 = viewContent(ignite1, TXS_MON_LIST, 2); // 1 near + 1 dht + List txs2 = viewContent(ignite2, TXS_MON_LIST, 2); // 1 near + 1 dht + + List keyLocks1 = viewContent(ignite1, CACHE_KEY_LOCKS_VIEW, 2); + List keyLocks2 = viewContent(ignite2, CACHE_KEY_LOCKS_VIEW, 2); + + // Check lock owners. + CacheKeyLockView owner1 = F.find(keyLocks1, null, CacheKeyLockView::isOwner); + CacheKeyLockView owner2 = F.find(keyLocks2, null, CacheKeyLockView::isOwner); + + assertNotNull(owner1); + assertNotNull(owner2); + + assertEquals(owner1.originatingNodeId(), ignite0.localNode().id()); + assertEquals(1, F.size(explicitLocks0, l -> l.xid().equals(owner1.originatingXid()))); + + assertEquals(owner2.originatingNodeId(), ignite1.localNode().id()); + assertEquals(1, F.size(txs1, l -> l.xid().equals(owner2.originatingXid()))); // Near. + assertEquals(1, F.size(txs2, l -> l.xid().equals(owner2.xid()))); // Dht. + + // Check waiting locks. + CacheKeyLockView waiting2on1 = F.find(keyLocks1, null, + l -> !l.isOwner() && l.originatingNodeId().equals(ignite2.localNode().id())); + CacheKeyLockView waiting2on2 = F.find(keyLocks2, null, + l -> !l.isOwner() && l.originatingNodeId().equals(ignite2.localNode().id())); + + assertNotNull(waiting2on1); + assertNotNull(waiting2on2); + + assertEquals(1, F.size(txs2, l -> l.xid().equals(waiting2on1.originatingXid()))); // Near. + assertEquals(1, F.size(txs1, l -> l.xid().equals(waiting2on1.xid()))); // Dht. + + assertEquals(1, F.size(explicitLocks2, l -> l.xid().equals(waiting2on2.originatingXid()))); + + finishLatch.countDown(); + + fut0.get(); + fut1.get(); + fut2a.get(); + fut2b.get(); + } + finally { + finishLatch.countDown(); + } + } + + /** */ + private static Runnable explicitLockTask(IgniteEx ignite, Runnable body, int... keysToLock) { + return () -> { + Lock[] locks = new Lock[keysToLock.length]; + + for (int i = 0; i < keysToLock.length; i++) { + locks[i] = ignite.cache(DEFAULT_CACHE_NAME).lock(keysToLock[i]); + locks[i].lock(); + } + + try { + body.run(); + } + finally { + for (int i = keysToLock.length - 1; i >= 0; i--) + locks[i].unlock(); + } + }; + } + + /** */ + private static Runnable txLockTask(IgniteEx ignite, Runnable body, int... keysToLock) { + return () -> { + try (Transaction tx = ignite.transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) { + for (int i = 0; i < keysToLock.length; i++) + ignite.cache(DEFAULT_CACHE_NAME).put(keysToLock[i], 0); + + body.run(); + + tx.commit(); + } + }; + } + + /** */ + private static List viewContent(IgniteEx ignite, String viewName, int expSize) throws Exception { + SystemView view = ignite.context().systemView().view(viewName); + + assertTrue("Failed to wait for view size [ignite=" + ignite.name() + ", viewName=" + viewName + + ", expSize=" + expSize + ", actSize=" + F.size(view.iterator()), + waitForCondition(() -> F.size(view.iterator()) == expSize, 1_000L)); + + return U.arrayList(view.iterator(), expSize); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite13.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite13.java index 2f4d1787be3f9..4426afc205343 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite13.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite13.java @@ -45,6 +45,7 @@ import org.apache.ignite.internal.metric.SystemViewConfigurationTest; import org.apache.ignite.internal.metric.SystemViewDSTest; import org.apache.ignite.internal.metric.SystemViewExecutorsTest; +import org.apache.ignite.internal.metric.SystemViewLocksTest; import org.apache.ignite.internal.metric.SystemViewMetastorageTest; import org.apache.ignite.internal.metric.SystemViewNodesTest; import org.apache.ignite.internal.metric.SystemViewPageListsTest; @@ -122,6 +123,7 @@ public static List> suite(Collection ignoredTests) { GridTestUtils.addTestIfNeeded(suite, SystemViewConfigurationTest.class, ignoredTests); GridTestUtils.addTestIfNeeded(suite, SystemViewPluginTest.class, ignoredTests); GridTestUtils.addTestIfNeeded(suite, SystemViewQueriesTest.class, ignoredTests); + GridTestUtils.addTestIfNeeded(suite, SystemViewLocksTest.class, ignoredTests); GridTestUtils.addTestIfNeeded(suite, CacheMetricsAddRemoveTest.class, ignoredTests); GridTestUtils.addTestIfNeeded(suite, CacheMetricsConflictResolverTest.class, ignoredTests); GridTestUtils.addTestIfNeeded(suite, JmxExporterSpiTest.class, ignoredTests); diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSystemViewsSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSystemViewsSelfTest.java index 5c74bdf53aa5a..1c7b4457f467a 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSystemViewsSelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSystemViewsSelfTest.java @@ -32,6 +32,7 @@ import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; import java.util.function.BiConsumer; import java.util.stream.Collectors; import java.util.stream.LongStream; @@ -81,6 +82,7 @@ import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.G; import org.apache.ignite.internal.util.typedef.X; +import org.apache.ignite.internal.util.typedef.internal.CU; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteFuture; import org.apache.ignite.lang.IgnitePredicate; @@ -92,6 +94,7 @@ import org.apache.ignite.spi.systemview.view.SystemView; import org.apache.ignite.spi.systemview.view.sql.SqlTableView; import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.transactions.Transaction; import org.junit.Assert; import org.junit.Test; @@ -102,6 +105,8 @@ import static org.apache.ignite.internal.processors.query.running.RunningQueryManager.SQL_QRY_VIEW; import static org.apache.ignite.internal.util.IgniteUtils.MB; import static org.apache.ignite.testframework.GridTestUtils.waitForCondition; +import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC; +import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ; import static org.junit.Assert.assertNotEquals; /** @@ -1896,6 +1901,56 @@ public void testPluginView() throws Exception { } } + /** */ + @Test + public void testLocksView() throws Exception { + try (IgniteEx ignite = startGrid()) { + IgniteCache cache = ignite.getOrCreateCache(new CacheConfiguration<>(DEFAULT_CACHE_NAME) + .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL)); + + Lock lock1 = cache.lock(1); + Lock lock2 = cache.lock(2); + + lock1.lock(); + lock2.lock(); + try (Transaction ignored = ignite.transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) { + cache.put(3, 3); + + // Join explicit locks with key locks. + List> res = execSql("SELECT el.cache_id, el.thread_id, kl.is_owner, kl.is_tx, kl.originating_node_id " + + "FROM SYS.CACHE_EXPLICIT_LOCKS el JOIN SYS.CACHE_KEY_LOCKS kl ON el.xid = kl.xid"); + + assertEquals(2, res.size()); + + for (List lock : res) { + assertEquals(CU.cacheId(DEFAULT_CACHE_NAME), lock.get(0)); + assertEquals(Thread.currentThread().getId(), lock.get(1)); + assertEquals(true, lock.get(2)); + assertEquals(false, lock.get(3)); + assertEquals(ignite.localNode().id(), lock.get(4)); + } + + // Join transactions with key locks. + res = execSql("SELECT kl.cache_id, tx.thread_id, kl.is_owner, kl.is_tx, kl.originating_node_id " + + "FROM SYS.TRANSACTIONS tx JOIN SYS.CACHE_KEY_LOCKS kl ON tx.xid = kl.xid"); + + assertEquals(1, res.size()); + + for (List lock : res) { + assertEquals(CU.cacheId(DEFAULT_CACHE_NAME), lock.get(0)); + assertEquals(Thread.currentThread().getId(), lock.get(1)); + assertEquals(true, lock.get(2)); + assertEquals(true, lock.get(3)); + assertEquals(ignite.localNode().id(), lock.get(4)); + } + } + finally { + lock2.unlock(); + lock1.unlock(); + } + } + } + /** * Mock for {@link ClusterMetricsImpl} that always returns big (more than 24h) duration for all duration metrics. */ From a700ad47f6ff180df86e721d1277e316e77c8fb5 Mon Sep 17 00:00:00 2001 From: Aleksey Plekhanov Date: Fri, 10 Jul 2026 16:50:17 +0300 Subject: [PATCH 2/2] IGNITE-28833 Review comments --- .../monitoring-metrics/system-views.adoc | 4 +- .../internal/jdbc2/JdbcMetadataSelfTest.java | 4 +- .../jdbc/thin/JdbcThinMetadataSelfTest.java | 18 +++++++- .../ignite/util/SystemViewCommandTest.java | 4 +- .../cache/GridCacheMvccCandidate.java | 16 ------- .../cache/GridCacheMvccManager.java | 16 +++---- ...cheKeyLockView.java => CacheLockView.java} | 8 ++-- .../internal/metric/SystemViewLocksTest.java | 46 +++++++++---------- .../cache/metric/SqlViewExporterSpiTest.java | 4 +- .../query/SqlSystemViewsSelfTest.java | 4 +- 10 files changed, 64 insertions(+), 60 deletions(-) rename modules/core/src/main/java/org/apache/ignite/spi/systemview/view/{CacheKeyLockView.java => CacheLockView.java} (94%) diff --git a/docs/_docs/monitoring-metrics/system-views.adoc b/docs/_docs/monitoring-metrics/system-views.adoc index 61a519e02c9b0..5e8efa8942424 100644 --- a/docs/_docs/monitoring-metrics/system-views.adoc +++ b/docs/_docs/monitoring-metrics/system-views.adoc @@ -314,7 +314,7 @@ Explicit locks are acquired using the `Cache.lock(key)` API. |XID | UUID | Lock ID (unique identifier) |=== -== CACHE_KEY_LOCKS +== CACHE_LOCKS This view exposes information about all locks (both explicit and transactional) requested for keys hosted on the current node. This includes locks from remote nodes trying to access primary keys on this node. @@ -328,7 +328,7 @@ This includes locks from remote nodes trying to access primary keys on this node |ORIGINATING_NODE_ID | UUID | ID of the node that initiated the lock request |IS_OWNER | boolean | `True` if the lock is currently owned |IS_TX | boolean | `True` if the lock is part of a transaction -|FLAGS | string | All flags for the lock +|FLAGS | short | All flags for the lock. This field represents a bit mask with possible values: LOCAL(0x01), OWNER(0x02), READY(0x04), REENTRY(0x08), USED(0x10), TX(0x40), SINGLE_IMPLICIT(0x80), DHT_LOCAL(0x100), NEAR_LOCAL(0x200), REMOVED(0x400), READ(0x800); |XID | UUID | Current transaction ID (or explicit lock ID) |ORIGINATING_XID | UUID | Originating transaction ID (or explicit lock ID) |=== diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java index 3f989f2e6ae93..0604f506b8c4c 100755 --- a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java @@ -369,7 +369,9 @@ public void testGetAllView() throws Exception { "STATISTICS_LOCAL_DATA", "STATISTICS_GLOBAL_DATA", "SQL_PLANS_HISTORY", - "IGNITE_PLUGINS" + "IGNITE_PLUGINS", + "CACHE_EXPLICIT_LOCKS", + "CACHE_LOCKS" )); Set actViews = new TreeSet<>(); diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java index b1bd8246ff915..cf7d9137f95d3 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java @@ -955,6 +955,7 @@ public void testGetAllColumns() throws Exception { "SYS.TRANSACTIONS.LOCAL_NODE_ID.null", "SYS.TRANSACTIONS.STATE.null", "SYS.TRANSACTIONS.XID.null", + "SYS.TRANSACTIONS.ORIGINATING_XID.null", "SYS.TRANSACTIONS.LABEL.null", "SYS.TRANSACTIONS.START_TIME.null", "SYS.TRANSACTIONS.ISOLATION.null", @@ -1178,8 +1179,21 @@ public void testGetAllColumns() throws Exception { "SYS.IGNITE_PLUGINS.NAME.null", "SYS.IGNITE_PLUGINS.INFO.null", "SYS.IGNITE_PLUGINS.VERSION.null", - "SYS.IGNITE_PLUGINS.CLASS_NAME.null" - )); + "SYS.IGNITE_PLUGINS.CLASS_NAME.null", + "SYS.CACHE_EXPLICIT_LOCKS.CACHE_ID.null", + "SYS.CACHE_EXPLICIT_LOCKS.KEY.null", + "SYS.CACHE_EXPLICIT_LOCKS.THREAD_ID.null", + "SYS.CACHE_EXPLICIT_LOCKS.XID.null", + "SYS.CACHE_LOCKS.CACHE_ID.null", + "SYS.CACHE_LOCKS.KEY.null", + "SYS.CACHE_LOCKS.NODE_ID.null", + "SYS.CACHE_LOCKS.ORIGINATING_NODE_ID.null", + "SYS.CACHE_LOCKS.IS_OWNER.null", + "SYS.CACHE_LOCKS.IS_TX.null", + "SYS.CACHE_LOCKS.FLAGS.null", + "SYS.CACHE_LOCKS.XID.null", + "SYS.CACHE_LOCKS.ORIGINATING_XID.null" + )); Assert.assertEquals(expectedCols, actualSysCols); } diff --git a/modules/control-utility/src/test/java/org/apache/ignite/util/SystemViewCommandTest.java b/modules/control-utility/src/test/java/org/apache/ignite/util/SystemViewCommandTest.java index d927b361a758e..42bbfa10683c0 100644 --- a/modules/control-utility/src/test/java/org/apache/ignite/util/SystemViewCommandTest.java +++ b/modules/control-utility/src/test/java/org/apache/ignite/util/SystemViewCommandTest.java @@ -502,7 +502,9 @@ public void testViews() { "DS_QUEUES", "PAGES_TIMESTAMP_HISTOGRAM", "SQL_PLANS_HISTORY", - "IGNITE_PLUGINS" + "IGNITE_PLUGINS", + "CACHE_EXPLICIT_LOCKS", + "CACHE_LOCKS" )); Set viewNames = new TreeSet<>(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccCandidate.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccCandidate.java index 4a6e96e4b8287..d0e624f94bb0d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccCandidate.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccCandidate.java @@ -607,22 +607,6 @@ public IgniteTxKey key() { return parent0.txKey(); } - /** */ - public String enabledFlags() { - SB sb = new SB(); - - for (Mask m : Mask.MASKS) { - if (m.bit(flags) != 0) { - if (sb.length() != 0) - sb.a(" | "); - - sb.a(m.name()); - } - } - - return sb.toString(); - } - /** {@inheritDoc} */ @Override public GridCacheMvccCandidate candidate(int idx) { assert idx == 0 : idx; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccManager.java index be2dc5bba5240..b7fd59015f261 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccManager.java @@ -51,7 +51,7 @@ import org.apache.ignite.internal.processors.cache.transactions.IgniteTxKey; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.systemview.CacheExplicitLockViewWalker; -import org.apache.ignite.internal.systemview.CacheKeyLockViewWalker; +import org.apache.ignite.internal.systemview.CacheLockViewWalker; import org.apache.ignite.internal.util.GridBoundedConcurrentLinkedHashSet; import org.apache.ignite.internal.util.GridConcurrentFactory; import org.apache.ignite.internal.util.GridConcurrentHashSet; @@ -71,7 +71,7 @@ import org.apache.ignite.lang.IgnitePredicate; import org.apache.ignite.lang.IgniteUuid; import org.apache.ignite.spi.systemview.view.CacheExplicitLockView; -import org.apache.ignite.spi.systemview.view.CacheKeyLockView; +import org.apache.ignite.spi.systemview.view.CacheLockView; import org.apache.ignite.util.deque.FastSizeDeque; import org.jetbrains.annotations.Nullable; @@ -106,10 +106,10 @@ public class GridCacheMvccManager extends GridCacheSharedManagerAdapter { public static final String CACHE_EXPLICIT_LOCKS_VIEW_DESC = "Explicit locks on cache keys"; /** System view name for cache locks. */ - public static final String CACHE_KEY_LOCKS_VIEW = "cacheKeyLocks"; + public static final String CACHE_LOCKS_VIEW = "cacheLocks"; /** System view description for cache keys locks. */ - public static final String CACHE_KEY_LOCKS_VIEW_DESC = "Held and queued locks on cache keys"; + public static final String CACHE_LOCKS_VIEW_DESC = "Held and queued locks on cache keys"; /** Pending locks per thread. */ private final ThreadLocal> pending = new ThreadLocal<>(); @@ -310,9 +310,9 @@ else if (log.isDebugEnabled()) ); cctx.kernalContext().systemView().registerInnerCollectionView( - CACHE_KEY_LOCKS_VIEW, - CACHE_KEY_LOCKS_VIEW_DESC, - new CacheKeyLockViewWalker(), + CACHE_LOCKS_VIEW, + CACHE_LOCKS_VIEW_DESC, + new CacheLockViewWalker(), locked.values(), entry -> { entry.lockEntry(); @@ -324,7 +324,7 @@ else if (log.isDebugEnabled()) entry.unlockEntry(); } }, - (entry, cand) -> new CacheKeyLockView(cand) + (entry, cand) -> new CacheLockView(cand) ); } diff --git a/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CacheKeyLockView.java b/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CacheLockView.java similarity index 94% rename from modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CacheKeyLockView.java rename to modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CacheLockView.java index 4209b038da582..dbee3e2e34a9c 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CacheKeyLockView.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CacheLockView.java @@ -30,14 +30,14 @@ * including explicit locks and transactional locks. */ @SystemViewDescriptor -public class CacheKeyLockView { +public class CacheLockView { /** Lock candidate. */ private final GridCacheMvccCandidate cand; /** * @param cand Lock candidate */ - public CacheKeyLockView(GridCacheMvccCandidate cand) { + public CacheLockView(GridCacheMvccCandidate cand) { this.cand = cand; } @@ -93,8 +93,8 @@ public boolean isTx() { * @return All enabled flags. */ @Order(6) - public String flags() { - return cand.enabledFlags(); + public short flags() { + return cand.flags(); } /** diff --git a/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewLocksTest.java b/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewLocksTest.java index 8830dbb36c21d..8d5f34dcdda7f 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewLocksTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewLocksTest.java @@ -26,7 +26,7 @@ import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.spi.systemview.view.CacheExplicitLockView; -import org.apache.ignite.spi.systemview.view.CacheKeyLockView; +import org.apache.ignite.spi.systemview.view.CacheLockView; import org.apache.ignite.spi.systemview.view.SystemView; import org.apache.ignite.spi.systemview.view.TransactionView; import org.apache.ignite.testframework.GridTestUtils; @@ -36,7 +36,7 @@ import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL; import static org.apache.ignite.cache.CacheMode.PARTITIONED; import static org.apache.ignite.internal.processors.cache.GridCacheMvccManager.CACHE_EXPLICIT_LOCKS_VIEW; -import static org.apache.ignite.internal.processors.cache.GridCacheMvccManager.CACHE_KEY_LOCKS_VIEW; +import static org.apache.ignite.internal.processors.cache.GridCacheMvccManager.CACHE_LOCKS_VIEW; import static org.apache.ignite.internal.processors.cache.transactions.IgniteTxManager.TXS_MON_LIST; import static org.apache.ignite.testframework.GridTestUtils.waitForCondition; import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC; @@ -106,9 +106,9 @@ public void testExplicitLocks() throws Exception { List explicitLocks1 = viewContent(ignite1, CACHE_EXPLICIT_LOCKS_VIEW, 2); List explicitLocks2 = viewContent(ignite2, CACHE_EXPLICIT_LOCKS_VIEW, 2); - List keyLocks0 = viewContent(ignite0, CACHE_KEY_LOCKS_VIEW, 3); - List keyLocks1 = viewContent(ignite1, CACHE_KEY_LOCKS_VIEW, 2); - List keyLocks2 = viewContent(ignite2, CACHE_KEY_LOCKS_VIEW, 1); + List keyLocks0 = viewContent(ignite0, CACHE_LOCKS_VIEW, 3); + List keyLocks1 = viewContent(ignite1, CACHE_LOCKS_VIEW, 2); + List keyLocks2 = viewContent(ignite2, CACHE_LOCKS_VIEW, 1); // Check threads. assertEquals(explicitLocks0.get(0).threadId(), explicitLocks0.get(1).threadId()); @@ -116,9 +116,9 @@ public void testExplicitLocks() throws Exception { assertNotSame(explicitLocks2.get(0).threadId(), explicitLocks2.get(1).threadId()); // Check lock owners. - CacheKeyLockView owner0 = F.find(keyLocks0, null, CacheKeyLockView::isOwner); - CacheKeyLockView owner1 = F.find(keyLocks1, null, CacheKeyLockView::isOwner); - CacheKeyLockView owner2 = F.find(keyLocks2, null, CacheKeyLockView::isOwner); + CacheLockView owner0 = F.find(keyLocks0, null, CacheLockView::isOwner); + CacheLockView owner1 = F.find(keyLocks1, null, CacheLockView::isOwner); + CacheLockView owner2 = F.find(keyLocks2, null, CacheLockView::isOwner); assertNotNull(owner0); assertNotNull(owner1); @@ -194,14 +194,14 @@ public void testTxLocks() throws Exception { List txs1 = viewContent(ignite1, TXS_MON_LIST, 3); // 1 near + 2 dht List txs2 = viewContent(ignite2, TXS_MON_LIST, 3); // 2 near + 1 dht - List keyLocks0 = viewContent(ignite0, CACHE_KEY_LOCKS_VIEW, 3); - List keyLocks1 = viewContent(ignite1, CACHE_KEY_LOCKS_VIEW, 2); - List keyLocks2 = viewContent(ignite2, CACHE_KEY_LOCKS_VIEW, 1); + List keyLocks0 = viewContent(ignite0, CACHE_LOCKS_VIEW, 3); + List keyLocks1 = viewContent(ignite1, CACHE_LOCKS_VIEW, 2); + List keyLocks2 = viewContent(ignite2, CACHE_LOCKS_VIEW, 1); // Check lock owners. - CacheKeyLockView owner0 = F.find(keyLocks0, null, CacheKeyLockView::isOwner); - CacheKeyLockView owner1 = F.find(keyLocks1, null, CacheKeyLockView::isOwner); - CacheKeyLockView owner2 = F.find(keyLocks2, null, CacheKeyLockView::isOwner); + CacheLockView owner0 = F.find(keyLocks0, null, CacheLockView::isOwner); + CacheLockView owner1 = F.find(keyLocks1, null, CacheLockView::isOwner); + CacheLockView owner2 = F.find(keyLocks2, null, CacheLockView::isOwner); assertNotNull(owner0); assertNotNull(owner1); @@ -219,11 +219,11 @@ public void testTxLocks() throws Exception { assertEquals(1, F.size(txs2, l -> l.xid().equals(owner2.xid()))); // Dht. // Check waiting locks. - CacheKeyLockView waiting1on0 = F.find(keyLocks0, null, + CacheLockView waiting1on0 = F.find(keyLocks0, null, l -> !l.isOwner() && l.originatingNodeId().equals(ignite1.localNode().id())); - CacheKeyLockView waiting2on0 = F.find(keyLocks0, null, + CacheLockView waiting2on0 = F.find(keyLocks0, null, l -> !l.isOwner() && l.originatingNodeId().equals(ignite2.localNode().id())); - CacheKeyLockView waiting2on1 = F.find(keyLocks1, null, + CacheLockView waiting2on1 = F.find(keyLocks1, null, l -> !l.isOwner() && l.originatingNodeId().equals(ignite2.localNode().id())); assertNotNull(waiting1on0); @@ -297,12 +297,12 @@ public void testMixedExplicitTxLocks() throws Exception { List txs1 = viewContent(ignite1, TXS_MON_LIST, 2); // 1 near + 1 dht List txs2 = viewContent(ignite2, TXS_MON_LIST, 2); // 1 near + 1 dht - List keyLocks1 = viewContent(ignite1, CACHE_KEY_LOCKS_VIEW, 2); - List keyLocks2 = viewContent(ignite2, CACHE_KEY_LOCKS_VIEW, 2); + List keyLocks1 = viewContent(ignite1, CACHE_LOCKS_VIEW, 2); + List keyLocks2 = viewContent(ignite2, CACHE_LOCKS_VIEW, 2); // Check lock owners. - CacheKeyLockView owner1 = F.find(keyLocks1, null, CacheKeyLockView::isOwner); - CacheKeyLockView owner2 = F.find(keyLocks2, null, CacheKeyLockView::isOwner); + CacheLockView owner1 = F.find(keyLocks1, null, CacheLockView::isOwner); + CacheLockView owner2 = F.find(keyLocks2, null, CacheLockView::isOwner); assertNotNull(owner1); assertNotNull(owner2); @@ -315,9 +315,9 @@ public void testMixedExplicitTxLocks() throws Exception { assertEquals(1, F.size(txs2, l -> l.xid().equals(owner2.xid()))); // Dht. // Check waiting locks. - CacheKeyLockView waiting2on1 = F.find(keyLocks1, null, + CacheLockView waiting2on1 = F.find(keyLocks1, null, l -> !l.isOwner() && l.originatingNodeId().equals(ignite2.localNode().id())); - CacheKeyLockView waiting2on2 = F.find(keyLocks2, null, + CacheLockView waiting2on2 = F.find(keyLocks2, null, l -> !l.isOwner() && l.originatingNodeId().equals(ignite2.localNode().id())); assertNotNull(waiting2on1); diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/metric/SqlViewExporterSpiTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/metric/SqlViewExporterSpiTest.java index 15a512dbaab88..e98770d4a5bb1 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/metric/SqlViewExporterSpiTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/metric/SqlViewExporterSpiTest.java @@ -465,7 +465,9 @@ public void testViews() { "DS_QUEUES", "PAGES_TIMESTAMP_HISTOGRAM", "SQL_PLANS_HISTORY", - "IGNITE_PLUGINS" + "IGNITE_PLUGINS", + "CACHE_LOCKS", + "CACHE_EXPLICIT_LOCKS" )); Set actViews = new TreeSet<>(); diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSystemViewsSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSystemViewsSelfTest.java index 1c7b4457f467a..87f000f273822 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSystemViewsSelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSystemViewsSelfTest.java @@ -1918,7 +1918,7 @@ public void testLocksView() throws Exception { // Join explicit locks with key locks. List> res = execSql("SELECT el.cache_id, el.thread_id, kl.is_owner, kl.is_tx, kl.originating_node_id " + - "FROM SYS.CACHE_EXPLICIT_LOCKS el JOIN SYS.CACHE_KEY_LOCKS kl ON el.xid = kl.xid"); + "FROM SYS.CACHE_EXPLICIT_LOCKS el JOIN SYS.CACHE_LOCKS kl ON el.xid = kl.xid"); assertEquals(2, res.size()); @@ -1932,7 +1932,7 @@ public void testLocksView() throws Exception { // Join transactions with key locks. res = execSql("SELECT kl.cache_id, tx.thread_id, kl.is_owner, kl.is_tx, kl.originating_node_id " + - "FROM SYS.TRANSACTIONS tx JOIN SYS.CACHE_KEY_LOCKS kl ON tx.xid = kl.xid"); + "FROM SYS.TRANSACTIONS tx JOIN SYS.CACHE_LOCKS kl ON tx.xid = kl.xid"); assertEquals(1, res.size());