From b457b03798b067ebbd1fb3093b6d149b0b7f3b8d Mon Sep 17 00:00:00 2001 From: antkr Date: Mon, 3 Jun 2019 14:59:25 +0300 Subject: [PATCH 01/62] GG-14719 jackson dependency upgraded to 2.9.9 (cherry picked from commit b5f3f72) --- parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parent/pom.xml b/parent/pom.xml index 137fe4645f991..b81b251ca7d1a 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -74,7 +74,7 @@ 1.2 4.5.1 4.4.3 - 2.9.6 + 2.9.9 1.9.13 3.20.0-GA 1.0.0_1 From 53899a00bc8685f996f194573c061d7c2ab9c90a Mon Sep 17 00:00:00 2001 From: antkr Date: Mon, 3 Jun 2019 14:57:33 +0300 Subject: [PATCH 02/62] GG-14930 Upgraded Jetty dependency to 9.4.18 (cherry picked from commit 7883609) --- .../http/jetty/GridJettyRestProtocol.java | 20 ++++++++++--------- parent/pom.xml | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestProtocol.java b/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestProtocol.java index d136eb590c558..c35457650425e 100644 --- a/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestProtocol.java +++ b/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestProtocol.java @@ -19,6 +19,7 @@ import java.io.FileNotFoundException; import java.io.IOException; +import java.net.BindException; import java.net.InetAddress; import java.net.SocketException; import java.net.URL; @@ -32,6 +33,7 @@ import org.apache.ignite.internal.processors.rest.protocols.GridRestProtocolAdapter; import org.apache.ignite.internal.util.typedef.C1; import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.internal.util.typedef.X; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.spi.IgniteSpiException; @@ -230,14 +232,6 @@ private boolean startJetty() throws IgniteCheckedException { return false; } - catch (SocketException ignore) { - if (log.isDebugEnabled()) - log.debug("Failed to bind HTTP server to configured port."); - - stopJetty(); - - return false; - } catch (MultiException e) { if (log.isDebugEnabled()) log.debug("Caught multi exception: " + e); @@ -254,7 +248,15 @@ private boolean startJetty() throws IgniteCheckedException { return false; } catch (Exception e) { - throw new IgniteCheckedException("Failed to start Jetty HTTP server.", e); + if (X.hasCause(e, BindException.class)) { + if (log.isDebugEnabled()) + log.debug("Failed to bind HTTP server to configured port."); + + stopJetty(); + + return false; + } else + throw new IgniteCheckedException("Failed to start Jetty HTTP server.", e); } } diff --git a/parent/pom.xml b/parent/pom.xml index b81b251ca7d1a..e31cd470c76e7 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -81,7 +81,7 @@ 1.0.1 1.0.0 16.0.3 - 9.4.11.v20180605 + 9.4.18.v20190429 1.13 1.1.1 0.1.53_1 From 422e6ceacedd51c0344ce330f1ab6f6c71a7774b Mon Sep 17 00:00:00 2001 From: antkr Date: Mon, 3 Jun 2019 14:55:43 +0300 Subject: [PATCH 03/62] GG-19121 commons-codec dependency upgraded to 1.12 (cherry picked from commit 7043f6c) --- parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parent/pom.xml b/parent/pom.xml index e31cd470c76e7..ba763b3232229 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -56,7 +56,7 @@ 2.22.0 1.9.2_1 1.9.3 - 1.11 + 1.12 3.2.2 2.6 2.2.5 From e33a69a1a4c2839850dd8d8e71126f5fa8359bcd Mon Sep 17 00:00:00 2001 From: Anton Kalashnikov Date: Tue, 2 Jul 2019 11:53:31 +0300 Subject: [PATCH 04/62] GG-20558 Recovery mode for page memory used only for binary restore --- .../persistence/GridCacheDatabaseSharedManager.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java index a566ae90b53eb..48c7cbf4f0465 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java @@ -2379,7 +2379,7 @@ private WALPointer performBinaryMemoryRestore( stripedApplyPage((pageMem) -> { try { - applyPageDelta(pageMem, pageDelta); + applyPageDelta(pageMem, pageDelta, true); applied.incrementAndGet(); } @@ -2575,24 +2575,25 @@ public void applyPageSnapshot(PageMemoryEx pageMem, PageSnapshot pageSnapshotRec /** * @param pageMem Page memory. * @param pageDeltaRecord Page delta record. + * @param restore Get page for restore. * @throws IgniteCheckedException If failed. */ - private void applyPageDelta(PageMemoryEx pageMem, PageDeltaRecord pageDeltaRecord) throws IgniteCheckedException { + private void applyPageDelta(PageMemoryEx pageMem, PageDeltaRecord pageDeltaRecord, boolean restore) throws IgniteCheckedException { int grpId = pageDeltaRecord.groupId(); long pageId = pageDeltaRecord.pageId(); // Here we do not require tag check because we may be applying memory changes after // several repetitive restarts and the same pages may have changed several times. - long page = pageMem.acquirePage(grpId, pageId, IoStatisticsHolderNoOp.INSTANCE, true); + long page = pageMem.acquirePage(grpId, pageId, IoStatisticsHolderNoOp.INSTANCE, restore); try { - long pageAddr = pageMem.writeLock(grpId, pageId, page, true); + long pageAddr = pageMem.writeLock(grpId, pageId, page, restore); try { pageDeltaRecord.applyDelta(pageMem, pageAddr); } finally { - pageMem.writeUnlock(grpId, pageId, page, null, true, true); + pageMem.writeUnlock(grpId, pageId, page, null, true, restore); } } finally { @@ -2840,7 +2841,7 @@ private RestoreLogicalState applyLogicalUpdates( stripedApplyPage((pageMem) -> { try { - applyPageDelta(pageMem, pageDelta); + applyPageDelta(pageMem, pageDelta, false); } catch (IgniteCheckedException e) { U.error(log, "Failed to apply page delta, " + pageDelta); From 859c40990c5453c1d469b836a1d83cb943358190 Mon Sep 17 00:00:00 2001 From: Anton Kalashnikov Date: Tue, 2 Jul 2019 12:45:24 +0300 Subject: [PATCH 05/62] GG-20536 Holding exception at the record reading until next call of iterator --- .../wal/AbstractWalRecordsIterator.java | 15 ++++++++++++++- .../IgniteAbstractWalIteratorInvalidCrcTest.java | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/AbstractWalRecordsIterator.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/AbstractWalRecordsIterator.java index 8a38f28e607ed..298a5b59e09a3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/AbstractWalRecordsIterator.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/AbstractWalRecordsIterator.java @@ -60,6 +60,11 @@ public abstract class AbstractWalRecordsIterator */ protected IgniteBiTuple curRec; + /** + * The exception which can be thrown during reading next record. It holds until the next calling of next record. + */ + private IgniteCheckedException curException; + /** * Current WAL segment absolute index.
Determined as lowest number of file at start, is changed during advance * segment @@ -118,9 +123,17 @@ protected AbstractWalRecordsIterator( /** {@inheritDoc} */ @Override protected IgniteBiTuple onNext() throws IgniteCheckedException { + if (curException != null) + throw curException; + IgniteBiTuple ret = curRec; - advance(); + try { + advance(); + } + catch (IgniteCheckedException e) { + curException = e; + } return ret; } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/crc/IgniteAbstractWalIteratorInvalidCrcTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/crc/IgniteAbstractWalIteratorInvalidCrcTest.java index 98d89308930c0..7915565165a64 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/crc/IgniteAbstractWalIteratorInvalidCrcTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/crc/IgniteAbstractWalIteratorInvalidCrcTest.java @@ -229,7 +229,7 @@ protected void doTest( // WAL iterator advances to the next record and only then returns current one, // so next record has to be valid as well. - assertEquals(lastReadPtr.next(), beforeCorruptedPtr); + assertEquals(lastReadPtr, beforeCorruptedPtr); } else try (WALIterator iter = getWalIterator(walMgr, ignoreArchiveDir)) { From c41982f25d2f35401528bb12c955c92e484460c6 Mon Sep 17 00:00:00 2001 From: Andrey Kalinin Date: Fri, 14 Jun 2019 13:06:04 +0300 Subject: [PATCH 06/62] GG-14970 IdleVerify command should print end time of execution. (cherry picked from commit 1a0fd3e8c1933dfc067eb875a8f75e0f025257e8) --- .../ignite/internal/commandline/CommandHandler.java | 12 +++++++++++- .../apache/ignite/util/GridCommandHandlerTest.java | 12 ++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java index 152fee0b16478..7ae90d31864bc 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java @@ -18,6 +18,7 @@ package org.apache.ignite.internal.commandline; import java.io.File; +import java.time.Duration; import java.time.LocalDateTime; import java.util.Arrays; import java.util.Collections; @@ -205,12 +206,14 @@ public CommandHandler(Logger logger) { * @return Exit code. */ public int execute(List rawArgs) { + LocalDateTime startTime = LocalDateTime.now(); + Thread.currentThread().setName("session=" + ses); logger.info("Control utility [ver. " + ACK_VER_STR + "]"); logger.info(COPYRIGHT); logger.info("User: " + System.getProperty("user.name")); - logger.info("Time: " + LocalDateTime.now()); + logger.info("Time: " + startTime); String commandName = ""; @@ -312,6 +315,13 @@ public int execute(List rawArgs) { return EXIT_CODE_UNEXPECTED_ERROR; } finally { + LocalDateTime endTime = LocalDateTime.now(); + + Duration diff = Duration.between(startTime, endTime); + + logger.info("Control utility has completed execution at: " + endTime); + logger.info("Execution time: " + diff.toMillis() + " ms"); + Arrays.stream(logger.getHandlers()) .filter(handler -> handler instanceof FileHandler) .forEach(Handler::close); diff --git a/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java b/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java index d5801bcd3399b..089943f377c17 100644 --- a/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java +++ b/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java @@ -1123,6 +1123,18 @@ public void testHelp() { assertNotContains(log, testOutStr, "Control.sh"); } + /** */ + @Test + public void testPrintTimestampAtEndsOfExecution() { + injectTestSystemOut(); + + assertEquals(EXIT_CODE_OK, execute()); + + String testOutStr = testOut.toString(); + + assertContains(log, testOutStr, "Control utility has completed execution at: "); + } + /** * @throws Exception If failed. */ From 7719fe9c6cd586ab22403dd76b5933d163eefc25 Mon Sep 17 00:00:00 2001 From: Dmitriy Govorukhin Date: Wed, 3 Jul 2019 11:31:58 +0300 Subject: [PATCH 07/62] GG-20761 [GG-20749] remove migration pendingTree compatibility test for 2.1 pds --- .../PdsWithTtlCompatibilityTest.java | 195 ------------------ .../IgniteCompatibilityBasicTestSuite.java | 3 - 2 files changed, 198 deletions(-) diff --git a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/PdsWithTtlCompatibilityTest.java b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/PdsWithTtlCompatibilityTest.java index 946caddb5f203..e69de29bb2d1d 100644 --- a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/PdsWithTtlCompatibilityTest.java +++ b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/PdsWithTtlCompatibilityTest.java @@ -1,195 +0,0 @@ -/* - * 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.compatibility; - -import java.util.Collection; -import java.util.concurrent.TimeUnit; -import javax.cache.Cache; -import javax.cache.expiry.AccessedExpiryPolicy; -import javax.cache.expiry.Duration; -import org.apache.ignite.Ignite; -import org.apache.ignite.IgniteCache; -import org.apache.ignite.cache.CacheAtomicityMode; -import org.apache.ignite.cache.CacheWriteSynchronizationMode; -import org.apache.ignite.compatibility.persistence.IgnitePersistenceCompatibilityAbstractTest; -import org.apache.ignite.configuration.CacheConfiguration; -import org.apache.ignite.configuration.DataRegionConfiguration; -import org.apache.ignite.configuration.DataStorageConfiguration; -import org.apache.ignite.configuration.IgniteConfiguration; -import org.apache.ignite.configuration.MemoryConfiguration; -import org.apache.ignite.configuration.PersistentStoreConfiguration; -import org.apache.ignite.configuration.WALMode; -import org.apache.ignite.internal.IgniteEx; -import org.apache.ignite.internal.IgniteInterruptedCheckedException; -import org.apache.ignite.internal.processors.cache.GridCacheAbstractFullApiSelfTest; -import org.apache.ignite.internal.processors.cache.persistence.migration.UpgradePendingTreeToPerPartitionTask; -import org.apache.ignite.internal.util.typedef.PA; -import org.apache.ignite.lang.IgniteFuture; -import org.apache.ignite.lang.IgniteInClosure; -import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; -import org.apache.ignite.testframework.GridTestUtils; - -/** - * Test PendingTree upgrading to per-partition basis. Test fill cache with persistence enabled and with ExpirePolicy - * configured on ignite-2.1 version and check if entries will be correctly expired when a new version node started. - * - * Note: Test for ignite-2.3 version will always fails due to entry ttl update fails with assertion on checkpoint lock - * check. - */ -public class PdsWithTtlCompatibilityTest extends IgnitePersistenceCompatibilityAbstractTest { - /** */ - static final String TEST_CACHE_NAME = PdsWithTtlCompatibilityTest.class.getSimpleName(); - - /** */ - static final int DURATION_SEC = 10; - - /** */ - private static final int ENTRIES_CNT = 100; - - /** {@inheritDoc} */ - @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { - IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); - - cfg.setPeerClassLoadingEnabled(false); - - cfg.setDataStorageConfiguration( - new DataStorageConfiguration() - .setDefaultDataRegionConfiguration( - new DataRegionConfiguration() - .setMaxSize(32L * 1024 * 1024) - .setPersistenceEnabled(true) - .setCheckpointPageBufferSize(16L * 1024 * 1024) - ).setWalMode(WALMode.LOG_ONLY)); - - return cfg; - } - - /** - * Tests opportunity to read data from previous Ignite DB version. - * - * @throws Exception If failed. - */ - public void testNodeStartByOldVersionPersistenceData_2_1() throws Exception { - doTestStartupWithOldVersion("2.1.0"); - } - - /** - * Tests opportunity to read data from previous Ignite DB version. - * - * @param igniteVer 3-digits version of ignite - * @throws Exception If failed. - */ - protected void doTestStartupWithOldVersion(String igniteVer) throws Exception { - try { - startGrid(1, igniteVer, new ConfigurationClosure(), new PostStartupClosure()); - - stopAllGrids(); - - IgniteEx ignite = startGrid(0); - - assertEquals(1, ignite.context().discovery().topologyVersion()); - - ignite.active(true); - - validateResultingCacheData(ignite, ignite.cache(TEST_CACHE_NAME)); - } - finally { - stopAllGrids(); - } - } - - /** - * @param cache to be filled by different keys and values. Results may be validated in {@link - * #validateResultingCacheData(Ignite, IgniteCache)}. - */ - public static void saveCacheData(Cache cache) { - for (int i = 0; i < ENTRIES_CNT; i++) - cache.put(i, "data-" + i); - - //Touch - for (int i = 0; i < ENTRIES_CNT; i++) - assertNotNull(cache.get(i)); - } - - /** - * Asserts cache contained all expected values as it was saved before. - * - * @param cache cache should be filled using {@link #saveCacheData(Cache)}. - */ - public static void validateResultingCacheData(Ignite ignite, - IgniteCache cache) throws IgniteInterruptedCheckedException { - - final long expireTime = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(DURATION_SEC + 1); - - final IgniteFuture> future = ignite.compute().broadcastAsync(new UpgradePendingTreeToPerPartitionTask()); - - GridTestUtils.waitForCondition(new PA() { - @Override public boolean apply() { - return future.isDone() && expireTime < System.currentTimeMillis(); - } - }, TimeUnit.SECONDS.toMillis(DURATION_SEC + 2)); - - for (Boolean res : future.get()) - assertTrue(res); - - for (int i = 0; i < ENTRIES_CNT; i++) - assertNull(cache.get(i)); - } - - /** */ - public static class ConfigurationClosure implements IgniteInClosure { - /** {@inheritDoc} */ - @Override public void apply(IgniteConfiguration cfg) { - cfg.setLocalHost("127.0.0.1"); - - TcpDiscoverySpi disco = new TcpDiscoverySpi(); - disco.setIpFinder(GridCacheAbstractFullApiSelfTest.LOCAL_IP_FINDER); - - cfg.setDiscoverySpi(disco); - - cfg.setPeerClassLoadingEnabled(false); - - cfg.setMemoryConfiguration(new MemoryConfiguration().setDefaultMemoryPolicySize(256L * 1024 * 1024)); - cfg.setPersistentStoreConfiguration(new PersistentStoreConfiguration().setWalMode(WALMode.LOG_ONLY) - .setCheckpointingPageBufferSize(16L * 1024 * 1024)); - } - } - - /** */ - public static class PostStartupClosure implements IgniteInClosure { - /** {@inheritDoc} */ - @Override public void apply(Ignite ignite) { - ignite.active(true); - - CacheConfiguration cacheCfg = new CacheConfiguration<>(); - cacheCfg.setName(TEST_CACHE_NAME); - cacheCfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL); - cacheCfg.setBackups(1); - cacheCfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC); - cacheCfg.setExpiryPolicyFactory(AccessedExpiryPolicy.factoryOf(new Duration(TimeUnit.SECONDS, DURATION_SEC))); - cacheCfg.setEagerTtl(true); - cacheCfg.setGroupName("myGroup"); - - IgniteCache cache = ignite.createCache(cacheCfg); - - saveCacheData(cache); - - ignite.active(false); - } - } -} diff --git a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testsuites/IgniteCompatibilityBasicTestSuite.java b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testsuites/IgniteCompatibilityBasicTestSuite.java index fcfd5a7939ca4..eaa38afdd6d61 100644 --- a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testsuites/IgniteCompatibilityBasicTestSuite.java +++ b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testsuites/IgniteCompatibilityBasicTestSuite.java @@ -19,7 +19,6 @@ import junit.framework.TestSuite; import org.apache.ignite.compatibility.persistence.DummyPersistenceCompatibilityTest; -import org.apache.ignite.compatibility.PdsWithTtlCompatibilityTest; import org.apache.ignite.compatibility.persistence.FoldersReuseCompatibilityTest; import org.apache.ignite.compatibility.persistence.IgniteUuidCompatibilityTest; import org.apache.ignite.compatibility.persistence.MigratingToWalV2SerializerWithCompactionTest; @@ -37,8 +36,6 @@ public static TestSuite suite() throws Exception { suite.addTestSuite(DummyPersistenceCompatibilityTest.class); - suite.addTestSuite(PdsWithTtlCompatibilityTest.class); - suite.addTestSuite(FoldersReuseCompatibilityTest.class); suite.addTestSuite(MigratingToWalV2SerializerWithCompactionTest.class); From 5a616de590a309f2e6b209b8df176d2f25c960e9 Mon Sep 17 00:00:00 2001 From: ktkalenko Date: Wed, 3 Jul 2019 12:16:36 +0300 Subject: [PATCH 08/62] GG-20420 NullPointerException If transaction failed and failure handler doesn't configured explicitly. (cherry picked from commit c8bd480f42a3f890bf2448bec735537fbfb3574c) --- .../processors/cache/transactions/IgniteTxAdapter.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxAdapter.java index 418311edb6ed1..11772f96df2ba 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxAdapter.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxAdapter.java @@ -754,18 +754,16 @@ public final IgniteCheckedException heuristicException(Throwable ex) { public void logTxFinishErrorSafe(@Nullable IgniteLogger log, boolean commit, Throwable e) { assert e != null : "Exception is expected"; - final String fmt = "Failed completing the transaction: [commit=%s, tx=%s, plc=%s]"; + final String fmt = "Failed completing the transaction: [commit=%s, tx=%s]"; try { // First try printing a full transaction. This is error prone. - U.error(log, String.format(fmt, commit, this, - cctx.gridConfig().getFailureHandler().getClass().getSimpleName()), e); + U.error(log, String.format(fmt, commit, this), e); } catch (Throwable e0) { e.addSuppressed(e0); - U.error(log, String.format(fmt, commit, CU.txString(this), - cctx.gridConfig().getFailureHandler().getClass().getSimpleName()), e); + U.error(log, String.format(fmt, commit, CU.txString(this)), e); } } From 3b97ac7b57acc9901c4747f811d19c765371512b Mon Sep 17 00:00:00 2001 From: Sergey Chugunov Date: Wed, 3 Jul 2019 17:04:45 +0300 Subject: [PATCH 09/62] GG-20193 fix IGNITE-9858 adapted into the branch (cherry-picked from commit #fa8e5da60546bf2e46cc16b13baf0a21c394e7b6) --- .../ignite/spi/discovery/tcp/ClientImpl.java | 2 +- .../ipfinder/TcpDiscoveryIpFinderAdapter.java | 14 +- .../TcpDiscoveryMulticastIpFinder.java | 213 +++++++++--------- .../TcpClientDiscoverySpiMulticastTest.java | 8 +- 4 files changed, 125 insertions(+), 112 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java index 2141819977868..58a09223c1130 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java @@ -292,7 +292,7 @@ class ClientImpl extends TcpDiscoveryImpl { sockReader = new SocketReader(); sockReader.start(); - if (spi.ipFinder.isShared()) + if (spi.ipFinder.isShared() && spi.isForceServerMode()) registerLocalNodeAddress(); msgWorker = new MessageWorker(log); diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/TcpDiscoveryIpFinderAdapter.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/TcpDiscoveryIpFinderAdapter.java index 1cd91f63b9fae..09951048b9c7c 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/TcpDiscoveryIpFinderAdapter.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/TcpDiscoveryIpFinderAdapter.java @@ -40,7 +40,13 @@ public abstract class TcpDiscoveryIpFinderAdapter implements TcpDiscoveryIpFinde @GridToStringExclude private volatile IgniteSpiContext spiCtx; - /** Ignite instance . */ + /** + * Ignite instance. + * + * @deprecated Since 2.8. May contain an invalid Ignite instance when multiple nodes shares same + * {@link TcpDiscoveryIpFinder} instance. + */ + @Deprecated @IgniteInstanceResource @GridToStringExclude protected Ignite ignite; @@ -57,8 +63,7 @@ public abstract class TcpDiscoveryIpFinderAdapter implements TcpDiscoveryIpFinde /** {@inheritDoc} */ @Override public void initializeLocalAddresses(Collection addrs) throws IgniteSpiException { - if (!discoveryClientMode()) - registerAddresses(addrs); + registerAddresses(addrs); } /** {@inheritDoc} */ @@ -92,7 +97,10 @@ public TcpDiscoveryIpFinderAdapter setShared(boolean shared) { /** * @return {@code True} if TCP discovery works in client mode. + * @deprecated Since 2.8. May return incorrect value if client and server nodes shares same {@link + * TcpDiscoveryIpFinder} instance. */ + @Deprecated protected boolean discoveryClientMode() { boolean clientMode; diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/multicast/TcpDiscoveryMulticastIpFinder.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/multicast/TcpDiscoveryMulticastIpFinder.java index c59fa78fffbd9..f73f18a849982 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/multicast/TcpDiscoveryMulticastIpFinder.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/multicast/TcpDiscoveryMulticastIpFinder.java @@ -29,6 +29,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Set; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteLogger; @@ -126,7 +127,7 @@ public class TcpDiscoveryMulticastIpFinder extends TcpDiscoveryVmIpFinder { @GridToStringExclude private InetAddress mcastAddr; - /** */ + /** Interfaces used to send requests. */ @GridToStringExclude private Set reqItfs; @@ -308,132 +309,66 @@ public int getTimeToLive() { /** {@inheritDoc} */ @Override public void initializeLocalAddresses(Collection addrs) throws IgniteSpiException { - // If IGNITE_OVERRIDE_MCAST_GRP system property is set, use its value to override multicast group from - // configuration. Used for testing purposes. - String overrideMcastGrp = System.getProperty(IGNITE_OVERRIDE_MCAST_GRP); - - if (overrideMcastGrp != null) - mcastGrp = overrideMcastGrp; - - if (F.isEmpty(mcastGrp)) - throw new IgniteSpiException("Multicast IP address is not specified."); - - if (mcastPort < 0 || mcastPort > 65535) - throw new IgniteSpiException("Invalid multicast port: " + mcastPort); - - if (resWaitTime <= 0) - throw new IgniteSpiException("Invalid wait time, value greater than zero is expected: " + resWaitTime); - - if (addrReqAttempts <= 0) - throw new IgniteSpiException("Invalid number of address request attempts, " + - "value greater than zero is expected: " + addrReqAttempts); - - if (ttl != -1 && (ttl < 0 || ttl > 255)) - throw new IgniteSpiException("Time-to-live value is out of 0 <= TTL <= 255 range: " + ttl); - - if (F.isEmpty(getRegisteredAddresses())) + if (F.isEmpty(super.getRegisteredAddresses())) U.warn(log, "TcpDiscoveryMulticastIpFinder has no pre-configured addresses " + "(it is recommended in production to specify at least one address in " + "TcpDiscoveryMulticastIpFinder.getAddresses() configuration property)"); - boolean clientMode = discoveryClientMode(); + Collection locAddrs = resolveLocalAddresses(); - try { - mcastAddr = InetAddress.getByName(mcastGrp); - } - catch (UnknownHostException e) { - throw new IgniteSpiException("Unknown multicast group: " + mcastGrp, e); - } + addrSnds = new ArrayList<>(locAddrs.size()); - if (!mcastAddr.isMulticastAddress()) - throw new IgniteSpiException("Invalid multicast group address: " + mcastAddr); + reqItfs = new HashSet<>(U.capacity(locAddrs.size())); // Interfaces used to send requests. - Collection locAddrs; + for (InetAddress addr : locAddrs) { + try { + addrSnds.add(new AddressSender(mcastAddr, addr, addrs)); - try { - locAddrs = U.resolveLocalAddresses(U.resolveLocalHost(locAddr)).get1(); - } - catch (IOException | IgniteCheckedException e) { - throw new IgniteSpiException("Failed to resolve local addresses [locAddr=" + locAddr + ']', e); + reqItfs.add(addr); + } + catch (IOException e) { + if (log.isDebugEnabled()) + log.debug("Failed to create multicast socket [mcastAddr=" + mcastAddr + + ", mcastGrp=" + mcastGrp + ", mcastPort=" + mcastPort + ", locAddr=" + addr + + ", err=" + e + ']'); + } } - assert locAddrs != null; - - addrSnds = new ArrayList<>(locAddrs.size()); - - reqItfs = new HashSet<>(locAddrs.size()); // Interfaces used to send requests. - - for (String locAddr : locAddrs) { - InetAddress addr; + locNodeAddrs = new HashSet<>(addrs); + if (addrSnds.isEmpty()) { try { - addr = InetAddress.getByName(locAddr); + // Create non-bound socket if local host is loopback or failed to create sockets explicitly + // bound to interfaces. + addrSnds.add(new AddressSender(mcastAddr, null, addrs)); } - catch (UnknownHostException e) { + catch (IOException e) { if (log.isDebugEnabled()) - log.debug("Failed to resolve local address [locAddr=" + locAddr + ", err=" + e + ']'); - - continue; + log.debug("Failed to create multicast socket [mcastAddr=" + mcastAddr + + ", mcastGrp=" + mcastGrp + ", mcastPort=" + mcastPort + ", err=" + e + ']'); } - if (!addr.isLoopbackAddress()) { + if (addrSnds.isEmpty()) { try { - if (!clientMode) - addrSnds.add(new AddressSender(mcastAddr, addr, addrs)); + addrSnds.add(new AddressSender(mcastAddr, mcastAddr, addrs)); - reqItfs.add(addr); + reqItfs.add(mcastAddr); } catch (IOException e) { if (log.isDebugEnabled()) log.debug("Failed to create multicast socket [mcastAddr=" + mcastAddr + - ", mcastGrp=" + mcastGrp + ", mcastPort=" + mcastPort + ", locAddr=" + addr + + ", mcastGrp=" + mcastGrp + ", mcastPort=" + mcastPort + ", locAddr=" + mcastAddr + ", err=" + e + ']'); } } } - if (!clientMode) { - locNodeAddrs = new HashSet<>(addrs); - - if (addrSnds.isEmpty()) { - try { - // Create non-bound socket if local host is loopback or failed to create sockets explicitly - // bound to interfaces. - addrSnds.add(new AddressSender(mcastAddr, null, addrs)); - } - catch (IOException e) { - if (log.isDebugEnabled()) - log.debug("Failed to create multicast socket [mcastAddr=" + mcastAddr + - ", mcastGrp=" + mcastGrp + ", mcastPort=" + mcastPort + ", err=" + e + ']'); - } - - if (addrSnds.isEmpty()) { - try { - addrSnds.add(new AddressSender(mcastAddr, mcastAddr, addrs)); - - reqItfs.add(mcastAddr); - } - catch (IOException e) { - if (log.isDebugEnabled()) - log.debug("Failed to create multicast socket [mcastAddr=" + mcastAddr + - ", mcastGrp=" + mcastGrp + ", mcastPort=" + mcastPort + ", locAddr=" + mcastAddr + - ", err=" + e + ']'); - } - } - } - - if (!addrSnds.isEmpty()) { - for (AddressSender addrSnd : addrSnds) - addrSnd.start(); - } - else - mcastErr = true; - } - else { - assert addrSnds.isEmpty() : addrSnds; - - locNodeAddrs = Collections.emptySet(); + if (!addrSnds.isEmpty()) { + for (AddressSender addrSnd : addrSnds) + addrSnd.start(); } + else + mcastErr = true; } /** {@inheritDoc} */ @@ -445,6 +380,9 @@ public int getTimeToLive() { /** {@inheritDoc} */ @Override public synchronized Collection getRegisteredAddresses() { + if (mcastAddr == null) + reqItfs = new HashSet<>(resolveLocalAddresses()); + if (mcastAddr != null && reqItfs != null) { Collection ret; @@ -460,7 +398,7 @@ public int getTimeToLive() { if (ret.isEmpty()) { if (mcastErr && firstReq) { - if (getRegisteredAddresses().isEmpty()) { + if (super.getRegisteredAddresses().isEmpty()) { InetSocketAddress addr = new InetSocketAddress("localhost", TcpDiscoverySpi.DFLT_PORT); U.quietAndWarn(log, "TcpDiscoveryMulticastIpFinder failed to initialize multicast, " + @@ -482,6 +420,77 @@ public int getTimeToLive() { return super.getRegisteredAddresses(); } + /** + * Resolve local addresses. + * + * @return List of non-loopback addresses. + */ + private Collection resolveLocalAddresses() { + // If IGNITE_OVERRIDE_MCAST_GRP system property is set, use its value to override multicast group from + // configuration. Used for testing purposes. + String overrideMcastGrp = System.getProperty(IGNITE_OVERRIDE_MCAST_GRP); + + if (overrideMcastGrp != null) + mcastGrp = overrideMcastGrp; + + if (F.isEmpty(mcastGrp)) + throw new IgniteSpiException("Multicast IP address is not specified."); + + if (mcastPort < 0 || mcastPort > 65535) + throw new IgniteSpiException("Invalid multicast port: " + mcastPort); + + if (resWaitTime <= 0) + throw new IgniteSpiException("Invalid wait time, value greater than zero is expected: " + resWaitTime); + + if (addrReqAttempts <= 0) + throw new IgniteSpiException("Invalid number of address request attempts, " + + "value greater than zero is expected: " + addrReqAttempts); + + if (ttl != -1 && (ttl < 0 || ttl > 255)) + throw new IgniteSpiException("Time-to-live value is out of 0 <= TTL <= 255 range: " + ttl); + + try { + mcastAddr = InetAddress.getByName(mcastGrp); + } + catch (UnknownHostException e) { + throw new IgniteSpiException("Unknown multicast group: " + mcastGrp, e); + } + + if (!mcastAddr.isMulticastAddress()) + throw new IgniteSpiException("Invalid multicast group address: " + mcastAddr); + + Collection locAddrs; + + try { + locAddrs = U.resolveLocalAddresses(U.resolveLocalHost(locAddr)).get1(); + } + catch (IOException | IgniteCheckedException e) { + throw new IgniteSpiException("Failed to resolve local addresses [locAddr=" + locAddr + ']', e); + } + + assert locAddrs != null; + + List inetAddrs = new ArrayList<>(locAddrs.size()); + + for (String locAddr : locAddrs) { + InetAddress addr; + + try { + addr = InetAddress.getByName(locAddr); + } + catch (UnknownHostException e) { + if (log.isDebugEnabled()) + log.debug("Failed to resolve local address [locAddr=" + locAddr + ", err=" + e + ']'); + + continue; + } + + if (!addr.isLoopbackAddress()) + inetAddrs.add(addr); + } + + return inetAddrs; + } /** * @param reqItfs Interfaces used to send requests. @@ -770,7 +779,7 @@ private class AddressReceiver extends IgniteSpiThread { * @param sockAddr Optional address multicast socket should be bound to. */ private AddressReceiver(InetAddress mcastAddr, InetAddress sockAddr) { - super(ignite == null ? null : ignite.name(), "tcp-disco-multicast-addr-rcvr", log); + super(null, "tcp-disco-multicast-addr-rcvr", log); this.mcastAddr = mcastAddr; this.sockAddr = sockAddr; } @@ -814,7 +823,7 @@ private class AddressSender extends IgniteSpiThread { */ private AddressSender(InetAddress mcastGrp, @Nullable InetAddress sockItf, Collection addrs) throws IOException { - super(ignite == null ? null : ignite.name(), "tcp-disco-multicast-addr-sender", log); + super(null, "tcp-disco-multicast-addr-sender", log); this.mcastGrp = mcastGrp; this.addrs = addrs; this.sockItf = sockItf; diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoverySpiMulticastTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoverySpiMulticastTest.java index e19b121aebdb7..17664444d5649 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoverySpiMulticastTest.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoverySpiMulticastTest.java @@ -24,6 +24,7 @@ import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.events.Event; 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.lang.IgnitePredicate; import org.apache.ignite.spi.discovery.DiscoverySpi; @@ -211,11 +212,6 @@ private void assertSpi(Ignite ignite, boolean client) { Collection addrSnds = GridTestUtils.getFieldValue(spi0.getIpFinder(), "addrSnds"); - assertNotNull(addrSnds); - - if (client) - assertTrue(addrSnds.isEmpty()); // Check client does not send its address. - else - assertFalse(addrSnds.isEmpty()); + assertEquals(client, F.isEmpty(addrSnds)); } } \ No newline at end of file From 58510ca8c307eb8ce12c6896d3b027384d4aaa7f Mon Sep 17 00:00:00 2001 From: Aleksei Scherbakov Date: Wed, 3 Jul 2019 17:34:36 +0300 Subject: [PATCH 10/62] GG-20702 Fix invalid partition clearing. (cherry picked from commit cafab0ded6fb5b6632826fe1b71d6fdde5a97823) # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java # modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsCacheWalDisabledOnRebalancingTest.java --- .../GridDhtPartitionsExchangeFuture.java | 14 +- .../dht/topology/GridDhtLocalPartition.java | 2 + .../GridDhtPartitionTopologyImpl.java | 86 +++++----- .../dht/topology/PartitionsEvictManager.java | 2 +- ...ePdsCacheWalDisabledOnRebalancingTest.java | 148 ++++++++++++++++-- .../junits/common/GridCommonAbstractTest.java | 5 +- 6 files changed, 203 insertions(+), 54 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java index 5f3188fc3145a..1fb6702e036f1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java @@ -198,6 +198,9 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte /** */ private AtomicBoolean added = new AtomicBoolean(false); + /** Exchange type. */ + private volatile ExchangeType exchangeType; + /** * Discovery event receive latch. There is a race between discovery event processing and single message * processing, so it is possible to create an exchange future before the actual discovery event is received. @@ -478,6 +481,13 @@ public void affinityChangeMessage(CacheAffinityChangeMessage affChangeMsg) { return isDone() ? result() : exchCtx.events().topologyVersion(); } + /** + * @return Exchange type or null if not determined yet. + */ + public ExchangeType exchangeType() { + return exchangeType; + } + /** * Retreives the node which has WAL history since {@code cntrSince}. * @@ -843,6 +853,8 @@ else if (msg instanceof WalStateAbstractMessage) cctx.cache().registrateProxyRestart(resolveCacheRequests(exchActions), afterLsnrCompleteFut); + exchangeType = exchange; + for (PartitionsExchangeAware comp : cctx.exchange().exchangeAwareComponents()) comp.onInitBeforeTopologyLock(this); @@ -5067,7 +5079,7 @@ public void cleanUp() { /** * */ - enum ExchangeType { + public enum ExchangeType { /** */ CLIENT, diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtLocalPartition.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtLocalPartition.java index 354a7851a61b1..39d457bb94257 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtLocalPartition.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtLocalPartition.java @@ -588,6 +588,8 @@ private boolean casState(long state, GridDhtPartitionState toState) { */ public boolean own() { while (true) { + assert !clear : "Could not own clearing partition " + this; + long state = this.state.get(); GridDhtPartitionState partState = getPartState(state); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java index d51f053597857..e9588a8de0c54 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java @@ -75,6 +75,7 @@ import static org.apache.ignite.events.EventType.EVT_CACHE_REBALANCE_PART_DATA_LOST; import static org.apache.ignite.internal.events.DiscoveryCustomEvent.EVT_DISCOVERY_CUSTOM_EVT; +import static org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionsExchangeFuture.ExchangeType.ALL; import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState.EVICTED; import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState.LOST; import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState.MOVING; @@ -764,58 +765,61 @@ private boolean partitionLocalNode(int p, AffinityTopologyVersion topVer) { long updateSeq = this.updateSeq.incrementAndGet(); - for (int p = 0; p < partitions; p++) { - GridDhtLocalPartition locPart = localPartition0(p, topVer, false, true); + // Skip partition updates in case of not real exchange. + if (!ctx.localNode().isClient() && exchFut.exchangeType() == ALL) { + for (int p = 0; p < partitions; p++) { + GridDhtLocalPartition locPart = localPartition0(p, topVer, false, true); - if (partitionLocalNode(p, topVer)) { - // Prepare partition to rebalance if it's not happened on full map update phase. - if (locPart == null || locPart.state() == RENTING || locPart.state() == EVICTED) - locPart = rebalancePartition(p, true, exchFut); + if (partitionLocalNode(p, topVer)) { + // Prepare partition to rebalance if it's not happened on full map update phase. + if (locPart == null || locPart.state() == RENTING || locPart.state() == EVICTED) + locPart = rebalancePartition(p, true, exchFut); - GridDhtPartitionState state = locPart.state(); + GridDhtPartitionState state = locPart.state(); - if (state == MOVING) { - if (grp.rebalanceEnabled()) { - Collection owners = owners(p); + if (state == MOVING) { + if (grp.rebalanceEnabled()) { + Collection owners = owners(p); + + // If an owner node left during exchange, then new exchange should be started with detecting lost partitions. + if (!F.isEmpty(owners)) { + if (log.isDebugEnabled()) + log.debug("Will not own partition (there are owners to rebalance from) " + + "[grp=" + grp.cacheOrGroupName() + ", p=" + p + ", owners = " + owners + ']'); + } - // If an owner node left during exchange, then new exchange should be started with detecting lost partitions. - if (!F.isEmpty(owners)) { - if (log.isDebugEnabled()) - log.debug("Will not own partition (there are owners to rebalance from) " + - "[grp=" + grp.cacheOrGroupName() + ", p=" + p + ", owners = " + owners + ']'); + // It's important to clear non empty moving partitions before full rebalancing. + // Consider the scenario: + // Node1 has keys k1 and k2 in the same partition. + // Node2 started rebalancing from Node1. + // Node2 received k1, k2 and failed before moving partition to OWNING state. + // Node1 removes k2 but update has not been delivered to Node1 because of failure. + // After new full rebalance Node1 will only send k1 to Node2 causing lost removal. + // NOTE: avoid calling clearAsync for partition twice per topology version. + // TODO FIXME clearing is not always needed see IGNITE-11799 + if (grp.persistenceEnabled() && !exchFut.isHistoryPartition(grp, locPart.id()) && + !locPart.isClearing() && !locPart.isEmpty()) + locPart.clearAsync(); } - - // It's important to clear non empty moving partitions before full rebalancing. - // Consider the scenario: - // Node1 has keys k1 and k2 in the same partition. - // Node2 started rebalancing from Node1. - // Node2 received k1, k2 and failed before moving partition to OWNING state. - // Node1 removes k2 but update has not been delivered to Node1 because of failure. - // After new full rebalance Node1 will only send k1 to Node2 causing lost removal. - // NOTE: avoid calling clearAsync for partition twice per topology version. - // TODO FIXME clearing is not always needed see IGNITE-11799 - if (grp.persistenceEnabled() && !exchFut.isHistoryPartition(grp, locPart.id()) && - !locPart.isClearing() && !locPart.isEmpty()) - locPart.clearAsync(); + else + updateSeq = updateLocal(p, locPart.state(), updateSeq, topVer); } - else - updateSeq = updateLocal(p, locPart.state(), updateSeq, topVer); } - } - else { - if (locPart != null) { - GridDhtPartitionState state = locPart.state(); + else { + if (locPart != null) { + GridDhtPartitionState state = locPart.state(); - if (state == MOVING) { - locPart.rent(false); + if (state == MOVING) { + locPart.rent(false); - updateSeq = updateLocal(p, locPart.state(), updateSeq, topVer); + updateSeq = updateLocal(p, locPart.state(), updateSeq, topVer); - changed = true; + changed = true; - if (log.isDebugEnabled()) { - log.debug("Evicting " + state + " partition (it does not belong to affinity) [" + - "grp=" + grp.cacheOrGroupName() + ", p=" + locPart.id() + ']'); + if (log.isDebugEnabled()) { + log.debug("Evicting " + state + " partition (it does not belong to affinity) [" + + "grp=" + grp.cacheOrGroupName() + ", p=" + locPart.id() + ']'); + } } } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/PartitionsEvictManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/PartitionsEvictManager.java index 826902cee1a87..704c7db3887f7 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/PartitionsEvictManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/PartitionsEvictManager.java @@ -369,7 +369,7 @@ private void showProgress() { ", grpId=" + grp.groupId() + ", remainingPartsToEvict=" + (totalTasks.get() - taskInProgress) + ", partsEvictInProgress=" + taskInProgress + - ", totalParts= " + grp.topology().localPartitions().size() + "]"); + ", totalParts=" + grp.topology().localPartitions().size() + "]"); } } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsCacheWalDisabledOnRebalancingTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsCacheWalDisabledOnRebalancingTest.java index 1246db1090cae..6be608c78279a 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsCacheWalDisabledOnRebalancingTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsCacheWalDisabledOnRebalancingTest.java @@ -17,14 +17,19 @@ package org.apache.ignite.internal.processors.cache.persistence.db; import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; import java.nio.file.Files; +import java.nio.file.OpenOption; import java.nio.file.Paths; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.Semaphore; +import java.util.function.BiFunction; import org.apache.ignite.Ignite; -import org.apache.ignite.IgniteCache; +import org.apache.ignite.IgniteDataStreamer; import org.apache.ignite.IgniteSystemProperties; import org.apache.ignite.cache.CacheAtomicityMode; import org.apache.ignite.cache.CacheMode; @@ -38,6 +43,10 @@ import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.TestRecordingCommunicationSpi; import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionDemandMessage; +import org.apache.ignite.internal.processors.cache.persistence.file.FileIO; +import org.apache.ignite.internal.processors.cache.persistence.file.FileIODecorator; +import org.apache.ignite.internal.processors.cache.persistence.file.FileIOFactory; +import org.apache.ignite.internal.processors.cache.persistence.file.RandomAccessFileIOFactory; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteBiPredicate; import org.apache.ignite.mxbean.CacheGroupMetricsMXBean; @@ -70,6 +79,15 @@ public class IgnitePdsCacheWalDisabledOnRebalancingTest extends GridCommonAbstra /** */ private static final String CACHE3_NAME = "cache3"; + /** Function to generate cache values. */ + private static final BiFunction GENERATING_FUNC = (s, i) -> s + "_value_" + i; + + /** */ + private static final Semaphore fileIoBlockingSemaphore = new Semaphore(Integer.MAX_VALUE); + + /** */ + private boolean useBlockingFileIO; + /** {@inheritDoc} */ @Override protected void beforeTest() throws Exception { super.beforeTest(); @@ -122,6 +140,9 @@ public class IgnitePdsCacheWalDisabledOnRebalancingTest extends GridCommonAbstra .setPersistenceEnabled(true) .setMaxSize(256 * 1024 * 1024)); + if (useBlockingFileIO) + dsCfg.setFileIOFactory(new BlockingCheckpointFileIOFactory()); + cfg.setDataStorageConfiguration(dsCfg); } @@ -143,8 +164,8 @@ public void testClientJoinsLeavesDuringRebalancing() throws Exception { ig0.active(true); - for (int i = 0; i < 3; i++) - fillCache(ig0.getOrCreateCache("cache" + i), CACHE_SIZE); + for (int i = 1; i < 4; i++) + fillCache(ig0.dataStreamer("cache" + i), CACHE_SIZE, GENERATING_FUNC); String ig1Name = "node01-" + grid(1).localNode().consistentId(); @@ -188,7 +209,7 @@ public void testClientJoinsLeavesDuringRebalancing() throws Exception { /** * If server nodes from BLT leave topology and then join again after additional keys were put to caches, * rebalance starts. - * + * * Test verifies that all moving partitions get owned after rebalance finishes. * * @throws Exception If failed. @@ -196,7 +217,7 @@ public void testClientJoinsLeavesDuringRebalancing() throws Exception { public void testServerNodesFromBltLeavesAndJoinsDuringRebalancing() throws Exception { Ignite ig0 = startGridsMultiThreaded(4); - fillCache(ig0.cache(CACHE3_NAME), CACHE_SIZE); + fillCache(ig0.dataStreamer(CACHE3_NAME), CACHE_SIZE, GENERATING_FUNC); List nonAffinityKeys1 = nearKeys(grid(1).cache(CACHE3_NAME), 100, CACHE_SIZE / 2); List nonAffinityKeys2 = nearKeys(grid(2).cache(CACHE3_NAME), 100, CACHE_SIZE / 2); @@ -209,7 +230,7 @@ public void testServerNodesFromBltLeavesAndJoinsDuringRebalancing() throws Excep nonAffinityKeysSet.addAll(nonAffinityKeys1); nonAffinityKeysSet.addAll(nonAffinityKeys2); - fillCache(ig0.cache(CACHE3_NAME), nonAffinityKeysSet); + fillCache(ig0.dataStreamer(CACHE3_NAME), nonAffinityKeysSet, GENERATING_FUNC); int groupId = ((IgniteEx) ig0).cachex(CACHE3_NAME).context().groupId(); @@ -238,6 +259,97 @@ public void testServerNodesFromBltLeavesAndJoinsDuringRebalancing() throws Excep " partitions in MOVING state", allOwned); } + /** + * Scenario: when rebalanced MOVING partitions are owning by checkpointer, + * concurrent no-op exchange should not trigger partition clearing. + * + * @throws Exception If failed. + */ + public void testRebalancedPartitionsOwningWithAffinitySwitch() throws Exception { + Ignite ig0 = startGridsMultiThreaded(4); + fillCache(ig0.dataStreamer(CACHE3_NAME), CACHE_SIZE, GENERATING_FUNC); + + // Stop idx=2 to prepare for baseline topology change later. + stopGrid(2); + + // Stop idx=1 and cleanup LFS to trigger full rebalancing after it restart. + String ig1Name = "node01-" + grid(1).localNode().consistentId(); + stopGrid(1); + cleanPersistenceFiles(ig1Name); + + // Blocking fileIO and blockMessagePredicate to block checkpointer and rebalancing for node idx=1. + useBlockingFileIO = true; + + // Enable blocking checkpointer on node idx=1 (see BlockingCheckpointFileIOFactory). + fileIoBlockingSemaphore.drainPermits(); + + // Wait for rebalance (all partitions will be in MOVING state until cp is finished). + startGrid(1).cachex(CACHE3_NAME).context().group().preloader().rebalanceFuture().get(); + + startGrid("client"); + + fileIoBlockingSemaphore.release(Integer.MAX_VALUE); + + awaitPartitionMapExchange(false, false, null, true); + + assertPartitionsSame(idleVerify(grid(0), CACHE3_NAME)); + } + + /** FileIOFactory implementation that enables blocking of writes to disk so checkpoint can be blocked. */ + private static class BlockingCheckpointFileIOFactory implements FileIOFactory { + /** Serial version uid. */ + private static final long serialVersionUID = 0L; + + /** Delegate factory. */ + private final FileIOFactory delegateFactory = new RandomAccessFileIOFactory(); + + /** {@inheritDoc} */ + @Override public FileIO create(File file, OpenOption... modes) throws IOException { + FileIO delegate = delegateFactory.create(file, modes); + + return new FileIODecorator(delegate) { + @Override public int write(ByteBuffer srcBuf) throws IOException { + if (Thread.currentThread().getName().contains("checkpoint")) { + try { + fileIoBlockingSemaphore.acquire(); + } + catch (InterruptedException ignored) { + // No-op. + } + } + + return delegate.write(srcBuf); + } + + @Override public int write(ByteBuffer srcBuf, long position) throws IOException { + if (Thread.currentThread().getName().contains("checkpoint")) { + try { + fileIoBlockingSemaphore.acquire(); + } + catch (InterruptedException ignored) { + // No-op. + } + } + + return delegate.write(srcBuf, position); + } + + @Override public int write(byte[] buf, int off, int len) throws IOException { + if (Thread.currentThread().getName().contains("checkpoint")) { + try { + fileIoBlockingSemaphore.acquire(); + } + catch (InterruptedException ignored) { + // No-op. + } + } + + return delegate.write(buf, off, len); + } + }; + } + } + /** */ private void cleanPersistenceFiles(String igName) throws Exception { String ig1DbPath = Paths.get(DFLT_STORE_DIR, igName).toString(); @@ -253,14 +365,30 @@ private void cleanPersistenceFiles(String igName) throws Exception { } /** */ - private void fillCache(IgniteCache cache, int cacheSize) { + private void fillCache( + IgniteDataStreamer streamer, + int cacheSize, + BiFunction generatingFunc + ) { + String name = streamer.cacheName(); + for (int i = 0; i < cacheSize; i++) - cache.put(i, "value_" + i); + streamer.addData(i, generatingFunc.apply(name, i)); + + streamer.close(); } /** */ - private void fillCache(IgniteCache cache, Collection keys) { + private void fillCache( + IgniteDataStreamer streamer, + Collection keys, + BiFunction generatingFunc + ) { + String cacheName = streamer.cacheName(); + for (Integer key : keys) - cache.put(key, "value_" + key); + streamer.addData(key, generatingFunc.apply(cacheName, key)); + + streamer.close(); } } diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java index 3641b5e3ba8df..fd1b3b564f863 100755 --- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java +++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java @@ -859,6 +859,8 @@ protected void printPartitionState(String cacheName, int firstParts) { sb.append("nodeId=") .append(k.context().localNodeId()) + .append(" consistentId=") + .append(k.localNode().consistentId()) .append(" isDone=") .append(syncFut.isDone()) .append("\n"); @@ -939,7 +941,8 @@ protected void printPartitionState(String cacheName, int firstParts) { .append(part == null ? "NA" : part.dataStore().partUpdateCounter()) .append(" fullSize=") .append(part == null ? "NA" : part.fullSize()) - .append(" state=").append(part.state()); + .append(" state=").append(part.state()) + .append(" reservations=").append(part.reservations()); } else sb.append(p).append(" is null"); From 1c9dbe22ca9a446c0a4fac657d6a87bad2878fad Mon Sep 17 00:00:00 2001 From: korlov Date: Wed, 3 Jul 2019 14:30:10 +0300 Subject: [PATCH 11/62] GG-20464 backport to 8.5-master of GG-19518 IoStatisticsBasicIndexSelfTest --- .../processors/query/h2/database/H2Tree.java | 5 +++++ .../index/IoStatisticsBasicIndexSelfTest.java | 15 +++++++++++---- .../IgniteCacheWithIndexingTestSuite.java | 3 +++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java index 1790134dd6270..29c1022ac1df0 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java @@ -323,6 +323,11 @@ public int compareRows(SearchRow r1, SearchRow r2) { return 0; } + /** {@inheritDoc} */ + @Override protected IoStatisticsHolder statisticsHolder() { + return stats; + } + /** * @param v1 First value. * @param v2 Second value. diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/IoStatisticsBasicIndexSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/IoStatisticsBasicIndexSelfTest.java index c7b0fa5cbfcd6..5faf579e9b57a 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/IoStatisticsBasicIndexSelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/IoStatisticsBasicIndexSelfTest.java @@ -22,6 +22,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Objects; @@ -77,11 +78,17 @@ public class IoStatisticsBasicIndexSelfTest extends GridCommonAbstractTest { fields.put("valLong", Long.class.getName()); fields.put("valPojo", Pojo.class.getName()); + Set keyFields = new HashSet<>(); + keyFields.add("keyStr"); + keyFields.add("keyLong"); + keyFields.add("keyPojo"); + CacheConfiguration ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME) .setQueryEntities(Collections.singleton( new QueryEntity() .setKeyType(Key.class.getName()) .setValueType(Val.class.getName()) + .setKeyFields(keyFields) .setFields(fields) .setIndexes(indexes) )); @@ -170,14 +177,14 @@ private void checkStat() { Assert.assertEquals(PK_HASH_INDEXES, hashIndexes); - Set sortedIndexCaches = ioStat.deriveStatisticNames(IoStatisticsType.SORTED_INDEX); + Set sortedIdxCaches = ioStat.deriveStatisticNames(IoStatisticsType.SORTED_INDEX); - Assert.assertEquals(1, sortedIndexCaches.size()); + Assert.assertEquals(1, sortedIdxCaches.size()); Set sortedIdxNames = ioStat.deriveStatisticSubNames(IoStatisticsType.SORTED_INDEX, - sortedIndexCaches.toArray()[0].toString()); + sortedIdxCaches.toArray()[0].toString()); - Assert.assertEquals(sortedIndexCaches.toString(), indexes.size() + NUMBER_OF_PK_SORTED_INDEXES, sortedIdxNames.size()); + Assert.assertEquals(sortedIdxCaches.toString(), indexes.size() + NUMBER_OF_PK_SORTED_INDEXES, sortedIdxNames.size()); for (String idxName : sortedIdxNames) { Long logicalReads = ioStat.logicalReads(IoStatisticsType.SORTED_INDEX, DEFAULT_CACHE_NAME, idxName); diff --git a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java index bd1c99fb0d24d..05e91e1c8751d 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java +++ b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java @@ -36,6 +36,7 @@ import org.apache.ignite.internal.processors.cache.IgniteCacheGroupsSqlTest; import org.apache.ignite.internal.processors.cache.IgniteCacheStarvationOnRebalanceTest; import org.apache.ignite.internal.processors.cache.IgniteClientReconnectQueriesTest; +import org.apache.ignite.internal.processors.cache.index.IoStatisticsBasicIndexSelfTest; import org.apache.ignite.internal.processors.cache.persistence.RebuildIndexLogMessageTest; import org.apache.ignite.internal.processors.cache.ttl.CacheTtlAtomicLocalSelfTest; import org.apache.ignite.internal.processors.cache.ttl.CacheTtlAtomicPartitionedSelfTest; @@ -95,6 +96,8 @@ public static TestSuite suite() throws Exception { suite.addTestSuite(RebuildIndexLogMessageTest.class); + suite.addTestSuite(IoStatisticsBasicIndexSelfTest.class); + return suite; } } From b823cc6757b6c09b11e0658a6daf398eb2030941 Mon Sep 17 00:00:00 2001 From: Aleksei Scherbakov Date: Wed, 3 Jul 2019 19:54:18 +0300 Subject: [PATCH 12/62] GG-20798 Fix failing tests. --- .../dht/preloader/GridDhtPartitionDemander.java | 2 +- .../dht/topology/GridDhtPartitionTopologyImpl.java | 5 ++--- .../transactions/TxPartitionCounterStatePutTest.java | 12 ++++-------- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java index d0a63211489ea..5179f075bb74e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java @@ -1082,7 +1082,7 @@ public static class RebalanceFuture extends GridFutureAdapter { this.log = null; this.rebalanceId = -1; this.routines = 0; - this.cancelLock = null; + this.cancelLock = new ReentrantReadWriteLock(); } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java index e9588a8de0c54..19ae255344f44 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java @@ -1591,9 +1591,8 @@ private boolean shouldOverridePartitionMap(GridDhtPartitionMap currentMap, GridD if (exchangeVer != null && nodeMap != null && grp.persistenceEnabled() && - readyTopVer.initialized()) { - - assert exchFut != null; + readyTopVer.initialized() && + exchFut != null) { for (Map.Entry e : nodeMap.entrySet()) { int p = e.getKey(); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxPartitionCounterStatePutTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxPartitionCounterStatePutTest.java index 69019d0137dca..209f4eb24b309 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxPartitionCounterStatePutTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxPartitionCounterStatePutTest.java @@ -133,16 +133,14 @@ public void testPutTxConcurrentPersistent() throws Exception { doTestPutConcurrent(TX_CACHE, true); } - /** */ + /** TODO https://issues.apache.org/jira/browse/IGNITE-11793 */ public void testPutAtomicConcurrentPersistentWithIsolatedMode() throws Exception { // doTestPutConcurrent(ATOMIC_CACHE, false); - fail("https://issues.apache.org/jira/browse/IGNITE-11793"); } - /** */ + /** TODO https://issues.apache.org/jira/browse/IGNITE-11793 */ public void testPutTxConcurrentPersistentWithIsolatedMode() throws Exception { //doTestPutConcurrent(TX_CACHE, false); - fail("https://issues.apache.org/jira/browse/IGNITE-11793"); } /** */ @@ -165,16 +163,14 @@ public void testPutTxConcurrentVolatile() throws Exception { doTestPutConcurrent(TX_CACHE_MEMORY, true); } - /** */ + /** TODO https://issues.apache.org/jira/browse/IGNITE-11793 */ public void testPutAtomicConcurrentVolatileWithIsolatedMode() throws Exception { // doTestPutConcurrent(ATOMIC_CACHE_MEMORY, false); - fail("https://issues.apache.org/jira/browse/IGNITE-11793"); } - /** */ + /** TODO https://issues.apache.org/jira/browse/IGNITE-11793 */ public void testPutTxConcurrentVolatileWithIsolatedMode() throws Exception { // doTestPutConcurrent(TX_CACHE_MEMORY, false); - fail("https://issues.apache.org/jira/browse/IGNITE-11793"); } /** */ From 44091fa2103acf1c0c72f5bbd53bcbff690f948c Mon Sep 17 00:00:00 2001 From: Andrey Kalinin Date: Mon, 1 Jul 2019 15:34:51 +0300 Subject: [PATCH 13/62] GG-19492 Add debug output for o.a.i.internal.processors.cache.persistence.GridCacheOffheapManager#restorePartitionStates method. (cherry picked from commit 621f6afb0983bcb52eaf5f71ade74cd453dd1749) --- .../persistence/GridCacheOffheapManager.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java index 5d6b53ae813cf..2e73094761469 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java @@ -511,6 +511,8 @@ else if (needSnapshot) for (int p = 0; p < grp.affinity().partitions(); p++) { Integer recoverState = partitionRecoveryStates.get(new GroupPartitionId(grp.groupId(), p)); + long startTime = U.currentTimeMillis(); + if (ctx.pageStore().exists(grp.groupId(), p)) { ctx.pageStore().ensure(grp.groupId(), p); @@ -555,7 +557,8 @@ else if (needSnapshot) if (log.isDebugEnabled()) log.debug("Restored partition state (from WAL) " + "[grp=" + grp.cacheOrGroupName() + ", p=" + p + ", state=" + part.state() + - ", updCntr=" + part.initialUpdateCounter() + "]"); + ", updCntr=" + part.initialUpdateCounter() + + ", size=" + part.fullSize() + "]"); } else { int stateId = (int) io.getPartitionState(pageAddr); @@ -565,7 +568,8 @@ else if (needSnapshot) if (log.isDebugEnabled()) log.debug("Restored partition state (from page memory) " + "[grp=" + grp.cacheOrGroupName() + ", p=" + p + ", state=" + part.state() + - ", updCntr=" + part.initialUpdateCounter() + ", stateId=" + stateId + "]"); + ", updCntr=" + part.initialUpdateCounter() + ", stateId=" + stateId + + ", size=" + part.fullSize() + "]"); } } finally { @@ -590,13 +594,19 @@ else if (recoverState != null) { // Pre-create partition if having valid state. if (log.isDebugEnabled()) log.debug("Restored partition state (from WAL) " + "[grp=" + grp.cacheOrGroupName() + ", p=" + p + ", state=" + part.state() + - ", updCntr=" + part.initialUpdateCounter() + "]"); + ", updCntr=" + part.initialUpdateCounter() + + ", size=" + part.fullSize() + "]"); } else { if (log.isDebugEnabled()) log.debug("Skipping partition on recovery (no page store OR wal state) " + "[grp=" + grp.cacheOrGroupName() + ", p=" + p + "]"); } + + if (log.isDebugEnabled()) + log.debug("Finished restoring partition state " + + "[grp=" + grp.cacheOrGroupName() + ", p=" + p + + ", time=" + (U.currentTimeMillis() - startTime) + " ms]"); } partitionStatesRestored = true; From b01ce115266b0f688a708023eb2053443b5232e7 Mon Sep 17 00:00:00 2001 From: ktkalenko Date: Thu, 4 Jul 2019 12:13:02 +0300 Subject: [PATCH 14/62] GG-18891 CommandHandlerParsingTest#testExperimentalCommandIsDisabled() doesn't work. (cherry picked from commit 93507600635af077d3cc6aaa1e297c92b0302da0) --- .../internal/commandline/WalCommands.java | 13 ++++++++- .../CommandHandlerParsingTest.java | 28 ++++++++----------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/WalCommands.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/WalCommands.java index e2489cf0c99a1..f892e985b5065 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/WalCommands.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/WalCommands.java @@ -69,8 +69,9 @@ public class WalCommands implements Command> { */ private String walArgs; + /** {@inheritDoc} */ @Override public void printUsage(Logger logger) { - if (IgniteSystemProperties.getBoolean(IGNITE_ENABLE_EXPERIMENTAL_COMMAND, false)) { + if (enableExperimental()) { Command.usage(logger, "Print absolute paths of unused archived wal segments on each node:", WAL, WAL_PRINT, "[consistentId1,consistentId2,....,consistentIdN]"); Command.usage(logger, "Delete unused archived wal segments on each node:", WAL, WAL_DELETE, @@ -115,6 +116,9 @@ public class WalCommands implements Command> { /** {@inheritDoc} */ @Override public void parseArguments(CommandArgIterator argIter) { + if (!enableExperimental()) + throw new IllegalArgumentException("Experimental command is disabled."); + String str = argIter.nextArg("Expected arguments for " + WAL.text()); String walAct = str.toLowerCase(); @@ -268,4 +272,11 @@ private void printDeleteWalSegments0(VisorWalTaskResult taskRes) { @Override public String name() { return WAL.toCommandName(); } + + /** + * @return Value of {@link IgniteSystemProperties#IGNITE_ENABLE_EXPERIMENTAL_COMMAND} + */ + private boolean enableExperimental() { + return IgniteSystemProperties.getBoolean(IGNITE_ENABLE_EXPERIMENTAL_COMMAND, false); + } } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java b/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java index 4235f00fda842..1d9df94b083f6 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java @@ -276,23 +276,19 @@ private void generateAllCombinations(List res, List source, Predicate< public void testExperimentalCommandIsDisabled() { System.clearProperty(IGNITE_ENABLE_EXPERIMENTAL_COMMAND); - try { - parseArgs(Arrays.asList(WAL.text(), WAL_PRINT)); - } - catch (Throwable e) { - e.printStackTrace(); - - assertTrue(e instanceof IllegalArgumentException); - } - - try { - parseArgs(Arrays.asList(WAL.text(), WAL_DELETE)); - } - catch (Throwable e) { - e.printStackTrace(); + GridTestUtils.assertThrows( + null, + () -> parseArgs(Arrays.asList(WAL.text(), WAL_PRINT)), + IllegalArgumentException.class, + null + ); - assertTrue(e instanceof IllegalArgumentException); - } + GridTestUtils.assertThrows( + null, + () -> parseArgs(Arrays.asList(WAL.text(), WAL_DELETE)), + IllegalArgumentException.class, + null + ); } /** From ad9070d89e99f5feadc09c60fb59f71e7574cae0 Mon Sep 17 00:00:00 2001 From: korlov Date: Thu, 4 Jul 2019 12:28:09 +0300 Subject: [PATCH 15/62] GG-20810 backport to 8.5-master of GG-20807 Fix failing IoStatisticsBasicIndexSelfTest --- .../IgniteCacheWithIndexingAndPersistenceTestSuite.java | 2 ++ .../ignite/testsuites/IgniteCacheWithIndexingTestSuite.java | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingAndPersistenceTestSuite.java b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingAndPersistenceTestSuite.java index 2f3ddecef0d66..7eef9318c3771 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingAndPersistenceTestSuite.java +++ b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingAndPersistenceTestSuite.java @@ -19,6 +19,7 @@ import junit.framework.TestSuite; import org.apache.ignite.internal.processors.cache.StartCachesInParallelTest; +import org.apache.ignite.internal.processors.cache.index.IoStatisticsBasicIndexSelfTest; import org.apache.ignite.util.GridCommandHandlerIndexingTest; /** @@ -34,6 +35,7 @@ public static TestSuite suite() throws Exception { suite.addTestSuite(GridCommandHandlerIndexingTest.class); suite.addTestSuite(StartCachesInParallelTest.class); + suite.addTestSuite(IoStatisticsBasicIndexSelfTest.class); return suite; } diff --git a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java index 05e91e1c8751d..bd1c99fb0d24d 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java +++ b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java @@ -36,7 +36,6 @@ import org.apache.ignite.internal.processors.cache.IgniteCacheGroupsSqlTest; import org.apache.ignite.internal.processors.cache.IgniteCacheStarvationOnRebalanceTest; import org.apache.ignite.internal.processors.cache.IgniteClientReconnectQueriesTest; -import org.apache.ignite.internal.processors.cache.index.IoStatisticsBasicIndexSelfTest; import org.apache.ignite.internal.processors.cache.persistence.RebuildIndexLogMessageTest; import org.apache.ignite.internal.processors.cache.ttl.CacheTtlAtomicLocalSelfTest; import org.apache.ignite.internal.processors.cache.ttl.CacheTtlAtomicPartitionedSelfTest; @@ -96,8 +95,6 @@ public static TestSuite suite() throws Exception { suite.addTestSuite(RebuildIndexLogMessageTest.class); - suite.addTestSuite(IoStatisticsBasicIndexSelfTest.class); - return suite; } } From 3616b6a7767a39206445af579073f313ef5a5e8b Mon Sep 17 00:00:00 2001 From: ibelyakov Date: Fri, 5 Jul 2019 15:03:40 +0300 Subject: [PATCH 16/62] GG-19515: GG: destroying of the cache and re-creating with the same name make DR paused in case of persistence. (cherry picked from commit e093716171736fca9c47a42df584338d4c29a511) --- .../dht/preloader/GridDhtPartitionsExchangeFuture.java | 2 +- .../internal/processors/cache/dr/GridCacheDrManager.java | 3 +-- .../internal/processors/cache/dr/GridOsCacheDrManager.java | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java index 1fb6702e036f1..368e1c80ceda7 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java @@ -2173,7 +2173,7 @@ private String exchangeTimingsLogMessage(String header, List timings) { if (drCacheCtx.isDrEnabled()) { try { - drCacheCtx.dr().onExchange(res, exchId.isLeft(), activateCluster()); + drCacheCtx.dr().onExchange(res, exchId.isLeft()); } catch (IgniteCheckedException e) { U.error(log, "Failed to notify DR: " + e, e); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/dr/GridCacheDrManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/dr/GridCacheDrManager.java index 33a52a11a03d1..f2a4b30c4af82 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/dr/GridCacheDrManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/dr/GridCacheDrManager.java @@ -60,10 +60,9 @@ public void replicate(KeyCacheObject key, * * @param topVer Topology version. * @param left {@code True} if exchange has been caused by node leave. - * @param activate {@code True} if exchange has been caused by cluster activation. * @throws IgniteCheckedException If failed. */ - public void onExchange(AffinityTopologyVersion topVer, boolean left, boolean activate) throws IgniteCheckedException; + public void onExchange(AffinityTopologyVersion topVer, boolean left) throws IgniteCheckedException; /** * @return {@code True} is DR is enabled. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/dr/GridOsCacheDrManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/dr/GridOsCacheDrManager.java index 425e79c536344..f3c1b23f7c7d6 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/dr/GridOsCacheDrManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/dr/GridOsCacheDrManager.java @@ -78,7 +78,7 @@ public class GridOsCacheDrManager implements GridCacheDrManager { } /** {@inheritDoc} */ - @Override public void onExchange(AffinityTopologyVersion topVer, boolean left, boolean activate) throws IgniteCheckedException { + @Override public void onExchange(AffinityTopologyVersion topVer, boolean left) throws IgniteCheckedException { // No-op. } From b04ec7e511056e24242e67cb5e0da7f9be39db42 Mon Sep 17 00:00:00 2001 From: "Andrey V. Mashenkov" Date: Fri, 5 Jul 2019 18:34:23 +0300 Subject: [PATCH 17/62] GG-20822: Compact log and drop log level down to info for cancelled queries. (cherry picked from commit 03283da8cbb7c70b0fed497d3c0e58ec010b6d52) --- .../h2/twostep/GridMapQueryExecutor.java | 43 +++++++++++++------ 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java index 15ae7652c1978..290d146f45bb0 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java @@ -583,23 +583,28 @@ private void onQueryRequest0( if (lazy) stopAndUnregisterCurrentLazyWorker(); - GridH2RetryException retryErr = X.cause(e, GridH2RetryException.class); - - if (retryErr != null) { - final String retryCause = String.format( - "Failed to execute non-collocated query (will retry) [localNodeId=%s, rmtNodeId=%s, reqId=%s, " + - "errMsg=%s]", ctx.localNodeId(), node.id(), reqId, retryErr.getMessage() - ); - - sendRetry(node, reqId, segmentId, retryCause); + if (e instanceof QueryCancelledException) { + sendError(node, reqId, e); } else { - U.error(log, "Failed to execute local query.", e); + GridH2RetryException retryErr = X.cause(e, GridH2RetryException.class); - sendError(node, reqId, e); + if (retryErr != null) { + final String retryCause = String.format( + "Failed to execute non-collocated query (will retry) [localNodeId=%s, rmtNodeId=%s, reqId=%s, " + + "errMsg=%s]", ctx.localNodeId(), node.id(), reqId, retryErr.getMessage() + ); - if (e instanceof Error) - throw (Error)e; + sendRetry(node, reqId, segmentId, retryCause); + } + else { + U.error(log, "Failed to execute local query.", e); + + sendError(node, reqId, e); + + if (e instanceof Error) + throw (Error)e; + } } } finally { @@ -733,7 +738,17 @@ private void sendError(ClusterNode node, long qryReqId, Throwable err) { GridQueryFailResponse msg = new GridQueryFailResponse(qryReqId, err); if (node.isLocal()) { - U.error(log, "Failed to run map query on local node.", err); + if (err instanceof QueryCancelledException) { + String errMsg = "Failed to run cancelled map query on local node: [localNodeId=" + + node.id() + ", reqId=" + qryReqId + ']'; + + if (log.isDebugEnabled()) + U.warn(log, errMsg, err); + else + log.info(errMsg); + } + else + U.error(log, "Failed to run map query on local node.", err); h2.reduceQueryExecutor().onMessage(ctx.localNodeId(), msg); } From 21de580adeb899d052fe7cbe79eb7dda76140f40 Mon Sep 17 00:00:00 2001 From: ibelyakov Date: Sun, 7 Jul 2019 18:39:24 +0300 Subject: [PATCH 18/62] Revert "GG-19515: GG: destroying of the cache and re-creating with the same name make DR paused in case of persistence." This reverts commit 3616b6a7767a39206445af579073f313ef5a5e8b. --- .../dht/preloader/GridDhtPartitionsExchangeFuture.java | 2 +- .../internal/processors/cache/dr/GridCacheDrManager.java | 3 ++- .../internal/processors/cache/dr/GridOsCacheDrManager.java | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java index 368e1c80ceda7..1fb6702e036f1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java @@ -2173,7 +2173,7 @@ private String exchangeTimingsLogMessage(String header, List timings) { if (drCacheCtx.isDrEnabled()) { try { - drCacheCtx.dr().onExchange(res, exchId.isLeft()); + drCacheCtx.dr().onExchange(res, exchId.isLeft(), activateCluster()); } catch (IgniteCheckedException e) { U.error(log, "Failed to notify DR: " + e, e); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/dr/GridCacheDrManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/dr/GridCacheDrManager.java index f2a4b30c4af82..33a52a11a03d1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/dr/GridCacheDrManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/dr/GridCacheDrManager.java @@ -60,9 +60,10 @@ public void replicate(KeyCacheObject key, * * @param topVer Topology version. * @param left {@code True} if exchange has been caused by node leave. + * @param activate {@code True} if exchange has been caused by cluster activation. * @throws IgniteCheckedException If failed. */ - public void onExchange(AffinityTopologyVersion topVer, boolean left) throws IgniteCheckedException; + public void onExchange(AffinityTopologyVersion topVer, boolean left, boolean activate) throws IgniteCheckedException; /** * @return {@code True} is DR is enabled. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/dr/GridOsCacheDrManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/dr/GridOsCacheDrManager.java index f3c1b23f7c7d6..425e79c536344 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/dr/GridOsCacheDrManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/dr/GridOsCacheDrManager.java @@ -78,7 +78,7 @@ public class GridOsCacheDrManager implements GridCacheDrManager { } /** {@inheritDoc} */ - @Override public void onExchange(AffinityTopologyVersion topVer, boolean left) throws IgniteCheckedException { + @Override public void onExchange(AffinityTopologyVersion topVer, boolean left, boolean activate) throws IgniteCheckedException { // No-op. } From b773b6c49c8ddab5c51a972afa48b86155f8da8c Mon Sep 17 00:00:00 2001 From: Dmitriy Govorukhin Date: Mon, 8 Jul 2019 14:31:54 +0300 Subject: [PATCH 19/62] GG-21061 [GG-21057] Fixed IgniteCacheReplicatedQuerySelfTest.testNodeLeft flaky failed on TC (cherry picked from commit fe0ec74478d0c513f25b306e384319ac9220933a) --- .../IgniteCacheReplicatedQuerySelfTest.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/IgniteCacheReplicatedQuerySelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/IgniteCacheReplicatedQuerySelfTest.java index 13942c2ede3d4..85748aa7d957a 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/IgniteCacheReplicatedQuerySelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/IgniteCacheReplicatedQuerySelfTest.java @@ -51,6 +51,7 @@ import static org.apache.ignite.cache.CacheMode.REPLICATED; import static org.apache.ignite.cache.CachePeekMode.ALL; +import static org.apache.ignite.events.EventType.EVT_NODE_FAILED; import static org.apache.ignite.events.EventType.EVT_NODE_LEFT; /** @@ -346,14 +347,13 @@ public void testLostIterator() throws Exception { /** * @throws Exception If failed. */ - @IgniteIgnore(value = "https://issues.apache.org/jira/browse/IGNITE-613", forceFailure = true) public void testNodeLeft() throws Exception { - Ignite g = startGrid("client"); + Ignite client = startGrid("client"); try { - assertTrue(g.configuration().isClientMode()); + assertTrue(client.configuration().isClientMode()); - IgniteCache cache = jcache(Integer.class, Integer.class); + IgniteCache cache = jcache(client, Integer.class, Integer.class); for (int i = 0; i < 1000; i++) cache.put(i, i); @@ -373,18 +373,21 @@ public void testNodeLeft() throws Exception { assertEquals(1, mapNode1.size() + mapNode2.size() + mapNode3.size()); - final UUID nodeId = g.cluster().localNode().id(); + final UUID nodeId = client.cluster().localNode().id(); - final CountDownLatch latch = new CountDownLatch(1); + final CountDownLatch latch = new CountDownLatch(3); - grid(0).events().localListen(new IgnitePredicate() { - @Override public boolean apply(Event evt) { - if (((DiscoveryEvent)evt).eventNode().id().equals(nodeId)) - latch.countDown(); + // Add listeners on all nodes. + for (int i = 0; i < 3; i++) { + grid(i).events().localListen(new IgnitePredicate() { + @Override public boolean apply(Event evt) { + if (((DiscoveryEvent)evt).eventNode().id().equals(nodeId)) + latch.countDown(); - return true; - } - }, EVT_NODE_LEFT); + return true; + } + }, EVT_NODE_LEFT, EVT_NODE_FAILED); + } stopGrid("client"); From d8a004f7077cb285cf3316633f1d90bf9536eb67 Mon Sep 17 00:00:00 2001 From: Dmitriy Govorukhin Date: Mon, 8 Jul 2019 15:17:28 +0300 Subject: [PATCH 20/62] GG-21074 [GG-21055] Fixed IgniteClusterActivateDeactivateTest.testDeactivateSimple_5_Servers_5_Clients_FromClient flaky failed on TC (cherry picked from commit 25789310de2a00b96a443fe2b02fb1322356061e) --- .../IgniteClusterActivateDeactivateTest.java | 52 +++++++++++-------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClusterActivateDeactivateTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClusterActivateDeactivateTest.java index e8b2d0a5ebb84..523904bc282c0 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClusterActivateDeactivateTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClusterActivateDeactivateTest.java @@ -320,7 +320,18 @@ private void rolloverSegmentAtLeastTwice(int activateFrom) { * @param nodes Number of nodes. * @param caches Number of caches. */ - final void checkCaches(int nodes, int caches) { + final void checkCaches(int nodes, int caches) throws InterruptedException { + checkCaches(nodes, caches, true); + } + + /** + * @param nodes Number of nodes. + * @param caches Number of caches. + */ + final void checkCaches(int nodes, int caches, boolean awaitExchange) throws InterruptedException { + if (awaitExchange) + awaitPartitionMapExchange(); + for (int i = 0; i < nodes; i++) { for (int c = 0; c < caches; c++) { IgniteCache cache = ignite(i).cache(CACHE_NAME_PREFIX + c); @@ -667,9 +678,6 @@ private void deactivateSimple(int srvs, int clients, int deactivateFrom) throws startGrid(i); } - if (persistenceEnabled()) - ignite(deactivateFrom).cluster().active(true); - ignite(deactivateFrom).cluster().active(true); // Should be no-op. checkCaches(srvs + clients, CACHES); @@ -712,7 +720,7 @@ private void deactivateSimple(int srvs, int clients, int deactivateFrom) throws checkCache(ignite(i), CACHE_NAME_PREFIX + c, true); } - checkCaches1(srvs + clients + 2); + checkCaches(srvs + clients + 2); } /** @@ -751,11 +759,11 @@ public void testClientReconnectClusterActive() throws Exception { checkCache(client, CU.UTILITY_CACHE_NAME, true); - checkCaches1(SRVS + CLIENTS); + checkCaches(SRVS + CLIENTS); IgniteClientReconnectAbstractTest.reconnectClientNode(log, client, srv, null); - checkCaches1(SRVS + CLIENTS); + checkCaches(SRVS + CLIENTS); this.client = false; @@ -765,7 +773,7 @@ public void testClientReconnectClusterActive() throws Exception { startGrid(SRVS + CLIENTS + 1); - checkCaches1(SRVS + CLIENTS + 2); + checkCaches(SRVS + CLIENTS + 2); } /** @@ -794,7 +802,7 @@ public void testClientReconnectClusterInactive() throws Exception { checkCache(client, CU.UTILITY_CACHE_NAME, true); - checkCaches1(SRVS + CLIENTS); + checkCaches(SRVS + CLIENTS); this.client = false; @@ -804,7 +812,7 @@ public void testClientReconnectClusterInactive() throws Exception { startGrid(SRVS + CLIENTS + 1); - checkCaches1(SRVS + CLIENTS); + checkCaches(SRVS + CLIENTS); } /** @@ -842,7 +850,7 @@ private void clientReconnectClusterDeactivated(final boolean transition) throws checkCache(client, CU.UTILITY_CACHE_NAME, true); - checkCaches1(SRVS + CLIENTS); + checkCaches(SRVS + CLIENTS); // Wait for late affinity assignment to finish. awaitPartitionMapExchange(); @@ -892,7 +900,7 @@ private void clientReconnectClusterDeactivated(final boolean transition) throws assertTrue(client.cluster().active()); - checkCaches1(SRVS + CLIENTS); + checkCaches(SRVS + CLIENTS); checkCache(client, CACHE_NAME_PREFIX + 0, true); @@ -904,7 +912,7 @@ private void clientReconnectClusterDeactivated(final boolean transition) throws startGrid(SRVS + CLIENTS + 1); - checkCaches1(SRVS + CLIENTS + 2); + checkCaches(SRVS + CLIENTS + 2); } /** @@ -979,7 +987,7 @@ private void clientReconnectClusterActivated(final boolean transition) throws Ex checkCache(client, CU.UTILITY_CACHE_NAME, true); - checkCaches1(SRVS + CLIENTS); + checkCaches(SRVS + CLIENTS); checkCache(client, CACHE_NAME_PREFIX + 0, true); @@ -991,7 +999,7 @@ private void clientReconnectClusterActivated(final boolean transition) throws Ex startGrid(SRVS + CLIENTS + 1); - checkCaches1(SRVS + CLIENTS + 2); + checkCaches(SRVS + CLIENTS + 2); } /** @@ -1033,7 +1041,7 @@ public void testInactiveTopologyChanges() throws Exception { ignite(0).cluster().active(true); - checkCaches1(SRVS + CLIENTS); + checkCaches(SRVS + CLIENTS); checkRecordedMessages(true); @@ -1047,7 +1055,7 @@ public void testInactiveTopologyChanges() throws Exception { checkRecordedMessages(true); - checkCaches1(SRVS + CLIENTS + 2); + checkCaches(SRVS + CLIENTS + 2); } /** @@ -1104,7 +1112,7 @@ private void stateChangeFailover1(boolean activate) throws Exception { ignite(0).cluster().active(true); } - checkCaches1(9); + checkCaches(9); } /** @@ -1172,7 +1180,7 @@ private void stateChangeFailover2(boolean activate) throws Exception { ignite(0).cluster().active(true); } - checkCaches1(10); + checkCaches(10); } /** @@ -1239,7 +1247,7 @@ protected void doFinalChecks() throws Exception { for (int i = 0; i < 4; i++) startGrid(i); - checkCaches1(6); + checkCaches(6); } /** @@ -1306,8 +1314,8 @@ private void checkRecordedMessages(boolean exp) { /** * @param nodes Expected nodes number. */ - private void checkCaches1(int nodes) { - checkCaches(nodes, 2); + private void checkCaches(int nodes) throws InterruptedException { + checkCaches(nodes, 2, false); } /** From dfff292fc093253767730755a79b32d758264a41 Mon Sep 17 00:00:00 2001 From: ktkalenko Date: Mon, 8 Jul 2019 15:36:03 +0300 Subject: [PATCH 21/62] GG-20185 control.sh validate_indexes SQL Index issue must contain information about cache group. (cherry picked from commit 82409a97a786d367d880600580b2d63bc659a292) --- .../ignite/internal/visor/verify/ValidateIndexesClosure.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesClosure.java b/modules/indexing/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesClosure.java index f7a96bb4947f5..10591752058fd 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesClosure.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesClosure.java @@ -738,7 +738,7 @@ else if (current++ % checkThrough > 0) } } - String uniqueIdxName = "[cache=" + ctx.name() + ", idx=" + idx.getName() + "]"; + String uniqueIdxName = "[cacheGroup=" + ctx.group().name() + ", cache=" + ctx.name() + ", idx=" + idx.getName() + "]"; processedIndexes.incrementAndGet(); From e093eeb4d749be476901073b99f2da41b18d67eb Mon Sep 17 00:00:00 2001 From: tledkov Date: Mon, 8 Jul 2019 18:11:06 +0300 Subject: [PATCH 22/62] GG-20917 [8.5-next]-[GG-20908] Set max possible maintenance version for all x.x-master branches --- modules/core/src/main/resources/ignite.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/src/main/resources/ignite.properties b/modules/core/src/main/resources/ignite.properties index d06256418df52..fa0a6771aa0d2 100644 --- a/modules/core/src/main/resources/ignite.properties +++ b/modules/core/src/main/resources/ignite.properties @@ -15,7 +15,7 @@ # limitations under the License. # -ignite.version=2.5.6-SNAPSHOT +ignite.version=2.5.127-SNAPSHOT ignite.build=0 ignite.revision=DEV ignite.rel.date=01011970 From 0adf555d42e6381bbe7b8ea2e5c99834aa2cc8b9 Mon Sep 17 00:00:00 2001 From: denis-chudov Date: Tue, 2 Jul 2019 18:05:48 +0300 Subject: [PATCH 23/62] GG-20729 Add ability to set default parallelism of rebuild indexes in ignite system properties (cherry picked from commit 05cdf467d97e3ee111c0bf89e9f51b12d5d82109) --- .../apache/ignite/IgniteSystemProperties.java | 8 ++++++++ .../schema/SchemaIndexCacheVisitorImpl.java | 16 +++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java index 4f8d06238099f..7920a9cd6a572 100644 --- a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java +++ b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java @@ -1121,6 +1121,14 @@ public final class IgniteSystemProperties { */ public static final String IGNITE_LOG_CLASSPATH_CONTENT_ON_STARTUP = "IGNITE_LOG_CLASSPATH_CONTENT_ON_STARTUP"; + /** + * Index rebuilding parallelism level. If specified, sets the count of threads that are used for index rebuilding + * and can only be greater than 0, otherwise default value will be used. Maximum count of threads + * can't be greater than total available processors count. + * Default value is minimum of 4 and processors count / 4, but always greater than 0. + */ + public static final String INDEX_REBUILDING_PARALLELISM = "INDEX_REBUILDING_PARALLELISM"; + /** * Enforces singleton. */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/SchemaIndexCacheVisitorImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/SchemaIndexCacheVisitorImpl.java index 43e3ccf31a685..bf8cf417e5f76 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/SchemaIndexCacheVisitorImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/SchemaIndexCacheVisitorImpl.java @@ -18,6 +18,7 @@ package org.apache.ignite.internal.processors.query.schema; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.IgniteSystemProperties; import org.apache.ignite.internal.IgniteInterruptedCheckedException; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheEntryEx; @@ -38,6 +39,7 @@ import java.util.List; +import static org.apache.ignite.IgniteSystemProperties.INDEX_REBUILDING_PARALLELISM; import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState.EVICTED; import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState.MOVING; import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState.OWNING; @@ -49,8 +51,7 @@ @SuppressWarnings("ForLoopReplaceableByForEach") public class SchemaIndexCacheVisitorImpl implements SchemaIndexCacheVisitor { /** Default degree of parallelism. */ - private static final int DFLT_PARALLELISM = - Math.min(4, Math.max(1, Runtime.getRuntime().availableProcessors() / 4)); + private static final int DFLT_PARALLELISM; /** Count of rows, being processed within a single checkpoint lock. */ private static final int BATCH_SIZE = 1000; @@ -70,6 +71,15 @@ public class SchemaIndexCacheVisitorImpl implements SchemaIndexCacheVisitor { /** Whether to stop the process. */ private volatile boolean stop; + static { + int parallelism = IgniteSystemProperties.getInteger(INDEX_REBUILDING_PARALLELISM, 0); + + if (parallelism > 0) + DFLT_PARALLELISM = Math.min(parallelism, Runtime.getRuntime().availableProcessors()); + else + DFLT_PARALLELISM = Math.min(4, Math.max(1, Runtime.getRuntime().availableProcessors() / 4)); + } + /** * Constructor. * @param cctx Cache context. @@ -94,7 +104,7 @@ public SchemaIndexCacheVisitorImpl(GridCacheContext cctx, SchemaIndexCacheFilter if (parallelism > 0) this.parallelism = Math.min(Runtime.getRuntime().availableProcessors(), parallelism); else - this.parallelism = DFLT_PARALLELISM; + this.parallelism = DFLT_PARALLELISM; if (cctx.isNear()) cctx = ((GridNearCacheAdapter)cctx.cache()).dht().context(); From ca61a704e3c58b0bba285930cbbef2de0b119980 Mon Sep 17 00:00:00 2001 From: ibessonov Date: Tue, 9 Jul 2019 17:27:44 +0300 Subject: [PATCH 24/62] GG-20845 Added explicit indexes to WALRecord.RecordType. --- .../pagemem/wal/record/WALRecord.java | 136 +++++++++++------- .../wal/serializer/RecordV1Serializer.java | 8 +- .../wal/serializer/RecordV2Serializer.java | 2 +- .../pagemem/wal/record/WALRecordTest.java | 41 ++++++ .../testsuites/IgniteBasicTestSuite.java | 3 + 5 files changed, 132 insertions(+), 58 deletions(-) create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/pagemem/wal/record/WALRecordTest.java diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java index 0031b22efa478..60e64e97e97f2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java @@ -32,126 +32,126 @@ public abstract class WALRecord { */ public enum RecordType { /** */ - TX_RECORD, + TX_RECORD (0), /** */ - PAGE_RECORD, + PAGE_RECORD (1), /** */ - DATA_RECORD, + DATA_RECORD (2), /** Checkpoint (begin) record */ - CHECKPOINT_RECORD, + CHECKPOINT_RECORD (3), /** WAL segment header record. */ - HEADER_RECORD, + HEADER_RECORD (4), // Delta records. /** */ - INIT_NEW_PAGE_RECORD, + INIT_NEW_PAGE_RECORD (5), /** */ - DATA_PAGE_INSERT_RECORD, + DATA_PAGE_INSERT_RECORD (6), /** */ - DATA_PAGE_INSERT_FRAGMENT_RECORD, + DATA_PAGE_INSERT_FRAGMENT_RECORD (7), /** */ - DATA_PAGE_REMOVE_RECORD, + DATA_PAGE_REMOVE_RECORD (8), /** */ - DATA_PAGE_SET_FREE_LIST_PAGE, + DATA_PAGE_SET_FREE_LIST_PAGE (9), /** */ - BTREE_META_PAGE_INIT_ROOT, + BTREE_META_PAGE_INIT_ROOT (10), /** */ - BTREE_META_PAGE_ADD_ROOT, + BTREE_META_PAGE_ADD_ROOT (11), /** */ - BTREE_META_PAGE_CUT_ROOT, + BTREE_META_PAGE_CUT_ROOT (12), /** */ - BTREE_INIT_NEW_ROOT, + BTREE_INIT_NEW_ROOT (13), /** */ - BTREE_PAGE_RECYCLE, + BTREE_PAGE_RECYCLE (14), /** */ - BTREE_PAGE_INSERT, + BTREE_PAGE_INSERT (15), /** */ - BTREE_FIX_LEFTMOST_CHILD, + BTREE_FIX_LEFTMOST_CHILD (16), /** */ - BTREE_FIX_COUNT, + BTREE_FIX_COUNT (17), /** */ - BTREE_PAGE_REPLACE, + BTREE_PAGE_REPLACE (18), /** */ - BTREE_PAGE_REMOVE, + BTREE_PAGE_REMOVE (19), /** */ - BTREE_PAGE_INNER_REPLACE, + BTREE_PAGE_INNER_REPLACE (20), /** */ - BTREE_FIX_REMOVE_ID, + BTREE_FIX_REMOVE_ID (21), /** */ - BTREE_FORWARD_PAGE_SPLIT, + BTREE_FORWARD_PAGE_SPLIT (22), /** */ - BTREE_EXISTING_PAGE_SPLIT, + BTREE_EXISTING_PAGE_SPLIT (23), /** */ - BTREE_PAGE_MERGE, + BTREE_PAGE_MERGE (24), /** */ - PAGES_LIST_SET_NEXT, + PAGES_LIST_SET_NEXT (25), /** */ - PAGES_LIST_SET_PREVIOUS, + PAGES_LIST_SET_PREVIOUS (26), /** */ - PAGES_LIST_INIT_NEW_PAGE, + PAGES_LIST_INIT_NEW_PAGE (27), /** */ - PAGES_LIST_ADD_PAGE, + PAGES_LIST_ADD_PAGE (28), /** */ - PAGES_LIST_REMOVE_PAGE, + PAGES_LIST_REMOVE_PAGE (29), /** */ - META_PAGE_INIT, + META_PAGE_INIT (30), /** */ - PARTITION_META_PAGE_UPDATE_COUNTERS, + PARTITION_META_PAGE_UPDATE_COUNTERS (31), /** Memory recovering start marker */ - MEMORY_RECOVERY, + MEMORY_RECOVERY (32), /** */ - TRACKING_PAGE_DELTA, + TRACKING_PAGE_DELTA (33), /** Meta page update last successful snapshot id. */ - META_PAGE_UPDATE_LAST_SUCCESSFUL_SNAPSHOT_ID, + META_PAGE_UPDATE_LAST_SUCCESSFUL_SNAPSHOT_ID (34), /** Meta page update last successful full snapshot id. */ - META_PAGE_UPDATE_LAST_SUCCESSFUL_FULL_SNAPSHOT_ID, + META_PAGE_UPDATE_LAST_SUCCESSFUL_FULL_SNAPSHOT_ID (35), /** Meta page update next snapshot id. */ - META_PAGE_UPDATE_NEXT_SNAPSHOT_ID, + META_PAGE_UPDATE_NEXT_SNAPSHOT_ID (36), /** Meta page update last allocated index. */ - META_PAGE_UPDATE_LAST_ALLOCATED_INDEX, + META_PAGE_UPDATE_LAST_ALLOCATED_INDEX (37), /** Partition meta update state. */ - PART_META_UPDATE_STATE, + PART_META_UPDATE_STATE (38), /** Page list meta reset count record. */ - PAGE_LIST_META_RESET_COUNT_RECORD, + PAGE_LIST_META_RESET_COUNT_RECORD (39), /** Switch segment record. * Marker record for indicate end of segment. @@ -160,41 +160,71 @@ public enum RecordType { * that one byte in the end,then we write SWITCH_SEGMENT_RECORD as marker end of segment. * No need write CRC or WAL pointer for this record. It is byte marker record. * */ - SWITCH_SEGMENT_RECORD, + SWITCH_SEGMENT_RECORD (40), /** */ - DATA_PAGE_UPDATE_RECORD, + DATA_PAGE_UPDATE_RECORD (41), /** init */ - BTREE_META_PAGE_INIT_ROOT2, + BTREE_META_PAGE_INIT_ROOT2 (42), /** Partition destroy. */ - PARTITION_DESTROY, + PARTITION_DESTROY (43), /** Snapshot record. */ - SNAPSHOT, + SNAPSHOT (44), /** Metastore data record. */ - METASTORE_DATA_RECORD, + METASTORE_DATA_RECORD (45), /** Exchange record. */ - EXCHANGE, + EXCHANGE (46), /** Reserved for future record. */ - RESERVED, + RESERVED (47), /** Rollback tx record. */ - ROLLBACK_TX_RECORD, + ROLLBACK_TX_RECORD (57), /** */ - PARTITION_META_PAGE_UPDATE_COUNTERS_V2; + PARTITION_META_PAGE_UPDATE_COUNTERS_V2 (58); + + /** Index for serialization. Should be consistent throughout all versions. */ + private final int idx; + + /** + * @param idx Index for serialization. + */ + RecordType(int idx) { + this.idx = idx; + } + + /** + * @return Index for serialization. + */ + public int index() { + return idx; + } /** */ - private static final RecordType[] VALS = RecordType.values(); + private static final RecordType[] VALS; + + static { + RecordType[] recordTypes = RecordType.values(); + + int maxIdx = 0; + for (RecordType recordType : recordTypes) + maxIdx = Math.max(maxIdx, recordType.idx); + + VALS = new RecordType[maxIdx + 1]; + + for (RecordType recordType : recordTypes) + VALS[recordType.idx] = recordType; + } /** */ - public static RecordType fromOrdinal(int ord) { - return ord < 0 || ord >= VALS.length ? null : VALS[ord]; + public static RecordType fromIndex(int idx) { + return idx < 0 || idx >= VALS.length ? null : VALS[idx]; } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV1Serializer.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV1Serializer.java index e27faa5f02025..193e492b06d3b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV1Serializer.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV1Serializer.java @@ -56,7 +56,7 @@ * Record V1 serializer. * Stores records in following format: *
    - *
  • Record type from {@link RecordType#ordinal()} incremented by 1
  • + *
  • Record type from {@link RecordType#index()} incremented by 1
  • *
  • WAL pointer to double check consistency
  • *
  • Data
  • *
  • CRC or zero padding
  • @@ -265,7 +265,7 @@ public static SegmentHeader readSegmentHeader(SegmentIO io, SegmentFileInputFact if (recordType == WALRecord.RecordType.STOP_ITERATION_RECORD_TYPE) throw new SegmentEofException("Reached logical end of the segment", null); - WALRecord.RecordType type = WALRecord.RecordType.fromOrdinal(recordType - 1); + WALRecord.RecordType type = WALRecord.RecordType.fromIndex(recordType - 1); if (type != WALRecord.RecordType.HEADER_RECORD) throw new IOException("Can't read serializer version", null); @@ -330,7 +330,7 @@ private static void putPositionOfRecord(ByteBuffer buf, WALRecord rec) { * @param rec WAL record. */ static void putRecordType(ByteBuffer buf, WALRecord rec) { - buf.put((byte)(rec.type().ordinal() + 1)); + buf.put((byte)(rec.type().index() + 1)); } /** @@ -347,7 +347,7 @@ static RecordType readRecordType(DataInput in) throws IgniteCheckedException, IO if (type == WALRecord.RecordType.STOP_ITERATION_RECORD_TYPE) throw new SegmentEofException("Reached logical end of the segment", null); - return RecordType.fromOrdinal(type - 1); + return RecordType.fromIndex(type - 1); } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV2Serializer.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV2Serializer.java index 4a5ab3da77674..22ee9fbf565f8 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV2Serializer.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV2Serializer.java @@ -46,7 +46,7 @@ * Record V2 serializer. * Stores records in following format: *
      - *
    • Record type from {@link RecordType#ordinal()} incremented by 1
    • + *
    • Record type from {@link RecordType#index()} incremented by 1
    • *
    • WAL pointer to double check consistency
    • *
    • Record length
    • *
    • Data
    • diff --git a/modules/core/src/test/java/org/apache/ignite/internal/pagemem/wal/record/WALRecordTest.java b/modules/core/src/test/java/org/apache/ignite/internal/pagemem/wal/record/WALRecordTest.java new file mode 100644 index 0000000000000..baf2ec736d291 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/pagemem/wal/record/WALRecordTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2019 GridGain Systems, Inc. and Contributors. + * + * Licensed under the GridGain Community Edition License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.gridgain.com/products/software/community-edition/gridgain-community-edition-license + * + * 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.pagemem.wal.record; + +import java.util.Arrays; +import junit.framework.TestCase; +import org.apache.ignite.internal.pagemem.wal.record.WALRecord.RecordType; + +/** */ +public class WALRecordTest extends TestCase { + + /** */ + public void testRecordTypeIndex() { + RecordType[] recordTypes = RecordType.values(); + + for (RecordType recordType : recordTypes) + assertSame(recordType, RecordType.fromIndex(recordType.index())); + + int minIdx = Arrays.stream(recordTypes).mapToInt(RecordType::index).min().orElse(Integer.MIN_VALUE); + + assertTrue(minIdx >= 0); + + int maxIdx = Arrays.stream(recordTypes).mapToInt(RecordType::index).max().orElse(Integer.MAX_VALUE); + + assertTrue(maxIdx < 256); + } +} \ No newline at end of file diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java index 83c360f99c6fa..9f76a8bfeef59 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java @@ -44,6 +44,7 @@ import org.apache.ignite.internal.MarshallerContextLockingSelfTest; import org.apache.ignite.internal.TransactionsMXBeanImplTest; import org.apache.ignite.internal.managers.IgniteDiagnosticMessagesTest; +import org.apache.ignite.internal.pagemem.wal.record.WALRecordTest; import org.apache.ignite.internal.processors.DeadLockOnNodeLeftExchangeTest; import org.apache.ignite.internal.processors.affinity.GridAffinityAssignmentV2Test; import org.apache.ignite.internal.processors.affinity.GridAffinityAssignmentV2TestNoOptimizations; @@ -196,6 +197,8 @@ public static TestSuite suite(@Nullable final Set ignoredTests) throws Ex suite.addTestSuite(AttributeNodeFilterSelfTest.class); + suite.addTestSuite(WALRecordTest.class); + // Basic DB data structures. suite.addTestSuite(BPlusTreeSelfTest.class); suite.addTestSuite(BPlusTreeFakeReuseSelfTest.class); From 91c2faa426b14bb311696d1269ffec6208e935f2 Mon Sep 17 00:00:00 2001 From: Slava Koptilin Date: Tue, 9 Jul 2019 17:52:57 +0300 Subject: [PATCH 25/62] GG-19486 Fixed IgniteOutOfMemoryException when IgniteCache#clear() is called (cherry picked from commit d1b0787c5f1f42a1dfe402fec859a86625dc0d0d) --- .../persistence/GridCacheOffheapManager.java | 1 - .../IgniteCacheDatabaseSharedManager.java | 67 ++++++++- .../cache/persistence/RowStore.java | 11 +- .../persistence/freelist/CacheFreeList.java | 5 +- .../cache/tree/CacheDataRowStore.java | 4 - .../CacheIgniteOutOfMemoryExceptionTest.java | 141 ++++++++++++++++++ .../database/CacheFreeListSelfTest.java | 1 - .../testsuites/IgniteCacheTestSuite6.java | 2 + 8 files changed, 219 insertions(+), 13 deletions(-) create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheIgniteOutOfMemoryExceptionTest.java diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java index 2e73094761469..5d72b8b1948a6 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java @@ -1686,7 +1686,6 @@ private CacheDataStore init0(boolean checkExists) throws IgniteCheckedException freeListName, grp.dataRegion().memoryMetrics(), grp.dataRegion(), - null, ctx.wal(), reuseRoot.pageId().pageId(), reuseRoot.isAllocated(), diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java index bd07673221c14..86e5e8e3772a5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java @@ -38,11 +38,14 @@ import org.apache.ignite.configuration.DataRegionConfiguration; import org.apache.ignite.configuration.DataStorageConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.failure.FailureContext; +import org.apache.ignite.failure.FailureType; import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.managers.discovery.GridDiscoveryManager; import org.apache.ignite.internal.mem.DirectMemoryProvider; import org.apache.ignite.internal.mem.DirectMemoryRegion; +import org.apache.ignite.internal.mem.IgniteOutOfMemoryException; import org.apache.ignite.internal.mem.file.MappedFileMemoryProvider; import org.apache.ignite.internal.mem.unsafe.UnsafeMemoryProvider; import org.apache.ignite.internal.pagemem.PageMemory; @@ -59,6 +62,7 @@ import org.apache.ignite.internal.processors.cache.persistence.evict.Random2LruPageEvictionTracker; import org.apache.ignite.internal.processors.cache.persistence.evict.RandomLruPageEvictionTracker; import org.apache.ignite.internal.processors.cache.persistence.filename.PdsFolderSettings; +import org.apache.ignite.internal.processors.cache.persistence.freelist.AbstractFreeList; import org.apache.ignite.internal.processors.cache.persistence.freelist.CacheFreeList; import org.apache.ignite.internal.processors.cache.persistence.freelist.FreeList; import org.apache.ignite.internal.processors.cache.persistence.metastorage.MetaStorage; @@ -257,7 +261,6 @@ protected void initPageMemoryDataStructures(DataStorageConfiguration dbCfg) thro freeListName, memMetrics, memPlc, - null, persistenceEnabled ? cctx.wal() : null, 0L, true, @@ -983,6 +986,68 @@ public void releaseHistoryForPreloading() { // No-op } + /** + * Checks that the given {@code region} has enough space for putting a new entry. + * + * This method makes sense then and only then + * the data region is not persisted {@link DataRegionConfiguration#isPersistenceEnabled()} + * and page eviction is disabled {@link DataPageEvictionMode#DISABLED}. + * + * The non-persistent region should reserve a number of pages to support a free list {@link AbstractFreeList}. + * For example, removing a row from underlying store may require allocating a new data page + * in order to move a tracked page from one bucket to another one which does not have a free space for a new stripe. + * See {@link AbstractFreeList#removeDataRowByLink}. + * Therefore, inserting a new entry should be prevented in case of some threshold is exceeded. + * + * @param region Data region to be checked. + * @throws IgniteOutOfMemoryException In case of the given data region does not have enough free space + * for putting a new entry. + */ + public void ensureFreeSpaceForInsert(DataRegion region) throws IgniteOutOfMemoryException { + if (region == null) + return; + + DataRegionConfiguration regCfg = region.config(); + + if (regCfg.getPageEvictionMode() != DataPageEvictionMode.DISABLED || regCfg.isPersistenceEnabled()) + return; + + long memorySize = regCfg.getMaxSize(); + + PageMemory pageMem = region.pageMemory(); + + CacheFreeList freeList = freeListMap.get(regCfg.getName()); + + long nonEmptyPages = (pageMem.loadedPages() - freeList.emptyDataPages()); + + // The maximum number of pages that can be allocated (memorySize / systemPageSize) + // should be greater or equal to the current number of non-empty pages plus + // the number of pages that may be required in order to move all pages to a reuse bucket, + // that is equal to nonEmptyPages * 8 / pageSize, where 8 is the size of a link. + // Note that not the whole page can be used to storing links, + // see PagesListNodeIO and PagesListMetaIO#getCapacity(), so we pessimistically multiply the result on 1.5, + // in any way, the number of required pages is less than 1 percent. + boolean oomThreshold = (memorySize / pageMem.systemPageSize()) < + (nonEmptyPages * (8.0 / pageMem.pageSize() + 1) * 1.5 + 256 /*one page per bucket*/); + + if (oomThreshold) { + IgniteOutOfMemoryException oom = new IgniteOutOfMemoryException("Out of memory in data region [" + + "name=" + regCfg.getName() + + ", initSize=" + U.readableSize(regCfg.getInitialSize(), false) + + ", maxSize=" + U.readableSize(regCfg.getMaxSize(), false) + + ", persistenceEnabled=" + regCfg.isPersistenceEnabled() + "] Try the following:" + U.nl() + + " ^-- Increase maximum off-heap memory size (DataRegionConfiguration.maxSize)" + U.nl() + + " ^-- Enable Ignite persistence (DataRegionConfiguration.persistenceEnabled)" + U.nl() + + " ^-- Enable eviction or expiration policies" + ); + + if (cctx.kernalContext() != null) + cctx.kernalContext().failure().process(new FailureContext(FailureType.CRITICAL_ERROR, oom)); + + throw oom; + } + } + /** * See {@link GridCacheMapEntry#ensureFreeSpace()} * diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java index 4ca6f7f34934a..fde5ca2a946e9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java @@ -25,8 +25,8 @@ import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.persistence.freelist.FreeList; import org.apache.ignite.internal.processors.query.GridQueryRowCacheCleaner; -import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.internal.stat.IoStatisticsHolder; +import org.apache.ignite.internal.util.typedef.internal.U; /** * Data store for H2 rows. @@ -50,6 +50,9 @@ public class RowStore { /** Row cache cleaner. */ private GridQueryRowCacheCleaner rowCacheCleaner; + /** */ + protected final CacheGroupContext grp; + /** * @param grp Cache group. * @param freeList Free list. @@ -58,6 +61,7 @@ public RowStore(CacheGroupContext grp, FreeList freeList) { assert grp != null; assert freeList != null; + this.grp = grp; this.freeList = freeList; ctx = grp.shared(); @@ -96,8 +100,11 @@ public void removeRow(long link, IoStatisticsHolder statHolder) throws IgniteChe * @throws IgniteCheckedException If failed. */ public void addRow(CacheDataRow row, IoStatisticsHolder statHolder) throws IgniteCheckedException { - if (!persistenceEnabled) + if (!persistenceEnabled) { + ctx.database().ensureFreeSpaceForInsert(grp.dataRegion()); + freeList.insertDataRow(row, statHolder); + } else { ctx.database().checkpointReadLock(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/CacheFreeList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/CacheFreeList.java index 755610cff59f6..f6f549563619e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/CacheFreeList.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/CacheFreeList.java @@ -23,7 +23,6 @@ import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow; import org.apache.ignite.internal.processors.cache.persistence.DataRegion; import org.apache.ignite.internal.processors.cache.persistence.DataRegionMetricsImpl; -import org.apache.ignite.internal.processors.cache.persistence.tree.reuse.ReuseList; import org.apache.ignite.internal.processors.cache.persistence.tree.util.PageLockListener; import org.apache.ignite.internal.stat.IoStatisticsHolder; import org.apache.ignite.internal.util.typedef.internal.U; @@ -37,7 +36,6 @@ public class CacheFreeList extends AbstractFreeList { * @param name Name. * @param regionMetrics Region metrics. * @param dataRegion Data region. - * @param reuseList Reuse list. * @param wal Wal. * @param metaPageId Meta page id. * @param initNew Initialize new. @@ -47,7 +45,6 @@ public CacheFreeList( String name, DataRegionMetricsImpl regionMetrics, DataRegion dataRegion, - ReuseList reuseList, IgniteWriteAheadLogManager wal, long metaPageId, boolean initNew, @@ -58,7 +55,7 @@ public CacheFreeList( name, regionMetrics, dataRegion, - reuseList, + null, wal, metaPageId, initNew, diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/CacheDataRowStore.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/CacheDataRowStore.java index 28d8919aa338e..152c74e2bb916 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/CacheDataRowStore.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/CacheDataRowStore.java @@ -32,9 +32,6 @@ public class CacheDataRowStore extends RowStore { /** */ private final int partId; - /** */ - private final CacheGroupContext grp; - /** * @param grp Cache group. * @param freeList Free list. @@ -44,7 +41,6 @@ public CacheDataRowStore(CacheGroupContext grp, FreeList freeList, int partId) { super(grp, freeList); this.partId = partId; - this.grp = grp; } /** diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheIgniteOutOfMemoryExceptionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheIgniteOutOfMemoryExceptionTest.java new file mode 100644 index 0000000000000..5cac543656423 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheIgniteOutOfMemoryExceptionTest.java @@ -0,0 +1,141 @@ +/* + * Copyright 2019 GridGain Systems, Inc. and Contributors. + * + * Licensed under the GridGain Community Edition License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.gridgain.com/products/software/community-edition/gridgain-community-edition-license + * + * 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.processors.cache; + +import java.util.concurrent.atomic.AtomicBoolean; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteCache; +import org.apache.ignite.cache.CacheAtomicityMode; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.DataRegionConfiguration; +import org.apache.ignite.configuration.DataStorageConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.failure.AbstractFailureHandler; +import org.apache.ignite.failure.FailureContext; +import org.apache.ignite.internal.mem.IgniteOutOfMemoryException; +import org.apache.ignite.internal.util.typedef.X; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; + +import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC; +import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL; +import static org.apache.ignite.configuration.DataPageEvictionMode.DISABLED; + +/** + * Tests behavior of IgniteCache when {@link IgniteOutOfMemoryException} is thrown. + */ +public class CacheIgniteOutOfMemoryExceptionTest extends GridCommonAbstractTest { + /** */ + private static final long DATA_REGION_SIZE = 20L * 1024 * 1024; + + /** */ + private static final int ATTEMPTS_NUM = 3; + + /** Node failure occurs. */ + private static final AtomicBoolean failure = new AtomicBoolean(false); + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(gridName); + + cfg.setDataStorageConfiguration(new DataStorageConfiguration() + .setDefaultDataRegionConfiguration( + new DataRegionConfiguration() + .setMaxSize(DATA_REGION_SIZE) + .setPageEvictionMode(DISABLED) + .setPersistenceEnabled(false))); + + cfg.setFailureHandler(new AbstractFailureHandler() { + /** {@inheritDoc} */ + @Override protected boolean handle(Ignite ignite, FailureContext failureCtx) { + failure.set(true); + + // Do not invalidate a node context. + return false; + } + }); + + cfg.setCacheConfiguration( + new CacheConfiguration(ATOMIC.name()).setAtomicityMode(ATOMIC), + new CacheConfiguration(TRANSACTIONAL.name()).setAtomicityMode(TRANSACTIONAL)); + + return cfg; + } + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + startGrid(0); + } + + /** {@inheritDoc} */ + @Override protected void afterTestsStopped() throws Exception { + stopAllGrids(); + } + + /** + * @throws Exception If failed. + */ + public void testLoadAndClearAtomicCache() throws Exception { + loadAndClearCache(ATOMIC, ATTEMPTS_NUM); + } + + /** + * @throws Exception If failed. + */ + public void testLoadAndClearTransactionalCache() throws Exception { + loadAndClearCache(TRANSACTIONAL, ATTEMPTS_NUM); + } + + /** + * Creates a new cache with the given atomicity node and tries to load & clear it in a loop. + * It is assumed that {@link IgniteOutOfMemoryException} is thrown during loading the cache, + * however {@link IgniteCache#clear()} should return the cache to the operable state. + * + * @param mode Cache atomicity mode. + * @param attempts Number of attempts to load and clear the cache. + */ + private void loadAndClearCache(CacheAtomicityMode mode, int attempts) { + IgniteCache cache = grid(0).cache(mode.name()); + + for (int i = 0; i < attempts; ++i) { + try { + for (int key = 0; key < 500_000; ++key) + cache.put(key, "abc"); + + fail("OutOfMemoryException hasn't been thrown"); + } + catch (Exception e) { + assertTrue( + "Exception has been thrown, but the exception type is unexpected [exc=" + e + ']', + X.hasCause(e, IgniteOutOfMemoryException.class)); + + assertTrue("Failure handler should be called due to IOOM.", failure.get()); + } + + // Let's check that the cache can be cleared without any errors. + failure.set(false); + + try { + cache.clear(); + } + catch (Exception e) { + fail("Clearing the cache should not trigger any exception [exc=" + e +']'); + } + + assertFalse("Failure handler should not be called during clearing the cache.", failure.get()); + } + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/database/CacheFreeListSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/CacheFreeListSelfTest.java index 77b9afeb7d44d..6f50bea56ff6b 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/database/CacheFreeListSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/CacheFreeListSelfTest.java @@ -352,7 +352,6 @@ protected FreeList createFreeList(int pageSize) throws Exception { regionMetrics, dataRegion, null, - null, metaPageId, true, null diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java index e0257318b090f..e0ab420dbb936 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java @@ -18,6 +18,7 @@ package org.apache.ignite.testsuites; import junit.framework.TestSuite; +import org.apache.ignite.internal.processors.cache.CacheIgniteOutOfMemoryExceptionTest; import org.apache.ignite.internal.processors.cache.CacheNoAffinityExchangeTest; import org.apache.ignite.internal.processors.cache.ClientFastReplyCoordinatorFailureTest; import org.apache.ignite.internal.processors.cache.PartitionedAtomicCacheGetsDistributionTest; @@ -100,6 +101,7 @@ public static TestSuite suite() throws Exception { // TODO enable this test after IGNITE-6753, now it takes too long // suite.addTestSuite(IgniteOutOfMemoryPropagationTest.class); + suite.addTestSuite(CacheIgniteOutOfMemoryExceptionTest.class); suite.addTestSuite(ReplicatedAtomicCacheGetsDistributionTest.class); suite.addTestSuite(ReplicatedTransactionalOptimisticCacheGetsDistributionTest.class); From f593ded5889f0970a4d54d22a08e3e9e7e27c375 Mon Sep 17 00:00:00 2001 From: Aleksei Scherbakov Date: Wed, 10 Jul 2019 11:33:32 +0300 Subject: [PATCH 26/62] GG-20875 Fix assertion on counter reservation. --- .../cache/PartitionTxUpdateCounterImpl.java | 37 ++-- .../distributed/dht/GridDhtCacheAdapter.java | 28 ++- .../dht/GridDhtTransactionalCacheAdapter.java | 4 +- .../dht/atomic/GridDhtAtomicCache.java | 2 +- .../cache/transactions/IgniteTxHandler.java | 12 +- .../CacheDataLossOnPartitionMoveTest.java | 2 +- .../TxPartitionCounterStateAbstractTest.java | 4 +- ...xPartitionCounterStateConsistencyTest.java | 181 +++++++++++++++++- .../discovery/tcp/BlockTcpDiscoverySpi.java | 83 ++++++++ ...iscoveryReconnectUnstableTopologyTest.java | 82 -------- .../junits/common/GridCommonAbstractTest.java | 34 ++-- ...tadataConcurrentUpdateWithIndexesTest.java | 82 +------- 12 files changed, 332 insertions(+), 219 deletions(-) create mode 100644 modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/BlockTcpDiscoverySpi.java diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionTxUpdateCounterImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionTxUpdateCounterImpl.java index fd58b29cf477f..14eb004f38969 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionTxUpdateCounterImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/PartitionTxUpdateCounterImpl.java @@ -74,6 +74,9 @@ public class PartitionTxUpdateCounterImpl implements PartitionUpdateCounter { /** HWM. */ protected final AtomicLong reserveCntr = new AtomicLong(); + /** */ + private boolean first = true; + /** * Initial counter points to last sequential update after WAL recovery. * @deprecated TODO FIXME https://issues.apache.org/jira/browse/IGNITE-11794 @@ -84,7 +87,7 @@ public class PartitionTxUpdateCounterImpl implements PartitionUpdateCounter { @Override public void init(long initUpdCntr, @Nullable byte[] cntrUpdData) { cntr.set(initUpdCntr); - initCntr = initUpdCntr; + reserveCntr.set(initCntr = initUpdCntr); queue = fromBytes(cntrUpdData); } @@ -120,11 +123,14 @@ protected synchronized long highestAppliedCounter() { // Reserved update counter is updated only on exchange. long cur = get(); - // Special case: single node in topology. - if (val == 0) - reserveCntr.set(cur); + // Always set reserved counter equal to max known counter. + long max = Math.max(val, cur); - if (val < cur) // Outdated counter (txs are possible before current topology future is finished). + if (reserveCntr.get() < max) + reserveCntr.set(max); + + // Outdated counter (txs are possible before current topology future is finished if primary is not changed). + if (val < cur) return; // Absolute counter should be not less than last applied update. @@ -133,15 +139,17 @@ protected synchronized long highestAppliedCounter() { if (val < highestAppliedCounter()) throw new IgniteCheckedException("Failed to update the counter [newVal=" + val + ", curState=" + this + ']'); - if (reserveCntr.get() < val) - reserveCntr.set(val); // Adjust counter on new primary. - cntr.set(val); - // If some holes are present at this point, that means some update were missed on recovery and will be restored - // during rebalance. All gaps are safe to "forget". - if (!queue.isEmpty()) - queue.clear(); + /** If some holes are present at this point, thar means some update were missed on recovery and will be restored + * during rebalance. All gaps are safe to "forget". + * Should only do it for first PME (later missed updates on node left are reset in {@link #finalizeUpdateCounters}. */ + if (first) { + if (!queue.isEmpty()) + queue.clear(); + + first = false; + } } /** {@inheritDoc} */ @@ -220,7 +228,10 @@ else if (last.within(start) && last.within(start + delta - 1)) @Override public void updateInitial(long start, long delta) { update(start, delta); - reserveCntr.set(initCntr = get()); + initCntr = get(); + + if (reserveCntr.get() < initCntr) + reserveCntr.set(initCntr); } /** */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java index 4c00300e590b8..6cdc5de57c925 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java @@ -1575,8 +1575,7 @@ private void updateTtl(GridCacheAdapter cache, * @param curVer Current topology version. * @return {@code True} if cache affinity changed and operation should be remapped. */ - protected final boolean needRemap(AffinityTopologyVersion expVer, AffinityTopologyVersion curVer, - Collection keys) { + protected final boolean needRemap(AffinityTopologyVersion expVer, AffinityTopologyVersion curVer) { if (curVer.equals(expVer)) return false; @@ -1585,24 +1584,21 @@ protected final boolean needRemap(AffinityTopologyVersion expVer, AffinityTopolo if (curVer.compareTo(lastAffChangedTopVer) >= 0 && curVer.compareTo(expVer) <= 0) return false; - // TODO IGNITE-7164 check mvcc crd for mvcc enabled txs. + Collection cacheNodes0 = ctx.discovery().cacheGroupAffinityNodes(ctx.groupId(), expVer); + Collection cacheNodes1 = ctx.discovery().cacheGroupAffinityNodes(ctx.groupId(), curVer); - for (KeyCacheObject key : keys) { - assert key.partition() != -1; + if (!cacheNodes0.equals(cacheNodes1) || ctx.affinity().affinityTopologyVersion().compareTo(curVer) < 0) + return true; - try { - List aff1 = ctx.affinity().assignments(expVer).get(key.partition()); - List aff2 = ctx.affinity().assignments(curVer).get(key.partition()); + try { + List> aff1 = ctx.affinity().assignments(expVer); + List> aff2 = ctx.affinity().assignments(curVer); - if (!aff1.containsAll(aff2) || aff2.isEmpty() || !aff1.get(0).equals(aff2.get(0))) - return true; - } - catch (IllegalStateException ignored) { - return true; - } + return !aff1.equals(aff2); + } + catch (IllegalStateException ignored) { + return true; } - - return false; } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTransactionalCacheAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTransactionalCacheAdapter.java index 35f2ceafef80a..9c700fc17a83e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTransactionalCacheAdapter.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTransactionalCacheAdapter.java @@ -938,7 +938,7 @@ public IgniteInternalFuture lockAllAsync( } try { - if (top != null && needRemap(req.topologyVersion(), top.readyTopologyVersion(), req.keys())) { + if (top != null && needRemap(req.topologyVersion(), top.readyTopologyVersion())) { if (log.isDebugEnabled()) { log.debug("Client topology version mismatch, need remap lock request [" + "reqTopVer=" + req.topologyVersion() + @@ -1043,7 +1043,7 @@ public IgniteInternalFuture lockAllAsync( } try { - if (top != null && needRemap(req.topologyVersion(), top.readyTopologyVersion(), req.keys())) { + if (top != null && needRemap(req.topologyVersion(), top.readyTopologyVersion())) { if (log.isDebugEnabled()) { log.debug("Client topology version mismatch, need remap lock request [" + "reqTopVer=" + req.topologyVersion() + diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java index 5cdb2009207d9..6f5898b157819 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java @@ -1745,7 +1745,7 @@ private void updateAllAsyncInternal0( // Can not wait for topology future since it will break // GridNearAtomicCheckUpdateRequest processing. remap = !top.topologyVersionFuture().exchangeDone() || - needRemap(req.topologyVersion(), top.readyTopologyVersion(), req.keys()); + needRemap(req.topologyVersion(), top.readyTopologyVersion()); } if (!remap) { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java index f4aa5693e164a..7f6f9836519ed 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java @@ -707,13 +707,17 @@ private boolean needRemap(AffinityTopologyVersion expVer, for (IgniteTxEntry e : F.concat(false, req.reads(), req.writes())) { GridCacheContext ctx = e.context(); - assert e.key().partition() != -1; + Collection cacheNodes0 = ctx.discovery().cacheGroupAffinityNodes(ctx.groupId(), expVer); + Collection cacheNodes1 = ctx.discovery().cacheGroupAffinityNodes(ctx.groupId(), curVer); + + if (!cacheNodes0.equals(cacheNodes1) || ctx.affinity().affinityTopologyVersion().compareTo(curVer) < 0) + return true; try { - List aff1 = ctx.affinity().assignments(expVer).get(e.key().partition()); - List aff2 = ctx.affinity().assignments(curVer).get(e.key().partition()); + List> aff1 = ctx.affinity().assignments(expVer); + List> aff2 = ctx.affinity().assignments(curVer); - if (!aff1.containsAll(aff2) || aff2.isEmpty() ||!aff1.get(0).equals(aff2.get(0))) + if (!aff1.equals(aff2)) return true; } catch (IllegalStateException ignored) { diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheDataLossOnPartitionMoveTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheDataLossOnPartitionMoveTest.java index 9ff072500b6fc..b514ccb44cb43 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheDataLossOnPartitionMoveTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheDataLossOnPartitionMoveTest.java @@ -125,7 +125,7 @@ public void testDataLossOnPartitionMove() throws Exception { ignite.cluster().active(true); List toCp = movingKeysAfterJoin(ignite, DEFAULT_CACHE_NAME, 1, - node -> ((GridTestNode)node).setAttribute(GRP_ATTR, ODD_GRP)); + node -> ((GridTestNode)node).setAttribute(GRP_ATTR, ODD_GRP), null); int blockPartId = ignite.affinity(DEFAULT_CACHE_NAME).partition(toCp.get(0)); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxPartitionCounterStateAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxPartitionCounterStateAbstractTest.java index 1cd016daff284..1d7c246efde9d 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxPartitionCounterStateAbstractTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxPartitionCounterStateAbstractTest.java @@ -90,7 +90,7 @@ */ public abstract class TxPartitionCounterStateAbstractTest extends GridCommonAbstractTest { /** IP finder. */ - private static final TcpDiscoveryVmIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true); + protected static final TcpDiscoveryVmIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true); /** */ private static final int MB = 1024 * 1024; @@ -171,7 +171,7 @@ protected CacheConfiguration cacheConfiguration(String name) { stopAllGrids(); - //cleanPersistenceDir(); + cleanPersistenceDir(); } /** diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxPartitionCounterStateConsistencyTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxPartitionCounterStateConsistencyTest.java index 1d727dfedd524..ef5a093f1a1f8 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxPartitionCounterStateConsistencyTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxPartitionCounterStateConsistencyTest.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal.processors.cache.transactions; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.LinkedList; @@ -30,11 +31,13 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.LongAdder; import java.util.stream.IntStream; + import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteSystemProperties; import org.apache.ignite.cluster.ClusterTopologyException; +import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.TestRecordingCommunicationSpi; @@ -44,8 +47,10 @@ import org.apache.ignite.internal.pagemem.wal.record.DataEntry; import org.apache.ignite.internal.pagemem.wal.record.DataRecord; import org.apache.ignite.internal.pagemem.wal.record.WALRecord; +import org.apache.ignite.internal.processors.cache.CacheAffinityChangeMessage; import org.apache.ignite.internal.processors.cache.CacheEntryInfoCollection; import org.apache.ignite.internal.processors.cache.GridCacheOperation; +import org.apache.ignite.internal.processors.cache.PartitionUpdateCounter; import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionSupplyMessage; import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionsFullMessage; import org.apache.ignite.internal.processors.cache.distributed.near.GridNearLockRequest; @@ -54,6 +59,8 @@ import org.apache.ignite.internal.util.typedef.X; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteBiTuple; +import org.apache.ignite.spi.discovery.tcp.BlockTcpDiscoverySpi; +import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; import org.apache.ignite.testframework.GridTestUtils; import org.apache.ignite.transactions.Transaction; import org.apache.ignite.transactions.TransactionRollbackException; @@ -72,6 +79,22 @@ public class TxPartitionCounterStateConsistencyTest extends TxPartitionCounterSt /** */ public static final int SERVER_NODES = 3; + /** */ + protected TcpDiscoverySpi customDiscoSpi; + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); + + if (customDiscoSpi != null) { + cfg.setDiscoverySpi(customDiscoSpi); + + customDiscoSpi = null; + } + + return cfg; + } + /** * Test if same updates order on all owners after txs are finished. */ @@ -436,6 +459,8 @@ public void testPartitionConsistencyDuringRebalanceAndConcurrentUpdates_SameAffi fut2.get(); log.info("TX: puts=" + puts.sum() + ", restarts=" + restarts.sum() + ", size=" + cache.size()); + + assertPartitionsSame(idleVerify(client)); } /** @@ -454,6 +479,10 @@ public void testPartitionConsistencyDuringRebalanceAndConcurrentUpdates_TxDuring IgniteCache cache = client.cache(DEFAULT_CACHE_NAME); + // Put one key per partition. + for (int k = 0; k < PARTS_CNT; k++) + cache.put(k, 0); + IgniteEx grid = grid(1); Integer key0 = primaryKey(grid.cache(DEFAULT_CACHE_NAME)); Integer key = primaryKey(grid(0).cache(DEFAULT_CACHE_NAME)); @@ -491,15 +520,15 @@ public void testPartitionConsistencyDuringRebalanceAndConcurrentUpdates_TxDuring }); IgniteInternalFuture txFut = GridTestUtils.runAsync(() -> { - try(Transaction tx = client.transactions().txStart()) { + try (Transaction tx = client.transactions().txStart()) { Map map = new LinkedHashMap<>(); - map.put(key, key); // clientFirst=true - map.put(key0, key0); // clientFirst=false + map.put(key, key); // clientFirst=true in lockAll. + map.put(key0, key0); // clientFirst=false in lockAll. cache.putAll(map); - tx.commit(); // Will start preparing in the middle of PME. + tx.commit(); // Will start preparing in the middle of PME. } }); @@ -526,6 +555,149 @@ public void testPartitionConsistencyDuringRebalanceAndConcurrentUpdates_TxDuring fut.get(); awaitPartitionMapExchange(); + + assertPartitionsSame(idleVerify(crd, DEFAULT_CACHE_NAME)); + } + + /** + * Tests tx load concurrently with PME for switching late affinity. + *

      + * Scenario: two keys tx mapped locally on late affinity topology and when mapped and prepared remotely on ideal + * topology, first key is mapped to non-moving partition, second is mapped on moving partition. + *

      + * Success: key over moving partition is prepared on new owner (choosed after late affinity switch), + * otherwise it's possible txs are prepared on different primaries after late affinity switch. + */ + public void testPartitionConsistencyDuringRebalanceAndConcurrentUpdates_LateAffinitySwitch() throws Exception { + backups = 1; + + customDiscoSpi = new BlockTcpDiscoverySpi().setIpFinder(IP_FINDER); + + Field rndAddrsField = U.findField(BlockTcpDiscoverySpi.class, "skipAddrsRandomization"); + assertNotNull(rndAddrsField); + rndAddrsField.set(customDiscoSpi, true); + + Ignite crd = startGrid(0); // Start coordinator with custom discovery SPI. + IgniteEx g1 = startGrid(1); + startGrid(2); + + crd.cluster().active(true); + + // Same name pattern as in test configuration. + String consistentId = "node" + getTestIgniteInstanceName(3); + + List g1Keys = primaryKeys(g1.cache(DEFAULT_CACHE_NAME), 10); + List movingFromG1 = movingKeysAfterJoin(g1, DEFAULT_CACHE_NAME, 10, null, consistentId); + + // Retain only stable keys; + g1Keys.removeAll(movingFromG1); + + // The key will move from grid0 to grid3. + Integer key = movingKeysAfterJoin(crd, DEFAULT_CACHE_NAME, 1, null, consistentId).get(0); + + IgniteEx g3 = startGrid(3); + + assertEquals(consistentId, g3.localNode().consistentId()); + + resetBaselineTopology(); + awaitPartitionMapExchange(); + + assertTrue(crd.affinity(DEFAULT_CACHE_NAME).isPrimary(g1.localNode(), g1Keys.get(0))); + + stopGrid(3); + + Ignite client = startGrid("client"); + + IgniteCache cache = client.cache(DEFAULT_CACHE_NAME); + IgniteCache cache2 = client.getOrCreateCache(cacheConfiguration(DEFAULT_CACHE_NAME + "2")); + + // Put one key per partition. + for (int k = 0; k < PARTS_CNT; k++) { + cache.put(k, 0); + cache2.put(k, 0); + } + + CountDownLatch resumeDiscoSndLatch = new CountDownLatch(1); + + BlockTcpDiscoverySpi crdDiscoSpi = (BlockTcpDiscoverySpi)grid(0).configuration().getDiscoverySpi(); + CyclicBarrier sync = new CyclicBarrier(2); + + crdDiscoSpi.setClosure((node, msg) -> { + if (msg instanceof CacheAffinityChangeMessage) { + U.awaitQuiet(sync); + U.awaitQuiet(resumeDiscoSndLatch); + } + + return null; + }); + + // Locks mapped wait. + IgniteInternalFuture fut = GridTestUtils.runAsync(() -> { + try { + startGrid(SERVER_NODES); + + awaitPartitionMapExchange(); + } + catch (Exception e) { + fail(X.getFullStackTrace(e)); + } + }); + + sync.await(); + + TestRecordingCommunicationSpi clientSpi = TestRecordingCommunicationSpi.spi(client); + clientSpi.blockMessages((node, msg) -> msg instanceof GridNearLockRequest); + + IgniteInternalFuture txFut = GridTestUtils.runAsync(new Runnable() { + @Override public void run() { + try (Transaction tx = client.transactions().txStart()) { + Map map = new LinkedHashMap<>(); + + map.put(g1Keys.get(0), g1Keys.get(0)); // clientFirst=true in lockAll mapped to stable part. + map.put(key, key); // clientFirst=false in lockAll mapped to moving part. + + cache.putAll(map); + cache2.putAll(new LinkedHashMap<>(map)); + + tx.commit(); // Will start preparing in the middle of PME. + } + } + }); + + IgniteInternalFuture lockFut = GridTestUtils.runAsync(new Runnable() { + @Override public void run() { + try { + // Wait for first lock request sent on local (late) topology. + clientSpi.waitForBlocked(); + // Continue late switch PME. + resumeDiscoSndLatch.countDown(); + crdDiscoSpi.setClosure(null); + + // Wait late affinity switch. + awaitPartitionMapExchange(); + // Continue tx mapping and preparing. + clientSpi.stopBlock(); + } + catch (InterruptedException e) { + fail(X.getFullStackTrace(e)); + } + } + }); + + fut.get(); + txFut.get(); + lockFut.get(); + + assertPartitionsSame(idleVerify(crd, DEFAULT_CACHE_NAME)); + + // TX must be prepared over new owner. + PartitionUpdateCounter cntr = counter(key, grid(3).name()); + assertNotNull(cntr); + assertEquals(cntr.toString(), 2, cntr.reserved()); + + PartitionUpdateCounter cntr2 = counter(key, DEFAULT_CACHE_NAME + "2", grid(3).name()); + assertNotNull(cntr2); + assertEquals(cntr2.toString(), 2, cntr2.reserved()); } /** @@ -649,4 +821,5 @@ public TestVal(int id) { @Override protected long getPartitionMapExchangeTimeout() { return getTestTimeout(); } + } diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/BlockTcpDiscoverySpi.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/BlockTcpDiscoverySpi.java new file mode 100644 index 0000000000000..33568211e3f23 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/BlockTcpDiscoverySpi.java @@ -0,0 +1,83 @@ +package org.apache.ignite.spi.discovery.tcp; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.internal.managers.discovery.CustomMessageWrapper; +import org.apache.ignite.internal.managers.discovery.DiscoveryCustomMessage; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgniteBiClosure; +import org.apache.ignite.spi.discovery.DiscoverySpiCustomMessage; +import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryAbstractMessage; +import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryCustomEventMessage; + +import static org.junit.Assert.assertNotNull; + +/** + * Custom discovery SPI allowing to block custom messages transfer between nodes. + */ +public class BlockTcpDiscoverySpi extends TcpDiscoverySpi { + /** Closure. */ + private volatile IgniteBiClosure clo; + + /** + * @param clo Closure. + */ + public void setClosure(IgniteBiClosure clo) { + this.clo = clo; + } + + /** + * @param addr Address. + * @param msg Message. + */ + private synchronized void apply(ClusterNode addr, TcpDiscoveryAbstractMessage msg) { + if (!(msg instanceof TcpDiscoveryCustomEventMessage)) + return; + + TcpDiscoveryCustomEventMessage cm = (TcpDiscoveryCustomEventMessage)msg; + + DiscoveryCustomMessage delegate; + + try { + DiscoverySpiCustomMessage custMsg = cm.message(marshaller(), U.resolveClassLoader(ignite().configuration())); + + assertNotNull(custMsg); + + delegate = ((CustomMessageWrapper)custMsg).delegate(); + + } + catch (Throwable throwable) { + throw new RuntimeException(throwable); + } + + if (clo != null) + clo.apply(addr, delegate); + } + + /** {@inheritDoc} */ + @Override protected void writeToSocket( + Socket sock, + TcpDiscoveryAbstractMessage msg, + byte[] data, + long timeout + ) throws IOException { + if (spiCtx != null) + apply(spiCtx.localNode(), msg); + + super.writeToSocket(sock, msg, data, timeout); + } + + /** {@inheritDoc} */ + @Override protected void writeToSocket(Socket sock, + OutputStream out, + TcpDiscoveryAbstractMessage msg, + long timeout) throws IOException, IgniteCheckedException { + if (spiCtx != null) + apply(spiCtx.localNode(), msg); + + super.writeToSocket(sock, out, msg, timeout); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryReconnectUnstableTopologyTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryReconnectUnstableTopologyTest.java index 79a8ed1053027..0740bdbd1f560 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryReconnectUnstableTopologyTest.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryReconnectUnstableTopologyTest.java @@ -17,34 +17,19 @@ package org.apache.ignite.spi.discovery.tcp; -import java.io.IOException; -import java.io.OutputStream; import java.lang.reflect.Field; -import java.net.Socket; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; import org.apache.ignite.Ignite; -import org.apache.ignite.IgniteCheckedException; -import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; -import org.apache.ignite.events.EventType; import org.apache.ignite.internal.DiscoverySpiTestListener; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.IgniteInternalFuture; -import org.apache.ignite.internal.managers.discovery.CustomMessageWrapper; -import org.apache.ignite.internal.managers.discovery.DiscoveryCustomMessage; import org.apache.ignite.internal.util.typedef.internal.U; -import org.apache.ignite.lang.IgniteBiClosure; -import org.apache.ignite.spi.discovery.DiscoverySpiCustomMessage; import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder; -import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryAbstractMessage; -import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryCustomEventMessage; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; /** * Test scenario: @@ -152,71 +137,4 @@ public void testReconnectUnstableTopology() throws Exception { private TcpDiscoverySpi spi(Ignite ig) { return (TcpDiscoverySpi)ig.configuration().getDiscoverySpi(); } - - /** - * Discovery SPI with blocking support. - */ - protected class BlockTcpDiscoverySpi extends TcpDiscoverySpi { - /** Closure. */ - private volatile IgniteBiClosure clo; - - /** - * @param clo Closure. - */ - public void setClosure(IgniteBiClosure clo) { - this.clo = clo; - } - - /** - * @param addr Address. - * @param msg Message. - */ - private synchronized void apply(ClusterNode addr, TcpDiscoveryAbstractMessage msg) { - if (!(msg instanceof TcpDiscoveryCustomEventMessage)) - return; - - TcpDiscoveryCustomEventMessage cm = (TcpDiscoveryCustomEventMessage)msg; - - DiscoveryCustomMessage delegate; - - try { - DiscoverySpiCustomMessage custMsg = cm.message(marshaller(), U.resolveClassLoader(ignite().configuration())); - - assertNotNull(custMsg); - - delegate = ((CustomMessageWrapper)custMsg).delegate(); - - } - catch (Throwable throwable) { - throw new RuntimeException(throwable); - } - - if (clo != null) - clo.apply(addr, delegate); - } - - /** {@inheritDoc} */ - @Override protected void writeToSocket( - Socket sock, - TcpDiscoveryAbstractMessage msg, - byte[] data, - long timeout - ) throws IOException { - if (spiCtx != null) - apply(spiCtx.localNode(), msg); - - super.writeToSocket(sock, msg, data, timeout); - } - - /** {@inheritDoc} */ - @Override protected void writeToSocket(Socket sock, - OutputStream out, - TcpDiscoveryAbstractMessage msg, - long timeout) throws IOException, IgniteCheckedException { - if (spiCtx != null) - apply(spiCtx.localNode(), msg); - - super.writeToSocket(sock, out, msg, timeout); - } - } } diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java index fd1b3b564f863..e904af6455e6e 100755 --- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java +++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java @@ -106,6 +106,7 @@ import org.apache.ignite.internal.util.typedef.G; import org.apache.ignite.internal.util.typedef.PA; import org.apache.ignite.internal.util.typedef.T2; +import org.apache.ignite.internal.util.typedef.T3; import org.apache.ignite.internal.util.typedef.internal.LT; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteBiInClosure; @@ -1350,7 +1351,7 @@ protected List nearKeys(IgniteCache cache, int cnt, int startFrom * @return List of keys. */ protected final List movingKeysAfterJoin(Ignite ign, String cacheName, int size) { - return movingKeysAfterJoin(ign, cacheName, size, null); + return movingKeysAfterJoin(ign, cacheName, size, null, null); } /** @@ -1361,11 +1362,13 @@ protected final List movingKeysAfterJoin(Ignite ign, String cacheName, * @param cacheName Cache name. * @param size Number of keys. * @param nodeInitializer Node initializer closure. + * @param joiningNodeConsistentId Joining node consistent id. * @return List of keys. */ protected final List movingKeysAfterJoin(Ignite ign, String cacheName, int size, - @Nullable IgniteInClosure nodeInitializer) { - assertEquals("Expected consistentId is set to node name", ign.name(), ign.cluster().localNode().consistentId()); + @Nullable IgniteInClosure nodeInitializer, @Nullable String joiningNodeConsistentId) { + if (joiningNodeConsistentId == null) + assertEquals("Expected consistentId is set to node name", ign.name(), ign.cluster().localNode().consistentId()); ArrayList nodes = new ArrayList<>(ign.cluster().nodes()); @@ -1376,7 +1379,8 @@ protected final List movingKeysAfterJoin(Ignite ign, String cacheName, if (nodeInitializer != null) nodeInitializer.apply(fakeNode); - fakeNode.consistentId(getTestIgniteInstanceName(nodes.size())); + fakeNode.consistentId(joiningNodeConsistentId == null ? getTestIgniteInstanceName(nodes.size()) : + joiningNodeConsistentId); nodes.add(fakeNode); @@ -2334,22 +2338,26 @@ protected void assertPartitionsSame(IdleVerifyResultV2 res) throws AssertionFail protected void assertCountersSame(int partId, boolean withReserveCntr) throws AssertionFailedError { PartitionUpdateCounter cntr0 = null; - for (Ignite ignite : G.allGrids()) { - if (ignite.configuration().isClientMode()) - continue; + List> cntrMap = G.allGrids().stream().filter(ignite -> + !ignite.configuration().isClientMode()).map(ignite -> + new T3<>(ignite.name(), counter(partId, ignite.name()), + ignite.affinity(DEFAULT_CACHE_NAME).isPrimary(ignite.cluster().localNode(), Integer.valueOf(partId)))).collect(Collectors.toList()); - PartitionUpdateCounter cntr = counter(partId, ignite.name()); - - log.info("node=" + ignite.name() + ", cntr=" + cntr); + for (T3 cntr : cntrMap) { + if (cntr.get2() == null) + continue; if (cntr0 != null) { - assertEquals("Expecting same counters [partId=" + partId + ']', cntr0, cntr); + assertEquals("Expecting same counters [partId=" + partId + + ", cntrs=" + cntrMap + ']', cntr0, cntr.get2()); if (withReserveCntr) - assertEquals("Expecting same reservation counters", cntr0.reserved(), cntr.reserved()); + assertEquals("Expecting same reservation counters [partId=" + partId + + ", cntrs=" + cntrMap + ']', + cntr0.reserved(), cntr.get2().reserved()); } - cntr0 = cntr; + cntr0 = cntr.get2(); } } } diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/BinaryMetadataConcurrentUpdateWithIndexesTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/BinaryMetadataConcurrentUpdateWithIndexesTest.java index 952045117f049..08b2c804deec9 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/BinaryMetadataConcurrentUpdateWithIndexesTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/BinaryMetadataConcurrentUpdateWithIndexesTest.java @@ -17,10 +17,7 @@ package org.apache.ignite.internal.processors.cache; -import java.io.IOException; -import java.io.OutputStream; import java.lang.reflect.Field; -import java.net.Socket; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -28,8 +25,6 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.ignite.Ignite; -import org.apache.ignite.IgniteCheckedException; -import org.apache.ignite.IgniteSystemProperties; import org.apache.ignite.binary.BinaryObject; import org.apache.ignite.binary.BinaryObjectBuilder; import org.apache.ignite.binary.BinaryObjectException; @@ -40,7 +35,6 @@ import org.apache.ignite.cache.QueryEntity; import org.apache.ignite.cache.QueryIndex; import org.apache.ignite.cache.QueryIndexType; -import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.DataRegionConfiguration; import org.apache.ignite.configuration.DataStorageConfiguration; @@ -49,19 +43,12 @@ import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.binary.BinaryMetadata; -import org.apache.ignite.internal.managers.discovery.CustomMessageWrapper; -import org.apache.ignite.internal.managers.discovery.DiscoveryCustomMessage; import org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl; import org.apache.ignite.internal.processors.cache.binary.MetadataUpdateProposedMessage; import org.apache.ignite.internal.processors.cache.index.AbstractIndexingCommonTest; import org.apache.ignite.internal.util.typedef.internal.U; -import org.apache.ignite.lang.IgniteBiClosure; -import org.apache.ignite.spi.discovery.DiscoverySpiCustomMessage; -import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; +import org.apache.ignite.spi.discovery.tcp.BlockTcpDiscoverySpi; import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder; -import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryAbstractMessage; -import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryCustomEventMessage; -import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import org.apache.ignite.transactions.Transaction; import static java.util.concurrent.TimeUnit.MILLISECONDS; @@ -355,73 +342,6 @@ protected BinaryObject build(Ignite ignite, String prefix, int... fields) { return builder.build(); } - /** - * Discovery SPI which can simulate network split. - */ - protected class BlockTcpDiscoverySpi extends TcpDiscoverySpi { - /** Closure. */ - private volatile IgniteBiClosure clo; - - /** - * @param clo Closure. - */ - public void setClosure(IgniteBiClosure clo) { - this.clo = clo; - } - - /** - * @param addr Address. - * @param msg Message. - */ - private synchronized void apply(ClusterNode addr, TcpDiscoveryAbstractMessage msg) { - if (!(msg instanceof TcpDiscoveryCustomEventMessage)) - return; - - TcpDiscoveryCustomEventMessage cm = (TcpDiscoveryCustomEventMessage)msg; - - DiscoveryCustomMessage delegate; - - try { - DiscoverySpiCustomMessage custMsg = cm.message(marshaller(), U.resolveClassLoader(ignite().configuration())); - - assertNotNull(custMsg); - - delegate = ((CustomMessageWrapper)custMsg).delegate(); - - } - catch (Throwable throwable) { - throw new RuntimeException(throwable); - } - - if (clo != null) - clo.apply(addr, delegate); - } - - /** {@inheritDoc} */ - @Override protected void writeToSocket( - Socket sock, - TcpDiscoveryAbstractMessage msg, - byte[] data, - long timeout - ) throws IOException { - if (spiCtx != null) - apply(spiCtx.localNode(), msg); - - super.writeToSocket(sock, msg, data, timeout); - } - - /** {@inheritDoc} */ - @Override protected void writeToSocket(Socket sock, - OutputStream out, - TcpDiscoveryAbstractMessage msg, - long timeout) throws IOException, IgniteCheckedException { - if (spiCtx != null) - apply(spiCtx.localNode(), msg); - - super.writeToSocket(sock, out, msg, timeout); - } - } - /** {@inheritDoc} */ @Override protected void beforeTest() throws Exception { super.beforeTest(); From 4b3419f88e7cdbf56b33c95c9d96b13aa50be720 Mon Sep 17 00:00:00 2001 From: Igor Seliverstov Date: Wed, 10 Jul 2019 13:00:52 +0300 Subject: [PATCH 27/62] GG-21105: [8.5-next]-[GG-21101] IgniteCacheClientReconnectTest.testClientInForceServerModeStopsOnExchangeHistoryExhaustion is flaky. --- .../IgniteCacheClientReconnectTest.java | 78 ++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheClientReconnectTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheClientReconnectTest.java index a0796a3e22ec7..9022c67877f74 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheClientReconnectTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheClientReconnectTest.java @@ -33,8 +33,12 @@ import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.IgniteInternalFuture; +import org.apache.ignite.internal.TestRecordingCommunicationSpi; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; +import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionsSingleMessage; import org.apache.ignite.internal.util.typedef.G; +import org.apache.ignite.lang.IgniteBiPredicate; +import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder; import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder; @@ -74,6 +78,15 @@ public class IgniteCacheClientReconnectTest extends GridCommonAbstractTest { /** */ private boolean forceServerMode; + /** */ + private boolean testCommunicationSpi; + + /** */ + private IgniteBiPredicate spiBlockPred; + + /** */ + private volatile TestRecordingCommunicationSpi spi; + /** {@inheritDoc} */ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); @@ -82,6 +95,13 @@ public class IgniteCacheClientReconnectTest extends GridCommonAbstractTest { ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setIpFinder(ipFinder); + if (testCommunicationSpi) { + spi = new TestRecordingCommunicationSpi(); + spi.blockMessages(spiBlockPred); + + cfg.setCommunicationSpi(spi); + } + if (!client) { CacheConfiguration[] ccfgs = new CacheConfiguration[CACHES]; @@ -161,7 +181,9 @@ public void testClientReconnectOnExchangeHistoryExhaustion() throws Exception { * * @throws Exception If failed */ - public void testClientInForceServerModeStopsOnExchangeHistoryExhaustion() throws Exception { + public void testClientInForceServerModeStopsOnExchangeHistoryExhaustionManyClients() throws Exception { + fail("https://ggsystems.atlassian.net/browse/GG-20801"); + System.setProperty(IgniteSystemProperties.IGNITE_EXCHANGE_HISTORY_SIZE, "1"); try { @@ -192,6 +214,60 @@ public void testClientInForceServerModeStopsOnExchangeHistoryExhaustion() throws } } + /** + * Verifies that in case of exchange history exhaustion + * (refer to javadoc at {@link #testClientReconnectOnExchangeHistoryExhaustion()} for more info about it) + * clients with forceServerMode=true flag don't try to reconnect to the cluster and stop. + * + * @throws Exception If failed + */ + public void testClientInForceServerModeStopsOnExchangeHistoryExhaustion() throws Exception { + System.setProperty(IgniteSystemProperties.IGNITE_EXCHANGE_HISTORY_SIZE, "1"); + + try { + testCommunicationSpi = true; + + startGrids(SRV_CNT); + + awaitPartitionMapExchange(); + + client = true; + + forceServerMode = true; + + CountDownLatch latch = new CountDownLatch(1); + + spiBlockPred = (n,m) -> { + if (m.getClass() == GridDhtPartitionsSingleMessage.class) { + latch.countDown(); + + return true; + } + + return false; + }; + + IgniteInternalFuture fut = GridTestUtils.runAsync(() -> startGrid(SRV_CNT)); + + assertTrue(latch.await(5000, MILLISECONDS)); + + TestRecordingCommunicationSpi spi = this.spi; + + spiBlockPred = null; + + startGrid(SRV_CNT + 1); + startGrid(SRV_CNT + 2); + + spi.stopBlock(); + + GridTestUtils.assertThrows(log(), () -> fut.get(5000), IgniteCheckedException.class, "Client node in forceServerMode is not allowed to reconnect to the cluster and will be stopped."); + } + finally { + System.clearProperty(IgniteSystemProperties.IGNITE_EXCHANGE_HISTORY_SIZE); + } + } + + /** * Verifies basic cache operations from all clients. */ From 715709770761d458b4822fbea55abb20669a6946 Mon Sep 17 00:00:00 2001 From: tledkov Date: Thu, 11 Jul 2019 11:13:34 +0300 Subject: [PATCH 28/62] GG-19609 [8.5-master]-[GG-19255] Inline index compatibility is broken from 8.4.9 to 8.5.7 if POJO primary key is used --- .../pagemem/wal/record/WALRecord.java | 5 +- ...itRootInlineFlagsCreatedVersionRecord.java | 97 ++++++++ .../cache/persistence/tree/BPlusTree.java | 112 ++++++++-- .../persistence/tree/io/BPlusMetaIO.java | 174 ++++++++++++++- .../serializer/RecordDataV1Serializer.java | 56 +++++ .../ignite/lang/IgniteProductVersion.java | 14 +- .../database/BPlusTreeSelfTest.java | 7 +- .../processors/query/h2/database/H2Tree.java | 210 ++++++++++++++++-- .../query/h2/database/H2TreeIndex.java | 8 +- .../database/H2TreeInlineObjectDetector.java | 125 +++++++++++ .../query/h2/database/InlineIndexHelper.java | 80 ++++--- .../h2/database/InlineIndexHelperTest.java | 16 +- 12 files changed, 808 insertions(+), 96 deletions(-) create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootInlineFlagsCreatedVersionRecord.java create mode 100644 modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java index 60e64e97e97f2..87ca9d689f9c4 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java @@ -187,7 +187,10 @@ public enum RecordType { ROLLBACK_TX_RECORD (57), /** */ - PARTITION_META_PAGE_UPDATE_COUNTERS_V2 (58); + PARTITION_META_PAGE_UPDATE_COUNTERS_V2 (58), + + /** Init root meta page (with flags and created version) */ + BTREE_META_PAGE_INIT_ROOT_V3 (59); /** Index for serialization. Should be consistent throughout all versions. */ private final int idx; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootInlineFlagsCreatedVersionRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootInlineFlagsCreatedVersionRecord.java new file mode 100644 index 0000000000000..9cbcbe7233ec4 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootInlineFlagsCreatedVersionRecord.java @@ -0,0 +1,97 @@ +/* + * Copyright 2019 GridGain Systems, Inc. and Contributors. + * + * Licensed under the GridGain Community Edition License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.gridgain.com/products/software/community-edition/gridgain-community-edition-license + * + * 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.pagemem.wal.record.delta; + +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.IgniteVersionUtils; +import org.apache.ignite.internal.pagemem.PageMemory; +import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusMetaIO; +import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.lang.IgniteProductVersion; + +/** + * + */ +public class MetaPageInitRootInlineFlagsCreatedVersionRecord extends MetaPageInitRootInlineRecord { + /** Created version. */ + private final long flags; + + /** Created version. */ + private final IgniteProductVersion createdVer; + + /** + * @param grpId Cache group ID. + * @param pageId Meta page ID. + * @param rootId Root id. + * @param inlineSize Inline size. + */ + public MetaPageInitRootInlineFlagsCreatedVersionRecord(int grpId, long pageId, long rootId, int inlineSize) { + super(grpId, pageId, rootId, inlineSize); + + createdVer = IgniteVersionUtils.VER; + flags = BPlusMetaIO.FLAGS_DEFAULT; + } + + /** + * @param grpId Cache group ID. + * @param pageId Meta page ID. + * @param rootId Root id. + * @param inlineSize Inline size. + * @param flags Flags. + * @param createdVer The version of ignite that creates this tree. + */ + public MetaPageInitRootInlineFlagsCreatedVersionRecord(int grpId, long pageId, long rootId, int inlineSize, + long flags, IgniteProductVersion createdVer) { + super(grpId, pageId, rootId, inlineSize); + + this.flags = flags; + this.createdVer = createdVer; + } + + /** {@inheritDoc} */ + @Override public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException { + super.applyDelta(pageMem, pageAddr); + + BPlusMetaIO io = BPlusMetaIO.VERSIONS.forPage(pageAddr); + + io.initFlagsAndVersion(pageAddr, flags, createdVer); + } + + /** {@inheritDoc} */ + @Override public RecordType type() { + return RecordType.BTREE_META_PAGE_INIT_ROOT_V3; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(MetaPageInitRootInlineFlagsCreatedVersionRecord.class, this, "super", super.toString()); + } + + /** + * @return Created version. + */ + public IgniteProductVersion createdVersion() { + return createdVer; + } + + /** + * @return Meta page flags. + */ + public long flags() { + return flags; + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/BPlusTree.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/BPlusTree.java index bf322bd485ceb..124736346419c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/BPlusTree.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/BPlusTree.java @@ -31,6 +31,7 @@ import org.apache.ignite.failure.FailureContext; import org.apache.ignite.failure.FailureType; import org.apache.ignite.internal.IgniteInterruptedCheckedException; +import org.apache.ignite.internal.IgniteVersionUtils; import org.apache.ignite.internal.UnregisteredBinaryTypeException; import org.apache.ignite.internal.UnregisteredClassException; import org.apache.ignite.internal.pagemem.PageIdUtils; @@ -42,7 +43,7 @@ import org.apache.ignite.internal.pagemem.wal.record.delta.InsertRecord; import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageAddRootRecord; import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageCutRootRecord; -import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageInitRootInlineRecord; +import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageInitRootInlineFlagsCreatedVersionRecord; import org.apache.ignite.internal.pagemem.wal.record.delta.NewRootInitRecord; import org.apache.ignite.internal.pagemem.wal.record.delta.RemoveRecord; import org.apache.ignite.internal.pagemem.wal.record.delta.ReplaceRecord; @@ -719,9 +720,10 @@ private class InitRoot extends PageHandler { io.initRoot(pageAddr, rootId, pageSize()); io.setInlineSize(pageAddr, inlineSize); + io.initFlagsAndVersion(pageAddr, BPlusMetaIO.FLAGS_DEFAULT, IgniteVersionUtils.VER); if (needWalDeltaRecord(metaId, metaPage, walPlc)) - wal.log(new MetaPageInitRootInlineRecord(cacheId, metaId, rootId, inlineSize)); + wal.log(new MetaPageInitRootInlineFlagsCreatedVersionRecord(cacheId, metaId, rootId, inlineSize)); assert io.getRootLevel(pageAddr) == 0; assert io.getFirstPageId(pageAddr, 0) == rootId; @@ -1042,44 +1044,105 @@ public final GridCursor find(L lower, L upper, Object x) throws IgniteChecked /** {@inheritDoc} */ @Override public T findFirst() throws IgniteCheckedException { + return findFirst(null); + } + + /** + * Returns a value mapped to the lowest key, or {@code null} if tree is empty or no entry matches the passed filter. + * @param filter Filter closure. + * @return Value. + * @throws IgniteCheckedException If failed. + */ + public T findFirst(TreeRowClosure filter) throws IgniteCheckedException { checkDestroyed(); long curPageId = 0L; long nextPageId = 0L; try { - long firstPageId; - - long metaPage = acquirePage(metaPageId); - try { - firstPageId = getFirstPageId(metaPageId, metaPage, 0); - } - finally { - releasePage(metaPageId, metaPage); - } + for (;;) { - long page = acquirePage(firstPageId); + long metaPage = acquirePage(metaPageId); - try { - long pageAddr = readLock(firstPageId, page); + try { + curPageId = getFirstPageId(metaPageId, metaPage, 0); // Level 0 is always at the bottom. + } + finally { + releasePage(metaPageId, metaPage); + } + long curPage = acquirePage(curPageId); try { - BPlusIO io = io(pageAddr); + long curPageAddr = readLock(curPageId, curPage); - int cnt = io.getCount(pageAddr); + if (curPageAddr == 0) + continue; // The first page has gone: restart scan. - if (cnt == 0) - return null; + try { + BPlusIO io = io(curPageAddr); + + assert io.isLeaf(); + + for (;;) { + int cnt = io.getCount(curPageAddr); - return getRow(io, pageAddr, 0); + for (int i = 0; i < cnt; ++i) { + if (filter == null || filter.apply(this, io, curPageAddr, i)) + return getRow(io, curPageAddr, i); + } + + nextPageId = io.getForward(curPageAddr); + + if (nextPageId == 0) + return null; + + long nextPage = acquirePage(nextPageId); + + try { + long nextPageAddr = readLock(nextPageId, nextPage); + + // In the current implementation the next page can't change when the current page is locked. + assert nextPageAddr != 0 : nextPageAddr; + + try { + long pa = curPageAddr; + curPageAddr = 0; // Set to zero to avoid double unlocking in finalizer. + + readUnlock(curPageId, curPage, pa); + + long p = curPage; + curPage = 0; // Set to zero to avoid double release in finalizer. + + releasePage(curPageId, p); + + curPageId = nextPageId; + curPage = nextPage; + curPageAddr = nextPageAddr; + + nextPage = 0; + nextPageAddr = 0; + } + finally { + if (nextPageAddr != 0) + readUnlock(nextPageId, nextPage, nextPageAddr); + } + } + finally { + if (nextPage != 0) + releasePage(nextPageId, nextPage); + } + } + } + finally { + if (curPageAddr != 0) + readUnlock(curPageId, curPage, curPageAddr); + } } finally { - readUnlock(firstPageId, page, pageAddr); + if (curPage != 0) + releasePage(curPageId, curPage); } } - finally { - releasePage(firstPageId, page); - } } catch (IgniteCheckedException e) { throw new IgniteCheckedException("Runtime failure on first row lookup", e); @@ -1092,6 +1155,7 @@ public final GridCursor find(L lower, L upper, Object x) throws IgniteChecked } } + /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public T findLast() throws IgniteCheckedException { @@ -4602,7 +4666,7 @@ protected int compare(int lvl, BPlusIO io, long pageAddr, int idx, L row) thr * @return Full detached data row. * @throws IgniteCheckedException If failed. */ - protected final T getRow(BPlusIO io, long pageAddr, int idx) throws IgniteCheckedException { + public final T getRow(BPlusIO io, long pageAddr, int idx) throws IgniteCheckedException { return getRow(io, pageAddr, idx, null); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/BPlusMetaIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/BPlusMetaIO.java index 623951bafc58d..56630e6bb25f2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/BPlusMetaIO.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/BPlusMetaIO.java @@ -19,8 +19,10 @@ import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteException; +import org.apache.ignite.internal.IgniteVersionUtils; import org.apache.ignite.internal.pagemem.PageUtils; import org.apache.ignite.internal.util.GridStringBuilder; +import org.apache.ignite.lang.IgniteProductVersion; /** * IO routines for B+Tree meta pages. @@ -28,17 +30,38 @@ public class BPlusMetaIO extends PageIO { /** */ public static final IOVersions VERSIONS = new IOVersions<>( - new BPlusMetaIO(1), new BPlusMetaIO(2) + new BPlusMetaIO(1), + new BPlusMetaIO(2), + new BPlusMetaIO(3), + new BPlusMetaIO(4) ); /** */ - private static final int LVLS_OFF = COMMON_HEADER_END; + private static final int LVLS_OFFSET = COMMON_HEADER_END; /** */ - private final int refsOff; + private static final int INLINE_SIZE_OFFSET = LVLS_OFFSET + 1; + + /** */ + private static final int FLAGS_OFFSET = INLINE_SIZE_OFFSET + 2; + + /** */ + private static final int CREATED_VER_OFFSET = FLAGS_OFFSET + 8; + + /** */ + private static final int REFS_OFFSET = CREATED_VER_OFFSET + IgniteProductVersion.SIZE_IN_BYTES; + + /** */ + private static final long FLAG_UNWRAPPED_PK = 1L; + + /** */ + private static final long FLAG_INLINE_OBJECT_SUPPORTED = 2L; + + /** FLAG_UNWRAPPED_PK - not set because unwrap PK not supported by 8.5.x versions. */ + public static final long FLAGS_DEFAULT = FLAG_INLINE_OBJECT_SUPPORTED; /** */ - private final int inlineSizeOff; + private final int refsOff; /** * @param ver Page format version. @@ -48,13 +71,19 @@ private BPlusMetaIO(int ver) { switch (ver) { case 1: - inlineSizeOff = -1; - refsOff = LVLS_OFF + 1; + refsOff = LVLS_OFFSET + 1; break; case 2: - inlineSizeOff = LVLS_OFF + 1; - refsOff = inlineSizeOff + 2; + refsOff = INLINE_SIZE_OFFSET + 2; + break; + + case 3: + refsOff = INLINE_SIZE_OFFSET + 2; + break; + + case 4: + refsOff = REFS_OFFSET; break; default: @@ -77,7 +106,7 @@ public void initRoot(long pageAdrr, long rootId, int pageSize) { * @return Number of levels in this tree. */ public int getLevelsCount(long pageAddr) { - return Byte.toUnsignedInt(PageUtils.getByte(pageAddr, LVLS_OFF)); + return Byte.toUnsignedInt(PageUtils.getByte(pageAddr, LVLS_OFFSET)); } /** @@ -97,7 +126,7 @@ private int getMaxLevels(long pageAddr, int pageSize) { private void setLevelsCount(long pageAddr, int lvls, int pageSize) { assert lvls >= 0 && lvls <= getMaxLevels(pageAddr, pageSize) : lvls; - PageUtils.putByte(pageAddr, LVLS_OFF, (byte)lvls); + PageUtils.putByte(pageAddr, LVLS_OFFSET, (byte)lvls); assert getLevelsCount(pageAddr) == lvls; } @@ -172,14 +201,105 @@ public void cutRoot(long pageAddr, int pageSize) { */ public void setInlineSize(long pageAddr, int size) { if (getVersion() > 1) - PageUtils.putShort(pageAddr, inlineSizeOff, (short)size); + PageUtils.putShort(pageAddr, INLINE_SIZE_OFFSET, (short)size); } /** * @param pageAddr Page address. + * @return Inline size. */ public int getInlineSize(long pageAddr) { - return getVersion() > 1 ? PageUtils.getShort(pageAddr, inlineSizeOff) : 0; + return getVersion() > 1 ? PageUtils.getShort(pageAddr, INLINE_SIZE_OFFSET) : 0; + } + + /** + * @param pageAddr Page address. + * @return {@code true} In case use unwrapped PK. + */ + public boolean unwrappedPk(long pageAddr) { + return supportFlags() && (flags(pageAddr) & FLAG_UNWRAPPED_PK) != 0L || getVersion() == 3; + } + + /** + * @param pageAddr Page address. + * @return {@code true} In case inline object is supported by the tree. + */ + public boolean inlineObjectSupported(long pageAddr) { + assert supportFlags(); + + return (flags(pageAddr) & FLAG_INLINE_OBJECT_SUPPORTED) != 0L; + } + + /** + * @return {@code true} If flags are supported. + */ + public boolean supportFlags() { + return getVersion() > 3; + } + + /** + * @param pageAddr Page address. + * @param flags Flags. + * @param createdVer The version of the product that creates the page (b+tree). + */ + public void initFlagsAndVersion(long pageAddr, long flags, IgniteProductVersion createdVer) { + PageUtils.putLong(pageAddr, FLAGS_OFFSET, flags); + + setCreatedVersion(pageAddr, createdVer); + } + + /** + * @param pageAddr Page address. + * @param curVer Ignite current version. + */ + public void setCreatedVersion(long pageAddr, IgniteProductVersion curVer) { + assert curVer != null; + + PageUtils.putByte(pageAddr, CREATED_VER_OFFSET, curVer.major()); + PageUtils.putByte(pageAddr, CREATED_VER_OFFSET + 1, curVer.minor()); + PageUtils.putByte(pageAddr, CREATED_VER_OFFSET + 2, curVer.maintenance()); + PageUtils.putLong(pageAddr, CREATED_VER_OFFSET + 3, curVer.revisionTimestamp()); + PageUtils.putBytes(pageAddr, CREATED_VER_OFFSET + 11, curVer.revisionHash()); + } + + /** + * @param pageAddr Page address. + * @return The version of product that creates the page. + */ + public IgniteProductVersion createdVersion(long pageAddr) { + if (getVersion() < 4) + return null; + + return new IgniteProductVersion( + PageUtils.getByte(pageAddr, CREATED_VER_OFFSET), + PageUtils.getByte(pageAddr, CREATED_VER_OFFSET + 1), + PageUtils.getByte(pageAddr, CREATED_VER_OFFSET + 2), + PageUtils.getLong(pageAddr, CREATED_VER_OFFSET + 3), + PageUtils.getBytes(pageAddr, CREATED_VER_OFFSET + 11, IgniteProductVersion.REV_HASH_SIZE)); + } + + /** + * @param pageAddr Page address. + * @return Long with flags. + */ + private long flags(long pageAddr) { + assert supportFlags(); + + return PageUtils.getLong(pageAddr, FLAGS_OFFSET); + } + + /** + * @param pageAddr Page address. + * @param unwrappedPk unwrapped primary key of this tree flag. + * @param inlineObjSupported inline POJO by created tree flag. + */ + public void setFlags(long pageAddr, boolean unwrappedPk, boolean inlineObjSupported) { + assert supportFlags(); + + long flags = unwrappedPk ? FLAG_UNWRAPPED_PK : 0; + flags |= inlineObjSupported ? FLAG_INLINE_OBJECT_SUPPORTED : 0; + + PageUtils.putLong(pageAddr, FLAGS_OFFSET, flags); } /** {@inheritDoc} */ @@ -191,4 +311,34 @@ public int getInlineSize(long pageAddr) { ; //TODO print firstPageIds by level } + + /** + * @param pageAddr Page address. + * @param inlineObjSupported Supports inline object flag. + * @param unwrappedPk Unwrap PK flag. + * @param pageSize Page size. + */ + public static void upgradePageVersion(long pageAddr, boolean inlineObjSupported, boolean unwrappedPk, int pageSize) { + BPlusMetaIO ioPrev = VERSIONS.forPage(pageAddr); + + long[] lvls = new long[ioPrev.getLevelsCount(pageAddr)]; + + for (int i = 0; i < lvls.length; ++i) + lvls[i] = ioPrev.getFirstPageId(pageAddr, i); + + int inlineSize = ioPrev.getInlineSize(pageAddr); + + BPlusMetaIO ioNew = VERSIONS.latest(); + + setVersion(pageAddr, VERSIONS.latest().getVersion()); + + ioNew.setLevelsCount(pageAddr, lvls.length, pageSize); + + for (int i = 0; i < lvls.length; ++i) + ioNew.setFirstPageId(pageAddr, i, lvls[i]); + + ioNew.setInlineSize(pageAddr, inlineSize); + ioNew.setCreatedVersion(pageAddr, IgniteVersionUtils.VER); + ioNew.setFlags(pageAddr, unwrappedPk, inlineObjSupported); + } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV1Serializer.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV1Serializer.java index 34bc50545cbc8..026b717163de3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV1Serializer.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV1Serializer.java @@ -54,6 +54,7 @@ import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageAddRootRecord; import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageCutRootRecord; import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageInitRecord; +import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageInitRootInlineFlagsCreatedVersionRecord; import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageInitRootInlineRecord; import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageInitRootRecord; import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageUpdateLastAllocatedIndex; @@ -93,6 +94,7 @@ import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.processors.cacheobject.IgniteCacheObjectProcessor; import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgniteProductVersion; /** * Record data V1 serializer. @@ -207,6 +209,9 @@ assert record instanceof PageSnapshot; case BTREE_META_PAGE_INIT_ROOT2: return 4 + 8 + 8 + 2; + case BTREE_META_PAGE_INIT_ROOT_V3: + return 4 + 8 + 8 + 2 + 8 + IgniteProductVersion.SIZE_IN_BYTES; + case BTREE_META_PAGE_ADD_ROOT: return 4 + 8 + 8; @@ -533,6 +538,34 @@ assert record instanceof PageSnapshot; break; + case BTREE_META_PAGE_INIT_ROOT_V3: + cacheId = in.readInt(); + pageId = in.readLong(); + + long rootId3 = in.readLong(); + int inlineSize3 = in.readShort(); + + long flags = in.readLong(); + + byte[] revHash = new byte[IgniteProductVersion.REV_HASH_SIZE]; + byte maj = in.readByte(); + byte min = in.readByte(); + byte maint = in.readByte(); + long verTs = in.readLong(); + in.readFully(revHash); + + IgniteProductVersion createdVer = new IgniteProductVersion( + maj, + min, + maint, + verTs, + revHash); + + res = new MetaPageInitRootInlineFlagsCreatedVersionRecord(cacheId, pageId, rootId3, + inlineSize3, flags, createdVer); + + break; + case BTREE_META_PAGE_ADD_ROOT: cacheId = in.readInt(); pageId = in.readLong(); @@ -1045,6 +1078,29 @@ assert record instanceof PageSnapshot; buf.putShort((short)imRec2.inlineSize()); break; + case BTREE_META_PAGE_INIT_ROOT_V3: + MetaPageInitRootInlineFlagsCreatedVersionRecord imRec3 = + (MetaPageInitRootInlineFlagsCreatedVersionRecord)rec; + + buf.putInt(imRec3.groupId()); + buf.putLong(imRec3.pageId()); + + buf.putLong(imRec3.rootId()); + + buf.putShort((short)imRec3.inlineSize()); + + buf.putLong(imRec3.flags()); + + // Write created version. + IgniteProductVersion createdVer = imRec3.createdVersion(); + buf.put(createdVer.major()); + buf.put(createdVer.minor()); + buf.put(createdVer.maintenance()); + buf.putLong(createdVer.revisionTimestamp()); + buf.put(createdVer.revisionHash()); + + break; + case BTREE_META_PAGE_ADD_ROOT: MetaPageAddRootRecord arRec = (MetaPageAddRootRecord)rec; diff --git a/modules/core/src/main/java/org/apache/ignite/lang/IgniteProductVersion.java b/modules/core/src/main/java/org/apache/ignite/lang/IgniteProductVersion.java index d456a10faa46b..409fb33474440 100644 --- a/modules/core/src/main/java/org/apache/ignite/lang/IgniteProductVersion.java +++ b/modules/core/src/main/java/org/apache/ignite/lang/IgniteProductVersion.java @@ -41,6 +41,12 @@ public class IgniteProductVersion implements Comparable, E /** */ private static final long serialVersionUID = 0L; + /** Size of the {@link #revHash }*/ + public static final int REV_HASH_SIZE = 20; + + /** Size in bytes of serialized: 3 bytes (maj, min, maintenance version), 8 bytes - timestamp */ + public static final int SIZE_IN_BYTES = 3 + 8 + REV_HASH_SIZE; + /** Regexp parse pattern. */ private static final Pattern VER_PATTERN = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)([-.]([^0123456789][^-]+)(-SNAPSHOT)?)?(-(\\d+))?(-([\\da-f]+))?"); @@ -90,15 +96,17 @@ public IgniteProductVersion(byte major, byte minor, byte maintenance, long revTs * @param revHash Revision hash. */ public IgniteProductVersion(byte major, byte minor, byte maintenance, String stage, long revTs, byte[] revHash) { - if (revHash != null && revHash.length != 20) - throw new IllegalArgumentException("Invalid length for SHA1 hash (must be 20): " + revHash.length); + if (revHash != null && revHash.length != REV_HASH_SIZE) { + throw new IllegalArgumentException("Invalid length for SHA1 hash (must be " + + REV_HASH_SIZE + "): " + revHash.length); + } this.major = major; this.minor = minor; this.maintenance = maintenance; this.stage = stage; this.revTs = revTs; - this.revHash = revHash != null ? revHash : new byte[20]; + this.revHash = revHash != null ? revHash : new byte[REV_HASH_SIZE]; } /** diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/database/BPlusTreeSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/BPlusTreeSelfTest.java index f6dc0a4375c22..359c76e2c5719 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/database/BPlusTreeSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/BPlusTreeSelfTest.java @@ -94,7 +94,7 @@ public class BPlusTreeSelfTest extends GridCommonAbstractTest { private static final short LONG_LEAF_IO = 30001; /** */ - protected static final int PAGE_SIZE = 256; + protected static final int PAGE_SIZE = 512; /** */ protected static final long MB = 1024 * 1024; @@ -142,6 +142,11 @@ protected void assertNoLocks() { assertTrue(TestPageLockListener.checkNoLocks()); } + /** {@inheritDoc} */ + @Override protected long getTestTimeout() { + return 15 * 60 * 1000L; + } + /** {@inheritDoc} */ @Override protected void beforeTest() throws Exception { stop.set(false); diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java index 29c1022ac1df0..0525f437dd3ac 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java @@ -20,10 +20,14 @@ import java.util.Comparator; import java.util.List; import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.IgniteException; +import org.apache.ignite.internal.pagemem.FullPageId; import org.apache.ignite.internal.pagemem.PageIdUtils; import org.apache.ignite.internal.pagemem.PageMemory; import org.apache.ignite.internal.pagemem.wal.IgniteWriteAheadLogManager; +import org.apache.ignite.internal.pagemem.wal.record.PageSnapshot; import org.apache.ignite.internal.processors.cache.persistence.tree.BPlusTree; import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusIO; import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusMetaIO; @@ -36,7 +40,11 @@ import org.apache.ignite.internal.processors.query.h2.opt.GridH2KeyValueRowOnheap; import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row; import org.apache.ignite.internal.stat.IoStatisticsHolder; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgnitePredicate; +import org.apache.ignite.lang.IgniteProductVersion; import org.apache.ignite.spi.indexing.IndexingQueryCacheFilter; import org.h2.result.SearchRow; import org.h2.table.IndexColumn; @@ -123,18 +131,9 @@ protected H2Tree( ); this.stats = stats; - - if (!initNew) { - // Page is ready - read inline size from it. - inlineSize = getMetaInlineSize(); - } - - this.inlineSize = inlineSize; - - assert rowStore != null; + this.rowCache = rowCache; this.rowStore = rowStore; - this.inlineIdxs = inlineIdxs; this.cols = cols; this.columnIds = new int[cols.length]; @@ -142,13 +141,68 @@ protected H2Tree( for (int i = 0; i < cols.length; i++) columnIds[i] = cols[i].column.getColumnId(); - this.rowCache = rowCache; + if (!initNew) { + // Page is ready - read meta information. + MetaPageInfo metaInfo = getMetaInfo(); + + if (metaInfo.useUnwrappedPk()) + throw new IgniteCheckedException("Unwrapped PK is not supported by current version"); + + this.inlineSize = metaInfo.inlineSize(); + + setIos( + H2ExtrasInnerIO.getVersions(inlineSize), + H2ExtrasLeafIO.getVersions(inlineSize)); + + boolean inlineObjSupported = inlineSize > 0 && inlineObjectSupported(metaInfo, inlineIdxs); + + this.inlineIdxs = inlineObjSupported ? inlineIdxs : inlineIdxs.stream() + .filter(ih -> ih.type() != Value.JAVA_OBJECT) + .collect(Collectors.toList()); + + if (!metaInfo.flagsSupported()) + upgradeMetaPage(inlineObjSupported); + } + else { + this.inlineSize = inlineSize; + + this.inlineIdxs = inlineIdxs; + + setIos( + H2ExtrasInnerIO.getVersions(inlineSize), + H2ExtrasLeafIO.getVersions(inlineSize)); + + initTree(initNew, inlineSize); + } + + created = initNew; + } - setIos(H2ExtrasInnerIO.getVersions(inlineSize), H2ExtrasLeafIO.getVersions(inlineSize)); + /** + * @param metaInfo Metapage info. + * @param inlineIdxs Base collection of index helpers. + * @return {@code true} if inline object is supported by exists tree. + */ + private boolean inlineObjectSupported(MetaPageInfo metaInfo, List inlineIdxs) { + if (metaInfo.flagsSupported()) + return metaInfo.inlineObjectSupported(); + else { + try { + if (H2TreeInlineObjectDetector.objectMayBeInlined(inlineSize, inlineIdxs)) { + H2TreeInlineObjectDetector inlineObjDetector = new H2TreeInlineObjectDetector( + inlineSize, inlineIdxs); - initTree(initNew, inlineSize); + findFirst(inlineObjDetector); - this.created = initNew; + return inlineObjDetector.inlineObjectSupported(); + } + else + return false; + } + catch (IgniteCheckedException e) { + throw new IgniteException("Unexpected exception on detect inline object", e); + } + } } /** @@ -204,7 +258,7 @@ private int inlineSize() { * @return Inline size. * @throws IgniteCheckedException If failed. */ - private int getMetaInlineSize() throws IgniteCheckedException { + private MetaPageInfo getMetaInfo() throws IgniteCheckedException { final long metaPage = acquirePage(metaPageId); try { @@ -216,7 +270,7 @@ private int getMetaInlineSize() throws IgniteCheckedException { try { BPlusMetaIO io = BPlusMetaIO.VERSIONS.forPage(pageAddr); - return io.getInlineSize(pageAddr); + return new MetaPageInfo(io, pageAddr); } finally { readUnlock(metaPageId, metaPage, pageAddr); @@ -227,6 +281,39 @@ private int getMetaInlineSize() throws IgniteCheckedException { } } + /** + * Update root meta page if need (previous version not supported features flags + * and created product version on root meta page). + * + * @param inlineObjSupported inline POJO by created tree flag. + * @throws IgniteCheckedException On error. + */ + private void upgradeMetaPage(boolean inlineObjSupported) throws IgniteCheckedException { + final long metaPage = acquirePage(metaPageId); + + try { + long pageAddr = writeLock(metaPageId, metaPage); // Meta can't be removed. + + assert pageAddr != 0 : "Failed to read lock meta page [metaPageId=" + + U.hexLong(metaPageId) + ']'; + + try { + BPlusMetaIO.upgradePageVersion(pageAddr, inlineObjSupported, false, pageSize()); + + if (wal != null) + wal.log(new PageSnapshot(new FullPageId(metaPageId, grpId), + pageAddr, pageMem.pageSize())); + } + finally { + writeUnlock(metaPageId, metaPage, pageAddr, true); + } + } + finally { + releasePage(metaPageId, metaPage); + } + } + + /** {@inheritDoc} */ @SuppressWarnings("ForLoopReplaceableByForEach") @Override protected int compare(BPlusIO io, long pageAddr, int idx, @@ -328,6 +415,92 @@ public int compareRows(SearchRow r1, SearchRow r2) { return stats; } + /** + * @return Inline indexes for the segment. + */ + public List inlineIndexes() { + return inlineIdxs; + } + + /** + * @param idxs Full set of inline helpers. + */ + public void refreshColumnIds(List idxs) { + assert inlineIdxs.size() <= idxs.size(); + + for (int i = 0; i < inlineIdxs.size(); ++i) { + final int idx = i; + + inlineIdxs.set(idx, F.find(idxs, null, + (IgnitePredicate)ih -> ih.colName().equals(inlineIdxs.get(idx).colName()))); + + assert inlineIdxs.get(idx) != null; + } + } + + /** + * + */ + private static class MetaPageInfo { + /** */ + int inlineSize; + + /** */ + boolean useUnwrappedPk; + + /** */ + boolean flagsSupported; + + /** */ + Boolean inlineObjectSupported; + + /** */ + IgniteProductVersion createdVer; + + /** + * @param io Metapage IO. + * @param pageAddr Page address. + */ + public MetaPageInfo(BPlusMetaIO io, long pageAddr) { + inlineSize = io.getInlineSize(pageAddr); + useUnwrappedPk = io.unwrappedPk(pageAddr); + flagsSupported = io.supportFlags(); + + if (flagsSupported) + inlineObjectSupported = io.inlineObjectSupported(pageAddr); + + createdVer = io.createdVersion(pageAddr); + } + + /** + * @return Inline size. + */ + public int inlineSize() { + return inlineSize; + } + + /** + * @return {@code true} In case use unwrapped PK for indexes. + */ + public boolean useUnwrappedPk() { + return useUnwrappedPk; + } + + /** + * @return {@code true} In case metapage contains flags. + */ + public boolean flagsSupported() { + return flagsSupported; + } + + /** + * @return {@code true} In case inline object is supported. + */ + public boolean inlineObjectSupported() { + return inlineObjectSupported; + } + } + /** * @param v1 First value. * @param v2 Second value. @@ -342,4 +515,9 @@ public int compareRows(SearchRow r1, SearchRow r2) { public boolean created() { return created; } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(H2Tree.class, this, "super", super.toString()); + } } diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java index 7ba9061a2c4c2..b221f1d18512b 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java @@ -205,6 +205,7 @@ private List getAvailableInlineColumns(IndexColumn[] cols) { break; InlineIndexHelper idx = new InlineIndexHelper( + col.column.getName(), col.column.getType(), col.column.getColumnId(), col.sortType, @@ -270,12 +271,12 @@ private List getAvailableInlineColumns(IndexColumn[] cols) { /** {@inheritDoc} */ @Override public boolean putx(GridH2Row row) { try { - InlineIndexHelper.setCurrentInlineIndexes(inlineIdxs); - int seg = segmentForRow(row); H2Tree tree = treeForRead(seg); + InlineIndexHelper.setCurrentInlineIndexes(tree.inlineIndexes()); + assert cctx.shared().database().checkpointLockIsHeldByThread(); return tree.putx(row); @@ -558,6 +559,9 @@ public PartitionFilterTreeRowClosure(IndexingQueryCacheFilter filter) { for (int pos = 0; pos < inlineHelpers.size(); ++pos) inlineIdxs.set(pos, inlineHelpers.get(pos)); + + for (H2Tree seg : segments) + seg.refreshColumnIds(inlineIdxs); } /** diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java new file mode 100644 index 0000000000000..83a3872f625a4 --- /dev/null +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java @@ -0,0 +1,125 @@ +/* + * Copyright 2019 GridGain Systems, Inc. and Contributors. + * + * Licensed under the GridGain Community Edition License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.gridgain.com/products/software/community-edition/gridgain-community-edition-license + * + * 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.processors.query.h2.database; + +import java.util.List; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.pagemem.PageUtils; +import org.apache.ignite.internal.processors.cache.persistence.tree.BPlusTree; +import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusIO; +import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row; +import org.h2.result.SearchRow; +import org.h2.value.Value; +import org.h2.value.ValueNull; + +/** + * Used to detect inline object. Because version wasn't upped. + */ +@SuppressWarnings("TypeMayBeWeakened") +public class H2TreeInlineObjectDetector implements BPlusTree.TreeRowClosure { + /** Inline size. */ + private final int inlineSize; + + /** Inline helpers. */ + private final List inlineHelpers; + + /** Inline object supported flag. */ + private boolean inlineObjSupported = true; + + /** + * @param inlineSize Inline size. + * @param inlineHelpers Inline helpers. + */ + H2TreeInlineObjectDetector(int inlineSize, List inlineHelpers) { + this.inlineSize = inlineSize; + this.inlineHelpers = inlineHelpers; + } + + /** {@inheritDoc} */ + @Override public boolean apply(BPlusTree tree, BPlusIO io, long pageAddr, + int idx) throws IgniteCheckedException { + GridH2Row r = tree.getRow(io, pageAddr, idx); + + int off = io.offset(idx); + + int fieldOff = 0; + + for (InlineIndexHelper ih : inlineHelpers) { + if (fieldOff >= inlineSize) + return false; + + if (ih.type() != Value.JAVA_OBJECT) { + fieldOff += ih.fullSize(pageAddr, off + fieldOff); + + continue; + } + + if (r.getValue(ih.columnIndex()) == ValueNull.INSTANCE) + return false; + + int type = PageUtils.getByte(pageAddr, off + fieldOff); + + if (type == 0) { + inlineObjSupported = false; + + return true; + } + else if (type == Value.JAVA_OBJECT) { + inlineObjSupported = true; + + return true; + } + else { + assert type == Value.UNKNOWN; + + return false; + } + } + + return true; + } + + /** + * @return {@code true} if inline object is supported on current tree. + */ + public boolean inlineObjectSupported() { + return inlineObjSupported; + } + + /** + * Static analyze inline_size and inline helpers set. + * e.g.: indexed: (long, obj) and inline_size < 12. + * In this case there is no space ti inline object. + * + * @param inlineHelpers Inline helpers. + * @param inlineSize Inline size. + * + * @return {@code true} If the object may be inlined. + */ + public static boolean objectMayBeInlined(int inlineSize, List inlineHelpers) { + int remainSize = inlineSize; + + for (InlineIndexHelper ih : inlineHelpers) { + if (ih.type() == Value.JAVA_OBJECT) + break; + + remainSize -= ih.size() > 0 ? 1 + ih.size() : 4; + } + + return remainSize >= 4; + } +} diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelper.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelper.java index 0299033fce399..1eb38ddf26872 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelper.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelper.java @@ -50,30 +50,41 @@ * Helper class for in-page indexes. */ public class InlineIndexHelper { + /** Value for comparison meaning 'Not enough information to compare'. */ + public static final int CANT_BE_COMPARE = -2; + private static final Charset CHARSET = StandardCharsets.UTF_8; /** PageContext for use in IO's */ private static final ThreadLocal> currentIndex = new ThreadLocal<>(); /** */ - public static final List AVAILABLE_TYPES = Arrays.asList( - Value.BOOLEAN, - Value.BYTE, - Value.SHORT, - Value.INT, - Value.LONG, - Value.FLOAT, - Value.DOUBLE, - Value.DATE, - Value.TIME, - Value.TIMESTAMP, - Value.UUID, - Value.STRING, - Value.STRING_FIXED, - Value.STRING_IGNORECASE, - Value.BYTES, - Value.JAVA_OBJECT - ); + public static final List AVAILABLE_TYPES; + + static { + List integers = Arrays.asList( + Value.BOOLEAN, + Value.BYTE, + Value.SHORT, + Value.INT, + Value.LONG, + Value.FLOAT, + Value.DOUBLE, + Value.DATE, + Value.TIME, + Value.TIMESTAMP, + Value.UUID, + Value.STRING, + Value.STRING_FIXED, + Value.STRING_IGNORECASE, + Value.BYTES, + Value.JAVA_OBJECT + ); + AVAILABLE_TYPES = integers; + } + + /** */ + private final String colName; /** */ private final int type; @@ -94,11 +105,16 @@ public class InlineIndexHelper { private final boolean compareStringsOptimized; /** + * @param colName Column name. * @param type Index type (see {@link Value}). * @param colIdx Index column index. * @param sortType Column sort type (see {@link IndexColumn#sortType}). + * @param compareMode Compare mode. */ - public InlineIndexHelper(int type, int colIdx, int sortType, CompareMode compareMode) { + public InlineIndexHelper(String colName, int type, int colIdx, int sortType, + CompareMode compareMode) { + + this.colName = colName; this.type = type; this.colIdx = colIdx; this.sortType = sortType; @@ -164,6 +180,13 @@ public InlineIndexHelper(int type, int colIdx, int sortType, CompareMode compare } } + /** + * @return Column name + */ + public String colName() { + return colName; + } + /** * @return Index type. */ @@ -227,7 +250,7 @@ public int fullSize(long pageAddr, int off) { if (size > 0) return size + 1; else - return PageUtils.getShort(pageAddr, off + 1) + 3; + return (PageUtils.getShort(pageAddr, off + 1) & 0x7FFF) + 3; } /** @@ -347,7 +370,7 @@ protected boolean isValueFull(long pageAddr, int off) { * @param maxSize Maximum size to read. * @param v Value to compare. * @param comp Comparator. - * @return Compare result (-2 means we can't compare). + * @return Compare result ( {@code CANT_BE_COMPARE} means we can't compare). */ public int compare(long pageAddr, int off, int maxSize, Value v, Comparator comp) { int c = tryCompareOptimized(pageAddr, off, maxSize, v); @@ -358,7 +381,7 @@ public int compare(long pageAddr, int off, int maxSize, Value v, Comparator 0 && size + 1 > maxSize) || maxSize < 1 || (type = PageUtils.getByte(pageAddr, off)) == Value.UNKNOWN) - return -2; + return CANT_BE_COMPARE; if (type == Value.NULL) return Integer.MIN_VALUE; @@ -568,7 +591,7 @@ private int compareAsPrimitive(long pageAddr, int off, Value v, int type) { * @param pageAddr Page address. * @param off Offset. * @param v Value to compare. - * @return Compare result ({@code -2} means we can't compare). + * @return Compare result ({@code CANT_BE_COMPARE} means we can't compare). */ private int compareAsBytes(long pageAddr, int off, Value v) { byte[] bytes = v.getBytesNoCopy(); @@ -620,7 +643,7 @@ private int compareAsBytes(long pageAddr, int off, Value v) { // b) Even truncated current value is longer, so that it's bigger. return fixSort(1, sortType()); - return -2; + return CANT_BE_COMPARE; } /** @@ -628,7 +651,7 @@ private int compareAsBytes(long pageAddr, int off, Value v) { * @param off Offset. * @param v Value to compare. * @param ignoreCase {@code True} if a case-insensitive comparison should be used. - * @return Compare result ({@code -2} means we can't compare). + * @return Compare result ({@code CANT_BE_COMPARE} means we can't compare). */ private int compareAsString(long pageAddr, int off, Value v, boolean ignoreCase) { String s = v.getString(); @@ -931,7 +954,6 @@ public int put(long pageAddr, int off, Value val, int maxSize) { return maxSize; } - } default: diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelperTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelperTest.java index fe77da32d84f4..724681bfde830 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelperTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/database/InlineIndexHelperTest.java @@ -207,7 +207,7 @@ private int putAndCompare(String v1, String v2, int maxSize) throws Exception { int off = 0; - InlineIndexHelper ih = new InlineIndexHelper(Value.STRING, 1, 0, + InlineIndexHelper ih = new InlineIndexHelper(null, Value.STRING, 1, 0, CompareMode.getInstance(null, 0)); ih.put(pageAddr, off, v1 == null ? ValueNull.INSTANCE : ValueString.get(v1), maxSize); @@ -232,7 +232,7 @@ public void testStringCut() { /** Test on String values compare */ public void testRelyOnCompare() { - InlineIndexHelper ha = new InlineIndexHelper(Value.STRING, 0, SortOrder.ASCENDING, + InlineIndexHelper ha = new InlineIndexHelper(null, Value.STRING, 0, SortOrder.ASCENDING, CompareMode.getInstance(null, 0)); // same size @@ -254,7 +254,7 @@ public void testRelyOnCompare() { /** Test on Bytes values compare */ public void testRelyOnCompareBytes() { - InlineIndexHelper ha = new InlineIndexHelper(Value.BYTES, 0, SortOrder.ASCENDING, + InlineIndexHelper ha = new InlineIndexHelper(null, Value.BYTES, 0, SortOrder.ASCENDING, CompareMode.getInstance(null, 0)); // same size @@ -276,7 +276,7 @@ public void testRelyOnCompareBytes() { /** Test on Bytes values compare */ public void testRelyOnCompareJavaObject() { - InlineIndexHelper ha = new InlineIndexHelper(Value.JAVA_OBJECT, 0, SortOrder.ASCENDING, + InlineIndexHelper ha = new InlineIndexHelper(null, Value.JAVA_OBJECT, 0, SortOrder.ASCENDING, CompareMode.getInstance(null, 0)); // different types @@ -323,7 +323,7 @@ public void testStringTruncate() throws Exception { int off = 0; - InlineIndexHelper ih = new InlineIndexHelper(Value.STRING, 1, 0, + InlineIndexHelper ih = new InlineIndexHelper(null, Value.STRING, 1, 0, CompareMode.getInstance(null, 0)); ih.put(pageAddr, off, ValueString.get("aaaaaaa"), 3 + 5); @@ -374,7 +374,7 @@ public void testBytes() throws Exception { int off = 0; - InlineIndexHelper ih = new InlineIndexHelper(Value.BYTES, 1, 0, + InlineIndexHelper ih = new InlineIndexHelper(null, Value.BYTES, 1, 0, CompareMode.getInstance(null, 0)); int maxSize = 3 + 3; @@ -432,7 +432,7 @@ public void testJavaObject() throws Exception { int off = 0; - InlineIndexHelper ih = new InlineIndexHelper(Value.JAVA_OBJECT, 1, 0, + InlineIndexHelper ih = new InlineIndexHelper(null, Value.JAVA_OBJECT, 1, 0, CompareMode.getInstance(null, 0)); int maxSize = 3 + 3; @@ -563,7 +563,7 @@ private void testPutGet(Value v1, Value v2, Value v3) throws Exception { int off = 0; int max = 255; - InlineIndexHelper ih = new InlineIndexHelper(v1.getType(), 1, 0, + InlineIndexHelper ih = new InlineIndexHelper(null, v1.getType(), 1, 0, CompareMode.getInstance(null, 0)); off += ih.put(pageAddr, off, v1, max - off); From 784d1e052d39ef6df66792a378694303c7127412 Mon Sep 17 00:00:00 2001 From: Slava Koptilin Date: Thu, 11 Jul 2019 13:46:54 +0300 Subject: [PATCH 29/62] GG-21186 Fixed IgniteDataStorageMetricsSelfTest --- .../CacheIgniteOutOfMemoryExceptionTest.java | 32 +++++++++++++------ .../IgniteDataStorageMetricsSelfTest.java | 11 +++++-- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheIgniteOutOfMemoryExceptionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheIgniteOutOfMemoryExceptionTest.java index 5cac543656423..6ceff6fc4ae1c 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheIgniteOutOfMemoryExceptionTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheIgniteOutOfMemoryExceptionTest.java @@ -1,11 +1,12 @@ /* - * Copyright 2019 GridGain Systems, Inc. and Contributors. + * 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 * - * Licensed under the GridGain Community Edition License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.gridgain.com/products/software/community-edition/gridgain-community-edition-license + * 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, @@ -20,6 +21,7 @@ import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; import org.apache.ignite.cache.CacheAtomicityMode; +import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.DataRegionConfiguration; import org.apache.ignite.configuration.DataStorageConfiguration; @@ -68,13 +70,23 @@ public class CacheIgniteOutOfMemoryExceptionTest extends GridCommonAbstractTest } }); - cfg.setCacheConfiguration( - new CacheConfiguration(ATOMIC.name()).setAtomicityMode(ATOMIC), - new CacheConfiguration(TRANSACTIONAL.name()).setAtomicityMode(TRANSACTIONAL)); + cfg.setCacheConfiguration(cacheConfiguration(ATOMIC), cacheConfiguration(TRANSACTIONAL)); return cfg; } + /** + * Creates a new cache configuration with the given cache atomicity mode. + * + * @param mode Cache atomicity mode. + * @return Cache configuration. + */ + private CacheConfiguration cacheConfiguration(CacheAtomicityMode mode) { + return new CacheConfiguration(mode.name()) + .setAtomicityMode(mode) + .setAffinity(new RendezvousAffinityFunction(false, 32)); + } + /** {@inheritDoc} */ @Override protected void beforeTestsStarted() throws Exception { startGrid(0); @@ -113,7 +125,7 @@ private void loadAndClearCache(CacheAtomicityMode mode, int attempts) { for (int i = 0; i < attempts; ++i) { try { for (int key = 0; key < 500_000; ++key) - cache.put(key, "abc"); + cache.put(key, new byte[4096]); fail("OutOfMemoryException hasn't been thrown"); } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgniteDataStorageMetricsSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgniteDataStorageMetricsSelfTest.java index a752605d276b2..a0d0b912e330f 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgniteDataStorageMetricsSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgniteDataStorageMetricsSelfTest.java @@ -24,6 +24,7 @@ import org.apache.ignite.IgniteCache; import org.apache.ignite.cache.CacheAtomicityMode; import org.apache.ignite.cache.CacheMode; +import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction; import org.apache.ignite.cache.query.annotations.QuerySqlField; import org.apache.ignite.configuration.BinaryConfiguration; import org.apache.ignite.configuration.CacheConfiguration; @@ -73,14 +74,16 @@ public class IgniteDataStorageMetricsSelfTest extends GridCommonAbstractTest { cfg.setConsistentId(gridName); + long maxRegionSize = 20L * 1024 * 1024; + DataStorageConfiguration memCfg = new DataStorageConfiguration() .setDefaultDataRegionConfiguration(new DataRegionConfiguration() - .setMaxSize(10 * 1024 * 1024) + .setMaxSize(maxRegionSize) .setPersistenceEnabled(true) .setMetricsEnabled(true) .setName("dflt-plc")) .setDataRegionConfigurations(new DataRegionConfiguration() - .setMaxSize(10 * 1024 * 1024) + .setMaxSize(maxRegionSize) .setPersistenceEnabled(false) .setMetricsEnabled(true) .setName("no-persistence")) @@ -94,7 +97,8 @@ public class IgniteDataStorageMetricsSelfTest extends GridCommonAbstractTest { ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setIpFinder(IP_FINDER); - cfg.setCacheConfiguration(cacheConfiguration(GROUP1, "cache", PARTITIONED, ATOMIC, 1, null), + cfg.setCacheConfiguration( + cacheConfiguration(GROUP1, "cache", PARTITIONED, ATOMIC, 1, null), cacheConfiguration(null, "cache-np", PARTITIONED, ATOMIC, 1, "no-persistence")); return cfg; @@ -134,6 +138,7 @@ private CacheConfiguration cacheConfiguration( ccfg.setCacheMode(cacheMode); ccfg.setWriteSynchronizationMode(FULL_SYNC); ccfg.setDataRegionName(dataRegName); + ccfg.setAffinity(new RendezvousAffinityFunction(false, 32)); return ccfg; } From 3b51081c4d4913cfe229173f20808aae7e9ea76f Mon Sep 17 00:00:00 2001 From: Dmitriy Govorukhin Date: Fri, 12 Jul 2019 11:55:51 +0300 Subject: [PATCH 30/62] GG-21295 [GG-21154] Invoke FailureProcessor if tree invariant is broken (cherry picked from commit 84e7b13a3bfdf62bc5ee3456cd2329542165e648) --- .../processors/cache/persistence/tree/BPlusTree.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/BPlusTree.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/BPlusTree.java index 124736346419c..84f04d911223b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/BPlusTree.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/BPlusTree.java @@ -1473,8 +1473,13 @@ private void validateFirstPages(long metaId, long metaPage, int rootLvl) throws /** * @param msg Message. */ - private static void fail(Object msg) { - throw new AssertionError(msg); + private void fail(Object msg) { + AssertionError err = new AssertionError(msg); + + if (failureProcessor != null) + failureProcessor.process(new FailureContext(FailureType.CRITICAL_ERROR, err)); + + throw err; } /** From 2923f19d49257a64a882ea9dad732d10d94d2273 Mon Sep 17 00:00:00 2001 From: Anton Kalashnikov Date: Fri, 12 Jul 2019 12:17:39 +0300 Subject: [PATCH 31/62] GG-21291 [GG-19570] Add extended logging for node start (cherry picked from commit 629115b67e0832dc35cee05b15366b9aa601145c) Signed-off-by: Dmitriy Govorukhin --- .../apache/ignite/internal/IgniteKernal.java | 22 ++++++- .../apache/ignite/internal/IgnitionEx.java | 63 +++++++++++-------- .../GridCacheDatabaseSharedManager.java | 10 ++- .../IgniteCacheDatabaseSharedManager.java | 7 ++- 4 files changed, 70 insertions(+), 32 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java index 867d6039ae0f7..96a11d929dead 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java @@ -171,6 +171,7 @@ import org.apache.ignite.internal.suggestions.JvmConfigurationSuggestions; import org.apache.ignite.internal.suggestions.OsConfigurationSuggestions; import org.apache.ignite.internal.util.StripedExecutor; +import org.apache.ignite.internal.util.TimeBag; import org.apache.ignite.internal.util.future.GridCompoundFuture; import org.apache.ignite.internal.util.future.GridFinishedFuture; import org.apache.ignite.internal.util.future.GridFutureAdapter; @@ -890,7 +891,8 @@ public void start( @Nullable final Map customExecSvcs, GridAbsClosure errHnd, WorkersRegistry workerRegistry, - Thread.UncaughtExceptionHandler hnd + Thread.UncaughtExceptionHandler hnd, + TimeBag startTimer ) throws IgniteCheckedException { gw.compareAndSet(null, new GridKernalGatewayImpl(cfg.getIgniteInstanceName())); @@ -1108,7 +1110,13 @@ public void start( startProcessor(createComponent(DiscoveryNodeValidationProcessor.class, ctx)); startProcessor(new GridAffinityProcessor(ctx)); startProcessor(createComponent(GridSegmentationProcessor.class, ctx)); + + startTimer.finishGlobalStage("Start managers"); + startProcessor(createComponent(IgniteCacheObjectProcessor.class, ctx)); + + startTimer.finishGlobalStage("Configure binary metadata"); + startProcessor(createComponent(IGridClusterStateProcessor.class, ctx)); startProcessor(new IgniteAuthenticationProcessor(ctx)); startProcessor(new GridCacheProcessor(ctx)); @@ -1128,11 +1136,15 @@ public void start( startProcessor(createComponent(PlatformProcessor.class, ctx)); startProcessor(new GridMarshallerMappingProcessor(ctx)); + startTimer.finishGlobalStage("Start processors"); + // Start plugins. for (PluginProvider provider : ctx.plugins().allProviders()) { ctx.add(new GridPluginComponent(provider)); provider.start(ctx.plugins().pluginContextForProvider(provider)); + + startTimer.finishGlobalStage("Start '"+ provider.name() + "' plugin"); } // Start platform plugins. @@ -1146,6 +1158,8 @@ public void start( ctx.cache().context().database().startMemoryRestore(ctx); ctx.recoveryMode(false); + + startTimer.finishGlobalStage("Finish recovery"); } catch (Throwable e) { U.error( @@ -1169,6 +1183,8 @@ public void start( gw.writeUnlock(); } + startTimer.finishGlobalStage("Join topology"); + // Check whether physical RAM is not exceeded. checkPhysicalRam(); @@ -1206,6 +1222,8 @@ public void start( else active = joinData.active(); + startTimer.finishGlobalStage("Await transition"); + boolean recon = false; // Callbacks. @@ -1472,6 +1490,8 @@ private long checkPoolStarvation( if (!isDaemon()) ctx.discovery().ackTopology(ctx.discovery().localJoin().joinTopologyVersion().topologyVersion(), EventType.EVT_NODE_JOINED, localNode()); + + startTimer.finishGlobalStage("Await exchange"); } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java b/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java index 641dde3cf34d9..766f3973b79aa 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java @@ -84,6 +84,7 @@ import org.apache.ignite.internal.util.GridConcurrentHashSet; import org.apache.ignite.internal.util.IgniteUtils; import org.apache.ignite.internal.util.StripedExecutor; +import org.apache.ignite.internal.util.TimeBag; import org.apache.ignite.internal.util.spring.IgniteSpringHelper; import org.apache.ignite.internal.util.typedef.CA; import org.apache.ignite.internal.util.typedef.F; @@ -125,6 +126,7 @@ import org.apache.ignite.thread.IgniteThreadPoolExecutor; import org.jetbrains.annotations.Nullable; +import static java.util.stream.Collectors.joining; import static org.apache.ignite.IgniteState.STARTED; import static org.apache.ignite.IgniteState.STOPPED; import static org.apache.ignite.IgniteState.STOPPED_ON_FAILURE; @@ -1726,7 +1728,16 @@ synchronized void start(GridStartContext startCtx) throws IgniteCheckedException try { starterThread = Thread.currentThread(); - start0(startCtx); + IgniteConfiguration myCfg = initializeConfiguration( + startCtx.config() != null ? startCtx.config() : new IgniteConfiguration() + ); + + TimeBag startNodeTimer = new TimeBag(TimeUnit.MILLISECONDS); + + start0(startCtx, myCfg, startNodeTimer); + + log.info("Node started : " + + startNodeTimer.stagesTimings().stream().collect(joining(",", "[", "]"))); } catch (Exception e) { if (log != null) @@ -1747,27 +1758,24 @@ synchronized void start(GridStartContext startCtx) throws IgniteCheckedException * @throws IgniteCheckedException If start failed. */ @SuppressWarnings({"unchecked", "TooBroadScope"}) - private void start0(GridStartContext startCtx) throws IgniteCheckedException { + private void start0(GridStartContext startCtx, IgniteConfiguration cfg, TimeBag startTimer) + throws IgniteCheckedException { assert grid == null : "Grid is already started: " + name; - IgniteConfiguration cfg = startCtx.config() != null ? startCtx.config() : new IgniteConfiguration(); - - IgniteConfiguration myCfg = initializeConfiguration(cfg); - // Set configuration URL, if any, into system property. if (startCtx.configUrl() != null) System.setProperty(IGNITE_CONFIG_URL, startCtx.configUrl().toString()); // Ensure that SPIs support multiple grid instances, if required. if (!startCtx.single()) { - ensureMultiInstanceSupport(myCfg.getDeploymentSpi()); - ensureMultiInstanceSupport(myCfg.getCommunicationSpi()); - ensureMultiInstanceSupport(myCfg.getDiscoverySpi()); - ensureMultiInstanceSupport(myCfg.getCheckpointSpi()); - ensureMultiInstanceSupport(myCfg.getEventStorageSpi()); - ensureMultiInstanceSupport(myCfg.getCollisionSpi()); - ensureMultiInstanceSupport(myCfg.getFailoverSpi()); - ensureMultiInstanceSupport(myCfg.getLoadBalancingSpi()); + ensureMultiInstanceSupport(cfg.getDeploymentSpi()); + ensureMultiInstanceSupport(cfg.getCommunicationSpi()); + ensureMultiInstanceSupport(cfg.getDiscoverySpi()); + ensureMultiInstanceSupport(cfg.getCheckpointSpi()); + ensureMultiInstanceSupport(cfg.getEventStorageSpi()); + ensureMultiInstanceSupport(cfg.getCollisionSpi()); + ensureMultiInstanceSupport(cfg.getFailoverSpi()); + ensureMultiInstanceSupport(cfg.getLoadBalancingSpi()); } validateThreadPoolSize(cfg.getPublicThreadPoolSize(), "public"); @@ -1919,14 +1927,14 @@ private void start0(GridStartContext startCtx) throws IgniteCheckedException { "callback", oomeHnd); - if (myCfg.getConnectorConfiguration() != null) { - validateThreadPoolSize(myCfg.getConnectorConfiguration().getThreadPoolSize(), "connector"); + if (cfg.getConnectorConfiguration() != null) { + validateThreadPoolSize(cfg.getConnectorConfiguration().getThreadPoolSize(), "connector"); restExecSvc = new IgniteThreadPoolExecutor( "rest", - myCfg.getIgniteInstanceName(), - myCfg.getConnectorConfiguration().getThreadPoolSize(), - myCfg.getConnectorConfiguration().getThreadPoolSize(), + cfg.getIgniteInstanceName(), + cfg.getConnectorConfiguration().getThreadPoolSize(), + cfg.getConnectorConfiguration().getThreadPoolSize(), DFLT_THREAD_KEEP_ALIVE_TIME, new LinkedBlockingQueue<>(), GridIoPolicy.UNDEFINED, @@ -1936,14 +1944,14 @@ private void start0(GridStartContext startCtx) throws IgniteCheckedException { restExecSvc.allowCoreThreadTimeOut(true); } - validateThreadPoolSize(myCfg.getUtilityCacheThreadPoolSize(), "utility cache"); + validateThreadPoolSize(cfg.getUtilityCacheThreadPoolSize(), "utility cache"); utilityCacheExecSvc = new IgniteThreadPoolExecutor( "utility", cfg.getIgniteInstanceName(), - myCfg.getUtilityCacheThreadPoolSize(), - myCfg.getUtilityCacheThreadPoolSize(), - myCfg.getUtilityCacheKeepAliveTime(), + cfg.getUtilityCacheThreadPoolSize(), + cfg.getUtilityCacheThreadPoolSize(), + cfg.getUtilityCacheKeepAliveTime(), new LinkedBlockingQueue<>(), GridIoPolicy.UTILITY_CACHE_POOL, oomeHnd); @@ -2024,7 +2032,7 @@ private void start0(GridStartContext startCtx) throws IgniteCheckedException { } // Register Ignite MBean for current grid instance. - registerFactoryMbean(myCfg.getMBeanServer()); + registerFactoryMbean(cfg.getMBeanServer()); boolean started = false; @@ -2034,8 +2042,10 @@ private void start0(GridStartContext startCtx) throws IgniteCheckedException { // Init here to make grid available to lifecycle listeners. grid = grid0; + startTimer.finishGlobalStage("Configure system pool"); + grid0.start( - myCfg, + cfg, utilityCacheExecSvc, execSvc, svcExecSvc, @@ -2058,7 +2068,8 @@ private void start0(GridStartContext startCtx) throws IgniteCheckedException { } }, workerRegistry, - oomeHnd + oomeHnd, + startTimer ); state = STARTED; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java index 48c7cbf4f0465..9f847b586e744 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java @@ -148,11 +148,11 @@ import org.apache.ignite.internal.processors.query.GridQueryProcessor; import org.apache.ignite.internal.stat.IoStatisticsHolderNoOp; import org.apache.ignite.internal.util.GridConcurrentHashSet; -import org.apache.ignite.internal.util.GridCountDownCallback; import org.apache.ignite.internal.util.GridMultiCollectionWrapper; import org.apache.ignite.internal.util.GridReadOnlyArrayView; import org.apache.ignite.internal.util.IgniteUtils; import org.apache.ignite.internal.util.StripedExecutor; +import org.apache.ignite.internal.util.TimeBag; import org.apache.ignite.internal.util.future.CountDownFuture; import org.apache.ignite.internal.util.future.GridCompoundFuture; import org.apache.ignite.internal.util.future.GridFutureAdapter; @@ -2110,7 +2110,7 @@ private WALPointer readPointer(File cpMarkerFile, ByteBuffer buf) throws IgniteC } /** {@inheritDoc} */ - @Override public void startMemoryRestore(GridKernalContext kctx) throws IgniteCheckedException { + @Override public void startMemoryRestore(GridKernalContext kctx, TimeBag startTimer) throws IgniteCheckedException { if (kctx.clientNode()) return; @@ -2120,6 +2120,8 @@ private WALPointer readPointer(File cpMarkerFile, ByteBuffer buf) throws IgniteC // Preform early regions startup before restoring state. initAndStartRegions(kctx.config().getDataStorageConfiguration()); + startTimer.finishGlobalStage("Init and start regions"); + for (DatabaseLifecycleListener lsnr : getDatabaseListeners(kctx)) lsnr.beforeBinaryMemoryRestore(this); @@ -2141,6 +2143,8 @@ private WALPointer readPointer(File cpMarkerFile, ByteBuffer buf) throws IgniteC dumpPartitionsInfo(cctx, log); } + startTimer.finishGlobalStage("Restore binary memory"); + for (DatabaseLifecycleListener lsnr : getDatabaseListeners(kctx)) lsnr.afterBinaryMemoryRestore(this); @@ -2168,6 +2172,8 @@ private WALPointer readPointer(File cpMarkerFile, ByteBuffer buf) throws IgniteC dumpPartitionsInfo(cctx, log); } + startTimer.finishGlobalStage("Restore logical state"); + walTail = tailPointer(logicalState.lastRead); cctx.wal().onDeActivate(kctx); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java index 86e5e8e3772a5..d9e9b5d82e2d8 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java @@ -27,13 +27,12 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import javax.management.InstanceNotFoundException; - import org.apache.ignite.DataRegionMetrics; +import org.apache.ignite.DataRegionMetricsProvider; import org.apache.ignite.DataStorageMetrics; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteLogger; import org.apache.ignite.IgniteSystemProperties; -import org.apache.ignite.DataRegionMetricsProvider; import org.apache.ignite.configuration.DataPageEvictionMode; import org.apache.ignite.configuration.DataRegionConfiguration; import org.apache.ignite.configuration.DataStorageConfiguration; @@ -70,6 +69,7 @@ import org.apache.ignite.internal.processors.cache.persistence.tree.reuse.ReuseList; import org.apache.ignite.internal.processors.cache.persistence.tree.util.PageLockListener; import org.apache.ignite.internal.processors.cluster.IgniteChangeGlobalStateSupport; +import org.apache.ignite.internal.util.TimeBag; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.CU; import org.apache.ignite.internal.util.typedef.internal.LT; @@ -909,9 +909,10 @@ public void beforeExchange(GridDhtPartitionsExchangeFuture discoEvt) throws Igni * Perform memory restore before {@link GridDiscoveryManager} start. * * @param kctx Current kernal context. + * @param startTimer Holder of start time of stages. * @throws IgniteCheckedException If fails. */ - public void startMemoryRestore(GridKernalContext kctx) throws IgniteCheckedException { + public void startMemoryRestore(GridKernalContext kctx, TimeBag startTimer) throws IgniteCheckedException { // No-op. } From c91304a6ce43bab855ebf8fa6b4483376b0cd66a Mon Sep 17 00:00:00 2001 From: Anton Kalashnikov Date: Fri, 12 Jul 2019 12:52:48 +0300 Subject: [PATCH 32/62] GG-21291 [GG-19570] Add extended logging for node start Signed-off-by: Dmitriy Govorukhin --- .../src/main/java/org/apache/ignite/internal/IgniteKernal.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java index 96a11d929dead..a84bd80c5224b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java @@ -1155,7 +1155,7 @@ public void start( fillNodeAttributes(clusterProc.updateNotifierEnabled()); - ctx.cache().context().database().startMemoryRestore(ctx); + ctx.cache().context().database().startMemoryRestore(ctx, startTimer); ctx.recoveryMode(false); From 9b86f7b69c58117919083eccd1b3e1bda1bf7b16 Mon Sep 17 00:00:00 2001 From: Andrey Novikov Date: Tue, 9 Jul 2019 14:25:35 +0700 Subject: [PATCH 33/62] GG-21283 Backported to 2.5-master of GG-18503 DR Sender/Receiver tab goes blank when switching back and forth between tabs. --- .../frontend/app/modules/agent/AgentManager.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/web-console/frontend/app/modules/agent/AgentManager.service.js b/modules/web-console/frontend/app/modules/agent/AgentManager.service.js index 03883ca452330..d8c60f48b0a7b 100644 --- a/modules/web-console/frontend/app/modules/agent/AgentManager.service.js +++ b/modules/web-console/frontend/app/modules/agent/AgentManager.service.js @@ -399,7 +399,7 @@ export default class AgentManager { * @private */ _sendToAgent(event, payload = {}) { - if (!this.socket) + if (!this.socket || !this.socket.connected) return this.$q.reject('Failed to connect to server'); const latch = this.$q.defer(); From bfedccabb7729d67735894001ad16660e2bc58f5 Mon Sep 17 00:00:00 2001 From: denis-chudov Date: Tue, 11 Jun 2019 11:55:52 +0300 Subject: [PATCH 34/62] GG-17447: Replace TcpDiscoveryNode to nodeId in TcpDiscoveryMessages (cherry picked from commit 3d162a42c05278753b271011bb36653dd9ae4e4f) --- .../ignite/internal/IgniteFeatures.java | 5 +- .../ignite/spi/discovery/tcp/ServerImpl.java | 200 +++++++++++++++--- .../spi/discovery/tcp/TcpDiscoverySpi.java | 5 +- .../TcpDiscoveryDuplicateIdMessage.java | 26 +++ .../TcpDiscoveryStatusCheckMessage.java | 33 ++- 5 files changed, 229 insertions(+), 40 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteFeatures.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteFeatures.java index 188a538a998cd..cbb2ffc0c817d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteFeatures.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteFeatures.java @@ -56,7 +56,10 @@ public enum IgniteFeatures { FIND_AND_DELETE_GARBAGE_COMMAND(8), /** Supports tracking update counter for transactions. */ - TX_TRACKING_UPDATE_COUNTER(12); + TX_TRACKING_UPDATE_COUNTER(12), + + /** Replacing TcpDiscoveryNode field with nodeId field in discovery messages. */ + TCP_DISCOVERY_MESSAGE_NODE_COMPACT_REPRESENTATION(14); /** * Unique feature identifier. diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java index 141c4ca8d9785..ca323a41b9637 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java @@ -163,6 +163,8 @@ import static org.apache.ignite.events.EventType.EVT_NODE_SEGMENTED; import static org.apache.ignite.failure.FailureType.CRITICAL_ERROR; import static org.apache.ignite.failure.FailureType.SYSTEM_WORKER_TERMINATION; +import static org.apache.ignite.internal.IgniteFeatures.TCP_DISCOVERY_MESSAGE_NODE_COMPACT_REPRESENTATION; +import static org.apache.ignite.internal.IgniteFeatures.nodeSupports; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_LATE_AFFINITY_ASSIGNMENT; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MARSHALLER; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MARSHALLER_COMPACT_FOOTER; @@ -268,6 +270,10 @@ class ServerImpl extends TcpDiscoveryImpl { /** Last time received message from ring. */ private volatile long lastRingMsgReceivedTime; + /** */ + private volatile boolean nodeCompactRepresentationSupported = + true; //assume that local node supports this feature + /** Map with proceeding ping requests. */ private final ConcurrentMap>> pingMap = new ConcurrentHashMap<>(); @@ -609,12 +615,82 @@ else if (log.isInfoEnabled()) { if (!res && node.clientRouterNodeId() == null && nodeAlive(nodeId)) { LT.warn(log, "Failed to ping node (status check will be initiated): " + nodeId); - msgWorker.addMessage(new TcpDiscoveryStatusCheckMessage(locNode, node.id())); + msgWorker.addMessage(createTcpDiscoveryStatusCheckMessage(locNode, locNode.id(), node.id())); } return res; } + /** + * Creates new instance of {@link TcpDiscoveryStatusCheckMessage} trying to choose most optimal constructor. + * + * @param creatorNode Creator node. It can be null when message will be sent from coordinator to creator node, + * in this case it will not contain creator node addresses as it will be discarded by creator; otherwise, + * this parameter must not be null. + * @param creatorNodeId Creator node id. + * @param failedNodeId Failed node id. + * @return null if creatorNode is null and we cannot retrieve creator node from ring + * by creatorNodeId, and new instance of {@link TcpDiscoveryStatusCheckMessage} in other cases. + */ + private @Nullable TcpDiscoveryStatusCheckMessage createTcpDiscoveryStatusCheckMessage( + @Nullable TcpDiscoveryNode creatorNode, + UUID creatorNodeId, + UUID failedNodeId + ) { + TcpDiscoveryStatusCheckMessage msg; + + if (nodeCompactRepresentationSupported) { + TcpDiscoveryNode crd = resolveCoordinator(); + + if (creatorNode == null) + msg = new TcpDiscoveryStatusCheckMessage(creatorNodeId, null, failedNodeId); + else { + boolean sameMacs = creatorNode != null && crd != null && U.sameMacs(creatorNode, crd); + + msg = new TcpDiscoveryStatusCheckMessage( + creatorNode.id(), + spi.getNodeAddresses(creatorNode, sameMacs), + failedNodeId + ); + } + } + else { + if (creatorNode == null) { + TcpDiscoveryNode node = ring.node(creatorNodeId); + + if (node == null) + return null; + else + msg = new TcpDiscoveryStatusCheckMessage(node, failedNodeId); + } + else + msg = new TcpDiscoveryStatusCheckMessage(creatorNode, failedNodeId); + } + + return msg; + } + + /** + * Creates new instance of {@link TcpDiscoveryDuplicateIdMessage}, trying to choose most optimal constructor. + * + * @param creatorNodeId Creator node id. + * @param node Node with duplicate ID. + * @return new instance of {@link TcpDiscoveryDuplicateIdMessage}. + */ + private TcpDiscoveryDuplicateIdMessage createTcpDiscoveryDuplicateIdMessage( + UUID creatorNodeId, + TcpDiscoveryNode node + ) { + TcpDiscoveryDuplicateIdMessage msg; + + if (nodeCompactRepresentationSupported) + msg = new TcpDiscoveryDuplicateIdMessage(creatorNodeId, node.id()); + else + msg = new TcpDiscoveryDuplicateIdMessage(creatorNodeId, node); + + return msg; + } + /** * For test purposes only. * @@ -3877,8 +3953,7 @@ private void processJoinRequestMessage(final TcpDiscoveryJoinRequestMessage msg) } try { - trySendMessageDirectly(node, new TcpDiscoveryDuplicateIdMessage(locNodeId, - existingNode)); + trySendMessageDirectly(node, createTcpDiscoveryDuplicateIdMessage(locNodeId, existingNode)); } catch (IgniteSpiException e) { if (log.isDebugEnabled()) @@ -3940,8 +4015,7 @@ else if (log.isDebugEnabled()) if (!node.isClient() && !node.isDaemon()) { if (nodesIdsHist.contains(node.id())) { try { - trySendMessageDirectly(node, new TcpDiscoveryDuplicateIdMessage(locNodeId, - node)); + trySendMessageDirectly(node, createTcpDiscoveryDuplicateIdMessage(locNodeId, node)); } catch (IgniteSpiException e) { if (log.isDebugEnabled()) @@ -4410,6 +4484,59 @@ private void nodeCheckError(TcpDiscoveryNode node, String errMsg, String sndMsg) } } + /** */ + private void trySendMessageDirectlyToAddrs( + Collection addrs, + @Nullable TcpDiscoveryNode node, + TcpDiscoveryAbstractMessage msg + ) { + IgniteSpiException ex = null; + + for (InetSocketAddress addr : addrs) { + try { + IgniteSpiOperationTimeoutHelper timeoutHelper = new IgniteSpiOperationTimeoutHelper(spi, true); + + sendMessageDirectly(msg, addr, timeoutHelper); + + if (node != null) + node.lastSuccessfulAddress(addr); + + return; + } + catch (IgniteSpiException e) { + ex = e; + } + } + + if (ex != null) + throw ex; + } + + /** + * Tries to send a message to all node's available addresses. + * + * @param addrs Node addresses, used when node could not be found in ring. + * @param nodeId Node ID to send message to. + * @param msg Message. + * @throws IgniteSpiException Last failure if all attempts failed. + */ + private void trySendMessageDirectly( + Collection addrs, + UUID nodeId, + TcpDiscoveryAbstractMessage msg + ) { + TcpDiscoveryNode node = ring.node(nodeId); + + if (node == null) { + if (!F.isEmpty(addrs)) + trySendMessageDirectlyToAddrs(addrs, null, msg); + else + throw new IgniteSpiException("Node does not exist: " + nodeId); + } + else + trySendMessageDirectly(node, msg); + } + /** * Tries to send a message to all node's available addresses. * @@ -4439,27 +4566,7 @@ private void trySendMessageDirectly(TcpDiscoveryNode node, TcpDiscoveryAbstractM return; } - IgniteSpiException ex = null; - - for (InetSocketAddress addr : spi.getNodeAddresses(node, U.sameMacs(locNode, node))) { - try { - IgniteSpiOperationTimeoutHelper timeoutHelper = new IgniteSpiOperationTimeoutHelper(spi, true); - - sendMessageDirectly(msg, addr, timeoutHelper); - - node.lastSuccessfulAddress(addr); - - ex = null; - - break; - } - catch (IgniteSpiException e) { - ex = e; - } - } - - if (ex != null) - throw ex; + trySendMessageDirectlyToAddrs(spi.getNodeAddresses(node, U.sameMacs(locNode, node)), node, msg); } /** @@ -4769,6 +4876,14 @@ else if (spiState == CONNECTING) // Make all preceding nodes and local node visible. n.visible(true); + + if (nodeCompactRepresentationSupported) { + nodeCompactRepresentationSupported = + nodeSupports( + n, + TCP_DISCOVERY_MESSAGE_NODE_COMPACT_REPRESENTATION + ); + } } joiningNodes.clear(); @@ -4849,6 +4964,12 @@ private void processNodeAddFinishedMessage(TcpDiscoveryNodeAddFinishedMessage ms if (log.isDebugEnabled()) log.debug("Node to finish add: " + node); + //we will need to recalculate this value since the topology changed + if (nodeCompactRepresentationSupported) { + nodeCompactRepresentationSupported = + nodeSupports(node, TCP_DISCOVERY_MESSAGE_NODE_COMPACT_REPRESENTATION); + } + boolean locNodeCoord = isLocalNodeCoordinator(); UUID locNodeId = getLocalNodeId(); @@ -5091,6 +5212,12 @@ private void processNodeLeftMessage(TcpDiscoveryNodeLeftMessage msg) { } if (msg.verified() && !locNodeId.equals(leavingNodeId)) { + //we will need to recalculate this value since the topology changed + if (!nodeCompactRepresentationSupported) { + nodeCompactRepresentationSupported = + allNodesSupport(TCP_DISCOVERY_MESSAGE_NODE_COMPACT_REPRESENTATION); + } + TcpDiscoveryNode leftNode = ring.removeNode(leavingNodeId); interruptPing(leavingNode); @@ -5291,6 +5418,12 @@ private void processNodeFailedMessage(TcpDiscoveryNodeFailedMessage msg) { } if (msg.verified()) { + //we will need to recalculate this value since the topology changed + if (!nodeCompactRepresentationSupported) { + nodeCompactRepresentationSupported = + allNodesSupport(TCP_DISCOVERY_MESSAGE_NODE_COMPACT_REPRESENTATION); + } + failedNode = ring.removeNode(failedNodeId); interruptPing(failedNode); @@ -5423,7 +5556,16 @@ private void processStatusCheckMessage(final TcpDiscoveryStatusCheckMessage msg) TcpDiscoveryStatusCheckMessage msg0 = msg; if (F.contains(msg.failedNodes(), msg.creatorNodeId())) { - msg0 = new TcpDiscoveryStatusCheckMessage(msg); + msg0 = createTcpDiscoveryStatusCheckMessage( + msg.creatorNode(), + msg.creatorNodeId(), + msg.failedNodeId()); + + if (msg0 == null) { + log.debug("Status check message discarded (creator node is not in topology)."); + + return; + } msg0.failedNodes(null); @@ -5434,7 +5576,7 @@ private void processStatusCheckMessage(final TcpDiscoveryStatusCheckMessage msg) } try { - trySendMessageDirectly(msg0.creatorNode(), msg0); + trySendMessageDirectly(msg0.creatorNodeAddrs(), msg0.creatorNodeId(), msg0); if (log.isDebugEnabled()) log.debug("Responded to status check message " + @@ -6030,7 +6172,7 @@ private void checkMetricsReceiving() { if (elapsed > 0) return; - msgWorker.addMessage(new TcpDiscoveryStatusCheckMessage(locNode, null)); + msgWorker.addMessage(createTcpDiscoveryStatusCheckMessage(locNode, locNode.id(), null)); lastTimeStatusMsgSentNanos = System.nanoTime(); } diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java index 169e63dc37733..5bca7c2ca4f21 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java @@ -1964,14 +1964,13 @@ protected Collection registeredAddresses() throws IgniteSpiEx protected IgniteSpiException duplicateIdError(TcpDiscoveryDuplicateIdMessage msg) { assert msg != null; - StringBuilder errorMsgBldr = new StringBuilder(); - errorMsgBldr + StringBuilder errorMsgBldr = new StringBuilder() .append("Node with the same ID was found in node IDs history ") .append("or existing node in topology has the same ID ") .append("(fix configuration and restart local node) [localNode=") .append(locNode) .append(", existingNode=") - .append(msg.node()) + .append(msg.node() == null ? msg.nodeId() : msg.node()) .append(']'); return new IgniteSpiException(errorMsgBldr.toString()); diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryDuplicateIdMessage.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryDuplicateIdMessage.java index 63c3af1aeb995..8ca7319bf7e92 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryDuplicateIdMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryDuplicateIdMessage.java @@ -32,6 +32,9 @@ public class TcpDiscoveryDuplicateIdMessage extends TcpDiscoveryAbstractMessage /** Node with duplicate ID. */ private final TcpDiscoveryNode node; + /** ID of the node with duplicate ID. */ + private final UUID nodeId; + /** * Constructor. * @@ -44,6 +47,22 @@ public TcpDiscoveryDuplicateIdMessage(UUID creatorNodeId, TcpDiscoveryNode node) assert node != null; this.node = node; + this.nodeId = null; + } + + /** + * Constructor. + * + * @param creatorNodeId Creator node ID. + * @param nodeId ID of node with same ID. + */ + public TcpDiscoveryDuplicateIdMessage(UUID creatorNodeId, UUID nodeId) { + super(creatorNodeId); + + assert nodeId != null; + + this.node = null; + this.nodeId = nodeId; } /** @@ -53,6 +72,13 @@ public TcpDiscoveryNode node() { return node; } + /** + * @return Node with duplicate ID. + */ + public UUID nodeId() { + return nodeId; + } + /** {@inheritDoc} */ @Override public String toString() { return S.toString(TcpDiscoveryDuplicateIdMessage.class, this, "super", super.toString()); diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryStatusCheckMessage.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryStatusCheckMessage.java index fdbeb75554fa6..1a00b1eaafa0e 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryStatusCheckMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryStatusCheckMessage.java @@ -17,6 +17,8 @@ package org.apache.ignite.spi.discovery.tcp.messages; +import java.net.InetSocketAddress; +import java.util.Collection; import java.util.UUID; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.S; @@ -43,6 +45,9 @@ public class TcpDiscoveryStatusCheckMessage extends TcpDiscoveryAbstractMessage /** Creator node. */ private final TcpDiscoveryNode creatorNode; + /** Creator node addresses. */ + private final Collection creatorNodeAddrs; + /** Failed node id. */ private final UUID failedNodeId; @@ -60,17 +65,22 @@ public TcpDiscoveryStatusCheckMessage(TcpDiscoveryNode creatorNode, UUID failedN this.creatorNode = creatorNode; this.failedNodeId = failedNodeId; + this.creatorNodeAddrs = null; } /** - * @param msg Message to copy. + * Constructor. + * + * @param creatorNodeAddrs Addresses of creator node, used to be able not to serialize node in message. + * @param creatorNodeId Creator node ID. + * @param failedNodeId Failed node id. */ - public TcpDiscoveryStatusCheckMessage(TcpDiscoveryStatusCheckMessage msg) { - super(msg); + public TcpDiscoveryStatusCheckMessage(UUID creatorNodeId, Collection creatorNodeAddrs, UUID failedNodeId) { + super(creatorNodeId); - this.creatorNode = msg.creatorNode; - this.failedNodeId = msg.failedNodeId; - this.status = msg.status; + this.creatorNodeAddrs = creatorNodeAddrs; + this.creatorNode = null; + this.failedNodeId = failedNodeId; } /** @@ -82,6 +92,15 @@ public TcpDiscoveryNode creatorNode() { return creatorNode; } + /** + * Gets creator node addresses. + * + * @return Creator node addresses. + */ + public Collection creatorNodeAddrs() { + return creatorNodeAddrs; + } + /** * Gets failed node id. * @@ -119,7 +138,7 @@ public void status(int status) { TcpDiscoveryStatusCheckMessage other = (TcpDiscoveryStatusCheckMessage)obj; - return F.eqNodes(other.creatorNode, creatorNode) && + return F.eq(other.creatorNodeId(), creatorNodeId()) && F.eq(other.failedNodeId, failedNodeId) && status == other.status; } From ca1d8b7cd9e4d5fb7ab20e37f991f40863a80fe6 Mon Sep 17 00:00:00 2001 From: Sergey Antonov Date: Mon, 15 Jul 2019 15:21:35 +0300 Subject: [PATCH 35/62] GG-21123 Fix threads parking for indefinite time during throttling after spurious wakeups. (cherry picked from commit 9ae8c447edffa99cf4037f71184f67fd09ba88a4) --- .../GridCacheDatabaseSharedManager.java | 3 + .../persistence/pagemem/PageMemoryImpl.java | 21 +++++-- .../pagemem/PagesWriteThrottle.java | 26 ++++++-- .../pagemem/PagesWriteThrottlePolicy.java | 7 +++ .../pagemem/IgniteThrottlingUnitTest.java | 61 +++++++++++++++++++ 5 files changed, 108 insertions(+), 10 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java index 9f847b586e744..7a317c82c9e5d 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java @@ -4713,6 +4713,9 @@ private WriteCheckpointPages( if (pagesToRetry.isEmpty()) doneFut.onDone((Void)null); else { + LT.warn(log, pagesToRetry.size() + " checkpoint pages were not written yet due to unsuccessful " + + "page write lock acquisition and will be retried"); + if (retryWriteExecutor == null) { while (!pagesToRetry.isEmpty()) pagesToRetry = writePages(pagesToRetry); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PageMemoryImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PageMemoryImpl.java index 1f8df6fc14859..a86d45ea3e552 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PageMemoryImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PageMemoryImpl.java @@ -858,7 +858,7 @@ private long refreshOutdatedPage(Segment seg, int grpId, long pageId, boolean rm // We pinned the page when allocated the temp buffer, release it now. PageHeader.releasePage(absPtr); - checkpointPool.releaseFreePage(tmpBufPtr); + releaseCheckpointBufferPage(tmpBufPtr); } if (rmv) @@ -877,6 +877,14 @@ private long refreshOutdatedPage(Segment seg, int grpId, long pageId, boolean rm return relPtr; } + /** */ + private void releaseCheckpointBufferPage(long tmpBufPtr) { + int resCntr = checkpointPool.releaseFreePage(tmpBufPtr); + + if (resCntr == checkpointBufferPagesSize() / 2 && writeThrottle != null) + writeThrottle.tryWakeupThrottledThreads(); + } + /** * Restores page from WAL page snapshot & delta records. * @@ -1213,7 +1221,7 @@ private boolean copyPageForCheckpoint( if (tracker != null) tracker.onCowPageWritten(); - checkpointPool.releaseFreePage(tmpRelPtr); + releaseCheckpointBufferPage(tmpRelPtr); // Need release again because we pin page when resolve abs pointer, // and page did not have tmp buffer page. @@ -1824,14 +1832,17 @@ private long allocateFreePage(long pageId) throws GridOffHeapOutOfMemoryExceptio /** * @param relPtr Relative pointer to free. + * @return Resulting number of pages in pool if pages counter is enabled, 0 otherwise. */ - private void releaseFreePage(long relPtr) { + private int releaseFreePage(long relPtr) { long absPtr = absolute(relPtr); assert !PageHeader.isAcquired(absPtr) : "Release pinned page: " + PageHeader.fullPageId(absPtr); + int resCntr = 0; + if (pagesCntr != null) - pagesCntr.getAndDecrement(); + resCntr = pagesCntr.decrementAndGet(); while (true) { long freePageRelPtrMasked = GridUnsafe.getLong(freePageListPtr); @@ -1841,7 +1852,7 @@ private void releaseFreePage(long relPtr) { GridUnsafe.putLong(absPtr, freePageRelPtr); if (GridUnsafe.compareAndSwapLong(null, freePageListPtr, freePageRelPtrMasked, relPtr)) - return; + return resCntr; } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PagesWriteThrottle.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PagesWriteThrottle.java index 2828c4348af8d..35a7dab30b580 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PagesWriteThrottle.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PagesWriteThrottle.java @@ -95,11 +95,8 @@ public PagesWriteThrottle(PageMemoryImpl pageMemory, boolean shouldThrottle = false; - if (isPageInCheckpoint) { - int checkpointBufLimit = (int)(pageMemory.checkpointBufferPagesSize() * CP_BUF_FILL_THRESHOLD); - - shouldThrottle = pageMemory.checkpointBufferPagesCount() > checkpointBufLimit; - } + if (isPageInCheckpoint) + shouldThrottle = shouldThrottle(); if (!shouldThrottle && !throttleOnlyPagesInCheckpoint) { AtomicInteger writtenPagesCntr = cpProgress.writtenPagesCounter(); @@ -152,6 +149,16 @@ public PagesWriteThrottle(PageMemoryImpl pageMemory, } } + /** {@inheritDoc} */ + @Override public void tryWakeupThrottledThreads() { + if (!shouldThrottle()) { + inCheckpointBackoffCntr.set(0); + + parkThrds.forEach(LockSupport::unpark); + parkThrds.clear(); + } + } + /** {@inheritDoc} */ @Override public void onBeginCheckpoint() { } @@ -162,4 +169,13 @@ public PagesWriteThrottle(PageMemoryImpl pageMemory, notInCheckpointBackoffCntr.set(0); } + + /** + * @return {@code True} if throttling should be enabled, and {@code False} otherwise. + */ + private boolean shouldThrottle() { + int checkpointBufLimit = (int)(pageMemory.checkpointBufferPagesSize() * CP_BUF_FILL_THRESHOLD); + + return pageMemory.checkpointBufferPagesCount() > checkpointBufLimit; + } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PagesWriteThrottlePolicy.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PagesWriteThrottlePolicy.java index e6aab794761eb..a271ed973ae9d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PagesWriteThrottlePolicy.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PagesWriteThrottlePolicy.java @@ -37,6 +37,13 @@ public interface PagesWriteThrottlePolicy { */ void onMarkDirty(boolean isPageInCheckpoint); + /** + * Callback to try wakeup throttled threads. + */ + default void tryWakeupThrottledThreads() { + // No-op. + } + /** * Callback to notify throttling policy checkpoint was started. */ diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/IgniteThrottlingUnitTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/IgniteThrottlingUnitTest.java index f9ca7e43ad3fb..bc07ae19f3789 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/IgniteThrottlingUnitTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/IgniteThrottlingUnitTest.java @@ -16,17 +16,24 @@ */ package org.apache.ignite.internal.processors.cache.persistence.pagemem; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.LockSupport; import org.apache.ignite.IgniteLogger; +import org.apache.ignite.internal.IgniteInterruptedCheckedException; import org.apache.ignite.internal.processors.cache.persistence.CheckpointLockStateChecker; import org.apache.ignite.internal.processors.cache.persistence.CheckpointWriteProgressSupplier; import org.apache.ignite.logger.NullLogger; import org.junit.Test; +import static java.lang.Thread.State.TIMED_WAITING; +import static org.apache.ignite.testframework.GridTestUtils.waitForCondition; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.doAnswer; @@ -219,6 +226,60 @@ public void tooMuchPagesMarkedDirty() { assertTrue(time == 0); } + /** */ + @Test + public void wakeupThrottledThread() throws IgniteInterruptedCheckedException, InterruptedException { + PagesWriteThrottlePolicy plc = new PagesWriteThrottle(pageMemory2g, null, stateChecker, true, log); + + AtomicBoolean stopLoad = new AtomicBoolean(); + List loadThreads = new ArrayList<>(); + + for (int i=0; i<3; i++) { + loadThreads.add(new Thread( + ()->{ + while(!stopLoad.get()) + plc.onMarkDirty(true); + }, + "load-" + i + )); + } + + when(pageMemory2g.checkpointBufferPagesSize()).thenReturn(100); + when(pageMemory2g.checkpointBufferPagesCount()).thenReturn(70); + + try { + loadThreads.forEach(Thread::start); + + for (int i = 0; i < 100_000; i++) + loadThreads.forEach(LockSupport::unpark); + + // Awaiting that all load threads are parked. + for (Thread t : loadThreads) + assertTrue(t.getName(), waitForCondition(() -> t.getState() == TIMED_WAITING, 500L)); + + plc.tryWakeupThrottledThreads(); + + // Threads shouldn't wakeup because of throttling enabled. + for (Thread t : loadThreads) + assertEquals(t.getName(), TIMED_WAITING, t.getState()); + + // Disable throttling + when(pageMemory2g.checkpointBufferPagesCount()).thenReturn(50); + + plc.tryWakeupThrottledThreads(); + + // Awaiting that all load threads are unparked. + for (Thread t : loadThreads) + assertTrue(t.getName(), waitForCondition(() -> t.getState() != TIMED_WAITING, 500L)); + + for (Thread t : loadThreads) + assertNotEquals(t.getName(), TIMED_WAITING, t.getState()); + } + finally { + stopLoad.set(true); + } + } + /** * */ From 9f580f0889392f25619a6e8f30ad22a4a44141cd Mon Sep 17 00:00:00 2001 From: pavlukhin Date: Mon, 15 Jul 2019 16:27:28 +0300 Subject: [PATCH 36/62] GG-20761 [GG-20749] Delete PdsWithTtlCompatibilityTest.java --- .../apache/ignite/compatibility/PdsWithTtlCompatibilityTest.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 modules/compatibility/src/test/java/org/apache/ignite/compatibility/PdsWithTtlCompatibilityTest.java diff --git a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/PdsWithTtlCompatibilityTest.java b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/PdsWithTtlCompatibilityTest.java deleted file mode 100644 index e69de29bb2d1d..0000000000000 From d49c448696a6b604f26c9e880cff5f3b0d1bd73e Mon Sep 17 00:00:00 2001 From: pavlukhin Date: Mon, 15 Jul 2019 17:29:16 +0300 Subject: [PATCH 37/62] GG-21302 [8.5-next]-[GG-21299] Add the WAL record type BTREE_META_PAGE_INIT_ROOT_V3 to the set RecordTypes#DELTA_TYPE_SET (#176) --- .../processors/cache/persistence/wal/record/RecordTypes.java | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/record/RecordTypes.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/record/RecordTypes.java index 996df70fee1fc..daaa470f35193 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/record/RecordTypes.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/record/RecordTypes.java @@ -66,5 +66,6 @@ public final class RecordTypes { DELTA_TYPE_SET.add(WALRecord.RecordType.PAGE_LIST_META_RESET_COUNT_RECORD); DELTA_TYPE_SET.add(WALRecord.RecordType.DATA_PAGE_UPDATE_RECORD); DELTA_TYPE_SET.add(WALRecord.RecordType.BTREE_META_PAGE_INIT_ROOT2); + DELTA_TYPE_SET.add(WALRecord.RecordType.BTREE_META_PAGE_INIT_ROOT_V3); } } From 7e43d973f1f7d9752b8543bfe98d836a721c62c4 Mon Sep 17 00:00:00 2001 From: vmalin Date: Mon, 15 Jul 2019 16:40:17 +0300 Subject: [PATCH 38/62] GG-19526 Optimize heap usage for TcpDiscoveryNodeAddedMessage stored in pending messages in ServerImpl. (cherry picked from commit ec3c0c7f167a523fab39946e2ebda06f5720664f) --- .../org/apache/ignite/spi/discovery/tcp/ServerImpl.java | 1 + .../spi/discovery/tcp/internal/DiscoveryDataPacket.java | 7 +++++++ .../tcp/messages/TcpDiscoveryNodeAddedMessage.java | 9 +++++++++ 3 files changed, 17 insertions(+) diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java index ca323a41b9637..f5f9110b81da3 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java @@ -1803,6 +1803,7 @@ private void clearNodeAddedMessage(TcpDiscoveryAbstractMessage msg) { nodeAddedMsg.topology(null); nodeAddedMsg.topologyHistory(null); nodeAddedMsg.messages(null, null, null); + nodeAddedMsg.clearUnmarshalledDiscoveryData(); } } diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/DiscoveryDataPacket.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/DiscoveryDataPacket.java index f25d76433d97a..0e1146cc76a29 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/DiscoveryDataPacket.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/DiscoveryDataPacket.java @@ -418,4 +418,11 @@ public DiscoveryDataBag bagForDataCollection() { public void joiningNodeClient(boolean joiningNodeClient) { this.joiningNodeClient = joiningNodeClient; } + + /** + * Clears {@link #unmarshalledJoiningNodeData} + */ + public void clearUnmarshalledJoiningNodeData() { + unmarshalledJoiningNodeData = null; + } } diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryNodeAddedMessage.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryNodeAddedMessage.java index cdd1f2af13705..a594c9ec44297 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryNodeAddedMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryNodeAddedMessage.java @@ -227,6 +227,15 @@ public void clearDiscoveryData() { dataPacket = null; } + /** + * Clears unmarshalled discovery data to minimize message size. + * These data are used only on "collect" stage and are not part of persistent state. + */ + public void clearUnmarshalledDiscoveryData() { + if (dataPacket != null) + dataPacket.clearUnmarshalledJoiningNodeData(); + } + /** * @return First grid node start time. */ From 2087ec3515a7794c945e9026184569a3dff9712e Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Mon, 15 Jul 2019 23:24:45 +0700 Subject: [PATCH 39/62] GG-21314 Backport to 2.5-master of GG-21312 Fixed collecting rebalance metrics on not active cluster. (#272) (cherry picked from commit 9a60da3cbaed238322dfe61d4354aa08dc18c90d) --- .../VisorCacheRebalanceCollectorTask.java | 86 ++++++------ ...orCacheRebalanceCollectorTaskSelfTest.java | 128 ++++++++++++++++++ .../IgniteComputeGridTestSuite.java | 2 + 3 files changed, 174 insertions(+), 42 deletions(-) create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/visor/VisorCacheRebalanceCollectorTaskSelfTest.java diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorCacheRebalanceCollectorTask.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorCacheRebalanceCollectorTask.java index 4ed373b70dcd7..882d49de8c869 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorCacheRebalanceCollectorTask.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorCacheRebalanceCollectorTask.java @@ -107,65 +107,71 @@ private VisorCacheRebalanceCollectorJob(VisorCacheRebalanceCollectorTaskArg arg, /** {@inheritDoc} */ @Override protected VisorCacheRebalanceCollectorJobResult run(VisorCacheRebalanceCollectorTaskArg arg) { VisorCacheRebalanceCollectorJobResult res = new VisorCacheRebalanceCollectorJobResult(); + res.setBaseline(BASELINE_NOT_AVAILABLE); long start0 = U.currentTimeMillis(); - try { - int partitions = 0; - double total = 0; - double ready = 0; - GridCacheProcessor cacheProc = ignite.context().cache(); + if (ignite.cluster().active()) { + try { + int partitions = 0; + double total = 0; + double ready = 0; - boolean rebalanceInProgress = false; + GridCacheProcessor cacheProc = ignite.context().cache(); - for (CacheGroupContext grp: cacheProc.cacheGroups()) { - String cacheName = grp.config().getName(); + boolean rebalanceInProgress = false; - if (isProxyCache(ignite, cacheName) || isRestartingCache(ignite, cacheName)) - continue; + for (CacheGroupContext grp: cacheProc.cacheGroups()) { + String cacheName = grp.config().getName(); - try { - GridCacheAdapter ca = cacheProc.internalCache(cacheName); - - if (ca == null || !ca.context().started()) + if (isProxyCache(ignite, cacheName) || isRestartingCache(ignite, cacheName)) continue; - CacheMetrics cm = ca.localMetrics(); + try { + GridCacheAdapter ca = cacheProc.internalCache(cacheName); - partitions += cm.getTotalPartitionsCount(); + if (ca == null || !ca.context().started()) + continue; - long keysTotal = cm.getEstimatedRebalancingKeys(); - long keysReady = cm.getRebalancedKeys(); + CacheMetrics cm = ca.localMetrics(); - if (keysReady >= keysTotal) - keysReady = Math.max(keysTotal - 1, 0); + partitions += cm.getTotalPartitionsCount(); - total += keysTotal; - ready += keysReady; + long keysTotal = cm.getEstimatedRebalancingKeys(); + long keysReady = cm.getRebalancedKeys(); - if (cm.getRebalancingPartitionsCount() > 0) - rebalanceInProgress = true; - } - catch(IllegalStateException | IllegalArgumentException e) { - if (debug && ignite.log() != null) - ignite.log().error("Ignored cache group: " + grp.cacheOrGroupName(), e); + if (keysReady >= keysTotal) + keysReady = Math.max(keysTotal - 1, 0); + + total += keysTotal; + ready += keysReady; + + if (cm.getRebalancingPartitionsCount() > 0) + rebalanceInProgress = true; + } + catch(IllegalStateException | IllegalArgumentException e) { + if (debug && ignite.log() != null) + ignite.log().error("Ignored cache group: " + grp.cacheOrGroupName(), e); + } } + + if (partitions == 0) + res.setRebalance(NOTHING_TO_REBALANCE); + else if (total == 0 && rebalanceInProgress) + res.setRebalance(MINIMAL_REBALANCE); + else + res.setRebalance(total > 0 && rebalanceInProgress ? Math.max(ready / total, MINIMAL_REBALANCE) : REBALANCE_COMPLETE); } + catch (Exception e) { + res.setRebalance(REBALANCE_NOT_AVAILABLE); - if (partitions == 0) - res.setRebalance(NOTHING_TO_REBALANCE); - else if (total == 0 && rebalanceInProgress) - res.setRebalance(MINIMAL_REBALANCE); - else - res.setRebalance(total > 0 && rebalanceInProgress ? Math.max(ready / total, MINIMAL_REBALANCE) : REBALANCE_COMPLETE); + ignite.log().error("Failed to collect rebalance metrics", e); + } } - catch (Exception e) { + else res.setRebalance(REBALANCE_NOT_AVAILABLE); - ignite.log().error("Failed to collect rebalance metrics", e); - } - if (GridCacheUtils.isPersistenceEnabled(ignite.configuration())) { IgniteClusterEx cluster = ignite.cluster(); @@ -178,11 +184,7 @@ else if (total == 0 && rebalanceInProgress) res.setBaseline(inBaseline ? NODE_IN_BASELINE : NODE_NOT_IN_BASELINE); } - else - res.setBaseline(BASELINE_NOT_AVAILABLE); } - else - res.setBaseline(BASELINE_NOT_AVAILABLE); if (debug) log(ignite.log(), "Collected rebalance metrics", getClass(), start0); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/visor/VisorCacheRebalanceCollectorTaskSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/visor/VisorCacheRebalanceCollectorTaskSelfTest.java new file mode 100644 index 0000000000000..c5056e419d862 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/visor/VisorCacheRebalanceCollectorTaskSelfTest.java @@ -0,0 +1,128 @@ +/* + * 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.visor; + +import java.util.UUID; +import org.apache.ignite.configuration.DataStorageConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.internal.visor.node.VisorCacheRebalanceCollectorTask; +import org.apache.ignite.internal.visor.node.VisorCacheRebalanceCollectorTaskArg; +import org.apache.ignite.internal.visor.node.VisorCacheRebalanceCollectorTaskResult; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.junit.Test; + +import static org.apache.ignite.configuration.WALMode.LOG_ONLY; +import static org.apache.ignite.internal.visor.node.VisorNodeBaselineStatus.BASELINE_NOT_AVAILABLE; +import static org.apache.ignite.internal.visor.node.VisorNodeBaselineStatus.NODE_IN_BASELINE; +import static org.apache.ignite.internal.visor.util.VisorTaskUtils.REBALANCE_COMPLETE; +import static org.apache.ignite.internal.visor.util.VisorTaskUtils.REBALANCE_NOT_AVAILABLE; + +/** + * Tests for {@link VisorCacheRebalanceCollectorTask}. + */ +public class VisorCacheRebalanceCollectorTaskSelfTest extends GridCommonAbstractTest { + /** {@inheritDoc} */ + @Override protected void beforeTest() throws Exception { + super.beforeTest(); + + stopAllGrids(); + + cleanPersistenceDir(); + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + stopAllGrids(); + + cleanPersistenceDir(); + + super.afterTest(); + } + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); + + cfg.setConsistentId(igniteInstanceName); + + DataStorageConfiguration storageCfg = new DataStorageConfiguration(); + + storageCfg.setPageSize(1024).setWalMode(LOG_ONLY).setWalSegmentSize(8 * 1024 * 1024); + + storageCfg.getDefaultDataRegionConfiguration() + .setPersistenceEnabled(true) + .setMaxSize(500L * 1024 * 1024); + + cfg.setDataStorageConfiguration(storageCfg); + + + return cfg; + } + + /** + * @param ignite Ignite. + * @param nid Node ID. + * @return Task result. + */ + private VisorCacheRebalanceCollectorTaskResult executeTask(IgniteEx ignite, UUID nid) { + return ignite + .compute() + .execute(VisorCacheRebalanceCollectorTask.class, + new VisorTaskArgument<>(nid, new VisorCacheRebalanceCollectorTaskArg(), false)); + } + + /** + * This test execute internal tasks over grid with custom balancer. + * + * @throws Exception In case of error. + */ + @Test + public void testCollectingRebalance() throws Exception { + IgniteEx ignite = startGrids(1); + + UUID nid = ignite.localNode().id(); + + VisorCacheRebalanceCollectorTaskResult taskRes = executeTask(ignite, nid); + + assertNotNull(taskRes); + assertFalse(F.isEmpty(taskRes.getBaseline())); + assertEquals(1, taskRes.getBaseline().size()); + assertEquals(BASELINE_NOT_AVAILABLE, taskRes.getBaseline().get(nid)); // In new cluster node is not in baseline. + assertEquals(REBALANCE_NOT_AVAILABLE, taskRes.getRebalance().get(nid), 0.001); + + ignite.cluster().active(true); + + taskRes = executeTask(ignite, nid); + + assertNotNull(taskRes); + assertEquals(NODE_IN_BASELINE, taskRes.getBaseline().get(nid)); + assertEquals(REBALANCE_COMPLETE, taskRes.getRebalance().get(nid), 0.001); + + ignite.cluster().active(false); + + taskRes = executeTask(ignite, nid); + + assertNotNull(taskRes); + assertFalse(F.isEmpty(taskRes.getBaseline())); + assertEquals(1, taskRes.getBaseline().size()); + assertEquals(NODE_IN_BASELINE, taskRes.getBaseline().get(nid)); // Node in baseline after first activation. + assertEquals(REBALANCE_NOT_AVAILABLE, taskRes.getRebalance().get(nid), 0.001); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteComputeGridTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteComputeGridTestSuite.java index f74b35f2aac77..504f704c455f7 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteComputeGridTestSuite.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteComputeGridTestSuite.java @@ -82,6 +82,7 @@ import org.apache.ignite.internal.processors.compute.IgniteComputeCustomExecutorSelfTest; import org.apache.ignite.internal.processors.compute.PublicThreadpoolStarvationTest; import org.apache.ignite.internal.util.StripedExecutorTest; +import org.apache.ignite.internal.visor.VisorCacheRebalanceCollectorTaskSelfTest; import org.apache.ignite.p2p.GridMultinodeRedeployContinuousModeSelfTest; import org.apache.ignite.p2p.GridMultinodeRedeployIsolatedModeSelfTest; import org.apache.ignite.p2p.GridMultinodeRedeployPrivateModeSelfTest; @@ -174,6 +175,7 @@ public static TestSuite suite() throws Exception { suite.addTestSuite(IgniteComputeJobOneThreadTest.class); suite.addTestSuite(VisorManagementEventSelfTest.class); + suite.addTestSuite(VisorCacheRebalanceCollectorTaskSelfTest.class); return suite; } From 2676c123ce2210605483d374c20b3489b67be33f Mon Sep 17 00:00:00 2001 From: ipavlukhin Date: Tue, 16 Jul 2019 14:46:30 +0300 Subject: [PATCH 40/62] GG-19412 Exclude test resource Wrapper.ser from license check (cherry picked from commit 7baa018c6500856901a8a50e93a7c8ba28a27c4a) --- parent/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/parent/pom.xml b/parent/pom.xml index ba763b3232229..e64a7c69fa8dd 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -860,6 +860,7 @@ src/test/binaries/repo/org/apache/ignite/binary/test2/maven-metadata-local.xml src/test/binaries/repo/org/apache/ignite/binary/test1/1.1/test1-1.1.pom src/test/binaries/repo/org/apache/ignite/binary/test1/maven-metadata-local.xml + src/test/resources/org/apache/ignite/internal/managers/discovery/Wrapper.ser ipc/shmem/**/Makefile.in ipc/shmem/**/Makefile From ebb260332c6382047ee0124c847989187a4e4619 Mon Sep 17 00:00:00 2001 From: Igor Seliverstov Date: Tue, 16 Jul 2019 15:11:58 +0300 Subject: [PATCH 41/62] GG-20850: Fix @Ignore link. --- .../cache/distributed/IgniteCacheClientReconnectTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheClientReconnectTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheClientReconnectTest.java index 9022c67877f74..16d5f295de9b6 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheClientReconnectTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheClientReconnectTest.java @@ -182,7 +182,7 @@ public void testClientReconnectOnExchangeHistoryExhaustion() throws Exception { * @throws Exception If failed */ public void testClientInForceServerModeStopsOnExchangeHistoryExhaustionManyClients() throws Exception { - fail("https://ggsystems.atlassian.net/browse/GG-20801"); + fail("https://ggsystems.atlassian.net/browse/GG-20850"); System.setProperty(IgniteSystemProperties.IGNITE_EXCHANGE_HISTORY_SIZE, "1"); From 2ca3f151bc7ad42f004a626b3d7fb994d4b3a574 Mon Sep 17 00:00:00 2001 From: pavlukhin Date: Tue, 16 Jul 2019 17:27:24 +0300 Subject: [PATCH 42/62] GG-19412 Fail Continuous Query registration and do not fail node if remote filter class is missing (#177) (cherry picked from commit a28138f9d784dcd9efce025c822f0fa5887f82ea) --- .../IncompleteDeserializationException.java | 52 +++++++ .../continuous/GridContinuousProcessor.java | 62 +++++--- .../StartRoutineDiscoveryMessage.java | 41 ++++- .../TcpDiscoveryCustomEventMessage.java | 14 +- ...ncompleteDeserializationExceptionTest.java | 131 ++++++++++++++++ ...emoteFilterMissingInClassPathSelfTest.java | 145 +++++++++++++----- .../testsuites/IgniteBasicTestSuite.java | 3 + .../internal/managers/discovery/Wrapper.ser | Bin 0 -> 260 bytes 8 files changed, 382 insertions(+), 66 deletions(-) create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/IncompleteDeserializationException.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/IncompleteDeserializationExceptionTest.java create mode 100644 modules/core/src/test/resources/org/apache/ignite/internal/managers/discovery/Wrapper.ser diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/IncompleteDeserializationException.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/IncompleteDeserializationException.java new file mode 100644 index 0000000000000..626a6f84aefc6 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/IncompleteDeserializationException.java @@ -0,0 +1,52 @@ +/* + * Copyright 2019 GridGain Systems, Inc. and Contributors. + * + * Licensed under the GridGain Community Edition License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.gridgain.com/products/software/community-edition/gridgain-community-edition-license + * + * 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.managers.discovery; + +import org.jetbrains.annotations.NotNull; + +/** + * Exception which can be used to access a message which failed to be deserialized completely using Java serialization. + * Throwed from deserialization methods it can be caught by a caller. + *

      + * Should be {@link RuntimeException} because of limitations of Java serialization mechanisms. + *

      + * Catching {@link ClassNotFoundException} inside deserialization methods cannot do the same trick because + * Java deserialization remembers such exception internally and will rethrow it anyway upon returing to a user. + */ +public class IncompleteDeserializationException extends RuntimeException { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private final DiscoveryCustomMessage m; + + /** + * @param m Message. + */ + public IncompleteDeserializationException(@NotNull DiscoveryCustomMessage m) { + super(null, null, false, false); + + this.m = m; + } + + /** + * @return Message. + */ + @NotNull public DiscoveryCustomMessage message() { + return m; + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/GridContinuousProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/GridContinuousProcessor.java index 6723ea42624c4..644264ea87298 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/GridContinuousProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/GridContinuousProcessor.java @@ -1035,37 +1035,37 @@ public IgniteInternalFuture stopRoutine(UUID routineId) { doStop = true; } - if (doStop) { - boolean stop = false; + if (doStop) { + boolean stop = false; - // Unregister routine locally. - LocalRoutineInfo routine = locInfos.remove(routineId); + // Unregister routine locally. + LocalRoutineInfo routine = locInfos.remove(routineId); - if (routine != null) { - stop = true; + if (routine != null) { + stop = true; - // Unregister handler locally. - unregisterHandler(routineId, routine.hnd, true); - } + // Unregister handler locally. + unregisterHandler(routineId, routine.hnd, true); + } - if (!stop && discoProtoVer == 2) - stop = routinesInfo.routineExists(routineId); + if (!stop && discoProtoVer == 2) + stop = routinesInfo.routineExists(routineId); - // Finish if routine is not found (wrong ID is provided). - if (!stop) { - stopFuts.remove(routineId); + // Finish if routine is not found (wrong ID is provided). + if (!stop) { + stopFuts.remove(routineId); fut.onDone(); return fut; } - try { - ctx.discovery().sendCustomEvent(new StopRoutineDiscoveryMessage(routineId)); - } - catch (IgniteCheckedException e) { - fut.onDone(e); - } + try { + ctx.discovery().sendCustomEvent(new StopRoutineDiscoveryMessage(routineId)); + } + catch (IgniteCheckedException e) { + fut.onDone(e); + } if (ctx.isStopping()) fut.onDone(); @@ -1296,10 +1296,21 @@ private void processStartAckRequest(AffinityTopologyVersion topVer, * @param req Start request. */ private void processStartRequest(ClusterNode node, StartRoutineDiscoveryMessage req) { - UUID routineId = req.routineId(); if (node.id().equals(ctx.localNodeId())) return; + UUID routineId = req.routineId(); + + if (req.deserializationException() != null && checkNodeFilter(req)) { + IgniteCheckedException err = new IgniteCheckedException(req.deserializationException()); + + req.addError(node.id(), err); + + U.error(log, "Failed to register handler [nodeId=" + node.id() + ", routineId=" + routineId + ']', err); + + return; + } + StartRequestData data = req.startRequestData(); GridContinuousHandler hnd = data.handler(); @@ -1400,6 +1411,15 @@ private void processStartRequest(ClusterNode node, StartRoutineDiscoveryMessage req.addError(ctx.localNodeId(), err); } + /** */ + private boolean checkNodeFilter(StartRoutineDiscoveryMessage req) { + StartRequestData reqData = req.startRequestData(); + IgnitePredicate prjPred; + + return reqData == null || (prjPred = reqData.projectionPredicate()) == null + || prjPred.apply(ctx.discovery().localNode()); + } + /** * @param sndId Sender node ID. * @param msg Message. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/StartRoutineDiscoveryMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/StartRoutineDiscoveryMessage.java index 82996d4bd7103..4bca717bd4dd3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/StartRoutineDiscoveryMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/StartRoutineDiscoveryMessage.java @@ -17,16 +17,21 @@ package org.apache.ignite.internal.processors.continuous; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.UUID; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.managers.discovery.DiscoveryCustomMessage; +import org.apache.ignite.internal.managers.discovery.IncompleteDeserializationException; import org.apache.ignite.internal.util.typedef.T2; import org.apache.ignite.internal.util.typedef.internal.S; +import org.jetbrains.annotations.Nullable; /** - * + * Discovery message used for Continuous Query registration. */ public class StartRoutineDiscoveryMessage extends AbstractContinuousMessage { /** */ @@ -36,7 +41,8 @@ public class StartRoutineDiscoveryMessage extends AbstractContinuousMessage { private final StartRequestData startReqData; /** */ - private final Map errs = new HashMap<>(); + // Initilized here as well to preserve compatibility with previous versions + private Map errs = new HashMap<>(); /** */ private Map> updateCntrs; @@ -47,6 +53,9 @@ public class StartRoutineDiscoveryMessage extends AbstractContinuousMessage { /** Keep binary flag. */ private boolean keepBinary; + /** */ + private transient ClassNotFoundException deserEx; + /** * @param routineId Routine id. * @param startReqData Start request data. @@ -70,6 +79,9 @@ public StartRequestData startRequestData() { * @param e Exception. */ public void addError(UUID nodeId, IgniteCheckedException e) { + if (errs == null) + errs = new HashMap<>(); + errs.put(nodeId, e); } @@ -108,7 +120,7 @@ public void addUpdateCounters(UUID nodeId, Map> cntrs) { * @return Errs. */ public Map errs() { - return errs; + return errs != null ? errs : Collections.emptyMap(); } /** @@ -125,7 +137,28 @@ public boolean keepBinary() { /** {@inheritDoc} */ @Override public DiscoveryCustomMessage ackMessage() { - return new StartRoutineAckDiscoveryMessage(routineId, errs, updateCntrs, updateCntrsPerNode); + return new StartRoutineAckDiscoveryMessage(routineId, errs(), updateCntrs, updateCntrsPerNode); + } + + /** */ + private void readObject(ObjectInputStream in) throws IOException { + // Override default serialization in order to tolerate missing classes exceptions (e.g. remote filter class). + // We need this means because CQ registration process assumes that an "ack message" will be sent. + try { + in.defaultReadObject(); + } + catch (ClassNotFoundException e) { + deserEx = e; + + throw new IncompleteDeserializationException(this); + } + } + + /** + * @return Exception occurred during deserialization. + */ + @Nullable public ClassNotFoundException deserializationException() { + return deserEx; } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryCustomEventMessage.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryCustomEventMessage.java index bbbcdd7ad216b..bc7de6abee186 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryCustomEventMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryCustomEventMessage.java @@ -18,6 +18,9 @@ package org.apache.ignite.spi.discovery.tcp.messages; import java.util.UUID; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.managers.discovery.CustomMessageWrapper; +import org.apache.ignite.internal.managers.discovery.IncompleteDeserializationException; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; @@ -96,7 +99,16 @@ public void message(@Nullable DiscoverySpiCustomMessage msg, @NotNull byte[] msg */ @Nullable public DiscoverySpiCustomMessage message(@NotNull Marshaller marsh, ClassLoader ldr) throws Throwable { if (msg == null) { - msg = U.unmarshal(marsh, msgBytes, ldr); + try { + msg = U.unmarshal(marsh, msgBytes, ldr); + } + catch (IgniteCheckedException e) { + // Try to resurrect a message in a case of deserialization failure + if (e.getCause() instanceof IncompleteDeserializationException) + return new CustomMessageWrapper(((IncompleteDeserializationException)e.getCause()).message()); + + throw e; + } assert msg != null; } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/IncompleteDeserializationExceptionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/IncompleteDeserializationExceptionTest.java new file mode 100644 index 0000000000000..a1de52aa67a14 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/IncompleteDeserializationExceptionTest.java @@ -0,0 +1,131 @@ +/* + * Copyright 2019 GridGain Systems, Inc. and Contributors. + * + * Licensed under the GridGain Community Edition License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.gridgain.com/products/software/community-edition/gridgain-community-edition-license + * + * 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.managers.discovery; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.UUID; +import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; +import org.apache.ignite.lang.IgniteUuid; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.jetbrains.annotations.Nullable; +import org.junit.Test; + +/** */ +public class IncompleteDeserializationExceptionTest extends GridCommonAbstractTest { + /** */ + private Path tmpDir; + + /** {@inheritDoc} */ + @Override protected void beforeTest() throws Exception { + super.beforeTest(); + + tmpDir = Files.createTempDirectory(UUID.randomUUID().toString()); + + Files.createDirectories(tmpDir); + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + Files.delete(tmpDir); + + super.afterTest(); + } + + /** */ + @Test + public void testMissingClassDeserialization() throws Exception { + try (ObjectInputStream in = new ObjectInputStream(getClass().getResourceAsStream("Wrapper.ser"))) { + in.readObject(); + + fail("Exception is expected"); + } + catch (IncompleteDeserializationException e) { + Wrapper wrp = (Wrapper)e.message(); + + assertNotNull(wrp); + assertEquals(42, wrp.i); + assertNull(wrp.o); + } + } + + /** */ + public static class Wrapper implements DiscoveryCustomMessage { + /** */ + private static final long serialVersionUID = 0; + + /** */ + private final int i; + + /** */ + private final Object o; + + /** */ + private Wrapper(int i, Object o) { + this.i = i; + this.o = o; + } + + /** */ + private void readObject(ObjectInputStream in) throws IOException { + try { + in.defaultReadObject(); + } + catch (ClassNotFoundException e) { + throw new IncompleteDeserializationException(this); + } + } + + /** {@inheritDoc} */ + @Override public IgniteUuid id() { + return null; + } + + /** {@inheritDoc} */ + @Override public @Nullable DiscoveryCustomMessage ackMessage() { + return null; + } + + /** {@inheritDoc} */ + @Override public boolean isMutable() { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean stopProcess() { + return false; + } + + /** {@inheritDoc} */ + @Override public DiscoCache createDiscoCache(GridDiscoveryManager mgr, AffinityTopologyVersion topVer, + DiscoCache discoCache) { + return null; + } + } + + // Commented lines were used to prepare serialized object +// public static void main(String[] args) throws IOException { +// try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("Wrapper.ser"))) { +// out.writeObject(new Wrapper(42, new ForeignClass())); +// } +// } +// +// public static class ForeignClass implements Serializable { +// } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/ContinuousQueryRemoteFilterMissingInClassPathSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/ContinuousQueryRemoteFilterMissingInClassPathSelfTest.java index 226302ff9d616..7dca641d7daa6 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/ContinuousQueryRemoteFilterMissingInClassPathSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/ContinuousQueryRemoteFilterMissingInClassPathSelfTest.java @@ -17,6 +17,14 @@ package org.apache.ignite.internal.processors.cache.query.continuous; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import javax.cache.configuration.Factory; +import javax.cache.event.CacheEntryEvent; +import javax.cache.event.CacheEntryEventFilter; +import javax.cache.event.CacheEntryListenerException; +import javax.cache.event.CacheEntryUpdatedListener; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; import org.apache.ignite.cache.CacheEntryEventSerializableFilter; @@ -24,19 +32,12 @@ import org.apache.ignite.cache.query.ContinuousQuery; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.util.typedef.X; +import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.testframework.GridStringLogger; import org.apache.ignite.testframework.config.GridTestProperties; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; -import javax.cache.configuration.Factory; -import javax.cache.event.CacheEntryEvent; -import javax.cache.event.CacheEntryEventFilter; -import javax.cache.event.CacheEntryListenerException; -import javax.cache.event.CacheEntryUpdatedListener; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; - /** * */ @@ -44,6 +45,9 @@ public class ContinuousQueryRemoteFilterMissingInClassPathSelfTest extends GridC /** URL of classes. */ private static final URL[] URLS; + /** */ + public static final String EXT_FILTER_CLASS = "org.apache.ignite.tests.p2p.CacheDeploymentCacheEntryEventSerializableFilter"; + static { try { URLS = new URL[] {new URL(GridTestProperties.getProperty("p2p.uri.cls"))}; @@ -63,7 +67,10 @@ public class ContinuousQueryRemoteFilterMissingInClassPathSelfTest extends GridC private boolean setExternalLoader; /** */ - private ClassLoader ldr; + private final ClassLoader extLdr = new URLClassLoader(URLS, getClass().getClassLoader()); + + /** */ + private boolean setFilterAttr; /** {@inheritDoc} */ @Override protected void afterTest() throws Exception { @@ -78,33 +85,35 @@ public class ContinuousQueryRemoteFilterMissingInClassPathSelfTest extends GridC cfg.setClientMode(clientMode); - CacheConfiguration cacheCfg = new CacheConfiguration(DEFAULT_CACHE_NAME); - - cacheCfg.setName("simple"); + CacheConfiguration cacheCfg = new CacheConfiguration<>(DEFAULT_CACHE_NAME); cacheCfg.setCacheMode(CacheMode.PARTITIONED); + cacheCfg.setNodeFilter(node -> node.attribute("filter") == null); + cfg.setCacheConfiguration(cacheCfg); if (setExternalLoader) - cfg.setClassLoader(ldr); - else + cfg.setClassLoader(extLdr); + + if (log != null) cfg.setGridLogger(log); + if (setFilterAttr) + cfg.setUserAttributes(U.map("filter", 1)); + return cfg; } /** * @throws Exception If fail. */ - public void testWarningMessageOnClientNode() throws Exception { - ldr = new URLClassLoader(URLS, getClass().getClassLoader()); - + public void testClientJoinsMissingClassWarning() throws Exception { clientMode = false; setExternalLoader = true; - final Ignite ignite0 = startGrid(1); + Ignite ignite0 = startGrid(1); - executeContinuousQuery(ignite0.cache("simple")); + executeContinuousQuery(ignite0.cache(DEFAULT_CACHE_NAME)); log = new GridStringLogger(); clientMode = true; @@ -121,15 +130,13 @@ public void testWarningMessageOnClientNode() throws Exception { /** * @throws Exception If fail. */ - public void testNoWarningMessageOnClientNode() throws Exception { - ldr = new URLClassLoader(URLS, getClass().getClassLoader()); - + public void testClientJoinsExtClassLoaderNoWarning() throws Exception { setExternalLoader = true; clientMode = false; - final Ignite ignite0 = startGrid(1); + Ignite ignite0 = startGrid(1); - executeContinuousQuery(ignite0.cache("simple")); + executeContinuousQuery(ignite0.cache(DEFAULT_CACHE_NAME)); log = new GridStringLogger(); clientMode = true; @@ -143,15 +150,13 @@ public void testNoWarningMessageOnClientNode() throws Exception { /** * @throws Exception If fail. */ - public void testExceptionOnServerNode() throws Exception { - ldr = new URLClassLoader(URLS, getClass().getClassLoader()); - + public void testServerJoinsMissingClassException() throws Exception { clientMode = false; setExternalLoader = true; - final Ignite ignite0 = startGrid(1); + Ignite ignite0 = startGrid(1); - executeContinuousQuery(ignite0.cache("simple")); + executeContinuousQuery(ignite0.cache(DEFAULT_CACHE_NAME)); log = new GridStringLogger(); setExternalLoader = false; @@ -168,15 +173,13 @@ public void testExceptionOnServerNode() throws Exception { /** * @throws Exception If fail. */ - public void testNoExceptionOnServerNode() throws Exception { - ldr = new URLClassLoader(URLS, getClass().getClassLoader()); - + public void testServerJoinsExtClassLoaderNoException() throws Exception { clientMode = false; setExternalLoader = true; - final Ignite ignite0 = startGrid(1); + Ignite ignite0 = startGrid(1); - executeContinuousQuery(ignite0.cache("simple")); + executeContinuousQuery(ignite0.cache(DEFAULT_CACHE_NAME)); log = new GridStringLogger(); @@ -186,11 +189,73 @@ public void testNoExceptionOnServerNode() throws Exception { "Failed to find class with given class loader for unmarshalling")); } + /** + * @throws Exception If fail. + */ + public void testServerMissingClassFailsRegistration() throws Exception { + clientMode = false; + + setExternalLoader = true; + + Ignite ign1 = startGrid(1); + + setExternalLoader = false; + + startGrid(2); + + try { + executeContinuousQuery(ign1.cache(DEFAULT_CACHE_NAME)); + + fail("Exception is expected"); + } + catch (Exception e) { + assertTrue(X.hasCause(e, ClassNotFoundException.class)); + } + } + + /** + * @throws Exception If fail. + */ + public void testClientMissingClassDoesNotFailRegistration() throws Exception { + clientMode = false; + + setExternalLoader = true; + + Ignite ign1 = startGrid(1); + + setExternalLoader = false; + + clientMode = true; + + startGrid(2); + + executeContinuousQuery(ign1.cache(DEFAULT_CACHE_NAME)); + } + + /** + * @throws Exception If fail. + */ + public void testNodeFilterServerMissingClassDoesNotFailRegistration() throws Exception { + clientMode = false; + + setExternalLoader = true; + + Ignite ign1 = startGrid(1); + + setExternalLoader = false; + + setFilterAttr = true; + + startGrid(2); + + executeContinuousQuery(ign1.cache(DEFAULT_CACHE_NAME)); + } + /** * @param cache Ignite cache. * @throws Exception If fail. */ - private void executeContinuousQuery(IgniteCache cache) throws Exception { + private void executeContinuousQuery(IgniteCache cache) throws Exception { ContinuousQuery qry = new ContinuousQuery<>(); qry.setLocalListener( @@ -203,10 +268,10 @@ private void executeContinuousQuery(IgniteCache cache) throws Exception { } ); - final Class remoteFilterClass = (Class) - ldr.loadClass("org.apache.ignite.tests.p2p.CacheDeploymentCacheEntryEventSerializableFilter"); + Class remoteFilterCls = (Class) + extLdr.loadClass(EXT_FILTER_CLASS); - qry.setRemoteFilterFactory(new ClassFilterFactory(remoteFilterClass)); + qry.setRemoteFilterFactory(new ClassFilterFactory(remoteFilterCls)); cache.query(qry); @@ -231,7 +296,7 @@ public ClassFilterFactory(Class cls) { /** {@inheritDoc} */ @Override public CacheEntryEventSerializableFilter create() { try { - return cls.newInstance(); + return (CacheEntryEventSerializableFilter)cls.newInstance(); } catch (Exception e) { throw new RuntimeException(e); diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java index 9f76a8bfeef59..336198fd757ae 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java @@ -44,6 +44,7 @@ import org.apache.ignite.internal.MarshallerContextLockingSelfTest; import org.apache.ignite.internal.TransactionsMXBeanImplTest; import org.apache.ignite.internal.managers.IgniteDiagnosticMessagesTest; +import org.apache.ignite.internal.managers.discovery.IncompleteDeserializationExceptionTest; import org.apache.ignite.internal.pagemem.wal.record.WALRecordTest; import org.apache.ignite.internal.processors.DeadLockOnNodeLeftExchangeTest; import org.apache.ignite.internal.processors.affinity.GridAffinityAssignmentV2Test; @@ -238,6 +239,8 @@ public static TestSuite suite(@Nullable final Set ignoredTests) throws Ex suite.addTestSuite(ClassPathContentLoggingTest.class); + suite.addTestSuite(IncompleteDeserializationExceptionTest.class); + return suite; } } diff --git a/modules/core/src/test/resources/org/apache/ignite/internal/managers/discovery/Wrapper.ser b/modules/core/src/test/resources/org/apache/ignite/internal/managers/discovery/Wrapper.ser new file mode 100644 index 0000000000000000000000000000000000000000..cbf16a8c377a36aa7f566074bafd38b68fd7c3e4 GIT binary patch literal 260 zcmcJKJqiLb5QWDDFW?!hEVA`tCH}FnU?bSrjB$urvdJ(B%j#|HEj^5v@D4`s3clvO z;w!%Qc*8gf9D^8zjQT>#8gElBpGZ79)uBg264lv89eR?hs=W>!J4&>oNMh018zvk4 zdeFq*v8R}(2SH{M_@#iNhLLSx6cS9D7JDomdQ Date: Wed, 17 Jul 2019 15:46:24 +1000 Subject: [PATCH 43/62] GG-20567 Updated dependencies to fix possible vulnerabilities --- modules/camel/pom.xml | 2 +- modules/cassandra/store/pom.xml | 2 +- modules/kafka/pom.xml | 2 +- modules/mesos/pom.xml | 2 +- .../apache/ignite/mesos/IgniteFramework.java | 3 +- .../ignite/mesos/IgniteSchedulerSelfTest.java | 11 + .../src/main/resources/features.xml | 4 +- modules/spark-2.10/README.txt | 4 - modules/spark-2.10/pom.xml | 237 ------------------ .../impl/optimization/StringExpressions.scala | 30 ++- .../spark/impl/optimization/package.scala | 2 +- .../sql/ignite/IgniteExternalCatalog.scala | 17 +- .../spark/sql/ignite/IgniteOptimization.scala | 14 +- .../spark/sql/ignite/IgniteSparkSession.scala | 10 +- .../ignite/spark/AbstractDataFrameSpec.scala | 2 +- .../ignite/spark/IgniteDataFrameSuite.scala | 2 +- ...gniteOptimizationAggregationFuncSpec.scala | 4 +- .../spark/IgniteOptimizationJoinSpec.scala | 6 +- .../IgniteOptimizationMathFuncSpec.scala | 46 ++-- .../ignite/spark/IgniteOptimizationSpec.scala | 8 +- .../IgniteOptimizationStringFuncSpec.scala | 101 ++++++-- modules/zookeeper/pom.xml | 4 +- parent/pom.xml | 20 +- 23 files changed, 188 insertions(+), 345 deletions(-) delete mode 100644 modules/spark-2.10/README.txt delete mode 100644 modules/spark-2.10/pom.xml diff --git a/modules/camel/pom.xml b/modules/camel/pom.xml index 0d65ce80aabe5..6cd725f5ba913 100644 --- a/modules/camel/pom.xml +++ b/modules/camel/pom.xml @@ -35,7 +35,7 @@ http://ignite.apache.org - 18.0 + 25.1-jre 2.5.0 diff --git a/modules/cassandra/store/pom.xml b/modules/cassandra/store/pom.xml index 32b10f5225b7b..8922a53472515 100644 --- a/modules/cassandra/store/pom.xml +++ b/modules/cassandra/store/pom.xml @@ -39,7 +39,7 @@ 3.0.0 3.3 4.1.27.Final - 19.0 + 25.1-jre 3.0.2 diff --git a/modules/kafka/pom.xml b/modules/kafka/pom.xml index c0f2d9cacf202..539768f4413f0 100644 --- a/modules/kafka/pom.xml +++ b/modules/kafka/pom.xml @@ -71,7 +71,7 @@ org.apache.curator curator-test - ${curator.version} + ${curator.test.version} test diff --git a/modules/mesos/pom.xml b/modules/mesos/pom.xml index 5a72f335e290d..777cd74907728 100644 --- a/modules/mesos/pom.xml +++ b/modules/mesos/pom.xml @@ -35,7 +35,7 @@ http://ignite.apache.org - 0.22.0 + 1.5.2 http://ignite.run/download_ignite.php https://archive.apache.org/dist/ignite/%s/apache-ignite-fabric-%s-bin.zip diff --git a/modules/mesos/src/main/java/org/apache/ignite/mesos/IgniteFramework.java b/modules/mesos/src/main/java/org/apache/ignite/mesos/IgniteFramework.java index eea510a5379ec..addd3e0b017ea 100644 --- a/modules/mesos/src/main/java/org/apache/ignite/mesos/IgniteFramework.java +++ b/modules/mesos/src/main/java/org/apache/ignite/mesos/IgniteFramework.java @@ -17,7 +17,6 @@ package org.apache.ignite.mesos; -import com.google.protobuf.ByteString; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.ignite.mesos.resource.IgniteProvider; @@ -105,7 +104,7 @@ public static void main(String[] args) throws Exception { Protos.Credential cred = Protos.Credential.newBuilder() .setPrincipal(System.getenv(DEFAULT_PRINCIPAL)) - .setSecret(ByteString.copyFrom(System.getenv(DEFAULT_SECRET).getBytes())) + .setSecret(System.getenv(DEFAULT_SECRET)) .build(); driver = new MesosSchedulerDriver(scheduler, igniteFramework.getFrameworkInfo(), clusterProps.masterUrl(), diff --git a/modules/mesos/src/test/java/org/apache/ignite/mesos/IgniteSchedulerSelfTest.java b/modules/mesos/src/test/java/org/apache/ignite/mesos/IgniteSchedulerSelfTest.java index 099daa2dd39cf..4e485698aa4f7 100644 --- a/modules/mesos/src/test/java/org/apache/ignite/mesos/IgniteSchedulerSelfTest.java +++ b/modules/mesos/src/test/java/org/apache/ignite/mesos/IgniteSchedulerSelfTest.java @@ -465,6 +465,12 @@ public void clear() { return null; } + /** {@inheritDoc} */ + @Override public Protos.Status acceptOffers(Collection collection, + Collection collection1, Protos.Filters filters) { + return null; + } + /** {@inheritDoc} */ @Override public Protos.Status declineOffer(Protos.OfferID offerId, Protos.Filters filters) { declinedOffer = offerId; @@ -484,6 +490,11 @@ public void clear() { return null; } + /** {@inheritDoc} */ + @Override public Protos.Status suppressOffers() { + return null; + } + /** {@inheritDoc} */ @Override public Protos.Status acknowledgeStatusUpdate(Protos.TaskStatus status) { return null; diff --git a/modules/osgi-karaf/src/main/resources/features.xml b/modules/osgi-karaf/src/main/resources/features.xml index 3e3989e3ea22f..62bdd6882b91a 100644 --- a/modules/osgi-karaf/src/main/resources/features.xml +++ b/modules/osgi-karaf/src/main/resources/features.xml @@ -282,7 +282,7 @@ wrap - mvn:com.google.guava/guava/${guava14.version} + mvn:com.google.guava/guava/${guava.version} wrap:mvn:com.twitter/hbc-core/${twitter.hbc.version}$Bundle-SymbolicName=Hosebird Client Core&Bundle-Version=${twitter.hbc.version} wrap:mvn:com.twitter/hbc-twitter4j/${twitter.hbc.version}$Bundle-SymbolicName=Hosebird Client Twitter4J&Bundle-Version=${twitter.hbc.version} mvn:org.apache.ignite/ignite-twitter/${project.version} @@ -323,7 +323,7 @@ mvn:org.apache.zookeeper/zookeeper/${zookeeper.version} - mvn:com.google.guava/guava/${guava16.version} + mvn:com.google.guava/guava/${guava.version} mvn:com.fasterxml.jackson.core/jackson-core/${jackson.version} mvn:com.fasterxml.jackson.core/jackson-databind/${jackson.version} mvn:org.apache.curator/curator-client/${curator.version} diff --git a/modules/spark-2.10/README.txt b/modules/spark-2.10/README.txt deleted file mode 100644 index 29d393012efa9..0000000000000 --- a/modules/spark-2.10/README.txt +++ /dev/null @@ -1,4 +0,0 @@ -Apache Ignite Spark Module ---------------------------- - -Apache Ignite Spark module to be build with Scala 2.10. diff --git a/modules/spark-2.10/pom.xml b/modules/spark-2.10/pom.xml deleted file mode 100644 index cd1b4c28f1b8c..0000000000000 --- a/modules/spark-2.10/pom.xml +++ /dev/null @@ -1,237 +0,0 @@ - - - - - - - 4.0.0 - - - org.apache.ignite - ignite-parent - 1 - ../../parent - - - ignite-spark_2.10 - 2.5.6-SNAPSHOT - http://ignite.apache.org - - - - org.apache.ignite - ignite-core - ${project.version} - - - - org.apache.ignite - ignite-core - ${project.version} - test-jar - test - - - - org.scala-lang - scala-library - ${scala210.library.version} - - - - org.scala-lang - scala-reflect - ${scala210.library.version} - - - - org.apache.spark - spark-core_2.10 - ${spark.version} - - - - org.apache.spark - spark-catalyst_2.10 - ${spark.version} - - - - org.apache.spark - spark-sql_2.10 - ${spark.version} - - - - org.apache.spark - spark-network-common_2.10 - ${spark.version} - - - - org.apache.spark - spark-network-shuffle_2.10 - ${spark.version} - - - - org.apache.hadoop - hadoop-common - ${spark.hadoop.version} - - - commons-beanutils - commons-beanutils - - - commons-beanutils - commons-beanutils-core - - - - - - com.fasterxml.jackson.core - jackson-annotations - ${jackson.version} - - - - org.json4s - json4s-core_2.10 - 3.5.0 - - - - org.apache.ignite - ignite-indexing - ${project.version} - - - - org.apache.ignite - ignite-spring - ${project.version} - - - - org.apache.ignite - ignite-log4j - ${project.version} - - - - - org.scalatest - scalatest_2.10 - 2.2.6 - test - - - org.scala-lang - scala-library - - - - - - org.apache.spark - spark-unsafe_2.10 - ${spark.version} - - - - org.apache.spark - spark-tags_2.10 - ${spark.version} - - - - org.apache.parquet - parquet-hadoop - 1.9.0 - - - - org.apache.hadoop - hadoop-mapreduce-client-core - ${hadoop.version} - - - - com.google.guava - guava - ${guava14.version} - - - - - ../spark/src/main/scala - ../spark/src/test/java - - - - ../spark/src/main/resources - - - - - - ../spark/src/test/resources - - - - - - net.alchim31.maven - scala-maven-plugin - - - - - - - scala-test - - - - - org.scalatest - scalatest-maven-plugin - 2.0.0 - - ${project.build.directory}/surefire-reports - . - WDF IgniteScalaTestSuites.txt - - - - test - - test - - - - - - - - - diff --git a/modules/spark/src/main/scala/org/apache/ignite/spark/impl/optimization/StringExpressions.scala b/modules/spark/src/main/scala/org/apache/ignite/spark/impl/optimization/StringExpressions.scala index 1ecab2ca0d16b..65882802fe803 100644 --- a/modules/spark/src/main/scala/org/apache/ignite/spark/impl/optimization/StringExpressions.scala +++ b/modules/spark/src/main/scala/org/apache/ignite/spark/impl/optimization/StringExpressions.scala @@ -55,15 +55,24 @@ private[optimization] object StringExpressions extends SupportedExpressions { case StringRPad(str, len, pad) ⇒ checkChild(str) && checkChild(len) && checkChild(pad) - case StringTrimLeft(child) ⇒ + case StringTrimLeft(child, None) ⇒ checkChild(child) - case StringTrimRight(child) ⇒ + case StringTrimRight(child, None) ⇒ checkChild(child) - case StringTrim(child) ⇒ + case StringTrim(child, None) ⇒ checkChild(child) + case StringTrimLeft(child, Some(trimStr)) ⇒ + checkChild(child) && checkChild(trimStr) + + case StringTrimRight(child, Some(trimStr)) ⇒ + checkChild(child) && checkChild(trimStr) + + case StringTrim(child, Some(trimStr)) ⇒ + checkChild(child) && checkChild(trimStr) + case RegExpReplace(subject, regexp, rep) ⇒ checkChild(subject) && checkChild(regexp) && checkChild(rep) @@ -121,15 +130,24 @@ private[optimization] object StringExpressions extends SupportedExpressions { case StringRPad(str, len, pad) ⇒ Some(s"RPAD(${childToString(str)}, ${childToString(len)}, ${childToString(pad)})") - case StringTrimLeft(child) ⇒ + case StringTrimLeft(child, None) ⇒ Some(s"LTRIM(${childToString(child)})") - case StringTrimRight(child) ⇒ + case StringTrimRight(child, None) ⇒ Some(s"RTRIM(${childToString(child)})") - case StringTrim(child) ⇒ + case StringTrim(child, None) ⇒ Some(s"TRIM(${childToString(child)})") + case StringTrimLeft(child, Some(trimStr)) ⇒ + Some(s"LTRIM(${childToString(child)}, ${childToString(trimStr)})") + + case StringTrimRight(child, Some(trimStr)) ⇒ + Some(s"RTRIM(${childToString(child)}, ${childToString(trimStr)})") + + case StringTrim(child, Some(trimStr)) ⇒ + Some(s"TRIM(${childToString(child)}, ${childToString(trimStr)})") + case RegExpReplace(subject, regexp, rep) ⇒ Some(s"REGEXP_REPLACE(${childToString(subject)}, ${childToString(regexp)}, ${childToString(rep)})") diff --git a/modules/spark/src/main/scala/org/apache/ignite/spark/impl/optimization/package.scala b/modules/spark/src/main/scala/org/apache/ignite/spark/impl/optimization/package.scala index 4e168f41dfc61..4f3220f011dd2 100644 --- a/modules/spark/src/main/scala/org/apache/ignite/spark/impl/optimization/package.scala +++ b/modules/spark/src/main/scala/org/apache/ignite/spark/impl/optimization/package.scala @@ -118,7 +118,7 @@ package object optimization { metadata = alias .map(new MetadataBuilder().withMetadata(toCopy.metadata).putString(ALIAS, _).build()) .getOrElse(toCopy.metadata) - )(exprId = exprId.getOrElse(toCopy.exprId), qualifier = toCopy.qualifier, isGenerated = toCopy.isGenerated) + )(exprId = exprId.getOrElse(toCopy.exprId), qualifier = toCopy.qualifier) case a: Alias ⇒ toAttributeReference(a.child, existingOutput, Some(a.exprId), Some(alias.getOrElse(a.name))) diff --git a/modules/spark/src/main/scala/org/apache/spark/sql/ignite/IgniteExternalCatalog.scala b/modules/spark/src/main/scala/org/apache/spark/sql/ignite/IgniteExternalCatalog.scala index 6876a3e6185b4..f632d2ac8f64a 100644 --- a/modules/spark/src/main/scala/org/apache/spark/sql/ignite/IgniteExternalCatalog.scala +++ b/modules/spark/src/main/scala/org/apache/spark/sql/ignite/IgniteExternalCatalog.scala @@ -94,8 +94,7 @@ private[ignite] class IgniteExternalCatalog(defaultIgniteContext: IgniteContext) /** @inheritdoc */ override def getTable(db: String, table: String): CatalogTable = getTableOption(db, table).get - /** @inheritdoc */ - override def getTableOption(db: String, tabName: String): Option[CatalogTable] = { + def getTableOption(db: String, tabName: String): Option[CatalogTable] = { val ignite = igniteOrDefault(db, default) val gridName = igniteName(ignite) @@ -234,17 +233,25 @@ private[ignite] class IgniteExternalCatalog(defaultIgniteContext: IgniteContext) override def listFunctions(db: String, pattern: String): Seq[String] = Seq.empty[String] /** @inheritdoc */ - override def alterDatabase(dbDefinition: CatalogDatabase): Unit = + override def doAlterDatabase(dbDefinition: CatalogDatabase): Unit = throw new UnsupportedOperationException("unsupported") /** @inheritdoc */ - override def alterTable(tableDefinition: CatalogTable): Unit = + override def doAlterFunction(db: String, funcDefinition: CatalogFunction): Unit = throw new UnsupportedOperationException("unsupported") /** @inheritdoc */ - override def alterTableSchema(db: String, table: String, schema: StructType): Unit = + override def doAlterTableStats(db: String, table: String, stats: Option[CatalogStatistics]): Unit = throw new UnsupportedOperationException("unsupported") + /** @inheritdoc */ + override def doAlterTable(tableDefinition: CatalogTable): Unit = + throw new UnsupportedOperationException("unsupported") + + /** @inheritdoc */ + override def doAlterTableDataSchema(db: String, table: String, schema: StructType): Unit = + throw new UnsupportedOperationException("unsupported") + /** @inheritdoc */ override protected def doCreateFunction(db: String, funcDefinition: CatalogFunction): Unit = { /* no-op */ } diff --git a/modules/spark/src/main/scala/org/apache/spark/sql/ignite/IgniteOptimization.scala b/modules/spark/src/main/scala/org/apache/spark/sql/ignite/IgniteOptimization.scala index b23cd6fc690cb..4a0f791bd127c 100644 --- a/modules/spark/src/main/scala/org/apache/spark/sql/ignite/IgniteOptimization.scala +++ b/modules/spark/src/main/scala/org/apache/spark/sql/ignite/IgniteOptimization.scala @@ -63,7 +63,7 @@ object IgniteOptimization extends Rule[LogicalPlan] with Logging { plan.transformUp { //We found basic node to transform. //We create new accumulator and going to the upper layers. - case LogicalRelation(igniteSqlRelation: IgniteSQLRelation[_, _], output, _catalogTable) ⇒ + case LogicalRelation(igniteSqlRelation: IgniteSQLRelation[_, _], output, _catalogTable, _) ⇒ //Clear flag to optimize each statement separately stepSkipped = false @@ -352,7 +352,8 @@ object IgniteOptimization extends Rule[LogicalPlan] with Logging { new LogicalRelation ( relation = IgniteSQLAccumulatorRelation(acc), output = acc.outputExpressions.map(toAttributeReference(_, Seq.empty)), - catalogTable = acc.igniteQueryContext.catalogTable) + catalogTable = acc.igniteQueryContext.catalogTable, + false) } /** @@ -407,19 +408,16 @@ object IgniteOptimization extends Rule[LogicalPlan] with Logging { nullable = found.nullable, metadata = found.metadata)( exprId = found.exprId, - qualifier = found.qualifier, - isGenerated = found.isGenerated), + qualifier = found.qualifier), alias.name) ( exprId = alias.exprId, qualifier = alias.qualifier, - explicitMetadata = alias.explicitMetadata, - isGenerated = alias.isGenerated).asInstanceOf[T] + explicitMetadata = alias.explicitMetadata).asInstanceOf[T] case attr: AttributeReference ⇒ attr.copy(name = found.name)( exprId = found.exprId, - qualifier = found.qualifier, - isGenerated = found.isGenerated).asInstanceOf[T] + qualifier = found.qualifier).asInstanceOf[T] case _ ⇒ ne.asInstanceOf[T] } diff --git a/modules/spark/src/main/scala/org/apache/spark/sql/ignite/IgniteSparkSession.scala b/modules/spark/src/main/scala/org/apache/spark/sql/ignite/IgniteSparkSession.scala index 1fccc3ab43026..1cc63ed71c565 100644 --- a/modules/spark/src/main/scala/org/apache/spark/sql/ignite/IgniteSparkSession.scala +++ b/modules/spark/src/main/scala/org/apache/spark/sql/ignite/IgniteSparkSession.scala @@ -167,7 +167,7 @@ class IgniteSparkSession private(ic: IgniteContext, proxy: SparkSession) extends /** @inheritdoc */ override private[sql] def applySchemaToPythonRDD(rdd: RDD[Array[Any]], schema: StructType) = { - val rowRdd = rdd.map(r => python.EvaluatePython.fromJava(r, schema).asInstanceOf[InternalRow]) + val rowRdd = rdd.map(r => python.EvaluatePython.makeFromJava(schema).asInstanceOf[InternalRow]) Dataset.ofRows(self, LogicalRDD(schema.toAttributes, rowRdd)(self)) } @@ -178,14 +178,6 @@ class IgniteSparkSession private(ic: IgniteContext, proxy: SparkSession) extends @transient override private[sql] val extensions = proxy.extensions - /** @inheritdoc */ - override private[sql] def internalCreateDataFrame( - catalystRows: RDD[InternalRow], - schema: StructType) = { - val logicalPlan = LogicalRDD(schema.toAttributes, catalystRows)(self) - Dataset.ofRows(self, logicalPlan) - } - /** @inheritdoc */ override private[sql] def createDataFrame(rowRDD: RDD[Row], schema: StructType, diff --git a/modules/spark/src/test/scala/org/apache/ignite/spark/AbstractDataFrameSpec.scala b/modules/spark/src/test/scala/org/apache/ignite/spark/AbstractDataFrameSpec.scala index 29a4e6f28acfb..b46ede159c26b 100644 --- a/modules/spark/src/test/scala/org/apache/ignite/spark/AbstractDataFrameSpec.scala +++ b/modules/spark/src/test/scala/org/apache/ignite/spark/AbstractDataFrameSpec.scala @@ -206,7 +206,7 @@ object AbstractDataFrameSpec { val plan = df.queryExecution.optimizedPlan val cnt = plan.collectLeaves.count { - case LogicalRelation(relation: IgniteSQLAccumulatorRelation[_, _], _, _) ⇒ + case LogicalRelation(relation: IgniteSQLAccumulatorRelation[_, _], _, _, _) ⇒ if (qry != "") assert(qry.toLowerCase == relation.acc.compileQuery().toLowerCase, s"Generated query should be equal to expected.\nexpected - $qry\ngenerated - ${relation.acc.compileQuery()}") diff --git a/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteDataFrameSuite.scala b/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteDataFrameSuite.scala index b3f702647ce3a..90a17d6b89e1d 100644 --- a/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteDataFrameSuite.scala +++ b/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteDataFrameSuite.scala @@ -20,7 +20,7 @@ package org.apache.ignite.spark import org.scalatest.Suites /** - * Test suite for Spark DataFram API implementation. + * Test suite for Spark DataFrame API implementation. */ class IgniteDataFrameSuite extends Suites ( new IgniteDataFrameSchemaSpec, diff --git a/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteOptimizationAggregationFuncSpec.scala b/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteOptimizationAggregationFuncSpec.scala index d2527c801758d..be0e1babd3239 100644 --- a/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteOptimizationAggregationFuncSpec.scala +++ b/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteOptimizationAggregationFuncSpec.scala @@ -51,7 +51,7 @@ class IgniteOptimizationAggregationFuncSpec extends AbstractDataFrameSpec { it("AVG - DOUBLE") { val df = igniteSession.sql("SELECT AVG(val) FROM numbers WHERE id <= 3") - checkOptimizationResult(df, "SELECT AVG(val) FROM numbers WHERE id IS NOT NULL and id <= 3") + checkOptimizationResult(df, "SELECT AVG(val) FROM numbers WHERE id <= 3") val data = Tuple1(.5) @@ -81,7 +81,7 @@ class IgniteOptimizationAggregationFuncSpec extends AbstractDataFrameSpec { it("SUM - DOUBLE") { val df = igniteSession.sql("SELECT SUM(val) FROM numbers WHERE id <= 3") - checkOptimizationResult(df, "SELECT SUM(val) FROM numbers WHERE id IS NOT NULL and id <= 3") + checkOptimizationResult(df, "SELECT SUM(val) FROM numbers WHERE id <= 3") val data = Tuple1(1.5) diff --git a/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteOptimizationJoinSpec.scala b/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteOptimizationJoinSpec.scala index b4b36a8627a6e..d4e94c9868a7c 100644 --- a/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteOptimizationJoinSpec.scala +++ b/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteOptimizationJoinSpec.scala @@ -279,7 +279,7 @@ class IgniteOptimizationJoinSpec extends AbstractDataFrameSpec { checkOptimizationResult(df, "SELECT jt1.id as id1, jt1.val1, jt2.id as id2, jt2.val2 " + "FROM jt1 JOIN jt2 ON jt1.val1 = jt2.val2 " + - "WHERE jt1.id IS NOT NULL AND jt1.id < 10 AND jt1.val1 IS NOT NULL and jt2.val2 IS NOT NULL") + "WHERE jt1.id < 10 AND jt1.val1 IS NOT NULL and jt2.val2 IS NOT NULL") val data = ( (2, "B", 1, "B"), @@ -427,9 +427,7 @@ class IgniteOptimizationJoinSpec extends AbstractDataFrameSpec { "SELECT jt1.id + jt2.id as sum_id, jt1.val1, jt2.val2 FROM " + "jt1 JOIN jt2 ON NOT jt1.id + jt2.id = 15 AND jt1.val1 = jt2.val2 " + "WHERE " + - "jt1.id IS NOT NULL AND " + "jt1.val1 IS NOT NULL AND " + - "jt2.id IS NOT NULL AND " + "jt2.val2 IS NOT NULL" ) @@ -458,7 +456,7 @@ class IgniteOptimizationJoinSpec extends AbstractDataFrameSpec { checkOptimizationResult(df, "SELECT CAST(SUM(JT1.ID + JT2.ID) AS BIGINT) AS \"sum(sum_id)\" " + "FROM JT1 JOIN JT2 ON NOT JT1.id + JT2.id = 15 AND JT1.val1 = JT2.val2 " + - "WHERE JT1.id IS NOT NULL AND JT1.val1 IS NOT NULL AND JT2.id IS NOT NULL AND JT2.val2 IS NOT NULL") + "WHERE JT1.val1 IS NOT NULL AND JT2.val2 IS NOT NULL") val data = Tuple1(8) diff --git a/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteOptimizationMathFuncSpec.scala b/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteOptimizationMathFuncSpec.scala index 02793c94f9570..2cb41ae34b73c 100644 --- a/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteOptimizationMathFuncSpec.scala +++ b/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteOptimizationMathFuncSpec.scala @@ -36,7 +36,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { it("ABS") { val df = igniteSession.sql("SELECT ABS(val) FROM numbers WHERE id = 6") - checkOptimizationResult(df, "SELECT ABS(val) FROM numbers WHERE id is not null AND id = 6") + checkOptimizationResult(df, "SELECT ABS(val) FROM numbers WHERE id = 6") val data = Tuple1(.5) @@ -46,7 +46,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { it("ACOS") { val df = igniteSession.sql("SELECT ACOS(val) FROM numbers WHERE id = 7") - checkOptimizationResult(df, "SELECT ACOS(val) FROM numbers WHERE id is not null AND id = 7") + checkOptimizationResult(df, "SELECT ACOS(val) FROM numbers WHERE id = 7") val data = Tuple1(Math.PI) @@ -56,7 +56,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { it("ASIN") { val df = igniteSession.sql("SELECT ASIN(val) FROM numbers WHERE id = 7") - checkOptimizationResult(df, "SELECT ASIN(val) FROM numbers WHERE id is not null AND id = 7") + checkOptimizationResult(df, "SELECT ASIN(val) FROM numbers WHERE id = 7") val data = Tuple1(-Math.PI/2) @@ -66,7 +66,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { it("ATAN") { val df = igniteSession.sql("SELECT ATAN(val) FROM numbers WHERE id = 7") - checkOptimizationResult(df, "SELECT ATAN(val) FROM numbers WHERE id is not null AND id = 7") + checkOptimizationResult(df, "SELECT ATAN(val) FROM numbers WHERE id = 7") val data = Tuple1(-Math.PI/4) @@ -76,7 +76,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { it("COS") { val df = igniteSession.sql("SELECT COS(val) FROM numbers WHERE id = 1") - checkOptimizationResult(df, "SELECT COS(val) FROM numbers WHERE id is not null AND id = 1") + checkOptimizationResult(df, "SELECT COS(val) FROM numbers WHERE id = 1") val data = Tuple1(1.0) @@ -86,7 +86,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { it("SIN") { val df = igniteSession.sql("SELECT SIN(val) FROM numbers WHERE id = 1") - checkOptimizationResult(df, "SELECT SIN(val) FROM numbers WHERE id is not null AND id = 1") + checkOptimizationResult(df, "SELECT SIN(val) FROM numbers WHERE id = 1") val data = Tuple1(.0) @@ -96,7 +96,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { it("TAN") { val df = igniteSession.sql("SELECT TAN(val) FROM numbers WHERE id = 1") - checkOptimizationResult(df, "SELECT TAN(val) FROM numbers WHERE id is not null AND id = 1") + checkOptimizationResult(df, "SELECT TAN(val) FROM numbers WHERE id = 1") val data = Tuple1(.0) @@ -106,7 +106,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { it("COSH") { val df = igniteSession.sql("SELECT COSH(val) FROM numbers WHERE id = 1") - checkOptimizationResult(df, "SELECT COSH(val) FROM numbers WHERE id is not null AND id = 1") + checkOptimizationResult(df, "SELECT COSH(val) FROM numbers WHERE id = 1") val data = Tuple1(1.0) @@ -116,7 +116,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { it("SINH") { val df = igniteSession.sql("SELECT SINH(val) FROM numbers WHERE id = 1") - checkOptimizationResult(df, "SELECT SINH(val) FROM numbers WHERE id is not null AND id = 1") + checkOptimizationResult(df, "SELECT SINH(val) FROM numbers WHERE id = 1") val data = Tuple1(.0) @@ -126,7 +126,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { it("TANH") { val df = igniteSession.sql("SELECT TANH(val) FROM numbers WHERE id = 1") - checkOptimizationResult(df, "SELECT TANH(val) FROM numbers WHERE id is not null AND id = 1") + checkOptimizationResult(df, "SELECT TANH(val) FROM numbers WHERE id = 1") val data = Tuple1(.0) @@ -137,7 +137,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { val df = igniteSession.sql("SELECT ATAN2(val, 0.0) FROM numbers WHERE id = 1") checkOptimizationResult(df, "SELECT ATAN2(val, 0.0) AS \"ATAN2(val, CAST(0.0 AS DOUBLE))\" " + - "FROM numbers WHERE id is not null AND id = 1") + "FROM numbers WHERE id = 1") val data = Tuple1(.0) @@ -148,7 +148,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { val df = igniteSession.sql("SELECT val % 9 FROM numbers WHERE id = 8") checkOptimizationResult(df, "SELECT val % 9.0 as \"(val % CAST(9 AS DOUBLE))\" " + - "FROM numbers WHERE id is not null AND id = 8") + "FROM numbers WHERE id = 8") val data = Tuple1(6.0) @@ -159,7 +159,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { val df = igniteSession.sql("SELECT CEIL(val) FROM numbers WHERE id = 2") checkOptimizationResult(df, "SELECT CAST(CEIL(val) AS LONG) as \"CEIL(val)\" " + - "FROM numbers WHERE id is not null AND id = 2") + "FROM numbers WHERE id = 2") val data = Tuple1(1) @@ -183,7 +183,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { val df = igniteSession.sql("SELECT FLOOR(val) FROM numbers WHERE id = 2") checkOptimizationResult(df, "SELECT CAST(FLOOR(val) AS LONG) as \"FLOOR(val)\" FROM numbers " + - "WHERE id is not null AND id = 2") + "WHERE id = 2") val data = Tuple1(0) @@ -194,7 +194,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { val df = igniteSession.sql("SELECT POWER(val, 3) FROM numbers WHERE id = 4") checkOptimizationResult(df, "SELECT POWER(val, 3.0) as \"POWER(val, CAST(3 AS DOUBLE))\" FROM numbers " + - "WHERE id is not null AND id = 4") + "WHERE id = 4") val data = Tuple1(8.0) @@ -217,7 +217,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { val df = igniteSession.sql("SELECT LOG(val) FROM numbers WHERE id = 12") checkOptimizationResult(df, "SELECT LOG(val) as \"LOG(E(), val)\" FROM numbers " + - "WHERE id IS NOT NULL AND id = 12") + "WHERE id = 12") val data = Tuple1(2.0) @@ -227,7 +227,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { it("LOG10") { val df = igniteSession.sql("SELECT LOG10(val) FROM numbers WHERE id = 11") - checkOptimizationResult(df, "SELECT LOG10(val) FROM numbers WHERE id IS NOT NULL AND id = 11") + checkOptimizationResult(df, "SELECT LOG10(val) FROM numbers WHERE id = 11") val data = Tuple1(2.0) @@ -237,7 +237,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { it("DEGREES") { val df = igniteSession.sql("SELECT DEGREES(val) FROM numbers WHERE id = 13") - checkOptimizationResult(df, "SELECT DEGREES(val) FROM numbers WHERE id IS NOT NULL AND id = 13") + checkOptimizationResult(df, "SELECT DEGREES(val) FROM numbers WHERE id = 13") val data = Tuple1(180.0) @@ -247,7 +247,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { it("RADIANS") { val df = igniteSession.sql("SELECT RADIANS(val) FROM numbers WHERE id = 14") - checkOptimizationResult(df, "SELECT RADIANS(val) FROM numbers WHERE id IS NOT NULL AND id = 14") + checkOptimizationResult(df, "SELECT RADIANS(val) FROM numbers WHERE id = 14") val data = Tuple1(Math.PI) @@ -258,7 +258,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { val df = igniteSession.sql("SELECT int_val&1 FROM numbers WHERE id = 15") checkOptimizationResult(df, "SELECT BITAND(int_val, 1) as \"(int_val & CAST(1 AS BIGINT))\" FROM numbers " + - "WHERE id IS NOT NULL AND id = 15") + "WHERE id = 15") val data = Tuple1(1) @@ -269,7 +269,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { val df = igniteSession.sql("SELECT int_val|1 FROM numbers WHERE id = 16") checkOptimizationResult(df, "SELECT BITOR(int_val, 1) as \"(int_val | CAST(1 AS BIGINt))\" FROM numbers " + - "WHERE id IS NOT NULL AND id = 16") + "WHERE id = 16") val data = Tuple1(3) @@ -280,7 +280,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { val df = igniteSession.sql("SELECT int_val^1 FROM numbers WHERE id = 17") checkOptimizationResult(df, "SELECT BITXOR(int_val, 1) AS \"(int_val ^ CAST(1 AS BIGINT))\" FROM numbers " + - "WHERE id IS NOT NULL AND id = 17") + "WHERE id = 17") val data = Tuple1(2) @@ -290,7 +290,7 @@ class IgniteOptimizationMathFuncSpec extends AbstractDataFrameSpec { it("RAND") { val df = igniteSession.sql("SELECT id, RAND(1) FROM numbers WHERE id = 17") - checkOptimizationResult(df, "SELECT id, RAND(1) FROM numbers WHERE id IS NOT NULL AND id = 17") + checkOptimizationResult(df, "SELECT id, RAND(1) FROM numbers WHERE id = 17") val data = df.rdd.collect diff --git a/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteOptimizationSpec.scala b/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteOptimizationSpec.scala index 128f625e5eb5b..ff367af854e47 100644 --- a/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteOptimizationSpec.scala +++ b/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteOptimizationSpec.scala @@ -60,7 +60,7 @@ class IgniteOptimizationSpec extends AbstractDataFrameSpec { it("SELECT id, name FROM person WHERE id > 3 ORDER BY id") { val df = igniteSession.sql("SELECT id, name FROM person WHERE id > 3 ORDER BY id") - checkOptimizationResult(df, "SELECT id, name FROM person WHERE id IS NOT NULL AND id > 3 ORDER BY id") + checkOptimizationResult(df, "SELECT id, name FROM person WHERE id > 3 ORDER BY id") val data = ( (4, "Richard Miles"), @@ -72,7 +72,7 @@ class IgniteOptimizationSpec extends AbstractDataFrameSpec { it("SELECT id, name FROM person WHERE id > 3 ORDER BY id DESC") { val df = igniteSession.sql("SELECT id, name FROM person WHERE id > 3 ORDER BY id DESC") - checkOptimizationResult(df, "SELECT id, name FROM person WHERE id IS NOT NULL AND id > 3 ORDER BY id DESC") + checkOptimizationResult(df, "SELECT id, name FROM person WHERE id > 3 ORDER BY id DESC") val data = ( (5, null), @@ -111,7 +111,7 @@ class IgniteOptimizationSpec extends AbstractDataFrameSpec { it("SELECT id FROM city HAVING id > 1") { val df = igniteSession.sql("SELECT id FROM city HAVING id > 1") - checkOptimizationResult(df, "SELECT id FROM city WHERE id IS NOT NULL AND id > 1") + checkOptimizationResult(df, "SELECT id FROM city WHERE id > 1") val data = (2, 3, 4) @@ -145,7 +145,7 @@ class IgniteOptimizationSpec extends AbstractDataFrameSpec { it("SELECT id, name FROM city WHERE id > 1 ORDER BY id") { val df = igniteSession.sql("SELECT id, name FROM city WHERE id > 1 ORDER BY id") - checkOptimizationResult(df, "SELECT id, name FROM city WHERE id IS NOT NULL and id > 1 ORDER BY id") + checkOptimizationResult(df, "SELECT id, name FROM city WHERE id > 1 ORDER BY id") val data = ( (2, "Denver"), diff --git a/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteOptimizationStringFuncSpec.scala b/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteOptimizationStringFuncSpec.scala index db106f2473b2b..de94de3d46f7f 100644 --- a/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteOptimizationStringFuncSpec.scala +++ b/modules/spark/src/test/scala/org/apache/ignite/spark/IgniteOptimizationStringFuncSpec.scala @@ -60,7 +60,7 @@ class IgniteOptimizationStringFuncSpec extends AbstractDataFrameSpec { val df = igniteSession.sql("SELECT LENGTH(str) FROM strings WHERE id <= 3") checkOptimizationResult(df, "SELECT CAST(LENGTH(str) AS INTEGER) as \"length(str)\" FROM strings " + - "WHERE id is not null AND id <= 3") + "WHERE id <= 3") val data = (3, 3, 6) @@ -70,37 +70,97 @@ class IgniteOptimizationStringFuncSpec extends AbstractDataFrameSpec { it("RTRIM") { val df = igniteSession.sql("SELECT RTRIM(str) FROM strings WHERE id = 3") - checkOptimizationResult(df, "SELECT RTRIM(str) FROM strings WHERE id is not null AND id = 3") + checkOptimizationResult(df, "SELECT RTRIM(str) FROM strings WHERE id = 3") val data = Tuple1("AAA") checkQueryData(df, data) } + it("RTRIMWithTrimStr") { + val df = igniteSession.sql("SELECT RTRIM('B', str) FROM strings WHERE id = 9") + + checkOptimizationResult(df, "SELECT RTRIM(str, 'B') FROM strings WHERE id = 9") + + val data = Tuple1("BAAA") + + checkQueryData(df, data) + } + it("LTRIM") { val df = igniteSession.sql("SELECT LTRIM(str) FROM strings WHERE id = 4") - checkOptimizationResult(df, "SELECT LTRIM(str) FROM strings WHERE id is not null AND id = 4") + checkOptimizationResult(df, "SELECT LTRIM(str) FROM strings WHERE id = 4") val data = Tuple1("AAA") checkQueryData(df, data) } + it("LTRIMWithTrimStr") { + val df = igniteSession.sql("SELECT LTRIM('B', str) FROM strings WHERE id = 9") + + checkOptimizationResult(df, "SELECT LTRIM(str, 'B') FROM strings WHERE id = 9") + + val data = Tuple1("AAAB") + + checkQueryData(df, data) + } + it("TRIM") { val df = igniteSession.sql("SELECT TRIM(str) FROM strings WHERE id = 5") - checkOptimizationResult(df, "SELECT TRIM(str) FROM strings WHERE id is not null AND id = 5") + checkOptimizationResult(df, "SELECT TRIM(str) FROM strings WHERE id = 5") val data = Tuple1("AAA") checkQueryData(df, data) } + it("TRIMWithTrimStr") { + val df = igniteSession.sql("SELECT TRIM('B', str) FROM strings WHERE id = 9") + + checkOptimizationResult(df, "SELECT TRIM(str, 'B') FROM strings WHERE id = 9") + + val data = Tuple1("AAA") + + checkQueryData(df, data) + } + + it("TRIMWithTrimStrBOTH") { + val df = igniteSession.sql("SELECT TRIM(BOTH 'B' FROM str) FROM strings WHERE id = 9") + + checkOptimizationResult(df, "SELECT TRIM(str, 'B') FROM strings WHERE id = 9") + + val data = Tuple1("AAA") + + checkQueryData(df, data) + } + + it("TRIMWithTrimStrLEADING") { + val df = igniteSession.sql("SELECT TRIM(LEADING 'B' FROM str) FROM strings WHERE id = 9") + + checkOptimizationResult(df, "SELECT LTRIM(str, 'B') FROM strings WHERE id = 9") + + val data = Tuple1("AAAB") + + checkQueryData(df, data) + } + + it("TRIMWithTrimStrTRAILING") { + val df = igniteSession.sql("SELECT TRIM(TRAILING 'B' FROM str) FROM strings WHERE id = 9") + + checkOptimizationResult(df, "SELECT RTRIM(str, 'B') FROM strings WHERE id = 9") + + val data = Tuple1("BAAA") + + checkQueryData(df, data) + } + it("LOWER") { val df = igniteSession.sql("SELECT LOWER(str) FROM strings WHERE id = 2") - checkOptimizationResult(df, "SELECT LOWER(str) FROM strings WHERE id is not null AND id = 2") + checkOptimizationResult(df, "SELECT LOWER(str) FROM strings WHERE id = 2") val data = Tuple1("aaa") @@ -110,7 +170,7 @@ class IgniteOptimizationStringFuncSpec extends AbstractDataFrameSpec { it("UPPER") { val df = igniteSession.sql("SELECT UPPER(str) FROM strings WHERE id = 1") - checkOptimizationResult(df, "SELECT UPPER(str) FROM strings WHERE id is not null AND id = 1") + checkOptimizationResult(df, "SELECT UPPER(str) FROM strings WHERE id = 1") val data = Tuple1("AAA") @@ -120,7 +180,7 @@ class IgniteOptimizationStringFuncSpec extends AbstractDataFrameSpec { it("LOWER(RTRIM)") { val df = igniteSession.sql("SELECT LOWER(RTRIM(str)) FROM strings WHERE id = 3") - checkOptimizationResult(df, "SELECT LOWER(RTRIM(str)) FROM strings WHERE id is not null AND id = 3") + checkOptimizationResult(df, "SELECT LOWER(RTRIM(str)) FROM strings WHERE id = 3") val data = Tuple1("aaa") @@ -130,7 +190,7 @@ class IgniteOptimizationStringFuncSpec extends AbstractDataFrameSpec { it("LOCATE") { val df = igniteSession.sql("SELECT LOCATE('D', str) FROM strings WHERE id = 6") - checkOptimizationResult(df, "SELECT LOCATE('D', str, 1) FROM strings WHERE id is not null AND id = 6") + checkOptimizationResult(df, "SELECT LOCATE('D', str, 1) FROM strings WHERE id = 6") val data = Tuple1(4) @@ -140,7 +200,7 @@ class IgniteOptimizationStringFuncSpec extends AbstractDataFrameSpec { it("LOCATE - 2") { val df = igniteSession.sql("SELECT LOCATE('A', str) FROM strings WHERE id = 6") - checkOptimizationResult(df, "SELECT LOCATE('A', str, 1) FROM strings WHERE id is not null AND id = 6") + checkOptimizationResult(df, "SELECT LOCATE('A', str, 1) FROM strings WHERE id = 6") val data = Tuple1(1) @@ -151,7 +211,7 @@ class IgniteOptimizationStringFuncSpec extends AbstractDataFrameSpec { val df = igniteSession.sql("SELECT instr(str, 'BCD') FROM strings WHERE id = 6") checkOptimizationResult(df, "SELECT POSITION('BCD', str) as \"instr(str, BCD)\" FROM strings " + - "WHERE id is not null AND id = 6") + "WHERE id = 6") val data = Tuple1(2) @@ -161,7 +221,7 @@ class IgniteOptimizationStringFuncSpec extends AbstractDataFrameSpec { it("CONCAT") { val df = igniteSession.sql("SELECT concat(str, 'XXX') FROM strings WHERE id = 6") - checkOptimizationResult(df, "SELECT concat(str, 'XXX') FROM strings WHERE id is not null AND id = 6") + checkOptimizationResult(df, "SELECT concat(str, 'XXX') FROM strings WHERE id = 6") val data = Tuple1("ABCDEFXXX") @@ -171,7 +231,7 @@ class IgniteOptimizationStringFuncSpec extends AbstractDataFrameSpec { it("RPAD") { val df = igniteSession.sql("SELECT RPAD(str, 10, 'X') FROM strings WHERE id = 6") - checkOptimizationResult(df, "SELECT RPAD(str, 10, 'X') FROM strings WHERE id is not null AND id = 6") + checkOptimizationResult(df, "SELECT RPAD(str, 10, 'X') FROM strings WHERE id = 6") val data = Tuple1("ABCDEFXXXX") @@ -181,7 +241,7 @@ class IgniteOptimizationStringFuncSpec extends AbstractDataFrameSpec { it("LPAD") { val df = igniteSession.sql("SELECT LPAD(str, 10, 'X') FROM strings WHERE id = 6") - checkOptimizationResult(df, "SELECT LPAD(str, 10, 'X') FROM strings WHERE id is not null AND id = 6") + checkOptimizationResult(df, "SELECT LPAD(str, 10, 'X') FROM strings WHERE id = 6") val data = Tuple1("XXXXABCDEF") @@ -191,7 +251,7 @@ class IgniteOptimizationStringFuncSpec extends AbstractDataFrameSpec { it("REPEAT") { val df = igniteSession.sql("SELECT REPEAT(str, 2) FROM strings WHERE id = 6") - checkOptimizationResult(df, "SELECT REPEAT(str, 2) FROM strings WHERE id is not null AND id = 6") + checkOptimizationResult(df, "SELECT REPEAT(str, 2) FROM strings WHERE id = 6") val data = Tuple1("ABCDEFABCDEF") @@ -202,7 +262,7 @@ class IgniteOptimizationStringFuncSpec extends AbstractDataFrameSpec { val df = igniteSession.sql("SELECT SUBSTRING(str, 4, 3) FROM strings WHERE id = 6") checkOptimizationResult(df, "SELECT SUBSTR(str, 4, 3) as \"SUBSTRING(str, 4, 3)\" FROM strings " + - "WHERE id is not null AND id = 6") + "WHERE id = 6") val data = Tuple1("DEF") @@ -213,7 +273,7 @@ class IgniteOptimizationStringFuncSpec extends AbstractDataFrameSpec { val df = igniteSession.sql("SELECT SPACE(LENGTH(str)) FROM strings WHERE id = 1") checkOptimizationResult(df, "SELECT SPACE(CAST(LENGTH(str) AS INTEGER)) as \"SPACE(LENGTH(str))\" " + - "FROM strings WHERE id is not null AND id = 1") + "FROM strings WHERE id = 1") val data = Tuple1(" ") @@ -223,7 +283,7 @@ class IgniteOptimizationStringFuncSpec extends AbstractDataFrameSpec { it("ASCII") { val df = igniteSession.sql("SELECT ASCII(str) FROM strings WHERE id = 7") - checkOptimizationResult(df, "SELECT ASCII(str) FROM strings WHERE id is not null AND id = 7") + checkOptimizationResult(df, "SELECT ASCII(str) FROM strings WHERE id = 7") val data = Tuple1(50) @@ -234,7 +294,7 @@ class IgniteOptimizationStringFuncSpec extends AbstractDataFrameSpec { val df = igniteSession.sql("SELECT REGEXP_REPLACE(str, '(\\\\d+)', 'num') FROM strings WHERE id = 7") checkOptimizationResult(df, "SELECT REGEXP_REPLACE(str, '(\\d+)', 'num') FROM strings " + - "WHERE id is not null AND id = 7") + "WHERE id = 7") val data = Tuple1("num") @@ -246,7 +306,7 @@ class IgniteOptimizationStringFuncSpec extends AbstractDataFrameSpec { "WHERE id >= 7 AND id <= 8") checkOptimizationResult(df, "SELECT id, CONCAT_WS(', ', str, 'after') FROM strings " + - "WHERE id is not null AND id >= 7 AND id <= 8") + "WHERE id >= 7 AND id <= 8") val data = ( (7, "222, after"), @@ -259,7 +319,7 @@ class IgniteOptimizationStringFuncSpec extends AbstractDataFrameSpec { val df = igniteSession.sql("SELECT id, TRANSLATE(str, 'DEF', 'ABC') FROM strings WHERE id = 6") checkOptimizationResult(df, "SELECT id, TRANSLATE(str, 'DEF', 'ABC') FROM strings " + - "WHERE id is not null AND id = 6") + "WHERE id = 6") val data = Tuple1((6, "ABCABC")) @@ -288,6 +348,7 @@ class IgniteOptimizationStringFuncSpec extends AbstractDataFrameSpec { cache.query(qry.setArgs(6L.asInstanceOf[JLong], "ABCDEF")).getAll cache.query(qry.setArgs(7L.asInstanceOf[JLong], "222")).getAll cache.query(qry.setArgs(8L.asInstanceOf[JLong], null)).getAll + cache.query(qry.setArgs(9L.asInstanceOf[JLong], "BAAAB")).getAll } override protected def beforeAll(): Unit = { diff --git a/modules/zookeeper/pom.xml b/modules/zookeeper/pom.xml index 532b95c1a9418..42f0c5fb290e4 100644 --- a/modules/zookeeper/pom.xml +++ b/modules/zookeeper/pom.xml @@ -68,7 +68,7 @@ com.google.guava guava - ${guava16.version} + ${guava.version} @@ -111,7 +111,7 @@ org.apache.curator curator-test - ${curator.version} + ${curator.test.version} test diff --git a/parent/pom.xml b/parent/pom.xml index e64a7c69fa8dd..7a4a412674c44 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -60,15 +60,15 @@ 3.2.2 2.6 2.2.5 - 2.9.1 + 4.2.0 + + 2.9.1 3.4 1.0.6_1 1.0.6 1.7.0 2.0.0 - 18.0 - 14.0.1 - 16.0.1 + 25.1-jre 1.4.195 2.4.1 1.2 @@ -84,8 +84,8 @@ 9.4.18.v20190429 1.13 1.1.1 - 0.1.53_1 - 0.1.53 + 0.1.54_1 + 0.1.54 2.4_1 2.4 r938 @@ -111,18 +111,18 @@ 1.7.7 1.6.4 2.6.5 - 2.2.0 + 2.3.3 1.13.14.RELEASE 4.3.18.RELEASE 4.1.7.RELEASE_1 - 1.1.1 - 8.0.23 + 1.1.3 + 9.0.21 2.2.0 2.2.0 2.2.0 0.8.3 0.5 - 3.4.13 + 3.4.14 * From 4c22ea91ee75920280f2af35809b088f049d9e11 Mon Sep 17 00:00:00 2001 From: mstepachev Date: Wed, 17 Jul 2019 11:59:28 +0300 Subject: [PATCH 44/62] GG-20594 GG-20593 GG-20592 GG-19428 [IGNITE-9560] Security Engine fixes and test coverage. Phase #1. --- .../JdbcDynamicIndexAbstractSelfTest.java | 25 +- .../jdbc/thin/JdbcThinAbstractSelfTest.java | 51 +-- .../jdbc/thin/JdbcThinConnectionSelfTest.java | 77 ++-- .../JdbcThinPreparedStatementSelfTest.java | 98 ++--- .../jdbc/thin/JdbcThinResultSetSelfTest.java | 293 +++++++-------- .../jdbc/thin/JdbcThinStatementSelfTest.java | 304 ++++++++------- .../internal/ComputeTaskInternalFuture.java | 2 +- .../ignite/internal/GridKernalContext.java | 8 +- .../internal/GridKernalContextImpl.java | 12 +- .../internal/GridMessageListenHandler.java | 2 +- .../ignite/internal/IgniteFeatures.java | 8 + .../apache/ignite/internal/IgniteKernal.java | 20 +- .../jdbc/JdbcConnectionValidationTask.java | 13 +- .../managers/communication/GridIoManager.java | 144 ++++++-- .../communication/GridIoMessageFactory.java | 5 + .../GridIoSecurityAwareMessage.java | 163 ++++++++ .../eventstorage/GridEventStorageManager.java | 4 +- .../processors/cache/GridCacheContext.java | 2 +- .../processors/cache/GridCacheProcessor.java | 54 +-- .../reader/StandaloneGridKernalContext.java | 4 +- .../cluster/GridClusterStateProcessor.java | 2 + .../datastreamer/DataStreamerImpl.java | 2 +- .../datastreamer/DataStreamerUpdateJob.java | 2 +- .../odbc/ClientListenerNioListener.java | 8 +- .../processors/rest/GridRestProcessor.java | 19 +- .../top/GridTopologyCommandHandler.java | 2 - .../security/GridSecurityProcessor.java | 5 +- .../processors/security/IgniteSecurity.java | 128 +++++++ .../security/IgniteSecurityProcessor.java | 278 ++++++++++++++ .../security/NoOpIgniteSecurityProcessor.java | 211 +++++++++++ .../security/OperationSecurityContext.java | 46 +++ .../processors/security/SecurityUtils.java | 29 ++ .../security/os/GridOsSecurityProcessor.java | 88 ----- .../service/GridServiceProcessor.java | 10 +- .../processors/task/GridTaskProcessor.java | 2 +- .../internal/visor/query/VisorQueryUtils.java | 14 +- .../SecurityPermissionSetBuilder.java | 7 +- .../ignite/spi/discovery/tcp/ServerImpl.java | 95 ++--- .../org.apache.ignite.plugin.PluginProvider | 2 +- .../IgniteOptimisticTxSuspendResumeTest.java | 23 +- ...ractCacheOperationPermissionCheckTest.java | 77 ++++ ...erationRemoteSecurityContextCheckTest.java | 72 ++++ ...bstractRemoteSecurityContextCheckTest.java | 349 ++++++++++++++++++ .../security/AbstractSecurityTest.java | 97 +++++ .../CacheOperationPermissionCheckTest.java | 89 +++++ .../EntryProcessorPermissionCheckTest.java | 114 ++++++ .../cache/ScanQueryPermissionCheckTest.java | 73 ++++ ...cheLoadRemoteSecurityContextCheckTest.java | 147 ++++++++ ...ocessorRemoteSecurityContextCheckTest.java | 101 +++++ ...anQueryRemoteSecurityContextCheckTest.java | 107 ++++++ .../client/ThinClientPermissionCheckTest.java | 224 +++++++++++ .../compute/ComputePermissionCheckTest.java | 296 +++++++++++++++ ...uteTaskRemoteSecurityContextCheckTest.java | 170 +++++++++ ...ClosureRemoteSecurityContextCheckTest.java | 118 ++++++ ...ServiceRemoteSecurityContextCheckTest.java | 88 +++++ .../DataStreamerPermissionCheckTest.java | 83 +++++ ...treamerRemoteSecurityContextCheckTest.java | 92 +++++ .../security/impl/TestSecurityContext.java | 125 +++++++ .../security/impl/TestSecurityData.java | 116 ++++++ .../impl/TestSecurityPluginConfiguration.java | 34 ++ .../security/impl/TestSecurityProcessor.java | 149 ++++++++ .../impl/TestSecurityProcessorProvider.java | 135 +++++++ .../security/impl/TestSecuritySubject.java | 146 ++++++++ .../discovery/AuthenticationRestartTest.java | 12 +- ...ryNodeAttributesUpdateOnReconnectTest.java | 12 +- .../discovery/tcp/TestReconnectProcessor.java | 64 +++- .../ignite/testframework/GridTestUtils.java | 123 ++++++ .../junits/common/GridCommonAbstractTest.java | 20 +- .../testsuites/IgniteBasicTestSuite.java | 2 + .../ignite/testsuites/SecurityTestSuite.java | 68 ++++ .../processors/query/h2/IgniteH2Indexing.java | 2 +- .../query/h2/ddl/DdlStatementsProcessor.java | 4 +- .../cache/index/AbstractSchemaSelfTest.java | 14 +- ...amicColumnsAbstractConcurrentSelfTest.java | 20 +- .../DynamicIndexAbstractBasicSelfTest.java | 61 +-- ...ynamicIndexAbstractConcurrentSelfTest.java | 9 +- .../index/H2DynamicIndexAbstractSelfTest.java | 13 +- .../zk/internal/ZookeeperDiscoveryImpl.java | 30 ++ 78 files changed, 4926 insertions(+), 792 deletions(-) create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoSecurityAwareMessage.java create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/processors/security/IgniteSecurity.java create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/processors/security/IgniteSecurityProcessor.java create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/processors/security/NoOpIgniteSecurityProcessor.java create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/processors/security/OperationSecurityContext.java delete mode 100644 modules/core/src/main/java/org/apache/ignite/internal/processors/security/os/GridOsSecurityProcessor.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/AbstractCacheOperationPermissionCheckTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/AbstractCacheOperationRemoteSecurityContextCheckTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/AbstractRemoteSecurityContextCheckTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/AbstractSecurityTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/CacheOperationPermissionCheckTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/EntryProcessorPermissionCheckTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/ScanQueryPermissionCheckTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/closure/CacheLoadRemoteSecurityContextCheckTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/closure/EntryProcessorRemoteSecurityContextCheckTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/closure/ScanQueryRemoteSecurityContextCheckTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/client/ThinClientPermissionCheckTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/compute/ComputePermissionCheckTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/compute/closure/ComputeTaskRemoteSecurityContextCheckTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/compute/closure/DistributedClosureRemoteSecurityContextCheckTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/compute/closure/ExecutorServiceRemoteSecurityContextCheckTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/datastreamer/DataStreamerPermissionCheckTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/datastreamer/closure/DataStreamerRemoteSecurityContextCheckTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecurityContext.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecurityData.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecurityPluginConfiguration.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecurityProcessor.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecurityProcessorProvider.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecuritySubject.java create mode 100644 modules/core/src/test/java/org/apache/ignite/testsuites/SecurityTestSuite.java diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcDynamicIndexAbstractSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcDynamicIndexAbstractSelfTest.java index 9485d0d54212c..652d635cbe4a1 100644 --- a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcDynamicIndexAbstractSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcDynamicIndexAbstractSelfTest.java @@ -31,6 +31,7 @@ import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.NearCacheConfiguration; import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.testframework.GridTestUtils; /** * Test that checks indexes handling with JDBC. @@ -168,9 +169,9 @@ public void testCreateIndex() throws SQLException { public void testCreateIndexWithDuplicateName() throws SQLException { jdbcRun(CREATE_INDEX); - assertSqlException(new RunnableX() { + assertSqlException(new GridTestUtils.RunnableX() { /** {@inheritDoc} */ - @Override public void run() throws Exception { + @Override public void runx() throws Exception { jdbcRun(CREATE_INDEX); } }); @@ -219,9 +220,9 @@ public void testDropIndex() throws SQLException { * Test that dropping a non-existent index yields an error. */ public void testDropMissingIndex() { - assertSqlException(new RunnableX() { + assertSqlException(new GridTestUtils.RunnableX() { /** {@inheritDoc} */ - @Override public void run() throws Exception { + @Override public void runx() throws Exception { jdbcRun(DROP_INDEX); } }); @@ -310,11 +311,11 @@ private IgniteCache cache() { * * @param r Runnable. */ - private static void assertSqlException(RunnableX r) { + private static void assertSqlException(GridTestUtils.RunnableX r) { // We expect IgniteSQLException with given code inside CacheException inside JDBC SQLException. try { - r.run(); + r.runx(); } catch (SQLException e) { return; @@ -325,16 +326,4 @@ private static void assertSqlException(RunnableX r) { fail(SQLException.class.getSimpleName() + " is not thrown."); } - - /** - * Runnable which can throw checked exceptions. - */ - private interface RunnableX { - /** - * Do run. - * - * @throws Exception If failed. - */ - public void run() throws Exception; - } } diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinAbstractSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinAbstractSelfTest.java index 2ba36c369c227..7ac96990a01eb 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinAbstractSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinAbstractSelfTest.java @@ -28,12 +28,12 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.concurrent.Callable; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.processors.odbc.ClientListenerProcessor; import org.apache.ignite.internal.processors.port.GridPortRecord; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.GridTestUtils.RunnableX; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; /** @@ -45,27 +45,18 @@ public class JdbcThinAbstractSelfTest extends GridCommonAbstractTest { * @param r Runnable to check support. */ protected void checkNotSupported(final RunnableX r) { - GridTestUtils.assertThrows(log, - new Callable() { - @Override public Object call() throws Exception { - r.run(); - - return null; - } - }, SQLFeatureNotSupportedException.class, null); + GridTestUtils.assertThrowsWithCause(r, SQLFeatureNotSupportedException.class); } /** * @param r Runnable to check on closed connection. */ protected void checkConnectionClosed(final RunnableX r) { - GridTestUtils.assertThrows(log, - new Callable() { - @Override public Object call() throws Exception { - r.run(); + GridTestUtils.assertThrowsAnyCause(log, + () -> { + r.run(); - return null; - } + return null; }, SQLException.class, "Connection is closed"); } @@ -73,13 +64,11 @@ protected void checkConnectionClosed(final RunnableX r) { * @param r Runnable to check on closed statement. */ protected void checkStatementClosed(final RunnableX r) { - GridTestUtils.assertThrows(log, - new Callable() { - @Override public Object call() throws Exception { - r.run(); + GridTestUtils.assertThrowsAnyCause(log, + () -> { + r.run(); - return null; - } + return null; }, SQLException.class, "Statement is closed"); } @@ -87,26 +76,14 @@ protected void checkStatementClosed(final RunnableX r) { * @param r Runnable to check on closed result set. */ protected void checkResultSetClosed(final RunnableX r) { - GridTestUtils.assertThrows(log, - new Callable() { - @Override public Object call() throws Exception { - r.run(); + GridTestUtils.assertThrowsAnyCause(log, + () -> { + r.run(); - return null; - } + return null; }, SQLException.class, "Result set is closed"); } - /** - * Runnable that can throw an exception. - */ - interface RunnableX { - /** - * @throws Exception On error. - */ - void run() throws Exception; - } - /** * @param node Node to connect to. * @param params Connection parameters. diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinConnectionSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinConnectionSelfTest.java index 6403cac5037f1..bd816e6ef5d2c 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinConnectionSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinConnectionSelfTest.java @@ -58,6 +58,7 @@ import static java.sql.ResultSet.TYPE_FORWARD_ONLY; import static java.sql.Statement.NO_GENERATED_KEYS; import static java.sql.Statement.RETURN_GENERATED_KEYS; +import static org.apache.ignite.testframework.GridTestUtils.RunnableX; /** * Connection test. @@ -570,7 +571,7 @@ public void testCreateStatement() throws Exception { // Exception when called on closed connection checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.createStatement(); } }); @@ -623,7 +624,7 @@ public void testCreateStatement2() throws Exception { // Exception when called on closed connection checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.createStatement(TYPE_FORWARD_ONLY, CONCUR_READ_ONLY); } @@ -682,7 +683,7 @@ public void testCreateStatement3() throws Exception { // Exception when called on closed connection checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.createStatement(TYPE_FORWARD_ONLY, CONCUR_READ_ONLY, HOLD_CURSORS_OVER_COMMIT); } @@ -716,7 +717,7 @@ public void testPrepareStatement() throws Exception { // Exception when called on closed connection checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.prepareStatement(sqlText); } }); @@ -774,7 +775,7 @@ public void testPrepareStatement3() throws Exception { // Exception when called on closed connection checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.prepareStatement(sqlText, TYPE_FORWARD_ONLY, CONCUR_READ_ONLY); } }); @@ -839,7 +840,7 @@ public void testPrepareStatement4() throws Exception { // Exception when called on closed connection checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.prepareStatement(sqlText, TYPE_FORWARD_ONLY, CONCUR_READ_ONLY, HOLD_CURSORS_OVER_COMMIT); } }); @@ -961,7 +962,7 @@ public void testNativeSql() throws Exception { // Exception when called on closed connection checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.nativeSQL(sqlText); } }); @@ -987,7 +988,7 @@ public void testGetSetAutoCommit() throws Exception { // Exception when called on closed connection checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.setAutoCommit(true); } }); @@ -1022,7 +1023,7 @@ public void testCommit() throws Exception { // Exception when called on closed connection checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.commit(); } }); @@ -1057,7 +1058,7 @@ public void testRollback() throws Exception { // Exception when called on closed connection checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.rollback(); } }); @@ -1077,7 +1078,7 @@ public void testGetMetaData() throws Exception { // Exception when called on closed connection checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.getMetaData(); } }); @@ -1093,14 +1094,14 @@ public void testGetSetReadOnly() throws Exception { // Exception when called on closed connection checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.setReadOnly(true); } }); // Exception when called on closed connection checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.isReadOnly(); } }); @@ -1124,14 +1125,14 @@ public void testGetSetCatalog() throws Exception { // Exception when called on closed connection checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.setCatalog(""); } }); // Exception when called on closed connection checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.getCatalog(); } }); @@ -1176,14 +1177,14 @@ public void testGetSetTransactionIsolation() throws Exception { // Exception when called on closed connection checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.getTransactionIsolation(); } }); // Exception when called on closed connection checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.setTransactionIsolation(TRANSACTION_SERIALIZABLE); } }); @@ -1209,14 +1210,14 @@ public void testClearGetWarnings() throws Exception { // Exception when called on closed connection checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.getWarnings(); } }); // Exception when called on closed connection checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.clearWarnings(); } }); @@ -1355,7 +1356,7 @@ public void testSetSavepoint() throws Exception { // Unsupported checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.setSavepoint(); } }); @@ -1363,7 +1364,7 @@ public void testSetSavepoint() throws Exception { conn.close(); checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.setSavepoint(); } }); @@ -1409,7 +1410,7 @@ public void testSetSavepointName() throws Exception { // Unsupported checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.setSavepoint(name); } }); @@ -1417,7 +1418,7 @@ public void testSetSavepointName() throws Exception { conn.close(); checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.setSavepoint(name); } }); @@ -1463,7 +1464,7 @@ public void testRollbackSavePoint() throws Exception { // Unsupported checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.rollback(savepoint); } }); @@ -1471,7 +1472,7 @@ public void testRollbackSavePoint() throws Exception { conn.close(); checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.rollback(savepoint); } }); @@ -1501,7 +1502,7 @@ public void testReleaseSavepoint() throws Exception { final Savepoint savepoint = getFakeSavepoint(); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.releaseSavepoint(savepoint); } }); @@ -1509,7 +1510,7 @@ public void testReleaseSavepoint() throws Exception { conn.close(); checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.releaseSavepoint(savepoint); } }); @@ -1655,7 +1656,7 @@ public void testGetSetClientInfoPair() throws Exception { conn.close(); checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.getClientInfo(name); } }); @@ -1693,7 +1694,7 @@ public void testGetSetClientInfoProperties() throws Exception { conn.close(); checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.getClientInfo(); } }); @@ -1734,7 +1735,7 @@ public void testCreateArrayOf() throws Exception { // Unsupported checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.createArrayOf(typeName, elements); } }); @@ -1742,7 +1743,7 @@ public void testCreateArrayOf() throws Exception { conn.close(); checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.createArrayOf(typeName, elements); } }); @@ -1770,7 +1771,7 @@ public void testCreateStruct() throws Exception { final Object[] attrs = new Object[] {100, "Tom"}; checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.createStruct(typeName, attrs); } }); @@ -1778,7 +1779,7 @@ public void testCreateStruct() throws Exception { conn.close(); checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.createStruct(typeName, attrs); } }); @@ -1805,13 +1806,13 @@ public void testGetSetSchema() throws Exception { conn.close(); checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.setSchema(schema); } }); checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.getSchema(); } }); @@ -1889,13 +1890,13 @@ public void testGetSetNetworkTimeout() throws Exception { conn.close(); checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.getNetworkTimeout(); } }); checkConnectionClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { conn.setNetworkTimeout(executor, timeout); } }); @@ -1980,4 +1981,4 @@ private Savepoint getFakeSavepoint() { } }; } -} \ No newline at end of file +} diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinPreparedStatementSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinPreparedStatementSelfTest.java index c5778537096f1..4635702a9dd78 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinPreparedStatementSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinPreparedStatementSelfTest.java @@ -797,146 +797,146 @@ public void testClearParameter() throws Exception { public void testNotSupportedTypes() throws Exception { stmt = conn.prepareStatement(""); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setArray(1, null); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setAsciiStream(1, null); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setAsciiStream(1, null, 0); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setAsciiStream(1, null, 0L); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setBinaryStream(1, null); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setBinaryStream(1, null, 0); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setBinaryStream(1, null, 0L); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setBlob(1, (Blob)null); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setBlob(1, (InputStream)null); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setBlob(1, null, 0L); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setCharacterStream(1, null); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setCharacterStream(1, null, 0); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setCharacterStream(1, null, 0L); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setClob(1, (Clob)null); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setClob(1, (Reader)null); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setClob(1, null, 0L); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setNCharacterStream(1, null); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setNCharacterStream(1, null, 0L); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setNClob(1, (NClob)null); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setNClob(1, (Reader)null); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setNClob(1, null, 0L); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setRowId(1, null); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setRef(1, null); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setSQLXML(1, null); } }); @@ -1055,4 +1055,4 @@ private TestObject(int id) { this.id = id; } } -} \ No newline at end of file +} diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinResultSetSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinResultSetSelfTest.java index 4f9480261c66b..94713afe873fa 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinResultSetSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinResultSetSelfTest.java @@ -49,6 +49,9 @@ import static org.apache.ignite.cache.CacheMode.PARTITIONED; import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC; +import static org.apache.ignite.testframework.GridTestUtils.RunnableX; +import static org.apache.ignite.testframework.GridTestUtils.assertThrows; +import static org.apache.ignite.testframework.GridTestUtils.assertThrowsAnyCause; /** * Result set test. @@ -772,133 +775,133 @@ public void testNotSupportedTypes() throws Exception { assert rs.next(); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getArray(1); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getArray("id"); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getAsciiStream(1); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getAsciiStream("id"); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getBinaryStream(1); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getBinaryStream("id"); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getBlob(1); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getBlob("id"); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getClob(1); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getClob("id"); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getCharacterStream(1); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getCharacterStream("id"); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getNCharacterStream(1); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getNCharacterStream("id"); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getNClob(1); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getNClob("id"); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getRef(1); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getRef("id"); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getRowId(1); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getRowId("id"); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getSQLXML(1); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getSQLXML("id"); } }); @@ -913,499 +916,499 @@ public void testUpdateNotSupported() throws Exception { assert rs.next(); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateBoolean(1, true); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateBoolean("id", true); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateByte(1, (byte)0); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateByte("id", (byte)0); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateShort(1, (short)0); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateShort("id", (short)0); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateInt(1, 0); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateInt("id", 0); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateLong(1, 0); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateLong("id", 0); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateFloat(1, (float)0.0); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateFloat("id", (float)0.0); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateDouble(1, 0.0); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateDouble("id", 0.0); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateString(1, ""); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateString("id", ""); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateTime(1, new Time(0)); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateTime("id", new Time(0)); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateDate(1, new Date(0)); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateDate("id", new Date(0)); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateTimestamp(1, new Timestamp(0)); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateTimestamp("id", new Timestamp(0)); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateBytes(1, new byte[]{}); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateBytes("id", new byte[]{}); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateArray(1, null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateArray("id", null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateBlob(1, (Blob)null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateBlob(1, (InputStream)null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateBlob(1, null, 0L); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateBlob("id", (Blob)null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateBlob("id", (InputStream)null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateBlob("id", null, 0L); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateClob(1, (Clob)null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateClob(1, (Reader)null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateClob(1, null, 0L); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateClob("id", (Clob)null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateClob("id", (Reader)null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateClob("id", null, 0L); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateNClob(1, (NClob)null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateNClob(1, (Reader)null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateNClob(1, null, 0L); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateNClob("id", (NClob)null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateNClob("id", (Reader)null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateNClob("id", null, 0L); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateAsciiStream(1, null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateAsciiStream(1, null, 0); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateAsciiStream(1, null, 0L); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateAsciiStream("id", null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateAsciiStream("id", null, 0); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateAsciiStream("id", null, 0L); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateCharacterStream(1, null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateCharacterStream(1, null, 0); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateCharacterStream(1, null, 0L); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateCharacterStream("id", null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateCharacterStream("id", null, 0); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateCharacterStream("id", null, 0L); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateNCharacterStream(1, null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateNCharacterStream(1, null, 0); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateNCharacterStream(1, null, 0L); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateNCharacterStream("id", null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateNCharacterStream("id", null, 0); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateNCharacterStream("id", null, 0L); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateRef(1, null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateRef("id", null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateRowId(1, null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateRowId("id", null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateNString(1, null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateNString("id", null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateSQLXML(1, null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateSQLXML("id", null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateObject(1, null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateObject(1, null, 0); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateObject("id", null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateObject("id", null, 0); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateBigDecimal(1, null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateBigDecimal("id", null); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateNull(1); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateNull("id"); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.cancelRowUpdates(); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.updateRow(); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.deleteRow(); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.insertRow(); } }); checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.moveToInsertRow(); } }); @@ -1423,235 +1426,235 @@ public void testExceptionOnClosedResultSet() throws Exception { rs.close(); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getBoolean(1); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getBoolean("id"); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getByte(1); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getByte("id"); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getShort(1); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getShort("id"); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getInt(1); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getInt("id"); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getLong(1); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getLong("id"); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getFloat(1); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getFloat("id"); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getDouble(1); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getDouble("id"); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getString(1); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getString("id"); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getBytes(1); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getBytes("id"); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getDate(1); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getDate(1, new GregorianCalendar()); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getDate("id"); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getDate("id", new GregorianCalendar()); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getTime(1); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getTime(1, new GregorianCalendar()); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getTime("id"); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getTime("id", new GregorianCalendar()); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getTimestamp(1); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getTimestamp(1, new GregorianCalendar()); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getTimestamp("id"); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getTimestamp("id", new GregorianCalendar()); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.wasNull(); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getMetaData(); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.next(); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.last(); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.afterLast(); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.beforeFirst(); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.first(); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.findColumn("id"); } }); checkResultSetClosed(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { rs.getRow(); } }); @@ -1847,4 +1850,4 @@ private TestObjectField(int a, String b) { return S.toString(TestObjectField.class, this); } } -} \ No newline at end of file +} diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java index 82c0512c7ab70..10dad914960cd 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java @@ -132,7 +132,7 @@ public class JdbcThinStatementSelfTest extends JdbcThinAbstractSelfTest { public void testExecuteQuery0() throws Exception { ResultSet rs = stmt.executeQuery(SQL); - assert rs != null; + assertNotNull(rs); int cnt = 0; @@ -140,22 +140,22 @@ public void testExecuteQuery0() throws Exception { int id = rs.getInt("id"); if (id == 2) { - assert "Joe".equals(rs.getString("firstName")); - assert "Black".equals(rs.getString("lastName")); - assert rs.getInt("age") == 35; + assertEquals("Joe", rs.getString("firstName")); + assertEquals("Black", rs.getString("lastName")); + assertEquals(35, rs.getInt("age")); } else if (id == 3) { - assert "Mike".equals(rs.getString("firstName")); - assert "Green".equals(rs.getString("lastName")); - assert rs.getInt("age") == 40; + assertEquals("Mike", rs.getString("firstName")); + assertEquals("Green", rs.getString("lastName")); + assertEquals(40, rs.getInt("age")); } else - assert false : "Wrong ID: " + id; + fail("Wrong ID: " + id); cnt++; } - assert cnt == 2; + assertEquals(2, cnt); } /** @@ -177,8 +177,8 @@ public void testExecuteQuery1() throws Exception { stmt.close(); // Call on a closed statement - checkStatementClosed(new RunnableX() { - @Override public void run() throws Exception { + checkStatementClosed(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.executeQuery(sqlText); } }); @@ -188,15 +188,13 @@ public void testExecuteQuery1() throws Exception { * @throws Exception If failed. */ public void testExecute() throws Exception { - assert stmt.execute(SQL); + assertTrue(stmt.execute(SQL)); - assert stmt.getUpdateCount() == -1 : "Update count must be -1 for SELECT query"; + assertEquals("Update count must be -1 for SELECT query", -1, stmt.getUpdateCount()); ResultSet rs = stmt.getResultSet(); - assert rs != null; - - assert stmt.getResultSet() == null; + assertNotNull(rs); int cnt = 0; @@ -204,22 +202,24 @@ public void testExecute() throws Exception { int id = rs.getInt("id"); if (id == 2) { - assert "Joe".equals(rs.getString("firstName")); - assert "Black".equals(rs.getString("lastName")); - assert rs.getInt("age") == 35; + assertEquals("Joe", rs.getString("firstName")); + assertEquals("Black", rs.getString("lastName")); + assertEquals(35, rs.getInt("age")); } else if (id == 3) { - assert "Mike".equals(rs.getString("firstName")); - assert "Green".equals(rs.getString("lastName")); - assert rs.getInt("age") == 40; + assertEquals( "Mike", rs.getString("firstName")); + assertEquals( "Green", rs.getString("lastName")); + assertEquals(40, rs.getInt("age")); } else - assert false : "Wrong ID: " + id; + fail("Wrong ID: " + id); cnt++; } - assert cnt == 2; + assertEquals(2, cnt); + + assertFalse("Statement has more results.", stmt.getMoreResults()); } /** @@ -228,11 +228,11 @@ else if (id == 3) { public void testMaxRows() throws Exception { stmt.setMaxRows(1); - assert stmt.getMaxRows() == 1; + assertEquals(1, stmt.getMaxRows()); ResultSet rs = stmt.executeQuery(SQL); - assert rs != null; + assertNotNull(rs); int cnt = 0; @@ -240,28 +240,28 @@ public void testMaxRows() throws Exception { int id = rs.getInt("id"); if (id == 2) { - assert "Joe".equals(rs.getString("firstName")); - assert "Black".equals(rs.getString("lastName")); - assert rs.getInt("age") == 35; + assertEquals("Joe", rs.getString("firstName")); + assertEquals("Black", rs.getString("lastName")); + assertEquals(35, rs.getInt("age")); } else if (id == 3) { - assert "Mike".equals(rs.getString("firstName")); - assert "Green".equals(rs.getString("lastName")); - assert rs.getInt("age") == 40; + assertEquals( "Mike", rs.getString("firstName")); + assertEquals( "Green", rs.getString("lastName")); + assertEquals(40, rs.getInt("age")); } else - assert false : "Wrong ID: " + id; + fail("Wrong ID: " + id); cnt++; } - assert cnt == 1; + assertEquals(1, cnt); stmt.setMaxRows(0); rs = stmt.executeQuery(SQL); - assert rs != null; + assertNotNull(rs); cnt = 0; @@ -269,22 +269,22 @@ else if (id == 3) { int id = rs.getInt("id"); if (id == 2) { - assert "Joe".equals(rs.getString("firstName")); - assert "Black".equals(rs.getString("lastName")); - assert rs.getInt("age") == 35; + assertEquals("Joe", rs.getString("firstName")); + assertEquals("Black", rs.getString("lastName")); + assertEquals(35, rs.getInt("age")); } else if (id == 3) { - assert "Mike".equals(rs.getString("firstName")); - assert "Green".equals(rs.getString("lastName")); - assert rs.getInt("age") == 40; + assertEquals( "Mike", rs.getString("firstName")); + assertEquals( "Green", rs.getString("lastName")); + assertEquals(40, rs.getInt("age")); } else - assert false : "Wrong ID: " + id; + fail("Wrong ID: " + id); cnt++; } - assert cnt == 2; + assertEquals(2, cnt); } /** @@ -295,14 +295,14 @@ public void testCloseResultSet0() throws Exception { ResultSet rs1 = stmt.executeQuery(SQL); ResultSet rs2 = stmt.executeQuery(SQL); - assert rs0.isClosed() : "ResultSet must be implicitly closed after re-execute statement"; - assert rs1.isClosed() : "ResultSet must be implicitly closed after re-execute statement"; + assertTrue("ResultSet must be implicitly closed after re-execute statement", rs0.isClosed()); + assertTrue("ResultSet must be implicitly closed after re-execute statement", rs1.isClosed()); - assert !rs2.isClosed() : "Last result set must be available"; + assertFalse("Last result set must be available", rs2.isClosed()); stmt.close(); - assert rs2.isClosed() : "ResultSet must be explicitly closed after close statement"; + assertTrue("ResultSet must be explicitly closed after close statement", rs2.isClosed()); } /** @@ -315,7 +315,7 @@ public void testCloseResultSet1() throws Exception { stmt.close(); - assert rs.isClosed() : "ResultSet must be explicitly closed after close statement"; + assertTrue("ResultSet must be explicitly closed after close statement", rs.isClosed()); } /** @@ -326,66 +326,66 @@ public void testCloseResultSetByConnectionClose() throws Exception { conn.close(); - assert stmt.isClosed() : "Statement must be implicitly closed after close connection"; - assert rs.isClosed() : "ResultSet must be implicitly closed after close connection"; + assertTrue("Statement must be implicitly closed after close connection", stmt.isClosed()); + assertTrue("ResultSet must be implicitly closed after close connection", rs.isClosed()); } /** * @throws Exception If failed. */ public void testCloseOnCompletionAfterQuery() throws Exception { - assert !stmt.isCloseOnCompletion() : "Invalid default closeOnCompletion"; + assertFalse("Invalid default closeOnCompletion", stmt.isCloseOnCompletion()); ResultSet rs0 = stmt.executeQuery(SQL); ResultSet rs1 = stmt.executeQuery(SQL); - assert rs0.isClosed() : "Result set must be closed implicitly"; + assertTrue("Result set must be closed implicitly", rs0.isClosed()); - assert !stmt.isClosed() : "Statement must not be closed"; + assertFalse("Statement must not be closed", stmt.isClosed()); rs1.close(); - assert !stmt.isClosed() : "Statement must not be closed"; + assertFalse("Statement must not be closed", stmt.isClosed()); ResultSet rs2 = stmt.executeQuery(SQL); stmt.closeOnCompletion(); - assert stmt.isCloseOnCompletion() : "Invalid closeOnCompletion"; + assertTrue("Invalid closeOnCompletion", stmt.isCloseOnCompletion()); rs2.close(); - assert stmt.isClosed() : "Statement must be closed"; + assertTrue("Statement must be closed", stmt.isClosed()); } /** * @throws Exception If failed. */ public void testCloseOnCompletionBeforeQuery() throws Exception { - assert !stmt.isCloseOnCompletion() : "Invalid default closeOnCompletion"; + assertFalse("Invalid default closeOnCompletion", stmt.isCloseOnCompletion()); ResultSet rs0 = stmt.executeQuery(SQL); ResultSet rs1 = stmt.executeQuery(SQL); - assert rs0.isClosed() : "Result set must be closed implicitly"; + assertTrue("Result set must be closed implicitly", rs0.isClosed()); - assert !stmt.isClosed() : "Statement must not be closed"; + assertFalse("Statement must not be closed", stmt.isClosed()); rs1.close(); - assert !stmt.isClosed() : "Statement must not be closed"; + assertFalse("Statement must not be closed", stmt.isClosed()); stmt.closeOnCompletion(); ResultSet rs2 = stmt.executeQuery(SQL); - assert stmt.isCloseOnCompletion() : "Invalid closeOnCompletion"; + assertTrue("Invalid closeOnCompletion", stmt.isCloseOnCompletion()); rs2.close(); - assert stmt.isClosed() : "Statement must be closed"; + assertTrue("Statement must be closed", stmt.isClosed()); } /** @@ -414,7 +414,7 @@ public void testExecuteQueryTimeout() throws Exception { * @throws Exception If failed. */ public void testExecuteQueryMultipleOnlyResultSets() throws Exception { - assert conn.getMetaData().supportsMultipleResultSets(); + assertTrue(conn.getMetaData().supportsMultipleResultSets()); int stmtCnt = 10; @@ -543,8 +543,8 @@ public void testExecuteUpdate() throws Exception { stmt.close(); - checkStatementClosed(new RunnableX() { - @Override public void run() throws Exception { + checkStatementClosed(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.executeUpdate(sqlText); } }); @@ -634,15 +634,15 @@ public void testGetSetMaxFieldSizeUnsupported() throws Exception { stmt.close(); // Call on a closed statement - checkStatementClosed(new RunnableX() { - @Override public void run() throws Exception { + checkStatementClosed(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.getMaxFieldSize(); } }); // Call on a closed statement - checkStatementClosed(new RunnableX() { - @Override public void run() throws Exception { + checkStatementClosed(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setMaxFieldSize(100); } }); @@ -684,15 +684,15 @@ public void testGetSetMaxRows() throws Exception { stmt.close(); // Call on a closed statement - checkStatementClosed(new RunnableX() { - @Override public void run() throws Exception { + checkStatementClosed(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.getMaxRows(); } }); // Call on a closed statement - checkStatementClosed(new RunnableX() { - @Override public void run() throws Exception { + checkStatementClosed(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setMaxRows(maxRows); } }); @@ -728,8 +728,8 @@ public void testSetEscapeProcessing() throws Exception { stmt.close(); - checkStatementClosed(new RunnableX() { - @Override public void run() throws Exception { + checkStatementClosed(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setEscapeProcessing(true); } }); @@ -765,15 +765,15 @@ public void testGetSetQueryTimeout() throws Exception { stmt.close(); // Call on a closed statement - checkStatementClosed(new RunnableX() { - @Override public void run() throws Exception { + checkStatementClosed(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.getQueryTimeout(); } }); // Call on a closed statement - checkStatementClosed(new RunnableX() { - @Override public void run() throws Exception { + checkStatementClosed(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setQueryTimeout(timeout); } }); @@ -783,7 +783,7 @@ public void testGetSetQueryTimeout() throws Exception { * @throws Exception If failed. */ public void testMaxFieldSize() throws Exception { - assert stmt.getMaxFieldSize() >= 0; + assertTrue(stmt.getMaxFieldSize() >= 0); GridTestUtils.assertThrows(log, new Callable() { @@ -797,8 +797,8 @@ public void testMaxFieldSize() throws Exception { "Invalid field limit" ); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setMaxFieldSize(100); } }); @@ -808,22 +808,22 @@ public void testMaxFieldSize() throws Exception { * @throws Exception If failed. */ public void testQueryTimeout() throws Exception { - assert stmt.getQueryTimeout() == 0 : "Default timeout invalid: " + stmt.getQueryTimeout(); + assertEquals("Default timeout invalid: " + stmt.getQueryTimeout(), 0, stmt.getQueryTimeout()); stmt.setQueryTimeout(10); - assert stmt.getQueryTimeout() == 10; + assertEquals(10, stmt.getQueryTimeout()); stmt.close(); - checkStatementClosed(new RunnableX() { - @Override public void run() throws Exception { + checkStatementClosed(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.getQueryTimeout(); } }); - checkStatementClosed(new RunnableX() { - @Override public void run() throws Exception { + checkStatementClosed(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setQueryTimeout(10); } }); @@ -835,18 +835,18 @@ public void testQueryTimeout() throws Exception { public void testWarningsOnClosedStatement() throws Exception { stmt.clearWarnings(); - assert stmt.getWarnings() == null; + assertNull(null, stmt.getWarnings()); stmt.close(); - checkStatementClosed(new RunnableX() { - @Override public void run() throws Exception { + checkStatementClosed(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.getWarnings(); } }); - checkStatementClosed(new RunnableX() { - @Override public void run() throws Exception { + checkStatementClosed(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.clearWarnings(); } }); @@ -856,16 +856,16 @@ public void testWarningsOnClosedStatement() throws Exception { * @throws Exception If failed. */ public void testCursorName() throws Exception { - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setCursorName("test"); } }); stmt.close(); - checkStatementClosed(new RunnableX() { - @Override public void run() throws Exception { + checkStatementClosed(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setCursorName("test"); } }); @@ -875,22 +875,22 @@ public void testCursorName() throws Exception { * @throws Exception If failed. */ public void testGetMoreResults() throws Exception { - assert !stmt.getMoreResults(); + assertFalse(stmt.getMoreResults()); stmt.execute("select 1; "); ResultSet rs = stmt.getResultSet(); - assert !stmt.getMoreResults(); + assertFalse(stmt.getMoreResults()); - assert stmt.getResultSet() == null; + assertNull(stmt.getResultSet()); - assert rs.isClosed(); + assertTrue(rs.isClosed()); stmt.close(); - checkStatementClosed(new RunnableX() { - @Override public void run() throws Exception { + checkStatementClosed(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.getMoreResults(); } }); @@ -899,37 +899,59 @@ public void testGetMoreResults() throws Exception { /** * @throws Exception If failed. */ - public void testGetMoreResults1() throws Exception { - assert !stmt.getMoreResults(Statement.CLOSE_CURRENT_RESULT); - assert !stmt.getMoreResults(Statement.KEEP_CURRENT_RESULT); - assert !stmt.getMoreResults(Statement.CLOSE_ALL_RESULTS); + public void testGetMoreResultsKeepCurrent() throws Exception { + assertFalse(stmt.getMoreResults(Statement.CLOSE_CURRENT_RESULT)); + assertFalse(stmt.getMoreResults(Statement.KEEP_CURRENT_RESULT)); + assertFalse(stmt.getMoreResults(Statement.CLOSE_ALL_RESULTS)); stmt.execute("select 1; "); ResultSet rs = stmt.getResultSet(); - assert !stmt.getMoreResults(Statement.KEEP_CURRENT_RESULT); + assertFalse(stmt.getMoreResults(Statement.KEEP_CURRENT_RESULT)); - assert !rs.isClosed(); + assertFalse(rs.isClosed()); - assert !stmt.getMoreResults(Statement.CLOSE_ALL_RESULTS); + stmt.close(); - assert rs.isClosed(); + checkStatementClosed(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { + stmt.getMoreResults(Statement.KEEP_CURRENT_RESULT); + } + }); + } + + /** + * @throws Exception If failed. + */ + @org.junit.Test + public void testGetMoreResultsCloseAll() throws Exception { + assertFalse(stmt.getMoreResults(Statement.CLOSE_CURRENT_RESULT)); + assertFalse(stmt.getMoreResults(Statement.KEEP_CURRENT_RESULT)); + assertFalse(stmt.getMoreResults(Statement.CLOSE_ALL_RESULTS)); + + stmt.execute("select 1; "); + + ResultSet rs = stmt.getResultSet(); + + assertFalse(stmt.getMoreResults(Statement.CLOSE_ALL_RESULTS)); stmt.close(); - checkStatementClosed(new RunnableX() { - @Override public void run() throws Exception { + checkStatementClosed(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.getMoreResults(Statement.KEEP_CURRENT_RESULT); } }); } /** + * Verifies that emty batch can be performed. + * * @throws Exception If failed. */ public void testBatchEmpty() throws Exception { - assert conn.getMetaData().supportsBatchUpdates(); + assertTrue(conn.getMetaData().supportsBatchUpdates()); stmt.addBatch(""); stmt.clearBatch(); @@ -951,7 +973,7 @@ public void testBatchEmpty() throws Exception { * @throws Exception If failed. */ public void testFetchDirection() throws Exception { - assert stmt.getFetchDirection() == ResultSet.FETCH_FORWARD; + assertEquals(ResultSet.FETCH_FORWARD, stmt.getFetchDirection()); GridTestUtils.assertThrows(log, new Callable() { @@ -967,14 +989,14 @@ public void testFetchDirection() throws Exception { stmt.close(); - checkStatementClosed(new RunnableX() { - @Override public void run() throws Exception { + checkStatementClosed(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.setFetchDirection(-1); } }); - checkStatementClosed(new RunnableX() { - @Override public void run() throws Exception { + checkStatementClosed(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.getFetchDirection(); } }); @@ -1006,46 +1028,46 @@ public void testAutogenerated() throws Exception { SQLException.class, "Invalid autoGeneratedKeys value"); - assert !conn.getMetaData().supportsGetGeneratedKeys(); + assertFalse(conn.getMetaData().supportsGetGeneratedKeys()); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.getGeneratedKeys(); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.executeUpdate("select 1", Statement.RETURN_GENERATED_KEYS); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.executeUpdate("select 1", new int[] {1, 2}); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.executeUpdate("select 1", new String[] {"a", "b"}); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.execute("select 1", Statement.RETURN_GENERATED_KEYS); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.execute("select 1", new int[] {1, 2}); } }); - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { + checkNotSupported(new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { stmt.execute("select 1", new String[] {"a", "b"}); } }); @@ -1115,7 +1137,7 @@ public void testStatementTypeMismatchSelectForCachedQuery() throws Exception { SQLException.class, "Given statement type does not match that declared by JDBC driver"); - assert stmt.getResultSet() == null : "Not results expected. Last statement is executed with exception"; + assertNull("Not results expected. Last statement is executed with exception", stmt.getResultSet()); } /** @@ -1137,18 +1159,20 @@ public void testStatementTypeMismatchUpdate() throws Exception { boolean next = rs.next(); - assert next; + assertTrue(next); - assert rs.getInt(1) == 1 : "The data must not be updated. " + + assertEquals("The data must not be updated. " + "Because update statement is executed via 'executeQuery' method." + - " Data [val=" + rs.getInt(1) + ']'; + " Data [val=" + rs.getInt(1) + ']', + 1, + rs.getInt(1)); } /** */ private void fillCache() { IgniteCache cachePerson = grid(0).cache(DEFAULT_CACHE_NAME); - assert cachePerson != null; + assertNotNull(cachePerson); cachePerson.put("p1", new Person(1, "John", "White", 25)); cachePerson.put("p2", new Person(2, "Joe", "Black", 35)); @@ -1229,4 +1253,4 @@ private Person(int id, String firstName, String lastName, int age) { this.age = age; } } -} \ No newline at end of file +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/ComputeTaskInternalFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/ComputeTaskInternalFuture.java index 2cb3dfad5e487..6ce9001138b1b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/ComputeTaskInternalFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/ComputeTaskInternalFuture.java @@ -234,7 +234,7 @@ public ComputeTaskSession getTaskSession() { /** {@inheritDoc} */ @Override public boolean cancel() throws IgniteCheckedException { - ctx.security().authorize(ses.getTaskName(), SecurityPermission.TASK_CANCEL, null); + ctx.security().authorize(ses.getTaskName(), SecurityPermission.TASK_CANCEL); if (onCancelled()) { ctx.task().onCancelled(ses.getId()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java index c38486a27a72d..53c7230b79277 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java @@ -61,7 +61,7 @@ import org.apache.ignite.internal.processors.resource.GridResourceProcessor; import org.apache.ignite.internal.processors.rest.GridRestProcessor; import org.apache.ignite.internal.processors.schedule.IgniteScheduleProcessorAdapter; -import org.apache.ignite.internal.processors.security.GridSecurityProcessor; +import org.apache.ignite.internal.processors.security.IgniteSecurity; import org.apache.ignite.internal.processors.segmentation.GridSegmentationProcessor; import org.apache.ignite.internal.processors.service.GridServiceProcessor; import org.apache.ignite.internal.processors.session.GridTaskSessionProcessor; @@ -405,11 +405,11 @@ public interface GridKernalContext extends Iterable { public GridCollisionManager collision(); /** - * Gets authentication processor. + * Gets instance of {@link IgniteSecurity}. * - * @return Authentication processor. + * @return Ignite security. */ - public GridSecurityProcessor security(); + public IgniteSecurity security(); /** * Gets load balancing manager. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java index b05d10913cb9d..486888448206d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java @@ -80,7 +80,7 @@ import org.apache.ignite.internal.processors.resource.GridResourceProcessor; import org.apache.ignite.internal.processors.rest.GridRestProcessor; import org.apache.ignite.internal.processors.schedule.IgniteScheduleProcessorAdapter; -import org.apache.ignite.internal.processors.security.GridSecurityProcessor; +import org.apache.ignite.internal.processors.security.IgniteSecurity; import org.apache.ignite.internal.processors.segmentation.GridSegmentationProcessor; import org.apache.ignite.internal.processors.service.GridServiceProcessor; import org.apache.ignite.internal.processors.session.GridTaskSessionProcessor; @@ -157,7 +157,7 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable /** */ @GridToStringExclude - private GridSecurityProcessor securityProc; + private IgniteSecurity security; /** */ @GridToStringExclude @@ -567,8 +567,6 @@ else if (comp instanceof GridFailoverManager) failoverMgr = (GridFailoverManager)comp; else if (comp instanceof GridCollisionManager) colMgr = (GridCollisionManager)comp; - else if (comp instanceof GridSecurityProcessor) - securityProc = (GridSecurityProcessor)comp; else if (comp instanceof GridLoadBalancerManager) loadMgr = (GridLoadBalancerManager)comp; else if (comp instanceof GridIndexingManager) @@ -643,6 +641,8 @@ else if (comp instanceof GridInternalSubscriptionProcessor) internalSubscriptionProc = (GridInternalSubscriptionProcessor)comp; else if (comp instanceof IgniteAuthenticationProcessor) authProc = (IgniteAuthenticationProcessor)comp; + else if (comp instanceof IgniteSecurity) + security = (IgniteSecurity)comp; else if (comp instanceof DiagnosticProcessor) diagnosticProcessor = (DiagnosticProcessor)comp; else if (!(comp instanceof DiscoveryNodeValidationProcessor @@ -803,8 +803,8 @@ else if (helper instanceof HadoopHelper) } /** {@inheritDoc} */ - @Override public GridSecurityProcessor security() { - return securityProc; + @Override public IgniteSecurity security() { + return security; } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridMessageListenHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/GridMessageListenHandler.java index c146eca255aba..7bfc6da05d7b8 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/GridMessageListenHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/GridMessageListenHandler.java @@ -134,7 +134,7 @@ public GridMessageListenHandler(GridMessageListenHandler orig) { /** {@inheritDoc} */ @Override public RegisterStatus register(UUID nodeId, UUID routineId, final GridKernalContext ctx) throws IgniteCheckedException { - ctx.io().addUserMessageListener(topic, pred); + ctx.io().addUserMessageListener(topic, pred, nodeId); return RegisterStatus.REGISTERED; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteFeatures.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteFeatures.java index cbb2ffc0c817d..8e404871a4944 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteFeatures.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteFeatures.java @@ -22,6 +22,7 @@ import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi; import org.apache.ignite.spi.communication.tcp.messages.HandshakeWaitMessage; +import static org.apache.ignite.IgniteSystemProperties.getBoolean; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_IGNITE_FEATURES; /** @@ -58,6 +59,9 @@ public enum IgniteFeatures { /** Supports tracking update counter for transactions. */ TX_TRACKING_UPDATE_COUNTER(12), + /** Distributed metastorage. */ + IGNITE_SECURITY_PROCESSOR(13), + /** Replacing TcpDiscoveryNode field with nodeId field in discovery messages. */ TCP_DISCOVERY_MESSAGE_NODE_COMPACT_REPRESENTATION(14); @@ -142,6 +146,10 @@ public static byte[] allFeatures() { final BitSet set = new BitSet(); for (IgniteFeatures value : IgniteFeatures.values()) { + // After rolling upgrade, our security has more strict validation. This may come as a surprise to customers. + if (IGNITE_SECURITY_PROCESSOR == value && !getBoolean(IGNITE_SECURITY_PROCESSOR.name(), false)) + continue; + final int featureId = value.getFeatureId(); assert !set.get(featureId) : "Duplicate feature ID found for [" + value + "] having same ID [" diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java index a84bd80c5224b..dc95de14b149f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java @@ -161,6 +161,9 @@ import org.apache.ignite.internal.processors.resource.GridSpringResourceContext; import org.apache.ignite.internal.processors.rest.GridRestProcessor; import org.apache.ignite.internal.processors.security.GridSecurityProcessor; +import org.apache.ignite.internal.processors.security.IgniteSecurityProcessor; +import org.apache.ignite.internal.processors.security.IgniteSecurity; +import org.apache.ignite.internal.processors.security.NoOpIgniteSecurityProcessor; import org.apache.ignite.internal.processors.segmentation.GridSegmentationProcessor; import org.apache.ignite.internal.processors.service.GridServiceProcessor; import org.apache.ignite.internal.processors.session.GridTaskSessionProcessor; @@ -1081,7 +1084,7 @@ public void start( startProcessor(new GridTimeoutProcessor(ctx)); // Start security processors. - startProcessor(createComponent(GridSecurityProcessor.class, ctx)); + startProcessor(securityProcessor()); // Start SPI managers. // NOTE: that order matters as there are dependencies between managers. @@ -1494,6 +1497,17 @@ private long checkPoolStarvation( startTimer.finishGlobalStage("Await exchange"); } + /** + * @return GridProcessor that implements {@link IgniteSecurity} + */ + private GridProcessor securityProcessor() throws IgniteCheckedException { + GridSecurityProcessor prc = createComponent(GridSecurityProcessor.class, ctx); + + return prc != null && prc.enabled() + ? new IgniteSecurityProcessor(ctx, prc) + : new NoOpIgniteSecurityProcessor(ctx, prc); + } + /** * Create description of an executor service for logging. * @@ -3586,6 +3600,7 @@ public IgniteInternalFuture getOrCreateCacheAsync(String cacheName, String te Ignition.stop(igniteInstanceName, true); } + /** {@inheritDoc} */ @Override public Affinity affinity(String cacheName) { CU.validateCacheName(cacheName); checkClusterState(); @@ -4106,6 +4121,9 @@ private static T createComponent(Class cls, GridKer if (cls.equals(IGridClusterStateProcessor.class)) return (T)new GridClusterStateProcessor(ctx); + if(cls.equals(GridSecurityProcessor.class)) + return null; + Class implCls = null; try { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/JdbcConnectionValidationTask.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/JdbcConnectionValidationTask.java index f4a57bf304ad5..d35bfb86c84f1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/JdbcConnectionValidationTask.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/JdbcConnectionValidationTask.java @@ -1,11 +1,12 @@ /* - * Copyright 2019 GridGain Systems, Inc. and Contributors. + * 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 * - * Licensed under the GridGain Community Edition License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.gridgain.com/products/software/community-edition/gridgain-community-edition-license + * 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, diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java index 267addb887169..71db0fc8d06f8 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java @@ -59,6 +59,7 @@ import org.apache.ignite.internal.IgniteClientDisconnectedCheckedException; import org.apache.ignite.internal.IgniteComponentType; import org.apache.ignite.internal.IgniteDeploymentCheckedException; +import org.apache.ignite.internal.IgniteFeatures; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; import org.apache.ignite.internal.direct.DirectMessageReader; @@ -69,6 +70,8 @@ import org.apache.ignite.internal.managers.eventstorage.GridLocalEventListener; import org.apache.ignite.internal.processors.platform.message.PlatformMessageFilter; import org.apache.ignite.internal.processors.pool.PoolProcessor; +import org.apache.ignite.internal.processors.security.OperationSecurityContext; +import org.apache.ignite.internal.processors.security.SecurityContext; import org.apache.ignite.internal.processors.timeout.GridTimeoutObject; import org.apache.ignite.internal.util.GridBoundedConcurrentLinkedHashSet; import org.apache.ignite.internal.util.StripedCompositeReadWriteLock; @@ -78,6 +81,7 @@ import org.apache.ignite.internal.util.lang.IgnitePair; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.internal.util.typedef.T2; import org.apache.ignite.internal.util.typedef.X; import org.apache.ignite.internal.util.typedef.internal.LT; import org.apache.ignite.internal.util.typedef.internal.S; @@ -96,6 +100,7 @@ import org.apache.ignite.spi.communication.CommunicationListener; import org.apache.ignite.spi.communication.CommunicationSpi; import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import static org.apache.ignite.events.EventType.EVT_NODE_FAILED; @@ -203,11 +208,7 @@ public class GridIoManager extends GridManagerAdapter {}; /** * @param ctx Grid kernal context. @@ -1048,7 +1049,7 @@ private void processP2PMessage( assert obj != null; - invokeListener(msg.policy(), lsnr, nodeId, obj); + invokeListener(msg.policy(), lsnr, nodeId, obj, secSubj(msg)); } finally { threadProcessingMessage(false, null); @@ -1090,7 +1091,11 @@ private void processRegularMessage( processRegularMessage0(msg, nodeId); } - finally { + catch (Throwable e) { + log.error("An error occurred processing the message [msg=" + msg + ", nodeId=" + nodeId + "].", e); + + throw e; + } finally { threadProcessingMessage(false, null); msgC.run(); @@ -1181,7 +1186,7 @@ private void processRegularMessage0(GridIoMessage msg, UUID nodeId) { assert obj != null; - invokeListener(msg.policy(), lsnr, nodeId, obj); + invokeListener(msg.policy(), lsnr, nodeId, obj, secSubj(msg)); } /** @@ -1543,8 +1548,9 @@ private void unwindMessageSet(GridCommunicationMessageSet msgSet, GridMessageLis * @param lsnr Listener. * @param nodeId Node ID. * @param msg Message. + * @param secCtxMsg Security subject that will be used to open a security session. */ - private void invokeListener(Byte plc, GridMessageListener lsnr, UUID nodeId, Object msg) { + private void invokeListener(Byte plc, GridMessageListener lsnr, UUID nodeId, Object msg, @Nullable T2 secCtxMsg) { Byte oldPlc = CUR_PLC.get(); boolean change = !F.eq(oldPlc, plc); @@ -1552,7 +1558,10 @@ private void invokeListener(Byte plc, GridMessageListener lsnr, UUID nodeId, Obj if (change) CUR_PLC.set(plc); - try { + SecurityContext secCtx = secCtxMsg != null ? secCtxMsg.get2() : null; + UUID newSecSubjId = secCtxMsg != null && secCtxMsg.get1() != null ? secCtxMsg.get1() : nodeId; + + try (OperationSecurityContext s = secCtx != null ? ctx.security().withContext(secCtx) : ctx.security().withContext(newSecSubjId)) { lsnr.onMessage(nodeId, msg, plc); } finally { @@ -1614,7 +1623,7 @@ private void send( assert !async || msg instanceof GridIoUserMessage : msg; // Async execution was added only for IgniteMessaging. assert topicOrd >= 0 || !(topic instanceof GridTopic) : msg; - GridIoMessage ioMsg = new GridIoMessage(plc, topic, topicOrd, msg, ordered, timeout, skipOnTimeout); + GridIoMessage ioMsg = createGridIoMessage(topic, topicOrd, msg, plc, ordered, timeout, skipOnTimeout); if (locNodeId.equals(node.id())) { assert plc != P2P_POOL; @@ -1656,6 +1665,38 @@ else if (async) } } + /** + * @return One of two message wrappers. The first is {@link GridIoMessage}, the second is secured version {@link + * GridIoSecurityAwareMessage}. + */ + private @NotNull GridIoMessage createGridIoMessage( + Object topic, + int topicOrd, + Message msg, + byte plc, + boolean ordered, + long timeout, + boolean skipOnTimeout) throws IgniteCheckedException { + boolean securityMsgSupported = IgniteFeatures.allNodesSupports(ctx.discovery().allNodes(), IgniteFeatures.IGNITE_SECURITY_PROCESSOR); + + if (ctx.security().enabled() && securityMsgSupported) { + UUID secSubjId = null; + + SecurityContext secCtx = ctx.security().securityContext(); + UUID curSecSubjId = secCtx.subject().id(); + + if (!locNodeId.equals(curSecSubjId)) + secSubjId = curSecSubjId; + + //Network optimization + byte[] secSubject = secSubjId != null && ctx.discovery().node(secSubjId) == null ? U.marshal(marsh, secCtx) : null; + + return new GridIoSecurityAwareMessage(secSubjId, secSubject, plc, topic, topicOrd, msg, ordered, timeout, skipOnTimeout); + } + + return new GridIoMessage(plc, topic, topicOrd, msg, ordered, timeout, skipOnTimeout); + } + /** * @param nodeId Id of destination node. * @param topic Topic to send the message to. @@ -1964,11 +2005,24 @@ else if (loc) { } /** + * Subscribe at messages from a topic. + * * @param topic Topic to subscribe to. * @param p Message predicate. */ - @SuppressWarnings("unchecked") - public void addUserMessageListener(@Nullable final Object topic, @Nullable final IgniteBiPredicate p) { + public void addUserMessageListener(final @Nullable Object topic, final @Nullable IgniteBiPredicate p) { + addUserMessageListener(topic, p, null); + } + + /** + * @param topic Topic to subscribe to. + * @param p Message predicate. + */ + public void addUserMessageListener( + final @Nullable Object topic, + final @Nullable IgniteBiPredicate p, + final @Nullable UUID nodeId + ) { if (p != null) { try { if (p instanceof PlatformMessageFilter) @@ -1977,7 +2031,7 @@ public void addUserMessageListener(@Nullable final Object topic, @Nullable final ctx.resource().injectGeneric(p); addMessageListener(TOPIC_COMM_USER, - new GridUserMessageListener(topic, (IgniteBiPredicate)p)); + new GridUserMessageListener(topic, (IgniteBiPredicate)p, nodeId)); } catch (IgniteCheckedException e) { throw new IgniteException(e); @@ -1991,13 +2045,8 @@ public void addUserMessageListener(@Nullable final Object topic, @Nullable final */ @SuppressWarnings("unchecked") public void removeUserMessageListener(@Nullable Object topic, IgniteBiPredicate p) { - try { - removeMessageListener(TOPIC_COMM_USER, - new GridUserMessageListener(topic, (IgniteBiPredicate)p)); - } - catch (IgniteCheckedException e) { - throw new IgniteException(e); - } + removeMessageListener(TOPIC_COMM_USER, + new GridUserMessageListener(topic, (IgniteBiPredicate)p)); } /** @@ -2416,15 +2465,27 @@ private class GridUserMessageListener implements GridMessageListener { /** User message topic. */ private final Object topic; + /** Initial node id. */ + private final UUID initNodeId; + /** * @param topic User topic. * @param predLsnr Predicate listener. - * @throws IgniteCheckedException If failed to inject resources to predicates. + * @param initNodeId Node id that registered given listener. */ - GridUserMessageListener(@Nullable Object topic, @Nullable IgniteBiPredicate predLsnr) - throws IgniteCheckedException { + GridUserMessageListener(@Nullable Object topic, @Nullable IgniteBiPredicate predLsnr, + @Nullable UUID initNodeId) { this.topic = topic; this.predLsnr = predLsnr; + this.initNodeId = initNodeId; + } + + /** + * @param topic User topic. + * @param predLsnr Predicate listener. + */ + GridUserMessageListener(@Nullable Object topic, @Nullable IgniteBiPredicate predLsnr) { + this(topic, predLsnr, null); } /** {@inheritDoc} */ @@ -2521,8 +2582,10 @@ private class GridUserMessageListener implements GridMessageListener { if (msgBody != null) { if (predLsnr != null) { - if (!predLsnr.apply(nodeId, msgBody)) - removeMessageListener(TOPIC_COMM_USER, this); + try(OperationSecurityContext s = ctx.security().withContext(initNodeId)) { + if (!predLsnr.apply(nodeId, msgBody)) + removeMessageListener(TOPIC_COMM_USER, this); + } } } } @@ -2749,7 +2812,7 @@ void unwind(GridMessageListener lsnr) { for (GridTuple3 t = msgs.poll(); t != null; t = msgs.poll()) { try { - invokeListener(plc, lsnr, nodeId, t.get1().message()); + invokeListener(plc, lsnr, nodeId, t.get1().message(), secSubj(t.get1())); } finally { if (t.get3() != null) @@ -3145,4 +3208,31 @@ public long binLatencyMcs() { return latencyLimit / (1000 * (resLatency.length - 1)); } } + + /** + * @param msg Communication message. + * @return A pair that represents a security subject id and security context. The returned value can be {@code null} + * in case of security context is not enabled. + */ + private T2 secSubj(GridIoMessage msg) { + if (ctx.security().enabled() && msg instanceof GridIoSecurityAwareMessage) { + GridIoSecurityAwareMessage secMsg = (GridIoSecurityAwareMessage)msg; + + SecurityContext secCtx = null; + + try { + secCtx = secMsg.getSecCtx() != null ? U.unmarshal(marsh, secMsg.getSecCtx(), U.resolveClassLoader(ctx.config())) : null; + } + catch (IgniteCheckedException e) { + log.error("Security context unmarshaled with error.", e); + } + + return new T2<>( + secMsg.secSubjId(), + secCtx + ); + } + + return null; + } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java index 0b296acf194f2..3c3f2a0f59c8d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java @@ -958,6 +958,11 @@ public GridIoMessageFactory(MessageFactory[] ext) { break; + case GridIoSecurityAwareMessage.TYPE_CODE: + msg = new GridIoSecurityAwareMessage(); + + break; + // [-3..119] [124..129] [-23..-28] [-36..-55] - this // [120..123] - DR // [-4..-22, -30..-35] - SQL diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoSecurityAwareMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoSecurityAwareMessage.java new file mode 100644 index 0000000000000..825644ddb0bf7 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoSecurityAwareMessage.java @@ -0,0 +1,163 @@ +/* + * 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.managers.communication; + +import java.io.Externalizable; +import java.nio.ByteBuffer; +import java.util.UUID; +import org.apache.ignite.plugin.extensions.communication.Message; +import org.apache.ignite.plugin.extensions.communication.MessageReader; +import org.apache.ignite.plugin.extensions.communication.MessageWriter; + +/** + * Represents a security communication message. + */ +public class GridIoSecurityAwareMessage extends GridIoMessage { + /** */ + private static final long serialVersionUID = 0L; + /** */ + public static final short TYPE_CODE = 174; + + /** Security subject id that will be used during message processing on an remote node. */ + private UUID secSubjId; + + /** Security context transmitting from node initiator of action. */ + private byte[] secCtx; + + /** + * No-op constructor to support {@link Externalizable} interface. + * This constructor is not meant to be used for other purposes. + */ + public GridIoSecurityAwareMessage() { + // No-op. + } + + /** + * @param secSubjId Security subject id. + * @param plc Policy. + * @param topic Communication topic. + * @param topicOrd Topic ordinal value. + * @param msg Message. + * @param ordered Message ordered flag. + * @param timeout Timeout. + * @param skipOnTimeout Whether message can be skipped on timeout. + */ + public GridIoSecurityAwareMessage( + UUID secSubjId, + byte[] secSubject, + byte plc, + Object topic, + int topicOrd, + Message msg, + boolean ordered, + long timeout, + boolean skipOnTimeout) { + super(plc, topic, topicOrd, msg, ordered, timeout, skipOnTimeout); + + this.secSubjId = secSubjId; + this.secCtx = secSubject; + } + + /** + * @return Security subject id. + */ + UUID secSubjId() { + return secSubjId; + } + + /** + * @return Security context + */ + public byte[] getSecCtx() { + return secCtx; + } + + /** {@inheritDoc} */ + @Override public short directType() { + return TYPE_CODE; + } + + /** {@inheritDoc} */ + @Override public byte fieldsCount() { + return 9; + } + + /** {@inheritDoc} */ + @Override public boolean writeTo(ByteBuffer buf, MessageWriter writer) { + writer.setBuffer(buf); + + if (!super.writeTo(buf, writer)) + return false; + + if (!writer.isHeaderWritten()) { + if (!writer.writeHeader(directType(), fieldsCount())) + return false; + + writer.onHeaderWritten(); + } + + switch (writer.state()) { + case 7: + if (!writer.writeByteArray("secCtx", secCtx)) + return false; + + writer.incrementState(); + + case 8: + if (!writer.writeUuid("secSubjId", secSubjId)) + return false; + + writer.incrementState(); + + } + + return true; + } + + /** {@inheritDoc} */ + @Override public boolean readFrom(ByteBuffer buf, MessageReader reader) { + reader.setBuffer(buf); + + if (!reader.beforeMessageRead()) + return false; + + if (!super.readFrom(buf, reader)) + return false; + + switch (reader.state()) { + case 7: + secCtx = reader.readByteArray("secCtx"); + + if (!reader.isLastRead()) + return false; + + reader.incrementState(); + + case 8: + secSubjId = reader.readUuid("secSubjId"); + + if (!reader.isLastRead()) + return false; + + reader.incrementState(); + + } + + return reader.afterMessageRead(GridIoSecurityAwareMessage.class); + } +} \ No newline at end of file diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/eventstorage/GridEventStorageManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/eventstorage/GridEventStorageManager.java index 793b4fc20a97e..522a9faa846a5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/eventstorage/GridEventStorageManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/eventstorage/GridEventStorageManager.java @@ -375,7 +375,7 @@ public int[] enabledEvents() { public synchronized void enableEvents(int[] types) { assert types != null; - ctx.security().authorize(null, SecurityPermission.EVENTS_ENABLE, null); + ctx.security().authorize(SecurityPermission.EVENTS_ENABLE); boolean[] userRecordableEvts0 = userRecordableEvts; boolean[] recordableEvts0 = recordableEvts; @@ -418,7 +418,7 @@ public synchronized void enableEvents(int[] types) { public synchronized void disableEvents(int[] types) { assert types != null; - ctx.security().authorize(null, SecurityPermission.EVENTS_DISABLE, null); + ctx.security().authorize(SecurityPermission.EVENTS_DISABLE); boolean[] userRecordableEvts0 = userRecordableEvts; boolean[] recordableEvts0 = recordableEvts; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java index 7db59ca58c2fd..82031fd7abe03 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java @@ -824,7 +824,7 @@ public void checkSecurity(SecurityPermission op) throws SecurityException { if (CU.isSystemCache(name())) return; - ctx.security().authorize(name(), op, null); + ctx.security().authorize(name(), op); } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java index 429b12090b97a..2bf598e284a9d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java @@ -135,6 +135,7 @@ import org.apache.ignite.internal.processors.query.schema.SchemaNodeLeaveExchangeWorkerTask; import org.apache.ignite.internal.processors.query.schema.message.SchemaAbstractDiscoveryMessage; import org.apache.ignite.internal.processors.query.schema.message.SchemaProposeDiscoveryMessage; +import org.apache.ignite.internal.processors.security.OperationSecurityContext; import org.apache.ignite.internal.processors.security.SecurityContext; import org.apache.ignite.internal.processors.timeout.GridTimeoutObject; import org.apache.ignite.internal.suggestions.GridPerformanceSuggestions; @@ -195,6 +196,7 @@ import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_TX_CONFIG; import static org.apache.ignite.internal.processors.cache.GridCacheUtils.isNearEnabled; import static org.apache.ignite.internal.processors.cache.GridCacheUtils.isPersistentCache; +import static org.apache.ignite.internal.processors.security.SecurityUtils.nodeSecurityContext; import static org.apache.ignite.internal.util.IgniteUtils.doInParallel; /** @@ -3218,7 +3220,7 @@ private GridCacheSharedContext createSharedContext( } /** {@inheritDoc} */ - @Nullable @Override public IgniteNodeValidationResult validateNode( + @Override public @Nullable IgniteNodeValidationResult validateNode( ClusterNode node, JoiningNodeDiscoveryData discoData ) { if(!cachesInfo.isMergeConfigSupports(node)) @@ -3231,22 +3233,28 @@ private GridCacheSharedContext createSharedContext( StringBuilder errorMessage = new StringBuilder(); - for (CacheJoinNodeDiscoveryData.CacheInfo cacheInfo : nodeData.caches().values()) { - try { - byte[] secCtxBytes = node.attribute(IgniteNodeAttributes.ATTR_SECURITY_SUBJECT_V2); + SecurityContext secCtx = null; - if (secCtxBytes != null) { - SecurityContext secCtx = U.unmarshal(marsh, secCtxBytes, U.resolveClassLoader(ctx.config())); + if (ctx.security().enabled()) { + try { + secCtx = nodeSecurityContext(marsh, U.resolveClassLoader(ctx.config()), node); + } + catch (SecurityException se) { + errorMessage.append(se.getMessage()); + } + } - if (secCtx != null && cacheInfo.cacheType() == CacheType.USER) - authorizeCacheCreate(cacheInfo.cacheData().config(), secCtx); + for (CacheJoinNodeDiscoveryData.CacheInfo cacheInfo : nodeData.caches().values()) { + if (secCtx != null && cacheInfo.cacheType() == CacheType.USER) { + try (OperationSecurityContext s = ctx.security().withContext(secCtx)) { + authorizeCacheCreate(cacheInfo.cacheData().config()); } - } - catch (SecurityException | IgniteCheckedException ex) { - if (errorMessage.length() > 0) - errorMessage.append("\n"); + catch (SecurityException ex) { + if (errorMessage.length() > 0) + errorMessage.append("\n"); - errorMessage.append(ex.getMessage()); + errorMessage.append(ex.getMessage()); + } } DynamicCacheDescriptor localDesc = cacheDescriptor(cacheInfo.cacheData().config().getName()); @@ -4169,28 +4177,28 @@ private Collection initiateCacheChanges( * Authorize creating cache. * * @param cfg Cache configuration. - * @param secCtx Optional security context. */ - private void authorizeCacheCreate(CacheConfiguration cfg, SecurityContext secCtx) { - ctx.security().authorize(null, SecurityPermission.CACHE_CREATE, secCtx); + private void authorizeCacheCreate(CacheConfiguration cfg) { + if(cfg != null) { + ctx.security().authorize(cfg.getName(), SecurityPermission.CACHE_CREATE); - if (cfg != null && cfg.isOnheapCacheEnabled() && - IgniteSystemProperties.getBoolean(IgniteSystemProperties.IGNITE_DISABLE_ONHEAP_CACHE)) - throw new SecurityException("Authorization failed for enabling on-heap cache."); + if (cfg.isOnheapCacheEnabled() && + IgniteSystemProperties.getBoolean(IgniteSystemProperties.IGNITE_DISABLE_ONHEAP_CACHE)) + throw new SecurityException("Authorization failed for enabling on-heap cache."); + } } /** - * Authorize dynamic cache management for this node. + * Authorize dynamic cache management. * * @param req start/stop cache request. */ private void authorizeCacheChange(DynamicCacheChangeRequest req) { - // Null security context means authorize this node. if (req.cacheType() == null || req.cacheType() == CacheType.USER) { if (req.stop()) - ctx.security().authorize(null, SecurityPermission.CACHE_DESTROY, null); + ctx.security().authorize(req.cacheName(), SecurityPermission.CACHE_DESTROY); else - authorizeCacheCreate(req.startCacheConfiguration(), null); + authorizeCacheCreate(req.startCacheConfiguration()); } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneGridKernalContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneGridKernalContext.java index d4253f3c2a108..05776cf889996 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneGridKernalContext.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneGridKernalContext.java @@ -77,7 +77,7 @@ import org.apache.ignite.internal.processors.resource.GridResourceProcessor; import org.apache.ignite.internal.processors.rest.GridRestProcessor; import org.apache.ignite.internal.processors.schedule.IgniteScheduleProcessorAdapter; -import org.apache.ignite.internal.processors.security.GridSecurityProcessor; +import org.apache.ignite.internal.processors.security.IgniteSecurity; import org.apache.ignite.internal.processors.segmentation.GridSegmentationProcessor; import org.apache.ignite.internal.processors.service.GridServiceProcessor; import org.apache.ignite.internal.processors.session.GridTaskSessionProcessor; @@ -445,7 +445,7 @@ protected IgniteConfiguration prepareIgniteConfiguration() { } /** {@inheritDoc} */ - @Override public GridSecurityProcessor security() { + @Override public IgniteSecurity security() { return null; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java index b159df31fd55e..df9a38110ecfe 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java @@ -57,6 +57,7 @@ import org.apache.ignite.internal.processors.cache.persistence.metastorage.MetastorageLifecycleListener; import org.apache.ignite.internal.processors.cache.persistence.metastorage.ReadOnlyMetastorage; import org.apache.ignite.internal.processors.cache.persistence.metastorage.ReadWriteMetastorage; +import org.apache.ignite.internal.processors.task.GridInternal; import org.apache.ignite.internal.util.future.GridFinishedFuture; import org.apache.ignite.internal.util.future.GridFutureAdapter; import org.apache.ignite.internal.util.future.IgniteFinishedFutureImpl; @@ -1479,6 +1480,7 @@ private void onAllReceived() { /** * */ + @GridInternal private static class ClientChangeGlobalStateComputeRequest implements IgniteRunnable { /** */ private static final long serialVersionUID = 0L; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerImpl.java index 7e81cfb181ee4..f34775800bbde 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerImpl.java @@ -1338,7 +1338,7 @@ private void checkSecurityPermission(SecurityPermission perm) if (!ctx.security().enabled()) return; - ctx.security().authorize(cacheName, perm, null); + ctx.security().authorize(cacheName, perm); } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerUpdateJob.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerUpdateJob.java index c2ab0c7cff679..ef9ef2db5f23f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerUpdateJob.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerUpdateJob.java @@ -166,6 +166,6 @@ private void checkSecurityPermission(SecurityPermission perm) if (!ctx.security().enabled()) return; - ctx.security().authorize(cacheName, perm, null); + ctx.security().authorize(cacheName, perm); } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerNioListener.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerNioListener.java index e5d7858c3dd88..72c5c32d58dce 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerNioListener.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerNioListener.java @@ -34,8 +34,7 @@ import org.apache.ignite.internal.processors.odbc.odbc.OdbcConnectionContext; import org.apache.ignite.internal.processors.platform.client.ClientConnectionContext; import org.apache.ignite.internal.processors.platform.client.ClientStatus; -import org.apache.ignite.internal.processors.security.SecurityContext; -import org.apache.ignite.internal.processors.security.SecurityContextHolder; +import org.apache.ignite.internal.processors.security.OperationSecurityContext; import org.apache.ignite.internal.util.GridSpinBusyLock; import org.apache.ignite.internal.util.nio.GridNioServerListenerAdapter; import org.apache.ignite.internal.util.nio.GridNioSession; @@ -173,17 +172,14 @@ public ClientListenerNioListener(GridKernalContext ctx, GridSpinBusyLock busyLoc ClientListenerResponse resp; AuthorizationContext authCtx = connCtx.authorizationContext(); - SecurityContext oldSecCtx = SecurityContextHolder.push(connCtx.securityContext()); if (authCtx != null) AuthorizationContext.context(authCtx); - try { + try(OperationSecurityContext s = ctx.security().withContext(connCtx.securityContext())) { resp = handler.handle(req); } finally { - SecurityContextHolder.pop(oldSecCtx); - if (authCtx != null) AuthorizationContext.clear(); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java index bb1d558420ac3..7a078dcd13eb4 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java @@ -62,6 +62,7 @@ import org.apache.ignite.internal.processors.rest.request.GridRestRequest; import org.apache.ignite.internal.processors.rest.request.GridRestTaskRequest; import org.apache.ignite.internal.processors.rest.request.RestQueryRequest; +import org.apache.ignite.internal.processors.security.OperationSecurityContext; import org.apache.ignite.internal.processors.security.SecurityContext; import org.apache.ignite.internal.util.GridSpinReadWriteLock; import org.apache.ignite.internal.util.future.GridFinishedFuture; @@ -269,7 +270,11 @@ private IgniteInternalFuture handleRequest(final GridRestReque if (secCtx0 == null || ses.isTokenExpired(sesTokTtl)) ses.secCtx = secCtx0 = authenticate(req, ses); - authorize(req, secCtx0); + try (OperationSecurityContext s = ctx.security().withContext(secCtx0)) { + authorize(req); + + return handle(req, true); + } } catch (SecurityException e) { assert secCtx0 != null; @@ -311,6 +316,11 @@ private IgniteInternalFuture handleRequest(final GridRestReque } } + return handle(req, authenticationEnabled); + } + + /** Executes particular command from a {@link GridRestRequest} */ + public IgniteInternalFuture handle(final GridRestRequest req, boolean securityIsActive) { interceptRequest(req); GridRestCommandHandler hnd = handlers.get(req.command()); @@ -362,7 +372,7 @@ private IgniteInternalFuture handleRequest(final GridRestReque assert res != null; - if ((authenticationEnabled || securityEnabled) && !failed) + if (securityIsActive && !failed) res.sessionTokenBytes(req.sessionToken()); interceptResponse(res, req); @@ -817,10 +827,9 @@ private SecurityContext authenticate(GridRestRequest req, Session ses) throws Ig /** * @param req REST request. - * @param sCtx Security context. * @throws SecurityException If authorization failed. */ - private void authorize(GridRestRequest req, SecurityContext sCtx) throws SecurityException { + private void authorize(GridRestRequest req) throws SecurityException { SecurityPermission perm = null; String name = null; @@ -921,7 +930,7 @@ private void authorize(GridRestRequest req, SecurityContext sCtx) throws Securit } if (perm != null) - ctx.security().authorize(name, perm, sCtx); + ctx.security().authorize(name, perm); } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/top/GridTopologyCommandHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/top/GridTopologyCommandHandler.java index 66cbe0e77061f..26cc0f3eb0908 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/top/GridTopologyCommandHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/top/GridTopologyCommandHandler.java @@ -58,7 +58,6 @@ import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_REST_TCP_HOST_NAMES; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_REST_TCP_PORT; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_SECURITY_CREDENTIALS; -import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_SECURITY_SUBJECT; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_SECURITY_SUBJECT_V2; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_TX_CONFIG; import static org.apache.ignite.internal.processors.rest.GridRestCommand.NODE; @@ -294,7 +293,6 @@ private GridClientNodeBean createNodeBean(ClusterNode node, boolean mtr, boolean attrs.remove(ATTR_CACHE); attrs.remove(ATTR_TX_CONFIG); - attrs.remove(ATTR_SECURITY_SUBJECT); attrs.remove(ATTR_SECURITY_SUBJECT_V2); attrs.remove(ATTR_SECURITY_CREDENTIALS); attrs.remove(ATTR_BINARY_CONFIGURATION); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/security/GridSecurityProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/GridSecurityProcessor.java index ef53566fd62bd..192cc3cd3a157 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/security/GridSecurityProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/GridSecurityProcessor.java @@ -27,7 +27,6 @@ import org.apache.ignite.plugin.security.SecurityException; import org.apache.ignite.plugin.security.SecurityPermission; import org.apache.ignite.plugin.security.SecuritySubject; -import org.jetbrains.annotations.Nullable; /** * This interface defines a grid authentication processor. @@ -84,7 +83,7 @@ public interface GridSecurityProcessor extends GridProcessor { * @param securityCtx Optional security context. * @throws SecurityException If security check failed. */ - public void authorize(String name, SecurityPermission perm, @Nullable SecurityContext securityCtx) + public void authorize(String name, SecurityPermission perm, SecurityContext securityCtx) throws SecurityException; /** @@ -96,6 +95,8 @@ public void authorize(String name, SecurityPermission perm, @Nullable SecurityCo /** * @return GridSecurityProcessor is enable. + * @deprecated To determine the security mode use {@link IgniteSecurity#enabled()}. */ + @Deprecated public boolean enabled(); } \ No newline at end of file diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/security/IgniteSecurity.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/IgniteSecurity.java new file mode 100644 index 0000000000000..ea90299be29ac --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/IgniteSecurity.java @@ -0,0 +1,128 @@ +/* + * 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.processors.security; + +import java.util.Collection; +import java.util.UUID; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.plugin.security.AuthenticationContext; +import org.apache.ignite.plugin.security.SecurityCredentials; +import org.apache.ignite.plugin.security.SecurityException; +import org.apache.ignite.plugin.security.SecurityPermission; +import org.apache.ignite.plugin.security.SecuritySubject; + +/** + * Ignite Security Processor. + *

      + * The differences between {@code IgniteSecurity} and {@code GridSecurityProcessor} are: + *

        + *
      • {@code IgniteSecurity} allows to define a current security context by + * {@link #withContext(SecurityContext)} or {@link #withContext(UUID)} methods. + *
      • {@code IgniteSecurity} doesn't require to pass {@code SecurityContext} to authorize operations. + *
      • {@code IgniteSecurity} doesn't extend {@code GridProcessor} interface + * sequentially it doesn't have any methods of the lifecycle of {@code GridProcessor}. + *
      + */ +public interface IgniteSecurity { + /** */ + static final String MSG_SEC_PROC_CLS_IS_INVALID = "Local node's grid security processor class " + + "is not equal to remote node's grid security processor class " + + "[locNodeId=%s, rmtNodeId=%s, locCls=%s, rmtCls=%s]"; + + /** + * Creates {@link OperationSecurityContext}. All calls of methods {@link #authorize(String, SecurityPermission)} or {@link + * #authorize(SecurityPermission)} will be processed into the context of passed {@link SecurityContext} until + * holder {@link OperationSecurityContext} will be closed. + * + * @param secCtx Security Context. + * @return Security context holder. + */ + public OperationSecurityContext withContext(SecurityContext secCtx); + + /** + * Creates {@link OperationSecurityContext}. All calls of methods {@link #authorize(String, SecurityPermission)} or {@link + * #authorize(SecurityPermission)} will be processed into the context of {@link SecurityContext} that is owned by + * the node with given nodeId until holder {@link OperationSecurityContext} will be closed. + * + * @param nodeId Node id. + * @return Security context holder. + */ + public OperationSecurityContext withContext(UUID nodeId); + + /** + * @return SecurityContext of holder {@link OperationSecurityContext}. + */ + public SecurityContext securityContext(); + + /** + * Delegates call to {@link GridSecurityProcessor#authenticateNode(org.apache.ignite.cluster.ClusterNode, + * org.apache.ignite.plugin.security.SecurityCredentials)} + */ + public SecurityContext authenticateNode(ClusterNode node, SecurityCredentials cred) throws IgniteCheckedException; + + /** + * Delegates call to {@link GridSecurityProcessor#isGlobalNodeAuthentication()} + */ + public boolean isGlobalNodeAuthentication(); + + /** + * Delegates call to {@link GridSecurityProcessor#authenticate(AuthenticationContext)} + */ + public SecurityContext authenticate(AuthenticationContext ctx) throws IgniteCheckedException; + + /** + * Delegates call to {@link GridSecurityProcessor#authenticatedSubjects()} + */ + public Collection authenticatedSubjects() throws IgniteCheckedException; + + /** + * Delegates call to {@link GridSecurityProcessor#authenticatedSubject(UUID)} + */ + public SecuritySubject authenticatedSubject(UUID subjId) throws IgniteCheckedException; + + /** + * Delegates call to {@link GridSecurityProcessor#onSessionExpired(UUID)} + */ + public void onSessionExpired(UUID subjId); + + /** + * Authorizes grid operation. + * + * @param name Cache name or task class name. + * @param perm Permission to authorize. + * @throws SecurityException If security check failed. + */ + public void authorize(String name, SecurityPermission perm) throws SecurityException; + + /** + * Authorizes grid system operation. + * + * @param perm Permission to authorize. + * @throws SecurityException If security check failed. + */ + public default void authorize(SecurityPermission perm) throws SecurityException { + authorize(null, perm); + } + + /** + * @return True if IgniteSecurity is a plugin implementation, + * false if it's used a default NoOp implementation. + */ + public boolean enabled(); +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/security/IgniteSecurityProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/IgniteSecurityProcessor.java new file mode 100644 index 0000000000000..d0361b3694699 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/IgniteSecurityProcessor.java @@ -0,0 +1,278 @@ +/* + * 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.processors.security; + +import java.util.Collection; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.IgniteFeatures; +import org.apache.ignite.internal.IgniteInternalFuture; +import org.apache.ignite.internal.processors.GridProcessor; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgniteFuture; +import org.apache.ignite.marshaller.MarshallerUtils; +import org.apache.ignite.marshaller.jdk.JdkMarshaller; +import org.apache.ignite.plugin.security.AuthenticationContext; +import org.apache.ignite.plugin.security.SecurityCredentials; +import org.apache.ignite.plugin.security.SecurityException; +import org.apache.ignite.plugin.security.SecurityPermission; +import org.apache.ignite.plugin.security.SecuritySubject; +import org.apache.ignite.spi.IgniteNodeValidationResult; +import org.apache.ignite.spi.discovery.DiscoveryDataBag; +import org.jetbrains.annotations.Nullable; + +import static org.apache.ignite.events.EventType.EVT_NODE_FAILED; +import static org.apache.ignite.events.EventType.EVT_NODE_LEFT; +import static org.apache.ignite.internal.processors.security.SecurityUtils.nodeSecurityContext; + +/** + * Default IgniteSecurity implementation. + */ +public class IgniteSecurityProcessor implements IgniteSecurity, GridProcessor { + /** Internal attribute name constant. */ + public static final String ATTR_GRID_SEC_PROC_CLASS = "grid.security.processor.class"; + + /** Current security context. */ + private final ThreadLocal curSecCtx = ThreadLocal.withInitial(this::localSecurityContext); + + /** Grid kernal context. */ + private final GridKernalContext ctx; + + /** Security processor. */ + private final GridSecurityProcessor secPrc; + + /** Must use JDK marshaller for Security Subject. */ + private final JdkMarshaller marsh; + + /** Map of security contexts. Key is the node's id. */ + private final Map secCtxs = new ConcurrentHashMap<>(); + + /** + * @param ctx Grid kernal context. + * @param secPrc Security processor. + */ + public IgniteSecurityProcessor(GridKernalContext ctx, GridSecurityProcessor secPrc) { + assert ctx != null; + assert secPrc != null; + + this.ctx = ctx; + this.secPrc = secPrc; + + marsh = MarshallerUtils.jdkMarshaller(ctx.igniteInstanceName()); + } + + /** {@inheritDoc} */ + @Override public OperationSecurityContext withContext(SecurityContext secCtx) { + assert secCtx != null; + + SecurityContext old = curSecCtx.get(); + + curSecCtx.set(secCtx); + + return new OperationSecurityContext(this, old); + } + + /** {@inheritDoc} */ + @Override public OperationSecurityContext withContext(UUID nodeId) { + return withContext( + secCtxs.computeIfAbsent(nodeId, + uuid -> nodeSecurityContext( + marsh, U.resolveClassLoader(ctx.config()), ctx.discovery().node(uuid) + ) + ) + ); + } + + /** {@inheritDoc} */ + @Override public SecurityContext securityContext() { + SecurityContext res = curSecCtx.get(); + + assert res != null; + + return res; + } + + /** {@inheritDoc} */ + @Override public SecurityContext authenticateNode(ClusterNode node, SecurityCredentials cred) + throws IgniteCheckedException { + return secPrc.authenticateNode(node, cred); + } + + /** {@inheritDoc} */ + @Override public boolean isGlobalNodeAuthentication() { + return secPrc.isGlobalNodeAuthentication(); + } + + /** {@inheritDoc} */ + @Override public SecurityContext authenticate(AuthenticationContext ctx) throws IgniteCheckedException { + return secPrc.authenticate(ctx); + } + + /** {@inheritDoc} */ + @Override public Collection authenticatedSubjects() throws IgniteCheckedException { + return secPrc.authenticatedSubjects(); + } + + /** {@inheritDoc} */ + @Override public SecuritySubject authenticatedSubject(UUID subjId) throws IgniteCheckedException { + return secPrc.authenticatedSubject(subjId); + } + + /** {@inheritDoc} */ + @Override public void onSessionExpired(UUID subjId) { + secPrc.onSessionExpired(subjId); + } + + /** {@inheritDoc} */ + @Override public void authorize(String name, SecurityPermission perm) throws SecurityException { + SecurityContext secCtx = curSecCtx.get(); + + assert secCtx != null; + + secPrc.authorize(name, perm, secCtx); + } + + /** {@inheritDoc} */ + @Override public boolean enabled() { + return true; + } + + /** {@inheritDoc} */ + @Override public void start() throws IgniteCheckedException { + ctx.addNodeAttribute(ATTR_GRID_SEC_PROC_CLASS, secPrc.getClass().getName()); + + secPrc.start(); + } + + /** {@inheritDoc} */ + @Override public void stop(boolean cancel) throws IgniteCheckedException { + secPrc.stop(cancel); + } + + /** {@inheritDoc} */ + @Override public void onKernalStart(boolean active) throws IgniteCheckedException { + ctx.event().addDiscoveryEventListener( + (evt, discoCache) -> secCtxs.remove(evt.eventNode().id()), EVT_NODE_FAILED, EVT_NODE_LEFT + ); + + secPrc.onKernalStart(active); + } + + /** {@inheritDoc} */ + @Override public void onKernalStop(boolean cancel) { + secPrc.onKernalStop(cancel); + } + + /** {@inheritDoc} */ + @Override public void collectJoiningNodeData(DiscoveryDataBag dataBag) { + secPrc.collectJoiningNodeData(dataBag); + } + + /** {@inheritDoc} */ + @Override public void collectGridNodeData(DiscoveryDataBag dataBag) { + secPrc.collectGridNodeData(dataBag); + } + + /** {@inheritDoc} */ + @Override public void onGridDataReceived(DiscoveryDataBag.GridDiscoveryData data) { + secPrc.onGridDataReceived(data); + } + + /** {@inheritDoc} */ + @Override public void onJoiningNodeDataReceived(DiscoveryDataBag.JoiningNodeDiscoveryData data) { + secPrc.onJoiningNodeDataReceived(data); + } + + /** {@inheritDoc} */ + @Override public void printMemoryStats() { + secPrc.printMemoryStats(); + } + + /** {@inheritDoc} */ + @Override public @Nullable IgniteNodeValidationResult validateNode(ClusterNode node) { + IgniteNodeValidationResult res = validateSecProcClass(node); + + return res != null ? res : secPrc.validateNode(node); + } + + /** {@inheritDoc} */ + @Override public @Nullable IgniteNodeValidationResult validateNode(ClusterNode node, + DiscoveryDataBag.JoiningNodeDiscoveryData discoData) { + IgniteNodeValidationResult res = validateSecProcClass(node); + + return res != null ? res : secPrc.validateNode(node, discoData); + } + + /** {@inheritDoc} */ + @Override public @Nullable DiscoveryDataExchangeType discoveryDataType() { + return secPrc.discoveryDataType(); + } + + /** {@inheritDoc} */ + @Override public void onDisconnected(IgniteFuture reconnectFut) throws IgniteCheckedException { + secPrc.onDisconnected(reconnectFut); + } + + /** {@inheritDoc} */ + @Override public @Nullable IgniteInternalFuture onReconnected( + boolean clusterRestarted) throws IgniteCheckedException { + return secPrc.onReconnected(clusterRestarted); + } + + /** + * Getting local node's security context. + * + * @return Security context of local node. + */ + private SecurityContext localSecurityContext() { + return nodeSecurityContext(marsh, U.resolveClassLoader(ctx.config()), ctx.discovery().localNode()); + } + + /** + * Validates that remote node's grid security processor class is the same as local one. + * + * @param node Joining node. + * @return Validation result or {@code null} in case of success. + */ + private IgniteNodeValidationResult validateSecProcClass(ClusterNode node) { + String rmtCls = node.attribute(ATTR_GRID_SEC_PROC_CLASS); + String locCls = secPrc.getClass().getName(); + + boolean securityMsgSupported = IgniteFeatures.allNodesSupports(ctx.discovery().allNodes(), IgniteFeatures.IGNITE_SECURITY_PROCESSOR); + + if (securityMsgSupported && !F.eq(locCls, rmtCls)) { + return new IgniteNodeValidationResult(node.id(), + String.format(MSG_SEC_PROC_CLS_IS_INVALID, ctx.localNodeId(), node.id(), locCls, rmtCls), + String.format(MSG_SEC_PROC_CLS_IS_INVALID, node.id(), ctx.localNodeId(), rmtCls, locCls)); + } + + return null; + } + + /** + * @return root security processor. + */ + public GridSecurityProcessor gridSecurityProcessor() { + return secPrc; + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/security/NoOpIgniteSecurityProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/NoOpIgniteSecurityProcessor.java new file mode 100644 index 0000000000000..c6b0e1d398074 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/NoOpIgniteSecurityProcessor.java @@ -0,0 +1,211 @@ +/* + * 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.processors.security; + +import java.util.Collection; +import java.util.UUID; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.IgniteFeatures; +import org.apache.ignite.internal.processors.GridProcessorAdapter; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.plugin.security.AuthenticationContext; +import org.apache.ignite.plugin.security.SecurityCredentials; +import org.apache.ignite.plugin.security.SecurityException; +import org.apache.ignite.plugin.security.SecurityPermission; +import org.apache.ignite.plugin.security.SecuritySubject; +import org.apache.ignite.spi.IgniteNodeValidationResult; +import org.apache.ignite.spi.discovery.DiscoveryDataBag; +import org.jetbrains.annotations.Nullable; + +import static org.apache.ignite.internal.processors.security.IgniteSecurityProcessor.ATTR_GRID_SEC_PROC_CLASS; + +/** + * No operation IgniteSecurity. + */ +public class NoOpIgniteSecurityProcessor extends GridProcessorAdapter implements IgniteSecurity { + /** No operation security context. */ + private final OperationSecurityContext opSecCtx = new OperationSecurityContext(this, null); + + /** Processor delegate. */ + private final GridSecurityProcessor processor; + + /** + * @param ctx Grid kernal context. + */ + public NoOpIgniteSecurityProcessor(GridKernalContext ctx, @Nullable GridSecurityProcessor processor) { + super(ctx); + this.processor =processor; + } + + /** {@inheritDoc} */ + @Override public void onKernalStart(boolean active) throws IgniteCheckedException { + super.onKernalStart(active); + + if(processor != null) + processor.onKernalStart(active); + } + + /** {@inheritDoc} */ + @Override public void onKernalStop(boolean cancel) { + super.onKernalStop(cancel); + + if(processor != null) + processor.onKernalStop(cancel); + } + + /** {@inheritDoc} */ + @Override public void start() throws IgniteCheckedException { + super.start(); + + if (processor != null) { + ctx.addNodeAttribute(ATTR_GRID_SEC_PROC_CLASS, processor.getClass().getName()); + + processor.start(); + } + else + ctx.addNodeAttribute(ATTR_GRID_SEC_PROC_CLASS, getClass().getName()); + } + + /** {@inheritDoc} */ + @Override public void stop(boolean cancel) throws IgniteCheckedException { + super.stop(cancel); + + if(processor != null) + processor.stop(cancel); + } + + /** {@inheritDoc} */ + @Override public OperationSecurityContext withContext(SecurityContext secCtx) { + return opSecCtx; + } + + /** {@inheritDoc} */ + @Override public OperationSecurityContext withContext(UUID nodeId) { + return opSecCtx; + } + + /** {@inheritDoc} */ + @Override public SecurityContext securityContext() { + return null; + } + + /** {@inheritDoc} */ + @Override public SecurityContext authenticateNode(ClusterNode node, SecurityCredentials cred) { + return null; + } + + /** {@inheritDoc} */ + @Override public boolean isGlobalNodeAuthentication() { + return false; + } + + /** {@inheritDoc} */ + @Override public SecurityContext authenticate(AuthenticationContext ctx) { + return null; + } + + /** {@inheritDoc} */ + @Override public Collection authenticatedSubjects() { + return null; + } + + /** {@inheritDoc} */ + @Override public SecuritySubject authenticatedSubject(UUID subjId) { + return null; + } + + /** {@inheritDoc} */ + @Override public void onSessionExpired(UUID subjId) { + // No-op. + } + + /** {@inheritDoc} */ + @Override public void authorize(String name, SecurityPermission perm) throws SecurityException { + // No-op. + } + + /** {@inheritDoc} */ + @Override public boolean enabled() { + if(processor != null) + return processor.enabled(); + + return false; + } + + /** {@inheritDoc} */ + @Override public @Nullable IgniteNodeValidationResult validateNode(ClusterNode node) { + IgniteNodeValidationResult res = validateSecProcClass(node); + + return res != null || processor == null ? res : processor.validateNode(node); + } + + /** {@inheritDoc} */ + @Override public @Nullable IgniteNodeValidationResult validateNode(ClusterNode node, + DiscoveryDataBag.JoiningNodeDiscoveryData discoData) { + IgniteNodeValidationResult res = validateSecProcClass(node); + + return res != null || processor == null ? res : processor.validateNode(node, discoData); + } + + /** + * Validates that remote the node's grid security processor class is undefined. + * + * @param node Joining node. + * @return Validation result or {@code null} in case of success. + */ + private IgniteNodeValidationResult validateSecProcClass(ClusterNode node){ + String rmtCls = node.attribute(ATTR_GRID_SEC_PROC_CLASS); + + boolean securityMsgSupported = IgniteFeatures.allNodesSupports(ctx.discovery().allNodes(), IgniteFeatures.IGNITE_SECURITY_PROCESSOR); + + if(securityMsgSupported && processor != null) { + String locCls = processor.getClass().getName(); + + // Compatibility. It allows connect an old node to a new cluster. + if (!processor.enabled() && rmtCls == null) + return null; + + if (!F.eq(locCls, rmtCls) && !F.eq(getClass().getName(), rmtCls)) { + return new IgniteNodeValidationResult(node.id(), + String.format(MSG_SEC_PROC_CLS_IS_INVALID, ctx.localNodeId(), node.id(), locCls, rmtCls), + String.format(MSG_SEC_PROC_CLS_IS_INVALID, node.id(), ctx.localNodeId(), rmtCls, locCls)); + } + + return null; + } + + if (securityMsgSupported && rmtCls != null && !rmtCls.equals(getClass().getName())) { + ClusterNode locNode = ctx.discovery().localNode(); + + return new IgniteNodeValidationResult( + node.id(), + String.format(MSG_SEC_PROC_CLS_IS_INVALID, locNode.id(), node.id(), "undefined", rmtCls), + String.format(MSG_SEC_PROC_CLS_IS_INVALID, node.id(), locNode.id(), rmtCls, "undefined") + ); + } + + return null; + } + + /** */ + public GridSecurityProcessor gridSecurityProcessor() { + return processor; + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/security/OperationSecurityContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/OperationSecurityContext.java new file mode 100644 index 0000000000000..3fdac47dc89d2 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/OperationSecurityContext.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.processors.security; + +/** + * + */ +public class OperationSecurityContext implements AutoCloseable { + /** Ignite Security. */ + private final IgniteSecurity proc; + + /** Security context. */ + private final SecurityContext secCtx; + + /** + * @param proc Ignite Security. + * @param secCtx Security context. + */ + OperationSecurityContext(IgniteSecurity proc, SecurityContext secCtx) { + assert proc != null; + assert secCtx != null || !proc.enabled(); + + this.proc = proc; + this.secCtx = secCtx; + } + + /** {@inheritDoc} */ + @Override public void close() { + proc.withContext(secCtx); + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/security/SecurityUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/SecurityUtils.java index 1016335888b3d..4a8858b4aa066 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/security/SecurityUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/SecurityUtils.java @@ -21,8 +21,14 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; +import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteSystemProperties; import org.apache.ignite.lang.IgniteProductVersion; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.internal.IgniteNodeAttributes; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.plugin.security.SecurityException; import org.apache.ignite.plugin.security.SecurityPermission; /** @@ -89,4 +95,27 @@ public static Map> compatibleServicePermi return srvcPerms; } + + /** + * Gets the node's security context. + * + * @param marsh Marshaller. + * @param ldr Class loader. + * @param node Node. + * @return Node's security context. + */ + public static SecurityContext nodeSecurityContext(Marshaller marsh, ClassLoader ldr, ClusterNode node) { + byte[] subjBytesV2 = node.attribute(IgniteNodeAttributes.ATTR_SECURITY_SUBJECT_V2); + byte[] subjBytes = node.attribute(IgniteNodeAttributes.ATTR_SECURITY_SUBJECT); + + if (subjBytes == null && subjBytesV2 == null) + throw new SecurityException("Security context isn't certain."); + + try { + return U.unmarshal(marsh, subjBytesV2 != null ? subjBytesV2 : subjBytes , ldr); + } + catch (IgniteCheckedException e) { + throw new SecurityException("Failed to get security context.", e); + } + } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/security/os/GridOsSecurityProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/os/GridOsSecurityProcessor.java deleted file mode 100644 index 42f9661cc005d..0000000000000 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/security/os/GridOsSecurityProcessor.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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.processors.security.os; - -import java.util.Collection; -import java.util.Collections; -import java.util.UUID; -import org.apache.ignite.IgniteCheckedException; -import org.apache.ignite.cluster.ClusterNode; -import org.apache.ignite.internal.GridKernalContext; -import org.apache.ignite.internal.processors.GridProcessorAdapter; -import org.apache.ignite.internal.processors.security.GridSecurityProcessor; -import org.apache.ignite.internal.processors.security.SecurityContext; -import org.apache.ignite.plugin.security.AuthenticationContext; -import org.apache.ignite.plugin.security.SecurityCredentials; -import org.apache.ignite.plugin.security.SecurityException; -import org.apache.ignite.plugin.security.SecurityPermission; -import org.apache.ignite.plugin.security.SecuritySubject; -import org.jetbrains.annotations.Nullable; - -/** - * No-op implementation for {@link GridSecurityProcessor}. - */ -public class GridOsSecurityProcessor extends GridProcessorAdapter implements GridSecurityProcessor { - /** - * @param ctx Kernal context. - */ - public GridOsSecurityProcessor(GridKernalContext ctx) { - super(ctx); - } - - /** {@inheritDoc} */ - @Override public SecurityContext authenticateNode(ClusterNode node, SecurityCredentials cred) - throws IgniteCheckedException { - return null; - } - - /** {@inheritDoc} */ - @Override public boolean isGlobalNodeAuthentication() { - return false; - } - - /** {@inheritDoc} */ - @Override public SecurityContext authenticate(AuthenticationContext authCtx) throws IgniteCheckedException { - return null; - } - - /** {@inheritDoc} */ - @Override public Collection authenticatedSubjects() { - return Collections.emptyList(); - } - - /** {@inheritDoc} */ - @Override public SecuritySubject authenticatedSubject(UUID nodeId) { - return null; - } - - /** {@inheritDoc} */ - @Override public void authorize(String name, SecurityPermission perm, @Nullable SecurityContext securityCtx) - throws SecurityException { - // No-op. - } - - /** {@inheritDoc} */ - @Override public void onSessionExpired(UUID subjId) { - // No-op. - } - - /** {@inheritDoc} */ - @Override public boolean enabled() { - return false; - } -} \ No newline at end of file diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java index b55f46e98c59a..cdd21cf4ccac2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java @@ -563,7 +563,7 @@ private PreparedConfigurations prepareServiceConfigurations(Collection T service(String name) { - ctx.security().authorize(name, SecurityPermission.SERVICE_INVOKE, null); + ctx.security().authorize(name, SecurityPermission.SERVICE_INVOKE); Collection ctxs; @@ -1079,7 +1079,7 @@ public ServiceContextImpl serviceContext(String name) { @SuppressWarnings("unchecked") public T serviceProxy(ClusterGroup prj, String name, Class svcItf, boolean sticky, long timeout) throws IgniteException { - ctx.security().authorize(name, SecurityPermission.SERVICE_INVOKE, null); + ctx.security().authorize(name, SecurityPermission.SERVICE_INVOKE); if (hasLocalNode(prj)) { ServiceContextImpl ctx = serviceContext(name); @@ -1120,7 +1120,7 @@ private boolean hasLocalNode(ClusterGroup prj) { */ @SuppressWarnings("unchecked") public Collection services(String name) { - ctx.security().authorize(name, SecurityPermission.SERVICE_INVOKE, null); + ctx.security().authorize(name, SecurityPermission.SERVICE_INVOKE); Collection ctxs; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/task/GridTaskProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/task/GridTaskProcessor.java index d3f64be4b9540..64d184d78c51e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/task/GridTaskProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/task/GridTaskProcessor.java @@ -581,7 +581,7 @@ private ComputeTaskInternalFuture startTask( thCtx.set(null); if (map.get(TC_SKIP_AUTH) == null) - ctx.security().authorize(taskClsName, SecurityPermission.TASK_EXECUTE, null); + ctx.security().authorize(taskClsName, SecurityPermission.TASK_EXECUTE); Long timeout = (Long)map.get(TC_TIMEOUT); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/query/VisorQueryUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/query/VisorQueryUtils.java index b590493cd90cd..406d4575b8b53 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/visor/query/VisorQueryUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/query/VisorQueryUtils.java @@ -30,6 +30,7 @@ import javax.cache.Cache; import org.apache.ignite.IgniteCache; import org.apache.ignite.IgniteException; +import org.apache.ignite.IgniteLogger; import org.apache.ignite.binary.BinaryObject; import org.apache.ignite.binary.BinaryObjectException; import org.apache.ignite.binary.BinaryType; @@ -44,6 +45,8 @@ import org.apache.ignite.internal.processors.cache.query.QueryCursorEx; import org.apache.ignite.internal.processors.query.GridQueryCancel; import org.apache.ignite.internal.processors.query.GridQueryFieldMetadata; +import org.apache.ignite.internal.processors.security.OperationSecurityContext; +import org.apache.ignite.internal.processors.security.SecurityContext; import org.apache.ignite.internal.processors.timeout.GridTimeoutObjectAdapter; import org.apache.ignite.internal.util.IgniteUtils; import org.apache.ignite.internal.util.typedef.F; @@ -361,8 +364,15 @@ public static void scheduleQueryStart( final VisorQueryTaskArg arg, final GridQueryCancel cancel ) { + SecurityContext initCtx = ignite.context().security().securityContext(); + ignite.context().closure().runLocalSafe(() -> { - try { + IgniteLogger log = ignite.log(); + + try(OperationSecurityContext ctx = ignite.context().security().withContext(initCtx)) { + if (log.isDebugEnabled()) + log.debug("Operation started with subject: " + ignite.context().security().securityContext().subject()); + SqlFieldsQuery qry = new SqlFieldsQuery(arg.getQueryText()); qry.setPageSize(arg.getPageSize()); @@ -428,6 +438,8 @@ public static void scheduleQueryStart( } } catch (Throwable e) { + log.warning("Fail to execute query.", e); + holder.setError(e); } }, MANAGEMENT_POOL); diff --git a/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityPermissionSetBuilder.java b/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityPermissionSetBuilder.java index 659613aa0e8c5..2eca640e4fa5b 100644 --- a/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityPermissionSetBuilder.java +++ b/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityPermissionSetBuilder.java @@ -67,13 +67,16 @@ public class SecurityPermissionSetBuilder { /** Default allow all.*/ private boolean dfltAllowAll; + /** */ + public static final SecurityPermissionSet ALLOW_ALL = create().defaultAllowAll(true).build(); + /** * Static factory method for create new permission builder. * * @return SecurityPermissionSetBuilder */ - public static SecurityPermissionSetBuilder create(){ - return new SecurityPermissionSetBuilder(); + public static SecurityPermissionSetBuilder create() { + return new SecurityPermissionSetBuilder().defaultAllowAll(true); } /** diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java index f5f9110b81da3..64d234a5584e0 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java @@ -170,6 +170,7 @@ import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MARSHALLER_COMPACT_FOOTER; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MARSHALLER_USE_BINARY_STRING_SER_VER_2; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MARSHALLER_USE_DFLT_SUID; +import static org.apache.ignite.internal.processors.security.SecurityUtils.nodeSecurityContext; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_SERVICES_COMPATIBILITY_MODE; import static org.apache.ignite.spi.IgnitePortProtocol.TCP; import static org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoverySpiState.AUTH_FAILED; @@ -1177,6 +1178,22 @@ private void localAuthentication(SecurityCredentials locCred){ } } + /** + * @param obj Object. + * @param ver Security serialize version. + * @return Marshaled object. + */ + private byte[] marshalWithSecurityVersion(Object obj, int ver) throws IgniteCheckedException { + try { + SecurityUtils.serializeVersion(ver); + + return U.marshal(spi.marshaller(), obj); + } + finally { + SecurityUtils.restoreDefaultSerializeVersion(); + } + } + /** * Tries to send join request message to a random node presenting in topology. * Address is provided by {@link org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder} and message is @@ -2289,39 +2306,6 @@ private void processMessageFailedNodes(TcpDiscoveryAbstractMessage msg) { } } - /** - * @param obj Object. - * @param ver Security serialize version. - * @return Marshaled object. - */ - private byte[] marshalWithSecurityVersion(Object obj, int ver) throws IgniteCheckedException { - try { - SecurityUtils.serializeVersion(ver); - - return U.marshal(spi.marshaller(), obj); - } - finally { - SecurityUtils.restoreDefaultSerializeVersion(); - } - } - - /** - * @param bytes Marshaled object. - * @param ver Security serialize version. - * @return Unmarshaled object. - */ - private T unmarshalWithSecurityVersion(byte[] bytes, int ver) throws IgniteCheckedException { - try { - if (ver > 0) - SecurityUtils.serializeVersion(ver); - - return spi.marshaller().unmarshal(bytes, U.resolveClassLoader(spi.ignite().configuration())); - } - finally { - SecurityUtils.restoreDefaultSerializeVersion(); - } - } - /** */ private static WorkersRegistry getWorkerRegistry(TcpDiscoverySpi spi) { return spi.ignite() instanceof IgniteEx ? ((IgniteEx)spi.ignite()).context().workersRegistry() : null; @@ -4715,22 +4699,9 @@ else if (!locNodeId.equals(node.id()) && ring.node(node.id()) != null) { else { SecurityContext subj = spi.nodeAuth.authenticateNode(node, cred); - byte[] subjBytes = node.attribute(IgniteNodeAttributes.ATTR_SECURITY_SUBJECT); - byte[] subjBytesV2 = node.attribute(IgniteNodeAttributes.ATTR_SECURITY_SUBJECT_V2); - - SecurityContext coordSubj; - - try { - if (subjBytesV2 == null) - SecurityUtils.serializeVersion(1); - - coordSubj = U.unmarshal(spi.marshaller(), - subjBytesV2 != null ? subjBytesV2 : subjBytes, - U.resolveClassLoader(spi.ignite().configuration())); - } - finally { - SecurityUtils.restoreDefaultSerializeVersion(); - } + SecurityContext coordSubj = nodeSecurityContext( + spi.marshaller(), U.resolveClassLoader(spi.ignite().configuration()), node + ); if (!permissionsEqual(coordSubj.subject().permissions(), subj.subject().permissions())) { // Node has not pass authentication. @@ -4747,7 +4718,7 @@ else if (!locNodeId.equals(node.id()) && ring.node(node.id()) != null) { authFailed = false; } } - catch (IgniteException | IgniteCheckedException e) { + catch (IgniteException e) { U.error(log, "Failed to verify node permissions consistency (will drop the node): " + node, e); } finally { @@ -4823,23 +4794,15 @@ else if (spiState == CONNECTING) new TcpDiscoveryAuthFailedMessage(locNodeId, spi.locHost, node.id()); try { - byte[] rmSubj = node.attribute(IgniteNodeAttributes.ATTR_SECURITY_SUBJECT); - byte[] locSubj = locNode.attribute(IgniteNodeAttributes.ATTR_SECURITY_SUBJECT); - - byte[] rmSubjV2 = node.attribute(IgniteNodeAttributes.ATTR_SECURITY_SUBJECT_V2); - byte[] locSubjV2 = locNode.attribute(IgniteNodeAttributes.ATTR_SECURITY_SUBJECT_V2); - - int ver = 1; // Compatible version. - - if (rmSubjV2 != null && locSubjV2 != null) { - rmSubj = rmSubjV2; - locSubj = locSubjV2; + ClassLoader ldr = U.resolveClassLoader(spi.ignite().configuration()); - ver = 0; // Default version. - } + SecurityContext rmCrd = nodeSecurityContext( + spi.marshaller(), ldr, node + ); - SecurityContext rmCrd = unmarshalWithSecurityVersion(rmSubj, ver); - SecurityContext locCrd = unmarshalWithSecurityVersion(locSubj, ver); + SecurityContext locCrd = nodeSecurityContext( + spi.marshaller(), ldr, locNode + ); if (!permissionsEqual(locCrd.subject().permissions(), rmCrd.subject().permissions())) { @@ -4858,7 +4821,7 @@ else if (spiState == CONNECTING) return; } } - catch (IgniteCheckedException e) { + catch (IgniteException e) { U.error(log, "Failed to verify node permissions consistency (will drop the node): " + node, e); joinRes.set(authFail); diff --git a/modules/core/src/test/java/META-INF/services/org.apache.ignite.plugin.PluginProvider b/modules/core/src/test/java/META-INF/services/org.apache.ignite.plugin.PluginProvider index 1c03b7c5f3211..84b3113346dcd 100644 --- a/modules/core/src/test/java/META-INF/services/org.apache.ignite.plugin.PluginProvider +++ b/modules/core/src/test/java/META-INF/services/org.apache.ignite.plugin.PluginProvider @@ -1,3 +1,3 @@ -org.apache.ignite.spi.discovery.tcp.TestReconnectPluginProvider +org.apache.ignite.internal.processors.security.impl.TestSecurityProcessorProvider org.apache.ignite.internal.processors.cache.persistence.standbycluster.IgniteStandByClusterTest$StanByClusterTestProvider org.apache.ignite.internal.processors.cache.persistence.wal.memtracker.PageMemoryTrackerPluginProvider diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteOptimisticTxSuspendResumeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteOptimisticTxSuspendResumeTest.java index 486fd6075d2ca..705cd037f7b60 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteOptimisticTxSuspendResumeTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteOptimisticTxSuspendResumeTest.java @@ -36,6 +36,7 @@ import org.apache.ignite.internal.util.typedef.X; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.GridTestUtils.RunnableX; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import org.apache.ignite.transactions.Transaction; import org.apache.ignite.transactions.TransactionIsolation; @@ -787,26 +788,4 @@ public static abstract class CI1Exc implements CI1 { } } } - - /** - * Runnable that can throw any exception. - */ - public static abstract class RunnableX implements Runnable { - /** - * Closure body. - * - * @throws Exception If failed. - */ - public abstract void runx() throws Exception; - - /** {@inheritdoc} */ - @Override public void run() { - try { - runx(); - } - catch (Exception e) { - throw new RuntimeException(e); - } - } - } } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/AbstractCacheOperationPermissionCheckTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/AbstractCacheOperationPermissionCheckTest.java new file mode 100644 index 0000000000000..46c88cda503e4 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/AbstractCacheOperationPermissionCheckTest.java @@ -0,0 +1,77 @@ +/* + * 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.processors.security; + +import java.util.concurrent.atomic.AtomicInteger; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.util.typedef.T2; + +/** + * + */ +public abstract class AbstractCacheOperationPermissionCheckTest extends AbstractSecurityTest { + /** Cache name for tests. */ + protected static final String CACHE_NAME = "TEST_CACHE"; + + /** Forbidden cache. */ + protected static final String FORBIDDEN_CACHE = "FORBIDDEN_TEST_CACHE"; + + /** Values. */ + protected AtomicInteger values = new AtomicInteger(0); + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + startGridAllowAll("server").cluster().active(true); + } + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + return super.getConfiguration(igniteInstanceName) + .setCacheConfiguration(getCacheConfigurations()); + } + + /** + * @return Array of cache configurations. + */ + protected CacheConfiguration[] getCacheConfigurations() { + return new CacheConfiguration[] { + new CacheConfiguration().setName(CACHE_NAME), + new CacheConfiguration().setName(FORBIDDEN_CACHE) + }; + } + + /** + * Getting login prefix. + * + * @param isClient True if is client mode. + * @return Prefix. + */ + protected String loginPrefix(boolean isClient) { + return isClient ? "client" : "server"; + } + + /** + * @return Cache entry for test. + */ + protected T2 entry() { + int val = values.incrementAndGet(); + + return new T2<>("key_" + val, -1 * val); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/AbstractCacheOperationRemoteSecurityContextCheckTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/AbstractCacheOperationRemoteSecurityContextCheckTest.java new file mode 100644 index 0000000000000..f7380c2d513c5 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/AbstractCacheOperationRemoteSecurityContextCheckTest.java @@ -0,0 +1,72 @@ +/* + * 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.processors.security; + +import org.apache.ignite.cache.CacheMode; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.util.typedef.G; + +/** + * + */ +public abstract class AbstractCacheOperationRemoteSecurityContextCheckTest extends AbstractRemoteSecurityContextCheckTest { + /** Cache name for tests. */ + protected static final String CACHE_NAME = "TEST_CACHE"; + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + return super.getConfiguration(igniteInstanceName) + .setCacheConfiguration(getCacheConfigurations()); + } + + /** + * Getting array of cache configurations. + */ + protected CacheConfiguration[] getCacheConfigurations() { + return new CacheConfiguration[] { + new CacheConfiguration<>() + .setName(CACHE_NAME) + .setCacheMode(CacheMode.PARTITIONED) + }; + } + + /** + * Getting the key that is contained on primary partition on passed node for {@link #CACHE_NAME} cache. + * + * @param ignite Node. + * @return Key. + */ + protected Integer prmKey(IgniteEx ignite) { + return findKeys(ignite.localNode(), ignite.cache(CACHE_NAME), 1, 0, 0) + .stream() + .findFirst() + .orElseThrow(() -> new IllegalStateException(ignite.name() + " isn't primary node for any key.")); + } + + /** + * Getting the key that is contained on primary partition on passed node for {@link #CACHE_NAME} cache. + * + * @param nodeName Node name. + * @return Key. + */ + protected Integer prmKey(String nodeName) { + return prmKey((IgniteEx)G.ignite(nodeName)); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/AbstractRemoteSecurityContextCheckTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/AbstractRemoteSecurityContextCheckTest.java new file mode 100644 index 0000000000000..29944dc3c237b --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/AbstractRemoteSecurityContextCheckTest.java @@ -0,0 +1,349 @@ +/* + * 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.processors.security; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Stream; +import javax.cache.Cache; +import javax.cache.processor.EntryProcessor; +import javax.cache.processor.MutableEntry; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteCompute; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.util.typedef.T2; +import org.apache.ignite.lang.IgniteBiInClosure; +import org.apache.ignite.lang.IgniteBiPredicate; +import org.apache.ignite.lang.IgniteCallable; +import org.apache.ignite.lang.IgniteClosure; +import org.apache.ignite.lang.IgniteRunnable; + +import static org.apache.ignite.Ignition.localIgnite; + +/** + * + */ +public abstract class AbstractRemoteSecurityContextCheckTest extends AbstractSecurityTest { + /** Name of server initiator node. */ + protected static final String SRV_INITIATOR = "srv_initiator"; + + /** Name of client initiator node. */ + protected static final String CLNT_INITIATOR = "clnt_initiator"; + + /** Name of server feature call node. */ + protected static final String SRV_RUN = "srv_run"; + + /** Name of client feature call node. */ + protected static final String CLNT_RUN = "clnt_run"; + + /** Name of server feature transit node. */ + protected static final String SRV_CHECK = "srv_check"; + + /** Name of client feature transit node. */ + protected static final String CLNT_CHECK = "clnt_check"; + + /** Name of server endpoint node. */ + protected static final String SRV_ENDPOINT = "srv_endpoint"; + + /** Name of client endpoint node. */ + protected static final String CLNT_ENDPOINT = "clnt_endpoint"; + + /** Verifier to check results of tests. */ + protected static final Verifier VERIFIER = new Verifier(); + + /** + * @return IgniteCompute is produced by passed node for cluster group that contains nodes with ids from collection. + */ + protected static IgniteCompute compute(Ignite ignite, Collection ids) { + return ignite.compute(ignite.cluster().forNodeIds(ids)); + } + + /** + * @return Collection of feature call nodes ids. + */ + protected Collection nodesToRun() { + return Arrays.asList(nodeId(SRV_RUN), nodeId(CLNT_RUN)); + } + + /** + * @return Collection of feature transit nodes ids. + */ + protected Collection nodesToCheck() { + return Arrays.asList(nodeId(SRV_CHECK), nodeId(CLNT_CHECK)); + } + + /** + * @return Collection of endpont nodes ids. + */ + protected Collection endpoints() { + return Arrays.asList(nodeId(SRV_ENDPOINT), nodeId(CLNT_ENDPOINT)); + } + + /** + * @param name Node name. + * @return Node id. + */ + protected UUID nodeId(String name) { + return grid(name).context().discovery().localNode().id(); + } + + /** + * Setups expected behavior to passed verifier. + */ + protected abstract void setupVerifier(Verifier verifier); + + /** + * @param initiator Node that initiates an execution. + * @param op Operation. + */ + protected void runAndCheck(IgniteEx initiator, IgniteRunnable op) { + runAndCheck(initiator, Stream.of(op)); + } + + /** + * Sets up VERIFIER, performs the runnable and checks the result. + * + * @param initiator Node that initiates an execution. + * @param ops Operations. + */ + protected void runAndCheck(IgniteEx initiator, Stream ops) { + ops.forEach(r -> { + VERIFIER.clear().initiator(initiator); + + setupVerifier(VERIFIER); + + compute(initiator, nodesToRun()).broadcast(r); + + VERIFIER.checkResult(); + }); + } + + /** + * Responsible for verifying of tests results. + */ + public static class Verifier { + /** + * Map that contains an expected behaviour. + */ + private final Map> expInvokes = new HashMap<>(); + + /** + * List of registered security subjects. + */ + private final List> registeredSubjects = new ArrayList<>(); + + /** + * Expected security subject id. + */ + private UUID expSecSubjId; + + /** */ + private Verifier clear() { + registeredSubjects.clear(); + expInvokes.clear(); + + expSecSubjId = null; + + return this; + } + + /** + * Adds expected behaivior the method {@link #register} will be invoke exp times on the node with + * passed name. + * + * @param nodeName Node name. + * @param num Expected number of invokes. + */ + public Verifier expect(String nodeName, int num) { + expInvokes.put(nodeName, new T2<>(num, 0)); + + return this; + } + + /** + * Registers current security context and increments invoke's counter. + */ + public synchronized void register() { + IgniteEx ignite = (IgniteEx)localIgnite(); + + registeredSubjects.add(new T2<>(secSubjectId(ignite), ignite.name())); + + expInvokes.computeIfPresent(ignite.name(), (name, t2) -> { + Integer val = t2.getValue(); + + t2.setValue(++val); + + return t2; + }); + } + + /** + * Checks result of test and clears expected behavior. + */ + private void checkResult() { + registeredSubjects.forEach(t -> + assertEquals("Invalide security context on node " + t.get2(), + t.get1(), expSecSubjId) + ); + + expInvokes.forEach((key, value) -> + assertEquals("Node " + key + ". Execution of register: ", + value.get2(), value.get1())); + + clear(); + } + + /** */ + private Verifier expectSubjId(UUID expSecSubjId) { + this.expSecSubjId = expSecSubjId; + + return this; + } + + /** */ + private void initiator(IgniteEx initiator) { + expSecSubjId = secSubjectId(initiator); + } + + /** */ + private UUID secSubjectId(IgniteEx node) { + return node.context().security().securityContext().subject().id(); + } + } + + /** */ + protected static class ExecRegisterAndForwardAdapter implements IgniteBiInClosure { + /** RegisterExecAndForward. */ + private RegisterExecAndForward instance; + + /** + * @param endpoints Collection of endpont nodes ids. + */ + public ExecRegisterAndForwardAdapter(Collection endpoints) { + instance = new RegisterExecAndForward<>(endpoints); + } + + /** {@inheritDoc} */ + @Override public void apply(K k, V v) { + instance.run(); + } + } + + /** */ + protected RegisterExecAndForward createRunner(String srvName) { + return new RegisterExecAndForward<>(srvName, endpoints()); + } + + /** */ + protected RegisterExecAndForward createRunner() { + return new RegisterExecAndForward<>(endpoints()); + } + + /** */ + protected static class RegisterExecAndForward implements IgniteBiPredicate, IgniteRunnable, + IgniteCallable, EntryProcessor, IgniteClosure { + /** Runnable. */ + private final IgniteRunnable runnable; + + /** Expected local node name. */ + private final String node; + + /** Collection of endpoint node ids. */ + private final Collection endpoints; + + /** + * @param runnable Runnable. + */ + public RegisterExecAndForward(IgniteRunnable runnable) { + this.runnable = Objects.requireNonNull(runnable); + node = null; + endpoints = Collections.emptyList(); + } + + /** + * @param node Expected local node name. + * @param endpoints Collection of endpont nodes ids. + */ + public RegisterExecAndForward(String node, Collection endpoints) { + this.node = node; + this.endpoints = endpoints; + runnable = null; + } + + /** + * @param endpoints Collection of endpont nodes ids. + */ + public RegisterExecAndForward(Collection endpoints) { + this.endpoints = endpoints; + runnable = null; + node = null; + } + + /** {@inheritDoc} */ + @Override public boolean apply(K k, V v) { + run(); + + return false; + } + + /** {@inheritDoc} */ + @Override public void run() { + Ignite loc = localIgnite(); + + if (node == null || node.equals(loc.name())) { + VERIFIER.register(); + + if (runnable != null) + runnable.run(); + else + compute(loc, endpoints).broadcast(() -> VERIFIER.register()); + } + } + + /** {@inheritDoc} */ + @Override public Object process(MutableEntry mutableEntry, Object... objects) { + run(); + + return null; + } + + /** {@inheritDoc} */ + @Override public V apply(K k) { + run(); + + if (k instanceof Cache.Entry) + return (V) ((Cache.Entry)k).getValue(); + + return null; + } + + /** {@inheritDoc} */ + @Override public V call() { + run(); + + return null; + } + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/AbstractSecurityTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/AbstractSecurityTest.java new file mode 100644 index 0000000000000..165c46a3e2d76 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/AbstractSecurityTest.java @@ -0,0 +1,97 @@ +/* + * 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.processors.security; + +import java.util.Arrays; +import org.apache.ignite.configuration.DataRegionConfiguration; +import org.apache.ignite.configuration.DataStorageConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.processors.security.impl.TestSecurityData; +import org.apache.ignite.internal.processors.security.impl.TestSecurityPluginConfiguration; +import org.apache.ignite.internal.processors.security.impl.TestSecurityProcessor; +import org.apache.ignite.plugin.security.SecurityPermission; +import org.apache.ignite.plugin.security.SecurityPermissionSet; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; + +import static org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.ALLOW_ALL; + +/** + * Common class for security tests. + */ +public class AbstractSecurityTest extends GridCommonAbstractTest { + /** Empty array of permissions. */ + protected static final SecurityPermission[] EMPTY_PERMS = new SecurityPermission[0]; + + /** {@inheritDoc} */ + @Override protected void afterTestsStopped() throws Exception { + stopAllGrids(); + + cleanPersistenceDir(); + } + + /** + * @param instanceName Instance name. + * @param secCfg Security plugin configuration. + */ + protected IgniteConfiguration getConfiguration(String instanceName, + TestSecurityPluginConfiguration secCfg) throws Exception { + + return getConfiguration(instanceName) + .setDataStorageConfiguration( + new DataStorageConfiguration() + .setDefaultDataRegionConfiguration( + new DataRegionConfiguration().setPersistenceEnabled(true) + ) + ) + .setAuthenticationEnabled(true) + .setPluginConfigurations(secCfg); + } + + /** + * @param login Login. + * @param pwd Password. + * @param prmSet Security permission set. + * @return Security plaugin configuration. + */ + protected TestSecurityPluginConfiguration secPluginCfg(String login, String pwd, SecurityPermissionSet prmSet, + TestSecurityData... clientData) { + return ctx -> new TestSecurityProcessor(ctx, + new TestSecurityData(login, pwd, prmSet), + Arrays.asList(clientData)); + } + + /** */ + protected IgniteEx startGridAllowAll(String login) throws Exception { + return startGrid(login, ALLOW_ALL, false); + } + + /** */ + protected IgniteEx startClientAllowAll(String login) throws Exception { + return startGrid(login, ALLOW_ALL, true); + } + + /** + * @param login Login. + * @param prmSet Security permission set. + * @param isClient Is client. + */ + protected IgniteEx startGrid(String login, SecurityPermissionSet prmSet, boolean isClient) throws Exception { + return startGrid(getConfiguration(login, secPluginCfg(login, "", prmSet)).setClientMode(isClient)); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/CacheOperationPermissionCheckTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/CacheOperationPermissionCheckTest.java new file mode 100644 index 0000000000000..8ed85609f39f3 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/CacheOperationPermissionCheckTest.java @@ -0,0 +1,89 @@ +/* + * 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.processors.security.cache; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteCache; +import org.apache.ignite.internal.processors.security.AbstractCacheOperationPermissionCheckTest; +import org.apache.ignite.plugin.security.SecurityException; +import org.apache.ignite.plugin.security.SecurityPermissionSetBuilder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static java.util.Collections.singletonMap; +import static org.apache.ignite.plugin.security.SecurityPermission.CACHE_PUT; +import static org.apache.ignite.plugin.security.SecurityPermission.CACHE_READ; +import static org.apache.ignite.plugin.security.SecurityPermission.CACHE_REMOVE; +import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause; + +/** + * Test CRUD cache permissions. + */ +public class CacheOperationPermissionCheckTest extends AbstractCacheOperationPermissionCheckTest { + /** */ + public void testServerNode() throws Exception { + testCrudCachePermissions(false); + } + + /** */ + public void testClientNode() throws Exception { + testCrudCachePermissions(true); + } + + /** + * @param isClient True if is client mode. + * @throws Exception If failed. + */ + private void testCrudCachePermissions(boolean isClient) throws Exception { + Ignite node = startGrid(loginPrefix(isClient) + "_test_node", + SecurityPermissionSetBuilder.create() + .appendCachePermissions(CACHE_NAME, CACHE_READ, CACHE_PUT, CACHE_REMOVE) + .appendCachePermissions(FORBIDDEN_CACHE, EMPTY_PERMS).build(), isClient); + + for (Consumer> c : operations()) { + c.accept(node.cache(CACHE_NAME)); + + assertThrowsWithCause(() -> c.accept(node.cache(FORBIDDEN_CACHE)), SecurityException.class); + } + } + + /** + * @return Collection of operations to invoke a cache operation. + */ + private List>> operations() { + return Arrays.asList( + c -> c.put("key", "value"), + c -> c.putAll(singletonMap("key", "value")), + c -> c.get("key"), + c -> c.getAll(Collections.singleton("key")), + c -> c.containsKey("key"), + c -> c.remove("key"), + c -> c.removeAll(Collections.singleton("key")), + IgniteCache::clear, + c -> c.replace("key", "value"), + c -> c.putIfAbsent("key", "value"), + c -> c.getAndPut("key", "value"), + c -> c.getAndRemove("key"), + c -> c.getAndReplace("key", "value") + ); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/EntryProcessorPermissionCheckTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/EntryProcessorPermissionCheckTest.java new file mode 100644 index 0000000000000..8dfa818ea605f --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/EntryProcessorPermissionCheckTest.java @@ -0,0 +1,114 @@ +/* + * 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.processors.security.cache; + +import java.util.Arrays; +import java.util.List; +import java.util.function.BiConsumer; +import java.util.stream.Stream; +import org.apache.ignite.Ignite; +import org.apache.ignite.cache.CacheEntryProcessor; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.processors.security.AbstractCacheOperationPermissionCheckTest; +import org.apache.ignite.internal.util.typedef.T2; +import org.apache.ignite.plugin.security.SecurityException; +import org.apache.ignite.plugin.security.SecurityPermissionSetBuilder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static java.util.Collections.singleton; +import static org.apache.ignite.plugin.security.SecurityPermission.CACHE_PUT; +import static org.apache.ignite.plugin.security.SecurityPermission.CACHE_READ; +import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +/** + * Test cache permission for Entry processor. + */ +public class EntryProcessorPermissionCheckTest extends AbstractCacheOperationPermissionCheckTest { + /** */ + public void test() throws Exception { + IgniteEx verifierNode = startGrid("verifier_node", + SecurityPermissionSetBuilder.create() + .appendCachePermissions(CACHE_NAME, CACHE_READ) + .appendCachePermissions(FORBIDDEN_CACHE, CACHE_READ).build(), false); + + IgniteEx srvNode = startGrid("server_node", + SecurityPermissionSetBuilder.create() + .appendCachePermissions(CACHE_NAME, CACHE_READ, CACHE_PUT) + .appendCachePermissions(FORBIDDEN_CACHE, EMPTY_PERMS).build(), false); + + IgniteEx clientNode = startGrid("client_node", + SecurityPermissionSetBuilder.create() + .appendCachePermissions(CACHE_NAME, CACHE_PUT, CACHE_READ) + .appendCachePermissions(FORBIDDEN_CACHE, EMPTY_PERMS).build(), true); + + srvNode.cluster().active(true); + + Stream.of(srvNode, clientNode).forEach(n -> + operations(n).forEach(c -> { + runOperation(verifierNode, c); + + runForbiddenOperation(verifierNode, c); + }) + ); + } + + /** */ + private void runOperation(Ignite verifierNode, BiConsumer> c) { + T2 entry = entry(); + + c.accept(CACHE_NAME, entry); + + assertEquals(verifierNode.cache(CACHE_NAME).get(entry.getKey()), entry.getValue()); + } + + /** */ + private void runForbiddenOperation(Ignite verifierNode, BiConsumer> c) { + T2 entry = entry(); + + assertThrowsWithCause(() -> c.accept(FORBIDDEN_CACHE, entry), SecurityException.class); + + assertNull(verifierNode.cache(FORBIDDEN_CACHE).get(entry.getKey())); + } + + /** + * @return Collection of operations to invoke entry processor. + */ + private List>> operations(final Ignite node) { + return Arrays.asList( + (cacheName, t) -> node.cache(cacheName).invoke(t.getKey(), processor(t)), + (cacheName, t) -> node.cache(cacheName).invokeAll(singleton(t.getKey()), processor(t)), + (cacheName, t) -> node.cache(cacheName).invokeAsync(t.getKey(), processor(t)).get(), + (cacheName, t) -> node.cache(cacheName).invokeAllAsync(singleton(t.getKey()), processor(t)).get() + ); + } + + /** + * @param t T2. + */ + private CacheEntryProcessor processor(T2 t) { + return (entry, o) -> { + entry.setValue(t.getValue()); + + return null; + }; + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/ScanQueryPermissionCheckTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/ScanQueryPermissionCheckTest.java new file mode 100644 index 0000000000000..72f59ea5e6f4b --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/ScanQueryPermissionCheckTest.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.internal.processors.security.cache; + +import java.util.Arrays; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteDataStreamer; +import org.apache.ignite.cache.query.ScanQuery; +import org.apache.ignite.internal.processors.security.AbstractCacheOperationPermissionCheckTest; +import org.apache.ignite.internal.util.typedef.G; +import org.apache.ignite.plugin.security.SecurityException; +import org.apache.ignite.plugin.security.SecurityPermissionSetBuilder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +import static org.apache.ignite.plugin.security.SecurityPermission.CACHE_READ; +import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause; + +/** + * Test cache permission for invoking of Scan Query. + */ +public class ScanQueryPermissionCheckTest extends AbstractCacheOperationPermissionCheckTest { + /** Parameters. */ + @Parameters(name = "clientMode={0}") + public static Iterable data() { + return Arrays.asList(new Boolean[] {true}, new Boolean[] {false}); + } + + /** Client mode. */ + @Parameter() + public boolean clientMode; + + /** */ + public void testScanQuery() throws Exception { + Ignite ignite = G.allGrids().stream().findFirst().orElseThrow(IllegalStateException::new); + + try (IgniteDataStreamer strAllowedCache = ignite.dataStreamer(CACHE_NAME); + IgniteDataStreamer strForbiddenCache = ignite.dataStreamer(FORBIDDEN_CACHE)) { + for (int i = 1; i <= 10; i++) { + strAllowedCache.addData(Integer.toString(i), i); + strForbiddenCache.addData(Integer.toString(i), i); + } + } + + Ignite node = startGrid(loginPrefix(clientMode) + "_test_node", + SecurityPermissionSetBuilder.create() + .appendCachePermissions(CACHE_NAME, CACHE_READ) + .appendCachePermissions(FORBIDDEN_CACHE, EMPTY_PERMS).build(), clientMode); + + assertFalse(node.cache(CACHE_NAME).query(new ScanQuery()).getAll().isEmpty()); + + assertThrowsWithCause(() -> node.cache(FORBIDDEN_CACHE).query(new ScanQuery()).getAll(), + SecurityException.class); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/closure/CacheLoadRemoteSecurityContextCheckTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/closure/CacheLoadRemoteSecurityContextCheckTest.java new file mode 100644 index 0000000000000..729e9c7b79683 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/closure/CacheLoadRemoteSecurityContextCheckTest.java @@ -0,0 +1,147 @@ +/* + * 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.processors.security.cache.closure; + +import java.util.Collection; +import java.util.Collections; +import java.util.UUID; +import javax.cache.Cache; +import javax.cache.configuration.Factory; +import org.apache.ignite.cache.CacheMode; +import org.apache.ignite.cache.store.CacheStoreAdapter; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.internal.processors.security.AbstractCacheOperationRemoteSecurityContextCheckTest; +import org.apache.ignite.internal.util.typedef.G; +import org.apache.ignite.lang.IgniteBiInClosure; +import org.apache.ignite.lang.IgniteRunnable; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static org.apache.ignite.Ignition.localIgnite; + +/** + * Testing operation security context when the filter of Load cache is executed on remote node. + *

      + * The initiator node broadcasts a task to 'run' node that starts load cache with filter. That filter is + * executed on 'check' node and broadcasts a task to 'endpoint' nodes. On every step, it is performed + * verification that operation security context is the initiator context. + */ +public class CacheLoadRemoteSecurityContextCheckTest extends AbstractCacheOperationRemoteSecurityContextCheckTest { + /** Transition load cache. */ + private static final String TRANSITION_LOAD_CACHE = "TRANSITION_LOAD_CACHE"; + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + startGridAllowAll(SRV_INITIATOR); + + startClientAllowAll(CLNT_INITIATOR); + + startGridAllowAll(SRV_RUN); + + startGridAllowAll(SRV_CHECK); + + startGridAllowAll(SRV_ENDPOINT); + + startClientAllowAll(CLNT_ENDPOINT); + + G.allGrids().get(0).cluster().active(true); + } + + /** {@inheritDoc} */ + @Override protected CacheConfiguration[] getCacheConfigurations() { + return new CacheConfiguration[] { + new CacheConfiguration() + .setName(CACHE_NAME) + .setCacheMode(CacheMode.PARTITIONED) + .setCacheStoreFactory(new TestStoreFactory()), + new CacheConfiguration() + .setName(TRANSITION_LOAD_CACHE) + .setCacheMode(CacheMode.PARTITIONED) + .setCacheStoreFactory(new TestStoreFactory()) + }; + } + + /** {@inheritDoc} */ + @Override protected void setupVerifier(Verifier verifier) { + verifier + .expect(SRV_RUN, 1) + .expect(SRV_CHECK, 1) + .expect(SRV_ENDPOINT, 1) + .expect(CLNT_ENDPOINT, 1); + } + + /** */ + public void test() throws Exception { + IgniteRunnable operation = () -> { + VERIFIER.register(); + + localIgnite().cache(CACHE_NAME).loadCache( + new RegisterExecAndForward<>(SRV_CHECK, endpoints()) + ); + }; + + runAndCheck(grid(SRV_INITIATOR), operation); + runAndCheck(grid(CLNT_INITIATOR), operation); + } + + /** {@inheritDoc} */ + @Override protected Collection nodesToRun() { + return Collections.singletonList(nodeId(SRV_RUN)); + } + + /** {@inheritDoc} */ + @Override protected Collection nodesToCheck() { + return Collections.singletonList(nodeId(SRV_CHECK)); + } + + /** + * Test store factory. + */ + private static class TestStoreFactory implements Factory { + /** {@inheritDoc} */ + @Override public TestCacheStore create() { + return new TestCacheStore(); + } + } + + /** + * Test cache store. + */ + private static class TestCacheStore extends CacheStoreAdapter { + /** {@inheritDoc} */ + @Override public void loadCache(IgniteBiInClosure clo, Object... args) { + clo.apply(1, 1); + } + + /** {@inheritDoc} */ + @Override public Integer load(Integer key) { + return key; + } + + /** {@inheritDoc} */ + @Override public void write(Cache.Entry entry) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @Override public void delete(Object key) { + // No-op. + } + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/closure/EntryProcessorRemoteSecurityContextCheckTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/closure/EntryProcessorRemoteSecurityContextCheckTest.java new file mode 100644 index 0000000000000..d8a3c0e189802 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/closure/EntryProcessorRemoteSecurityContextCheckTest.java @@ -0,0 +1,101 @@ +/* + * 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.processors.security.cache.closure; + +import java.util.Collection; +import java.util.Collections; +import java.util.UUID; +import java.util.stream.Stream; +import org.apache.ignite.internal.processors.security.AbstractCacheOperationRemoteSecurityContextCheckTest; +import org.apache.ignite.internal.util.typedef.G; +import org.apache.ignite.lang.IgniteRunnable; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static java.util.Collections.singleton; +import static org.apache.ignite.Ignition.localIgnite; + +/** + * Testing operation security context when EntryProcessor closure is executed on remote node. + *

      + * The initiator node broadcasts a task to 'run' node that starts EntryProcessor closure. That closure is executed on + * 'check' node and broadcasts a task to 'endpoint' nodes. On every step, it is performed verification that operation + * security context is the initiator context. + */ +public class EntryProcessorRemoteSecurityContextCheckTest extends AbstractCacheOperationRemoteSecurityContextCheckTest { + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + startGridAllowAll(SRV_INITIATOR); + + startClientAllowAll(CLNT_INITIATOR); + + startGridAllowAll(SRV_RUN); + + startGridAllowAll(SRV_CHECK); + + startGridAllowAll(SRV_ENDPOINT); + + startClientAllowAll(CLNT_ENDPOINT); + + G.allGrids().get(0).cluster().active(true); + } + + /** {@inheritDoc} */ + @Override protected void setupVerifier(Verifier verifier) { + verifier + .expect(SRV_RUN, 1) + .expect(SRV_CHECK, 1) + .expect(SRV_ENDPOINT, 1) + .expect(CLNT_ENDPOINT, 1); + } + + /** */ + public void test() { + runAndCheck(grid(SRV_INITIATOR), operations()); + runAndCheck(grid(CLNT_INITIATOR), operations()); + } + + /** {@inheritDoc} */ + @Override protected Collection nodesToRun() { + return Collections.singletonList(nodeId(SRV_RUN)); + } + + /** {@inheritDoc} */ + @Override protected Collection nodesToCheck() { + return Collections.singletonList(nodeId(SRV_CHECK)); + } + + /** + * @return Stream of runnables to call invoke methods. + */ + private Stream operations() { + final Integer key = prmKey(grid(SRV_CHECK)); + + return Stream.of( + () -> localIgnite().cache(CACHE_NAME).invoke(key, createRunner()), + + () -> localIgnite().cache(CACHE_NAME).invokeAll(singleton(key), createRunner()), + + () -> localIgnite().cache(CACHE_NAME).invokeAsync(key, createRunner()).get(), + + () -> localIgnite().cache(CACHE_NAME) + .invokeAllAsync(singleton(key), createRunner()).get() + ).map(RegisterExecAndForward::new); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/closure/ScanQueryRemoteSecurityContextCheckTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/closure/ScanQueryRemoteSecurityContextCheckTest.java new file mode 100644 index 0000000000000..4abb584268f74 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/cache/closure/ScanQueryRemoteSecurityContextCheckTest.java @@ -0,0 +1,107 @@ +/* + * 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.processors.security.cache.closure; + +import java.util.Collection; +import java.util.Collections; +import java.util.UUID; +import java.util.stream.Stream; +import org.apache.ignite.cache.query.ScanQuery; +import org.apache.ignite.internal.processors.security.AbstractCacheOperationRemoteSecurityContextCheckTest; +import org.apache.ignite.internal.util.typedef.G; +import org.apache.ignite.lang.IgniteRunnable; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static org.apache.ignite.Ignition.localIgnite; + +/** + * Testing operation security context when the filter of ScanQuery is executed on remote node. + *

      + * The initiator node broadcasts a task to 'run' node that starts ScanQuery's filter. That filter is executed on + * 'check' node and broadcasts a task to 'endpoint' nodes. On every step, it is performed verification that + * operation security context is the initiator context. + */ +public class ScanQueryRemoteSecurityContextCheckTest extends AbstractCacheOperationRemoteSecurityContextCheckTest { + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + startGridAllowAll(SRV_INITIATOR); + + startClientAllowAll(CLNT_INITIATOR); + + startGridAllowAll(SRV_RUN); + + startClientAllowAll(CLNT_RUN); + + startGridAllowAll(SRV_CHECK); + + startGridAllowAll(SRV_ENDPOINT); + + startClientAllowAll(CLNT_ENDPOINT); + + G.allGrids().get(0).cluster().active(true); + } + + /** {@inheritDoc} */ + @Override protected void setupVerifier(Verifier verifier) { + verifier + .expect(SRV_RUN, 1) + .expect(CLNT_RUN, 1) + .expect(SRV_CHECK, 2) + .expect(SRV_ENDPOINT, 2) + .expect(CLNT_ENDPOINT, 2); + } + + /** */ + public void test() throws Exception { + grid(SRV_INITIATOR).cache(CACHE_NAME) + .put(prmKey(grid(SRV_CHECK)), 1); + + awaitPartitionMapExchange(); + + runAndCheck(grid(SRV_INITIATOR), operations()); + runAndCheck(grid(CLNT_INITIATOR), operations()); + } + + /** {@inheritDoc} */ + @Override protected Collection nodesToCheck() { + return Collections.singletonList(nodeId(SRV_CHECK)); + } + + /** + * Stream of runnables to call query methods. + */ + private Stream operations() { + return Stream.of( + () -> { + VERIFIER.register(); + + localIgnite().cache(CACHE_NAME).query(new ScanQuery<>(createRunner(SRV_CHECK))).getAll(); + }, + () -> { + VERIFIER.register(); + + localIgnite().cache(CACHE_NAME).query( + new ScanQuery<>((k, v) -> true), + createRunner(SRV_CHECK) + ).getAll(); + } + ); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/client/ThinClientPermissionCheckTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/client/ThinClientPermissionCheckTest.java new file mode 100644 index 0000000000000..e7fab8fb1cd4a --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/client/ThinClientPermissionCheckTest.java @@ -0,0 +1,224 @@ +/* + * 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.processors.security.client; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; +import org.apache.ignite.IgniteException; +import org.apache.ignite.Ignition; +import org.apache.ignite.client.ClientAuthorizationException; +import org.apache.ignite.client.Config; +import org.apache.ignite.client.IgniteClient; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.ClientConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.processors.security.AbstractSecurityTest; +import org.apache.ignite.internal.processors.security.impl.TestSecurityData; +import org.apache.ignite.internal.util.typedef.G; +import org.apache.ignite.lang.IgniteBiTuple; +import org.apache.ignite.plugin.security.SecurityPermissionSetBuilder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static java.util.Collections.singletonMap; +import static org.apache.ignite.internal.util.lang.GridFunc.t; +import static org.apache.ignite.plugin.security.SecurityPermission.CACHE_CREATE; +import static org.apache.ignite.plugin.security.SecurityPermission.CACHE_DESTROY; +import static org.apache.ignite.plugin.security.SecurityPermission.CACHE_PUT; +import static org.apache.ignite.plugin.security.SecurityPermission.CACHE_READ; +import static org.apache.ignite.plugin.security.SecurityPermission.CACHE_REMOVE; +import static org.apache.ignite.plugin.security.SecurityPermission.TASK_EXECUTE; +import static org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.ALLOW_ALL; +import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause; + +/** + * Security tests for thin client. + */ +public class ThinClientPermissionCheckTest extends AbstractSecurityTest { + /** Client. */ + private static final String CLIENT = "client"; + + /** Client that has system permissions. */ + private static final String CLIENT_SYS_PERM = "client_sys_perm"; + + /** Client that has system permissions. */ + private static final String CLIENT_CACHE_TASK_OPER = "client_task_oper"; + + /** Cache. */ + private static final String CACHE = "TEST_CACHE"; + + /** Forbidden cache. */ + private static final String FORBIDDEN_CACHE = "FORBIDDEN_TEST_CACHE"; + + /** Cache to test system oper permissions. */ + private static final String DYNAMIC_CACHE = "DYNAMIC_TEST_CACHE"; + + /** Remove all task name. */ + public static final String REMOVE_ALL_TASK = + "org.apache.ignite.internal.processors.cache.distributed.GridDistributedCacheAdapter$RemoveAllTask"; + + /** Clear task name. */ + public static final String CLEAR_TASK = + "org.apache.ignite.internal.processors.cache.GridCacheAdapter$ClearTask"; + + /** + * @param clientData Array of client security data. + */ + private IgniteConfiguration getConfiguration(TestSecurityData... clientData) throws Exception { + return getConfiguration(G.allGrids().size(), clientData); + } + + /** + * @param idx Index. + * @param clientData Array of client security data. + */ + private IgniteConfiguration getConfiguration(int idx, TestSecurityData... clientData) throws Exception { + String instanceName = getTestIgniteInstanceName(idx); + + return getConfiguration( + instanceName, + secPluginCfg("srv_" + instanceName, null, ALLOW_ALL, clientData) + ).setCacheConfiguration( + new CacheConfiguration().setName(CACHE), + new CacheConfiguration().setName(FORBIDDEN_CACHE) + ); + } + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + IgniteEx ignite = startGrid( + getConfiguration( + new TestSecurityData(CLIENT, + SecurityPermissionSetBuilder.create().defaultAllowAll(false) + .appendCachePermissions(CACHE, CACHE_READ, CACHE_PUT, CACHE_REMOVE) + .appendCachePermissions(FORBIDDEN_CACHE, EMPTY_PERMS) + .build() + ), + new TestSecurityData(CLIENT_SYS_PERM, + SecurityPermissionSetBuilder.create().defaultAllowAll(false) + .appendSystemPermissions(CACHE_CREATE, CACHE_DESTROY) + .build() + ), + new TestSecurityData(CLIENT_CACHE_TASK_OPER, + SecurityPermissionSetBuilder.create().defaultAllowAll(false) + .appendCachePermissions(CACHE, CACHE_REMOVE) + .appendTaskPermissions(REMOVE_ALL_TASK, TASK_EXECUTE) + .appendTaskPermissions(CLEAR_TASK, TASK_EXECUTE) + .build() + ) + ) + ); + + ignite.cluster().active(true); + } + + /** */ + public void testCacheSinglePermOperations() throws Exception { + for (IgniteBiTuple, String> t : operations(CACHE)) + runOperation(CLIENT, t); + + for (IgniteBiTuple, String> t : operations(FORBIDDEN_CACHE)) + assertThrowsWithCause(() -> runOperation(CLIENT, t), ClientAuthorizationException.class); + } + + /** + * That test shows the wrong case when a client has permission for a remove operation + * but a removeAll operation is forbidden for it. To have permission for the removeAll (clear) operation + * a client need to have the permission to execute {@link #REMOVE_ALL_TASK} ({@link #CLEAR_TASK}) task. + * + * @throws Exception If error occurs. + */ + public void testCacheTaskPermOperations() throws Exception { + List, String>> ops = Arrays.asList( + t(c -> c.cache(CACHE).removeAll(), "removeAll"), + t(c -> c.cache(CACHE).clear(), "clear") + ); + + for (IgniteBiTuple, String> op : ops) { + runOperation(CLIENT_CACHE_TASK_OPER, op); + + assertThrowsWithCause(() -> runOperation(CLIENT, op), ClientAuthorizationException.class); + } + } + + /** */ + public void testSysOperation() throws Exception { + try (IgniteClient sysPrmClnt = startClient(CLIENT_SYS_PERM)) { + sysPrmClnt.createCache(DYNAMIC_CACHE); + + assertTrue(sysPrmClnt.cacheNames().contains(DYNAMIC_CACHE)); + + sysPrmClnt.destroyCache(DYNAMIC_CACHE); + + assertFalse(sysPrmClnt.cacheNames().contains(DYNAMIC_CACHE)); + } + + List, String>> ops = Arrays.asList( + t(c -> c.createCache(DYNAMIC_CACHE), "createCache"), + t(c -> c.destroyCache(CACHE), "destroyCache") + ); + + for (IgniteBiTuple, String> op : ops) + assertThrowsWithCause(() -> runOperation(CLIENT, op), ClientAuthorizationException.class); + } + + /** + * @param cacheName Cache name. + */ + private Collection, String>> operations(final String cacheName) { + return Arrays.asList( + t(c -> c.cache(cacheName).put("key", "value"), "put"), + t(c -> c.cache(cacheName).putAll(singletonMap("key", "value")), "putAll"), + t(c -> c.cache(cacheName).get("key"), "get)"), + t(c -> c.cache(cacheName).getAll(Collections.singleton("key")), "getAll"), + t(c -> c.cache(cacheName).containsKey("key"), "containsKey"), + t(c -> c.cache(cacheName).remove("key"), "remove"), + t(c -> c.cache(cacheName).replace("key", "value"), "replace"), + t(c -> c.cache(cacheName).putIfAbsent("key", "value"), "putIfAbsent"), + t(c -> c.cache(cacheName).getAndPut("key", "value"), "getAndPut"), + t(c -> c.cache(cacheName).getAndRemove("key"), "getAndRemove"), + t(c -> c.cache(cacheName).getAndReplace("key", "value"), "getAndReplace") + ); + } + + /** */ + private void runOperation(String clientName, IgniteBiTuple, String> op) { + try (IgniteClient client = startClient(clientName)) { + op.get1().accept(client); + } + catch (Exception e) { + throw new IgniteException(op.get2(), e); + } + } + + /** + * @param userName User name. + */ + private IgniteClient startClient(String userName) { + return Ignition.startClient( + new ClientConfiguration().setAddresses(Config.SERVER) + .setUserName(userName) + .setUserPassword("") + ); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/compute/ComputePermissionCheckTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/compute/ComputePermissionCheckTest.java new file mode 100644 index 0000000000000..9903b846f7c25 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/compute/ComputePermissionCheckTest.java @@ -0,0 +1,296 @@ +/* + * 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.processors.security.compute; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Stream; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteException; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.compute.ComputeJob; +import org.apache.ignite.compute.ComputeJobResult; +import org.apache.ignite.compute.ComputeJobResultPolicy; +import org.apache.ignite.compute.ComputeTask; +import org.apache.ignite.internal.processors.security.AbstractSecurityTest; +import org.apache.ignite.lang.IgniteCallable; +import org.apache.ignite.lang.IgniteClosure; +import org.apache.ignite.lang.IgniteFuture; +import org.apache.ignite.lang.IgniteRunnable; +import org.apache.ignite.plugin.security.SecurityException; +import org.apache.ignite.plugin.security.SecurityPermission; +import org.apache.ignite.plugin.security.SecurityPermissionSet; +import org.apache.ignite.plugin.security.SecurityPermissionSetBuilder; +import org.apache.ignite.testframework.GridTestUtils.RunnableX; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static java.util.Collections.singletonList; +import static java.util.function.Function.identity; +import static org.apache.ignite.plugin.security.SecurityPermission.TASK_CANCEL; +import static org.apache.ignite.plugin.security.SecurityPermission.TASK_EXECUTE; +import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause; + +/** + * Task execute permission tests. + */ +public class ComputePermissionCheckTest extends AbstractSecurityTest { + /** Flag that shows task was executed. */ + private static final AtomicBoolean IS_EXECUTED = new AtomicBoolean(false); + + /** Reentrant lock. */ + private static final ReentrantLock RNT_LOCK = new ReentrantLock(); + + /** Reentrant lock timeout. */ + private static final int RNT_LOCK_TIMEOUT = 20_000; + + /** Test compute task. */ + private static final TestComputeTask TEST_COMPUTE_TASK = new TestComputeTask(); + + /** Test callable. */ + private static final IgniteCallable TEST_CALLABLE = () -> { + waitForCancel(); + + IS_EXECUTED.set(true); + + return null; + }; + + /** Test runnable. */ + private static final IgniteRunnable TEST_RUNNABLE = () -> { + waitForCancel(); + + IS_EXECUTED.set(true); + }; + + /** Test closure. */ + private static final IgniteClosure TEST_CLOSURE = a -> { + waitForCancel(); + + IS_EXECUTED.set(true); + + return null; + }; + + /** Waits for InterruptedException on RNT_LOCK. */ + private static void waitForCancel() { + boolean isLocked = false; + + try { + isLocked = RNT_LOCK.tryLock(RNT_LOCK_TIMEOUT, TimeUnit.MILLISECONDS); + + if (!isLocked) + throw new IgniteException("tryLock should succeed or interrupted"); + } + catch (InterruptedException e) { + // This is expected. + } + finally { + if (isLocked) + RNT_LOCK.unlock(); + } + } + + /** */ + public void test() throws Exception { + Ignite srvAllowed = startGrid("srv_allowed", permissions(TASK_EXECUTE, TASK_CANCEL), false); + + Ignite srvForbidden = startGrid("srv_forbidden", permissions(EMPTY_PERMS), false); + + Ignite srvForbiddenCancel = startGrid("srv_forbidden_cnl", permissions(TASK_EXECUTE), false); + + Ignite clntAllowed = startGrid("clnt_allowed", permissions(TASK_EXECUTE, TASK_CANCEL), true); + + Ignite clntForbidden = startGrid("clnt_forbidden", permissions(EMPTY_PERMS), true); + + Ignite clntForbiddenCancel = startGrid("clnt_forbidden_cnl", permissions(TASK_EXECUTE), true); + + srvAllowed.cluster().active(true); + + operations(srvAllowed, clntAllowed).forEach(this::runOperation); + + operations(srvForbidden, clntForbidden).forEach(op -> assertThrowsWithCause(op, SecurityException.class)); + + asyncOperations(srvAllowed, clntAllowed).forEach(this::runOperationCancel); + + asyncOperations(srvForbiddenCancel, clntForbiddenCancel).forEach(op -> + assertThrowsWithCause(() -> runOperationCancel(op), SecurityException.class)); + } + + /** + * @param nodes Array of nodes. + */ + private Stream operations(Ignite... nodes) { + Function> nodeOps = (node) -> Stream.of( + () -> node.compute().execute(TEST_COMPUTE_TASK, 0), + () -> node.compute().broadcast(TEST_CALLABLE), + () -> node.compute().call(TEST_CALLABLE), + () -> node.compute().run(TEST_RUNNABLE), + () -> node.compute().apply(TEST_CLOSURE, new Object()), + () -> node.executorService().invokeAll(singletonList(TEST_CALLABLE)), + () -> node.executorService().invokeAny(singletonList(TEST_CALLABLE)) + ); + + Stream ops = Arrays.stream(nodes).map(nodeOps).flatMap(identity()); + + return Stream.concat(ops, asyncOperations(nodes).map(s -> () -> s.get().get())); + } + + /** */ + private Stream> asyncOperations(Ignite... nodes) { + Function>> nodeOps = (node) -> Stream.of( + () -> new FutureAdapter<>(node.compute().executeAsync(TEST_COMPUTE_TASK, 0)), + () -> new FutureAdapter<>(node.compute().broadcastAsync(TEST_CALLABLE)), + () -> new FutureAdapter<>(node.compute().callAsync(TEST_CALLABLE)), + () -> new FutureAdapter<>(node.compute().runAsync(TEST_RUNNABLE)), + () -> new FutureAdapter<>(node.compute().applyAsync(TEST_CLOSURE, new Object())), + () -> node.executorService().submit(TEST_CALLABLE) + ); + + return Arrays.stream(nodes).map(nodeOps).flatMap(identity()); + } + + /** + * @param perms Permissions. + */ + private SecurityPermissionSet permissions(SecurityPermission... perms) { + return SecurityPermissionSetBuilder.create() + .appendTaskPermissions(TEST_COMPUTE_TASK.getClass().getName(), perms) + .appendTaskPermissions(TEST_CALLABLE.getClass().getName(), perms) + .appendTaskPermissions(TEST_RUNNABLE.getClass().getName(), perms) + .appendTaskPermissions(TEST_CLOSURE.getClass().getName(), perms) + .build(); + } + + /** + * @param r TestRunnable. + */ + private void runOperation(Runnable r) { + IS_EXECUTED.set(false); + + r.run(); + + assertTrue(IS_EXECUTED.get()); + } + + /** + * @param s Supplier. + */ + private void runOperationCancel(Supplier s) { + RNT_LOCK.lock(); + + try { + Future f = s.get(); + + f.cancel(true); + + assertTrue(f.isCancelled()); + } + finally { + RNT_LOCK.unlock(); + } + } + + /** */ + private static class FutureAdapter implements Future { + /** Ignite future. */ + private final IgniteFuture igniteFut; + + /** */ + public FutureAdapter(IgniteFuture igniteFut) { + this.igniteFut = igniteFut; + } + + /** {@inheritDoc} */ + @Override public boolean cancel(boolean mayInterruptIfRunning) { + return igniteFut.cancel(); + } + + /** {@inheritDoc} */ + @Override public boolean isCancelled() { + return igniteFut.isCancelled(); + } + + /** {@inheritDoc} */ + @Override public boolean isDone() { + return igniteFut.isDone(); + } + + /** {@inheritDoc} */ + @Override public T get() throws InterruptedException, ExecutionException { + return igniteFut.get(); + } + + /** {@inheritDoc} */ + @Override public T get(long timeout, + @NotNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + return igniteFut.get(timeout, unit); + } + } + + /** + * Abstract test compute task. + */ + private static class TestComputeTask implements ComputeTask { + /** {@inheritDoc} */ + @Override public @Nullable Map map(List subgrid, + @Nullable Object arg) { + IS_EXECUTED.set(true); + + return Collections.singletonMap( + new ComputeJob() { + @Override public void cancel() { + // no-op + } + + @Override public Object execute() { + waitForCancel(); + + return null; + } + }, subgrid.stream().findFirst().orElseThrow(IllegalStateException::new) + ); + } + + /** {@inheritDoc} */ + @Override public ComputeJobResultPolicy result(ComputeJobResult res, List rcvd) { + if (res.getException() != null) + throw res.getException(); + + return ComputeJobResultPolicy.REDUCE; + } + + /** {@inheritDoc} */ + @Override public @Nullable Integer reduce(List results) { + return null; + } + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/compute/closure/ComputeTaskRemoteSecurityContextCheckTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/compute/closure/ComputeTaskRemoteSecurityContextCheckTest.java new file mode 100644 index 0000000000000..27bcede494170 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/compute/closure/ComputeTaskRemoteSecurityContextCheckTest.java @@ -0,0 +1,170 @@ +/* + * 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.processors.security.compute.closure; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Stream; +import org.apache.ignite.Ignite; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.compute.ComputeJob; +import org.apache.ignite.compute.ComputeJobResult; +import org.apache.ignite.compute.ComputeJobResultPolicy; +import org.apache.ignite.compute.ComputeTask; +import org.apache.ignite.internal.processors.security.AbstractRemoteSecurityContextCheckTest; +import org.apache.ignite.internal.util.typedef.G; +import org.apache.ignite.lang.IgniteRunnable; +import org.apache.ignite.resources.IgniteInstanceResource; +import org.jetbrains.annotations.Nullable; +import org.junit.Test; + +import static org.apache.ignite.Ignition.localIgnite; + +/** + * Testing operation security context when the compute task is executed on remote nodes. + *

      + * The initiator node broadcasts a task to 'run' nodes that starts compute task. That compute task is executed on + * 'check' nodes and broadcasts a task to 'endpoint' nodes. On every step, it is performed verification that + * operation security context is the initiator context. + */ +public class ComputeTaskRemoteSecurityContextCheckTest extends AbstractRemoteSecurityContextCheckTest { + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + startGridAllowAll(SRV_INITIATOR); + + startClientAllowAll(CLNT_INITIATOR); + + startGridAllowAll(SRV_RUN); + + startClientAllowAll(CLNT_RUN); + + startGridAllowAll(SRV_CHECK); + + startClientAllowAll(CLNT_CHECK); + + startGridAllowAll(SRV_ENDPOINT); + + startClientAllowAll(CLNT_ENDPOINT); + + G.allGrids().get(0).cluster().active(true); + } + + /** {@inheritDoc} */ + @Override protected void setupVerifier(Verifier verifier) { + verifier + .expect(SRV_RUN, 1) + .expect(CLNT_RUN, 1) + .expect(SRV_CHECK, 2) + .expect(CLNT_CHECK, 2) + .expect(SRV_ENDPOINT, 4) + .expect(CLNT_ENDPOINT, 4); + } + + /** */ + public void test() { + runAndCheck(grid(SRV_INITIATOR), operations()); + runAndCheck(grid(CLNT_INITIATOR), operations()); + } + + /** + * @return Stream of check cases. + */ + private Stream operations() { + return Stream.of( + () -> { + VERIFIER.register(); + + localIgnite().compute().execute(new ComputeTaskClosure(nodesToCheck(), endpoints()), 0); + }, + () -> { + VERIFIER.register(); + + localIgnite().compute().executeAsync(new ComputeTaskClosure(nodesToCheck(), endpoints()), 0).get(); + } + ); + } + + /** + * Compute task for tests. + */ + static class ComputeTaskClosure implements ComputeTask { + /** Collection of transition node ids. */ + private final Collection remotes; + + /** Collection of endpoint node ids. */ + private final Collection endpoints; + + /** Local ignite. */ + @IgniteInstanceResource + protected transient Ignite loc; + + /** + * @param remotes Collection of transition node ids. + * @param endpoints Collection of endpoint node ids. + */ + public ComputeTaskClosure(Collection remotes, Collection endpoints) { + this.remotes = remotes; + this.endpoints = endpoints; + } + + /** {@inheritDoc} */ + @Override public @Nullable Map map(List subgrid, + @Nullable Integer arg) { + Map res = new HashMap<>(); + + for (UUID id : remotes) { + res.put( + new ComputeJob() { + @IgniteInstanceResource + private Ignite loc; + + @Override public void cancel() { + // no-op + } + + @Override public Object execute() { + VERIFIER.register(); + + compute(loc, endpoints).broadcast(() -> VERIFIER.register()); + + return null; + } + }, loc.cluster().node(id) + ); + } + + return res; + } + + /** {@inheritDoc} */ + @Override public ComputeJobResultPolicy result(ComputeJobResult res, List rcvd) { + if (res.getException() != null) + throw res.getException(); + + return ComputeJobResultPolicy.WAIT; + } + + /** {@inheritDoc} */ + @Override public @Nullable Integer reduce(List results) { + return null; + } + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/compute/closure/DistributedClosureRemoteSecurityContextCheckTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/compute/closure/DistributedClosureRemoteSecurityContextCheckTest.java new file mode 100644 index 0000000000000..17a0a6b9a79e7 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/compute/closure/DistributedClosureRemoteSecurityContextCheckTest.java @@ -0,0 +1,118 @@ +/* + * 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.processors.security.compute.closure; + +import java.util.UUID; +import java.util.stream.Stream; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteCompute; +import org.apache.ignite.internal.processors.security.AbstractRemoteSecurityContextCheckTest; +import org.apache.ignite.internal.util.typedef.G; +import org.apache.ignite.lang.IgniteRunnable; +import org.junit.Test; + +import static org.apache.ignite.Ignition.localIgnite; +import static org.apache.ignite.internal.IgniteFeatures.IGNITE_SECURITY_PROCESSOR; + +/** + * Testing operation security context when the compute closure is executed on remote nodes. + *

      + * The initiator node broadcasts a task to 'run' nodes that starts compute operation. That operation is executed on + * 'check' nodes and broadcasts a task to 'endpoint' nodes. On every step, it is performed verification that operation + * security context is the initiator context. + */ +public class DistributedClosureRemoteSecurityContextCheckTest extends AbstractRemoteSecurityContextCheckTest { + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + startGridAllowAll(SRV_INITIATOR); + + startClientAllowAll(CLNT_INITIATOR); + + startGridAllowAll(SRV_RUN); + + startClientAllowAll(CLNT_RUN); + + startGridAllowAll(SRV_CHECK); + + startClientAllowAll(CLNT_CHECK); + + startGridAllowAll(SRV_ENDPOINT); + + startClientAllowAll(CLNT_ENDPOINT); + + G.allGrids().get(0).cluster().active(true); + } + + /** {@inheritDoc} */ + @Override protected void setupVerifier(Verifier verifier) { + verifier + .expect(SRV_RUN, 1) + .expect(CLNT_RUN, 1) + .expect(SRV_CHECK, 2) + .expect(CLNT_CHECK, 2) + .expect(SRV_ENDPOINT, 4) + .expect(CLNT_ENDPOINT, 4); + } + + /** */ + public void test() { + runAndCheck(grid(SRV_INITIATOR), operations()); + runAndCheck(grid(CLNT_INITIATOR), operations()); + } + + /** */ + private IgniteCompute compute(UUID id) { + Ignite loc = localIgnite(); + + return loc.compute(loc.cluster().forNodeId(id)); + } + + /** + * @return Stream of check cases. + */ + private Stream operations() { + return Stream.of( + () -> compute(localIgnite(), nodesToCheck()).broadcast((IgniteRunnable) createRunner()), + () -> compute(localIgnite(), nodesToCheck()).broadcastAsync((IgniteRunnable) createRunner()).get(), + () -> { + for (UUID id : nodesToCheck()) + compute(id).call(createRunner()); + }, + () -> { + for (UUID id : nodesToCheck()) + compute(id).callAsync(createRunner()).get(); + }, + () -> { + for (UUID id : nodesToCheck()) + compute(id).run(createRunner()); + }, + () -> { + for (UUID id : nodesToCheck()) + compute(id).runAsync(createRunner()).get(); + }, + () -> { + for (UUID id : nodesToCheck()) + compute(id).apply(createRunner(), new Object()); + }, + () -> { + for (UUID id : nodesToCheck()) + compute(id).applyAsync(createRunner(), new Object()).get(); + } + ).map(RegisterExecAndForward::new); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/compute/closure/ExecutorServiceRemoteSecurityContextCheckTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/compute/closure/ExecutorServiceRemoteSecurityContextCheckTest.java new file mode 100644 index 0000000000000..898034037f251 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/compute/closure/ExecutorServiceRemoteSecurityContextCheckTest.java @@ -0,0 +1,88 @@ +/* + * 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.processors.security.compute.closure; + +import java.util.UUID; +import java.util.concurrent.ExecutorService; +import org.apache.ignite.Ignite; +import org.apache.ignite.Ignition; +import org.apache.ignite.internal.processors.security.AbstractRemoteSecurityContextCheckTest; +import org.apache.ignite.internal.util.typedef.G; +import org.apache.ignite.testframework.GridTestUtils.IgniteRunnableX; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Testing operation security context when the service task is executed on remote nodes. + *

      + * The initiator node broadcasts a task to 'run' nodes that starts service task. That service task is executed + * on 'check' nodes and broadcasts a task to 'endpoint' nodes. On every step, it is performed verification that + * operation security context is the initiator context. + */ +public class ExecutorServiceRemoteSecurityContextCheckTest extends AbstractRemoteSecurityContextCheckTest { + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + startGridAllowAll(SRV_INITIATOR); + + startClientAllowAll(CLNT_INITIATOR); + + startGridAllowAll(SRV_RUN); + + startClientAllowAll(CLNT_RUN); + + startGridAllowAll(SRV_CHECK); + + startClientAllowAll(CLNT_CHECK); + + startGridAllowAll(SRV_ENDPOINT); + + startClientAllowAll(CLNT_ENDPOINT); + + G.allGrids().get(0).cluster().active(true); + } + + /** {@inheritDoc} */ + @Override protected void setupVerifier(Verifier verifier) { + verifier + .expect(SRV_RUN, 1) + .expect(CLNT_RUN, 1) + .expect(SRV_CHECK, 2) + .expect(CLNT_CHECK, 2) + .expect(SRV_ENDPOINT, 4) + .expect(CLNT_ENDPOINT, 4); + } + + /** */ + public void test() { + IgniteRunnableX operation = () -> { + VERIFIER.register(); + + Ignite loc = Ignition.localIgnite(); + + for (UUID nodeId : nodesToCheck()) { + ExecutorService svc = loc.executorService(loc.cluster().forNodeId(nodeId)); + + svc.submit((Runnable) createRunner()).get(); + } + }; + + runAndCheck(grid(SRV_INITIATOR), operation); + runAndCheck(grid(CLNT_INITIATOR), operation); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/datastreamer/DataStreamerPermissionCheckTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/datastreamer/DataStreamerPermissionCheckTest.java new file mode 100644 index 0000000000000..5ba3485c0a7e3 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/datastreamer/DataStreamerPermissionCheckTest.java @@ -0,0 +1,83 @@ +/* + * 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.processors.security.datastreamer; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteDataStreamer; +import org.apache.ignite.internal.processors.security.AbstractCacheOperationPermissionCheckTest; +import org.apache.ignite.plugin.security.SecurityException; +import org.apache.ignite.plugin.security.SecurityPermission; +import org.apache.ignite.plugin.security.SecurityPermissionSetBuilder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; +import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause; + +/** + * Test cache permissions for Data Streamer. + */ +public class DataStreamerPermissionCheckTest extends AbstractCacheOperationPermissionCheckTest { + /** Parameters. */ + @Parameters(name = "clientMode={0}") + public static Iterable data() { + return Arrays.asList(new Boolean[] {true}, new Boolean[] {false}); + } + + /** Client mode. */ + @Parameter() + public boolean clientMode; + + /** */ + public void testDataStreamer() throws Exception { + Ignite node = startGrid(loginPrefix(clientMode) + "_test_node", + SecurityPermissionSetBuilder.create() + .appendCachePermissions(CACHE_NAME, SecurityPermission.CACHE_PUT) + .appendCachePermissions(FORBIDDEN_CACHE, SecurityPermission.CACHE_READ) + .build(), clientMode); + + List>> ops = Arrays.asList( + s -> s.addData("k", 1), + s -> s.addData(singletonMap("key", 2)), + s -> s.addData((Map.Entry)entry()), + s -> s.addData(singletonList(entry()))); + + ops.forEach(c -> runOperation(node, CACHE_NAME, c)); + + ops.forEach(c -> + assertThrowsWithCause(() -> runOperation(node, FORBIDDEN_CACHE, c), SecurityException.class)); + } + + /** + * @param node Node. + * @param c Consumer. + */ + private void runOperation(Ignite node, String cache, Consumer> c) { + try (IgniteDataStreamer s = node.dataStreamer(cache)) { + c.accept(s); + } + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/datastreamer/closure/DataStreamerRemoteSecurityContextCheckTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/datastreamer/closure/DataStreamerRemoteSecurityContextCheckTest.java new file mode 100644 index 0000000000000..7ab2c0b715ccd --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/datastreamer/closure/DataStreamerRemoteSecurityContextCheckTest.java @@ -0,0 +1,92 @@ +/* + * 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.processors.security.datastreamer.closure; + +import java.util.Collection; +import java.util.Collections; +import java.util.UUID; +import org.apache.ignite.IgniteDataStreamer; +import org.apache.ignite.Ignition; +import org.apache.ignite.internal.processors.security.AbstractCacheOperationRemoteSecurityContextCheckTest; +import org.apache.ignite.internal.util.typedef.G; +import org.apache.ignite.lang.IgniteRunnable; +import org.apache.ignite.stream.StreamVisitor; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Testing operation security context when the closure of DataStreamer is executed on remote node. + *

      + * The initiator node broadcasts a task to 'run' node that starts DataStreamer's closure. That closure is executed on + * 'check' node and broadcasts a task to 'endpoint' nodes. On every step, it is performed verification that operation + * security context is the initiator context. + */ +public class DataStreamerRemoteSecurityContextCheckTest extends AbstractCacheOperationRemoteSecurityContextCheckTest { + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + startGridAllowAll(SRV_INITIATOR); + + startClientAllowAll(CLNT_INITIATOR); + + startGridAllowAll(SRV_RUN); + + startGridAllowAll(SRV_CHECK); + + startGridAllowAll(SRV_ENDPOINT); + + startClientAllowAll(CLNT_ENDPOINT); + + G.allGrids().get(0).cluster().active(true); + } + + /** {@inheritDoc} */ + @Override protected void setupVerifier(Verifier verifier) { + verifier + .expect(SRV_RUN, 1) + .expect(SRV_CHECK, 1) + .expect(SRV_ENDPOINT, 1) + .expect(CLNT_ENDPOINT, 1); + } + + /** */ + public void testDataStreamer() { + IgniteRunnable op = () -> { + VERIFIER.register(); + + try (IgniteDataStreamer strm = Ignition.localIgnite().dataStreamer(CACHE_NAME)) { + strm.receiver(StreamVisitor.from(new ExecRegisterAndForwardAdapter<>(endpoints()))); + + strm.addData(prmKey(grid(SRV_CHECK)), 100); + } + }; + + runAndCheck(grid(SRV_INITIATOR), op); + runAndCheck(grid(CLNT_INITIATOR), op); + } + + /** {@inheritDoc} */ + @Override protected Collection nodesToRun() { + return Collections.singletonList(nodeId(SRV_RUN)); + } + + /** {@inheritDoc} */ + @Override protected Collection nodesToCheck() { + return Collections.singletonList(nodeId(SRV_CHECK)); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecurityContext.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecurityContext.java new file mode 100644 index 0000000000000..846762c8a8dd1 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecurityContext.java @@ -0,0 +1,125 @@ +/* + * 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.processors.security.impl; + +import java.io.Serializable; +import java.util.Collection; +import org.apache.ignite.internal.processors.security.SecurityContext; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.plugin.security.SecurityPermission; +import org.apache.ignite.plugin.security.SecuritySubject; + +/** + * Security context for tests. + */ +public class TestSecurityContext implements SecurityContext, Serializable { + /** Subject. */ + private final SecuritySubject subject; + + /** + * @param subject Subject. + */ + public TestSecurityContext(SecuritySubject subject) { + this.subject = subject; + } + + /** + * @param opName Op name. + * @param perm Permission. + */ + public boolean operationAllowed(String opName, SecurityPermission perm) { + switch (perm) { + case CACHE_PUT: + case CACHE_READ: + case CACHE_REMOVE: + + return cacheOperationAllowed(opName, perm); + + case TASK_CANCEL: + case TASK_EXECUTE: + return taskOperationAllowed(opName, perm); + + case SERVICE_DEPLOY: + case SERVICE_INVOKE: + case SERVICE_CANCEL: + return serviceOperationAllowed(opName, perm); + + case EVENTS_DISABLE: + case EVENTS_ENABLE: + case ADMIN_VIEW: + case ADMIN_CACHE: + case ADMIN_QUERY: + case ADMIN_OPS: + case CACHE_CREATE: + case CACHE_DESTROY: + case JOIN_AS_SERVER: + return systemOperationAllowed(perm); + + default: + throw new IllegalStateException("Invalid security permission: " + perm); + } + } + + /** {@inheritDoc} */ + @Override public SecuritySubject subject() { + return subject; + } + + /** {@inheritDoc} */ + @Override public boolean taskOperationAllowed(String taskClsName, SecurityPermission perm) { + return hasPermission(subject.permissions().taskPermissions().get(taskClsName), perm); + } + + /** {@inheritDoc} */ + @Override public boolean cacheOperationAllowed(String cacheName, SecurityPermission perm) { + return hasPermission(subject.permissions().cachePermissions().get(cacheName), perm); + } + + /** {@inheritDoc} */ + @Override public boolean serviceOperationAllowed(String srvcName, SecurityPermission perm) { + return hasPermission(subject.permissions().servicePermissions().get(srvcName), perm); + } + + /** {@inheritDoc} */ + @Override public boolean systemOperationAllowed(SecurityPermission perm) { + Collection perms = subject.permissions().systemPermissions(); + + if (F.isEmpty(perms)) + return subject.permissions().defaultAllowAll(); + + return perms.stream().anyMatch(p -> perm == p); + } + + /** + * @param perms Permissions. + * @param perm Permission. + */ + private boolean hasPermission(Collection perms, SecurityPermission perm) { + if (perms == null) + return subject.permissions().defaultAllowAll(); + + return perms.stream().anyMatch(p -> perm == p); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return "TestSecurityContext{" + + "subject=" + subject + + '}'; + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecurityData.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecurityData.java new file mode 100644 index 0000000000000..66bc171a20982 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecurityData.java @@ -0,0 +1,116 @@ +/* + * 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.processors.security.impl; + +import org.apache.ignite.plugin.security.SecurityCredentials; +import org.apache.ignite.plugin.security.SecurityPermissionSet; + +/** + * Test security data for subject configuration. + */ +public class TestSecurityData { + /** Login. */ + private String login; + + /** Password. */ + private String pwd; + + /** Security permission set. */ + private SecurityPermissionSet prmSet; + + /** + * Default constructor. + */ + public TestSecurityData() { + // No-op. + } + + /** + * @param login Login. + * @param pwd Password. + * @param prmSet Permissions. + */ + public TestSecurityData(String login, String pwd, SecurityPermissionSet prmSet) { + this.login = login; + this.pwd = pwd; + this.prmSet = prmSet; + } + + /** + * @param login Login. + * @param prmSet Permissions. + */ + public TestSecurityData(String login, SecurityPermissionSet prmSet) { + this(login, "", prmSet); + } + + /** + * Getting security permission set. + */ + public SecurityPermissionSet getPermissions() { + return prmSet; + } + + /** + * @param prmSet Security permission set. + */ + public TestSecurityData setPermissions(SecurityPermissionSet prmSet) { + this.prmSet = prmSet; + + return this; + } + + /** + * Login. + */ + public String getLogin() { + return login; + } + + /** + * @param login Login. + */ + public TestSecurityData setLogin(String login) { + this.login = login; + + return this; + } + + /** + * Password. + */ + public String getPwd() { + return pwd; + } + + /** + * @param pwd Password. + */ + public TestSecurityData setPwd(String pwd) { + this.pwd = pwd; + + return this; + } + + /** + * @return Security credentials. + */ + public SecurityCredentials credentials() { + return new SecurityCredentials(getLogin(), getPwd(), null); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecurityPluginConfiguration.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecurityPluginConfiguration.java new file mode 100644 index 0000000000000..97c1e450d3ae8 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecurityPluginConfiguration.java @@ -0,0 +1,34 @@ +/* + * 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.processors.security.impl; + +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.processors.security.GridSecurityProcessor; +import org.apache.ignite.plugin.PluginConfiguration; + +/** + * Grid security configuration for tests. + */ +@FunctionalInterface +public interface TestSecurityPluginConfiguration extends PluginConfiguration { + /** + * @param ctx GridKernalContext. + * @return GridSecurityProcessor. + */ + public GridSecurityProcessor build(GridKernalContext ctx); +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecurityProcessor.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecurityProcessor.java new file mode 100644 index 0000000000000..0bda5b7a65844 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecurityProcessor.java @@ -0,0 +1,149 @@ +/* + * 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.processors.security.impl; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.IgniteNodeAttributes; +import org.apache.ignite.internal.processors.GridProcessorAdapter; +import org.apache.ignite.internal.processors.security.GridSecurityProcessor; +import org.apache.ignite.internal.processors.security.SecurityContext; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.plugin.security.AuthenticationContext; +import org.apache.ignite.plugin.security.SecurityCredentials; +import org.apache.ignite.plugin.security.SecurityException; +import org.apache.ignite.plugin.security.SecurityPermission; +import org.apache.ignite.plugin.security.SecurityPermissionSet; +import org.apache.ignite.plugin.security.SecuritySubject; + +import static org.apache.ignite.plugin.security.SecuritySubjectType.REMOTE_NODE; + +/** + * Security processor for test. + */ +public class TestSecurityProcessor extends GridProcessorAdapter implements GridSecurityProcessor { + /** Permissions. */ + private static final Map PERMS = new ConcurrentHashMap<>(); + + /** Node security data. */ + private final TestSecurityData nodeSecData; + + /** Users security data. */ + private final Collection predefinedAuthData; + + /** + * Constructor. + */ + public TestSecurityProcessor(GridKernalContext ctx, TestSecurityData nodeSecData, + Collection predefinedAuthData) { + super(ctx); + + this.nodeSecData = nodeSecData; + this.predefinedAuthData = predefinedAuthData.isEmpty() + ? Collections.emptyList() + : new ArrayList<>(predefinedAuthData); + } + + /** {@inheritDoc} */ + @Override public SecurityContext authenticateNode(ClusterNode node, SecurityCredentials cred) { + return new TestSecurityContext( + new TestSecuritySubject() + .setType(REMOTE_NODE) + .setId(node.id()) + .setAddr(new InetSocketAddress(F.first(node.addresses()), 0)) + .setLogin(cred.getLogin()) + .setPerms(PERMS.get(cred)) + ); + } + + /** {@inheritDoc} */ + @Override public boolean isGlobalNodeAuthentication() { + return false; + } + + /** {@inheritDoc} */ + @Override public SecurityContext authenticate(AuthenticationContext ctx) { + return new TestSecurityContext( + new TestSecuritySubject() + .setType(ctx.subjectType()) + .setId(ctx.subjectId()) + .setAddr(ctx.address()) + .setLogin(ctx.credentials().getLogin()) + .setPerms(PERMS.get(ctx.credentials())) + ); + } + + /** {@inheritDoc} */ + @Override public Collection authenticatedSubjects() { + return Collections.emptyList(); + } + + /** {@inheritDoc} */ + @Override public SecuritySubject authenticatedSubject(UUID subjId) { + return null; + } + + /** {@inheritDoc} */ + @Override public void authorize(String name, SecurityPermission perm, SecurityContext securityCtx) + throws SecurityException { + if (!((TestSecurityContext)securityCtx).operationAllowed(name, perm)) + throw new SecurityException("Authorization failed [perm=" + perm + + ", name=" + name + + ", subject=" + securityCtx.subject() + ']'); + } + + /** {@inheritDoc} */ + @Override public void onSessionExpired(UUID subjId) { + // No-op. + } + + /** {@inheritDoc} */ + @Override public boolean enabled() { + return true; + } + + /** {@inheritDoc} */ + @Override public void start() throws IgniteCheckedException { + super.start(); + + PERMS.put(nodeSecData.credentials(), nodeSecData.getPermissions()); + + ctx.addNodeAttribute(IgniteNodeAttributes.ATTR_SECURITY_CREDENTIALS, nodeSecData.credentials()); + + for (TestSecurityData data : predefinedAuthData) + PERMS.put(data.credentials(), data.getPermissions()); + } + + /** {@inheritDoc} */ + @Override public void stop(boolean cancel) throws IgniteCheckedException { + super.stop(cancel); + + PERMS.remove(nodeSecData.credentials()); + + for (TestSecurityData data : predefinedAuthData) + PERMS.remove(data.credentials()); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecurityProcessorProvider.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecurityProcessorProvider.java new file mode 100644 index 0000000000000..1ff5a201af204 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecurityProcessorProvider.java @@ -0,0 +1,135 @@ +/* + * 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.processors.security.impl; + +import java.io.Serializable; +import java.util.UUID; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.processors.security.GridSecurityProcessor; +import org.apache.ignite.plugin.CachePluginContext; +import org.apache.ignite.plugin.CachePluginProvider; +import org.apache.ignite.plugin.ExtensionRegistry; +import org.apache.ignite.plugin.IgnitePlugin; +import org.apache.ignite.plugin.PluginConfiguration; +import org.apache.ignite.plugin.PluginContext; +import org.apache.ignite.plugin.PluginProvider; +import org.apache.ignite.plugin.PluginValidationException; +import org.jetbrains.annotations.Nullable; + +/** + * Security processor provider for tests. + */ +public class TestSecurityProcessorProvider implements PluginProvider { + /** {@inheritDoc} */ + @Override public String name() { + return "TestSecurityProcessorProvider"; + } + + /** {@inheritDoc} */ + @Override public String version() { + return "1.0"; + } + + /** {@inheritDoc} */ + @Override public String copyright() { + return null; + } + + /** {@inheritDoc} */ + @Override public IgnitePlugin plugin() { + return new IgnitePlugin() { + }; + } + + /** {@inheritDoc} */ + @Override public void initExtensions(PluginContext ctx, ExtensionRegistry registry) { + // No-op. + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + @Override public @Nullable Object createComponent(PluginContext ctx, Class cls) { + if (cls.isAssignableFrom(GridSecurityProcessor.class)) { + TestSecurityPluginConfiguration cfg = secProcBuilder(ctx); + + return cfg != null ? cfg.build(((IgniteEx)ctx.grid()).context()) : null; + } + + return null; + } + + /** + * Gets security processor builder. + * + * @param ctx Context. + */ + private TestSecurityPluginConfiguration secProcBuilder(PluginContext ctx){ + IgniteConfiguration igniteCfg = ctx.igniteConfiguration(); + + if (igniteCfg.getPluginConfigurations() != null) { + for (PluginConfiguration pluginCfg : igniteCfg.getPluginConfigurations()) { + if (pluginCfg instanceof TestSecurityPluginConfiguration) + return (TestSecurityPluginConfiguration)pluginCfg; + } + } + + return null; + } + + /** {@inheritDoc} */ + @Override public CachePluginProvider createCacheProvider(CachePluginContext ctx) { + return null; + } + + /** {@inheritDoc} */ + @Override public void start(PluginContext ctx) { + // No-op. + } + + /** {@inheritDoc} */ + @Override public void stop(boolean cancel) { + // No-op. + } + + /** {@inheritDoc} */ + @Override public void onIgniteStart() { + // No-op. + } + + /** {@inheritDoc} */ + @Override public void onIgniteStop(boolean cancel) { + // No-op. + } + + /** {@inheritDoc} */ + @Override public @Nullable Serializable provideDiscoveryData(UUID nodeId) { + return null; + } + + /** {@inheritDoc} */ + @Override public void receiveDiscoveryData(UUID nodeId, Serializable data) { + // No-op. + } + + /** {@inheritDoc} */ + @Override public void validateNewNode(ClusterNode node) throws PluginValidationException { + // No-op. + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecuritySubject.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecuritySubject.java new file mode 100644 index 0000000000000..6fa47cf19e24b --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestSecuritySubject.java @@ -0,0 +1,146 @@ +/* + * 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.processors.security.impl; + +import java.net.InetSocketAddress; +import java.util.UUID; +import org.apache.ignite.plugin.security.SecurityPermissionSet; +import org.apache.ignite.plugin.security.SecuritySubject; +import org.apache.ignite.plugin.security.SecuritySubjectType; + +/** + * Security subject for tests. + */ +public class TestSecuritySubject implements SecuritySubject { + /** Id. */ + private UUID id; + + /** Type. */ + private SecuritySubjectType type = SecuritySubjectType.REMOTE_NODE; + + /** Login. */ + private Object login; + + /** Address. */ + private InetSocketAddress addr; + + /** Permissions. */ + private SecurityPermissionSet perms; + + /** + * Default constructor. + */ + public TestSecuritySubject() { + // No-op. + } + + /** + * @param id Id. + * @param login Login. + * @param addr Address. + * @param perms Permissions. + */ + public TestSecuritySubject(UUID id, + Object login, + InetSocketAddress addr, + SecurityPermissionSet perms) { + this.id = id; + this.login = login; + this.addr = addr; + this.perms = perms; + } + + /** {@inheritDoc} */ + @Override public UUID id() { + return id; + } + + /** + * @param id Id. + */ + public TestSecuritySubject setId(UUID id) { + this.id = id; + + return this; + } + + /** {@inheritDoc} */ + @Override public SecuritySubjectType type() { + return type; + } + + /** + * @param type Type. + */ + public TestSecuritySubject setType(SecuritySubjectType type) { + this.type = type; + + return this; + } + + /** {@inheritDoc} */ + @Override public Object login() { + return login; + } + + /** + * @param login Login. + */ + public TestSecuritySubject setLogin(Object login) { + this.login = login; + + return this; + } + + /** {@inheritDoc} */ + @Override public InetSocketAddress address() { + return addr; + } + + /** + * @param addr Address. + */ + public TestSecuritySubject setAddr(InetSocketAddress addr) { + this.addr = addr; + + return this; + } + + /** {@inheritDoc} */ + @Override public SecurityPermissionSet permissions() { + return perms; + } + + /** + * @param perms Permissions. + */ + public TestSecuritySubject setPerms(SecurityPermissionSet perms) { + this.perms = perms; + + return this; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return "TestSecuritySubject{" + + "id=" + id + + ", type=" + type + + ", login=" + login + + '}'; + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/AuthenticationRestartTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/AuthenticationRestartTest.java index 5841094bf2749..949b1b291d8c1 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/AuthenticationRestartTest.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/AuthenticationRestartTest.java @@ -19,10 +19,10 @@ import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.processors.security.impl.TestSecurityPluginConfiguration; import org.apache.ignite.internal.util.lang.GridAbsPredicate; import org.apache.ignite.lang.IgniteFuture; import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; -import org.apache.ignite.spi.discovery.tcp.TestReconnectPluginProvider; import org.apache.ignite.spi.discovery.tcp.TestReconnectProcessor; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; @@ -41,23 +41,21 @@ public class AuthenticationRestartTest extends GridCommonAbstractTest { ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setJoinTimeout(1120_000); + cfg.setPluginConfigurations( + (TestSecurityPluginConfiguration)TestReconnectProcessor::new + ); + return cfg; } /** {@inheritDoc} */ @Override protected void beforeTestsStarted() throws Exception { - TestReconnectPluginProvider.enabled = true; - TestReconnectProcessor.enabled = true; - startGrid("server"); startGrid("client"); } /** {@inheritDoc} */ @Override protected void afterTestsStopped() throws Exception { - TestReconnectPluginProvider.enabled = false; - TestReconnectProcessor.enabled = false; - stopAllGrids(); } diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryNodeAttributesUpdateOnReconnectTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryNodeAttributesUpdateOnReconnectTest.java index 56dc4ece5f4fc..01c31172cf0a9 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryNodeAttributesUpdateOnReconnectTest.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryNodeAttributesUpdateOnReconnectTest.java @@ -28,6 +28,7 @@ import org.apache.ignite.events.Event; import org.apache.ignite.events.EventType; import org.apache.ignite.internal.IgniteClientReconnectAbstractTest; +import org.apache.ignite.internal.processors.security.impl.TestSecurityPluginConfiguration; import org.apache.ignite.lang.IgnitePredicate; import org.apache.ignite.resources.LoggerResource; import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder; @@ -67,21 +68,18 @@ public class TcpDiscoveryNodeAttributesUpdateOnReconnectTest extends GridCommonA cfg.setDiscoverySpi(spi); + cfg.setPluginConfigurations( + (TestSecurityPluginConfiguration)TestReconnectProcessor::new + ); + return cfg; } /** {@inheritDoc} */ @Override protected void afterTest() throws Exception { - TestReconnectPluginProvider.enabled = false; - stopAllGrids(); } - /** {@inheritDoc} */ - @Override protected void beforeTest() throws Exception { - TestReconnectPluginProvider.enabled = true; - } - /** * @throws Exception If failed. */ diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TestReconnectProcessor.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TestReconnectProcessor.java index 2476bd3d787bf..30d3ac7ebb93e 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TestReconnectProcessor.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TestReconnectProcessor.java @@ -18,6 +18,7 @@ package org.apache.ignite.spi.discovery.tcp; import java.io.Serializable; +import java.net.InetSocketAddress; import java.util.Collection; import java.util.UUID; import org.apache.ignite.IgniteCheckedException; @@ -32,7 +33,9 @@ import org.apache.ignite.plugin.security.SecurityCredentials; import org.apache.ignite.plugin.security.SecurityException; import org.apache.ignite.plugin.security.SecurityPermission; +import org.apache.ignite.plugin.security.SecurityPermissionSet; import org.apache.ignite.plugin.security.SecuritySubject; +import org.apache.ignite.plugin.security.SecuritySubjectType; import org.jetbrains.annotations.Nullable; /** @@ -40,12 +43,12 @@ */ public class TestReconnectProcessor extends GridProcessorAdapter implements GridSecurityProcessor { /** Enabled flag. */ - public static boolean enabled; + public static boolean enabled = true; /** * @param ctx Kernal context. */ - protected TestReconnectProcessor(GridKernalContext ctx) { + public TestReconnectProcessor(GridKernalContext ctx) { super(ctx); } @@ -57,7 +60,7 @@ protected TestReconnectProcessor(GridKernalContext ctx) { /** {@inheritDoc} */ @Override public SecurityContext authenticateNode(ClusterNode node, SecurityCredentials cred) throws IgniteCheckedException { - return new TestSecurityContext(); + return new TestSecurityContext(new TestSecuritySubject(ctx.localNodeId())); } /** {@inheritDoc} */ @@ -101,6 +104,47 @@ protected TestReconnectProcessor(GridKernalContext ctx) { ctx.addNodeAttribute("test", "2"); } + /** + * + */ + private static class TestSecuritySubject implements SecuritySubject { + + /** Id. */ + private final UUID id; + + /** + * @param id Id. + */ + public TestSecuritySubject(UUID id) { + this.id = id; + } + + /** {@inheritDoc} */ + @Override public UUID id() { + return id; + } + + /** {@inheritDoc} */ + @Override public SecuritySubjectType type() { + return SecuritySubjectType.REMOTE_NODE; + } + + /** {@inheritDoc} */ + @Override public Object login() { + return null; + } + + /** {@inheritDoc} */ + @Override public InetSocketAddress address() { + return null; + } + + /** {@inheritDoc} */ + @Override public SecurityPermissionSet permissions() { + return null; + } + } + /** * */ @@ -108,9 +152,19 @@ private static class TestSecurityContext implements SecurityContext, Serializabl /** Serial version uid. */ private static final long serialVersionUID = 0L; + /** Subj. */ + final SecuritySubject subj; + + /** + * @param subj Subj. + */ + public TestSecurityContext(SecuritySubject subj) { + this.subj = subj; + } + /** {@inheritDoc} */ @Override public SecuritySubject subject() { - return null; + return subj; } /** {@inheritDoc} */ @@ -133,4 +187,4 @@ private static class TestSecurityContext implements SecurityContext, Serializabl return true; } } -} +} \ No newline at end of file diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java b/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java index fb035105caaa7..7f6d605ba5fd3 100644 --- a/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java +++ b/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java @@ -72,6 +72,7 @@ import org.apache.ignite.IgniteException; import org.apache.ignite.IgniteLogger; import org.apache.ignite.Ignition; +import org.apache.ignite.cache.query.annotations.QuerySqlFunction; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.IgniteFutureCancelledCheckedException; @@ -100,6 +101,7 @@ import org.apache.ignite.lang.IgniteFuture; import org.apache.ignite.lang.IgniteInClosure; import org.apache.ignite.lang.IgnitePredicate; +import org.apache.ignite.lang.IgniteRunnable; import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.spi.discovery.DiscoverySpiCustomMessage; import org.apache.ignite.spi.discovery.DiscoverySpiListener; @@ -489,6 +491,22 @@ public static Throwable assertThrowsAnyCause(@Nullable IgniteLogger log, Callabl throw new AssertionError("Exception has not been thrown."); } + /** + * Checks whether callable throws exception, which is itself of a specified + * class, or has a cause of the specified class. + * + * @param runnable Runnable. + * @param cls Expected class. + * @return Thrown throwable. + */ + @Nullable public static Throwable assertThrowsWithCause(Runnable runnable, Class cls) { + return assertThrowsWithCause(() -> { + runnable.run(); + + return 0; + }, cls); + } + /** * Checks whether callable throws exception, which is itself of a specified * class, or has a cause of the specified class. @@ -2120,4 +2138,109 @@ public static void cleanIdleVerifyLogFiles() { for (File f : dir.listFiles(n -> n.getName().startsWith(IdleVerifyResultV2.IDLE_VERIFY_FILE_PREFIX))) f.delete(); } + + public static class SqlTestFunctions { + /** Sleep milliseconds. */ + public static volatile long sleepMs; + /** Fail flag. */ + public static volatile boolean fail; + + /** + * Do sleep {@code sleepMs} milliseconds + * + * @return amount of milliseconds to sleep + */ + @QuerySqlFunction + @SuppressWarnings("BusyWait") + public static long sleep() { + long end = System.currentTimeMillis() + sleepMs; + + long remainTime =sleepMs; + + do { + try { + Thread.sleep(remainTime); + } + catch (InterruptedException ignored) { + // No-op + } + } + while ((remainTime = end - System.currentTimeMillis()) > 0); + + return sleepMs; + } + + /** + * Function do fail in case of {@code fail} is true, return 0 otherwise. + * + * @return in case of {@code fail} is false return 0, fail otherwise. + */ + @QuerySqlFunction + public static int can_fail() { + if (fail) + throw new IllegalArgumentException(); + else + return 0; + } + + /** + * Function do sleep {@code sleepMs} milliseconds and do fail in case of {@code fail} is true, return 0 otherwise. + * + * @return amount of milliseconds to sleep in case of {@code fail} is false, fail otherwise. + */ + @QuerySqlFunction + public static long sleep_and_can_fail() { + long sleep = sleep(); + + can_fail(); + + return sleep; + } + } + + /** + * Runnable that can throw exceptions. + */ + @FunctionalInterface + public interface RunnableX extends Runnable { + /** + * Runnable body. + * + * @throws Exception If failed. + */ + void runx() throws Exception; + + /** {@inheritdoc} */ + @Override default void run() { + try { + runx(); + } + catch (Exception e) { + throw new IgniteException(e); + } + } + } + + /** + * IgniteRunnable that can throw exceptions. + */ + @FunctionalInterface + public interface IgniteRunnableX extends IgniteRunnable { + /** + * Runnable body. + * + * @throws Exception If failed. + */ + void runx() throws Exception; + + /** {@inheritdoc} */ + @Override default void run() { + try { + runx(); + } + catch (Exception e) { + throw new IgniteException(e); + } + } + } } diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java index e904af6455e6e..a8d62d0c7b66b 100755 --- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java +++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java @@ -1173,11 +1173,23 @@ protected List primaryKeys(IgniteCache cache, final int cnt, fina */ @SuppressWarnings("unchecked") protected List findKeys(IgniteCache cache, final int cnt, final int startFrom, final int type) { + return findKeys(null, cache, cnt, startFrom, type); + } + + /** + * @param node Node. + * @param cache Cache. + * @param cnt Keys count. + * @param startFrom Start value for keys search. + * @return Collection of keys for which given cache is primary. + */ + protected List findKeys(@Nullable ClusterNode node, IgniteCache cache, + final int cnt, final int startFrom, final int type) { assert cnt > 0 : cnt; final List found = new ArrayList<>(cnt); - final ClusterNode locNode = localNode(cache); + final ClusterNode node0 = node != null ? node : localNode(cache); final Affinity aff = (Affinity)affinity(cache); @@ -1190,11 +1202,11 @@ protected List findKeys(IgniteCache cache, final int cnt, final i boolean ok; if (type == 0) - ok = aff.isPrimary(locNode, key); + ok = aff.isPrimary(node0, key); else if (type == 1) - ok = aff.isBackup(locNode, key); + ok = aff.isBackup(node0, key); else if (type == 2) - ok = !aff.isPrimaryOrBackup(locNode, key); + ok = !aff.isPrimaryOrBackup(node0, key); else { fail(); diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java index 336198fd757ae..74f258c97a935 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java @@ -136,6 +136,8 @@ public static TestSuite suite(@Nullable final Set ignoredTests) throws Ex suite.addTest(IgnitePlatformsTestSuite.suite()); + suite.addTest(SecurityTestSuite.suite()); + suite.addTest(new TestSuite(GridSelfTest.class)); suite.addTest(new TestSuite(ClusterGroupHostsSelfTest.class)); suite.addTest(new TestSuite(IgniteMessagingWithClientTest.class)); diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/SecurityTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/SecurityTestSuite.java new file mode 100644 index 0000000000000..4a6d1b4037149 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/SecurityTestSuite.java @@ -0,0 +1,68 @@ +/* + * 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.testsuites; + +import junit.framework.TestSuite; +import org.apache.ignite.internal.processors.security.cache.CacheOperationPermissionCheckTest; +import org.apache.ignite.internal.processors.security.cache.EntryProcessorPermissionCheckTest; +import org.apache.ignite.internal.processors.security.cache.ScanQueryPermissionCheckTest; +import org.apache.ignite.internal.processors.security.cache.closure.CacheLoadRemoteSecurityContextCheckTest; +import org.apache.ignite.internal.processors.security.cache.closure.EntryProcessorRemoteSecurityContextCheckTest; +import org.apache.ignite.internal.processors.security.cache.closure.ScanQueryRemoteSecurityContextCheckTest; +import org.apache.ignite.internal.processors.security.client.ThinClientPermissionCheckTest; +import org.apache.ignite.internal.processors.security.compute.ComputePermissionCheckTest; +import org.apache.ignite.internal.processors.security.compute.closure.ComputeTaskRemoteSecurityContextCheckTest; +import org.apache.ignite.internal.processors.security.compute.closure.DistributedClosureRemoteSecurityContextCheckTest; +import org.apache.ignite.internal.processors.security.compute.closure.ExecutorServiceRemoteSecurityContextCheckTest; +import org.apache.ignite.internal.processors.security.datastreamer.DataStreamerPermissionCheckTest; +import org.apache.ignite.internal.processors.security.datastreamer.closure.DataStreamerRemoteSecurityContextCheckTest; +import org.junit.BeforeClass; + +import static org.apache.ignite.internal.IgniteFeatures.IGNITE_SECURITY_PROCESSOR; + +/** + * Security test suite. + */ +public class SecurityTestSuite extends TestSuite { + /** + * @return Test suite. + * @throws Exception If failed. + */ + public static TestSuite suite() throws Exception { + TestSuite suite = new TestSuite("Ignite security suite."); + + System.setProperty(IGNITE_SECURITY_PROCESSOR.name(), "true"); + + suite.addTestSuite(CacheOperationPermissionCheckTest.class); + suite.addTestSuite(DataStreamerPermissionCheckTest.class); + suite.addTestSuite(ScanQueryPermissionCheckTest.class); + suite.addTestSuite(EntryProcessorPermissionCheckTest.class); + suite.addTestSuite(ComputePermissionCheckTest.class); + + suite.addTestSuite(DistributedClosureRemoteSecurityContextCheckTest.class); + suite.addTestSuite(ComputeTaskRemoteSecurityContextCheckTest.class); + suite.addTestSuite(ExecutorServiceRemoteSecurityContextCheckTest.class); + suite.addTestSuite(ScanQueryRemoteSecurityContextCheckTest.class); + suite.addTestSuite(EntryProcessorRemoteSecurityContextCheckTest.class); + suite.addTestSuite(DataStreamerRemoteSecurityContextCheckTest.class); + suite.addTestSuite(CacheLoadRemoteSecurityContextCheckTest.class); + suite.addTestSuite(ThinClientPermissionCheckTest.class); + + return suite; + } +} diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index 36e66d5e2a4d1..d946eb251a1c3 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -1536,7 +1536,7 @@ private void checkSecurity(Collection cacheIds) { DynamicCacheDescriptor desc = ctx.cache().cacheDescriptor(cacheId); if (desc != null) - ctx.security().authorize(desc.cacheName(), SecurityPermission.CACHE_READ, null); + ctx.security().authorize(desc.cacheName(), SecurityPermission.CACHE_READ); } } diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java index 75249789e5b0e..2ea5507c73902 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java @@ -330,7 +330,7 @@ else if (stmt0 instanceof GridSqlDropIndex) { } } else if (stmt0 instanceof GridSqlCreateTable) { - ctx.security().authorize(null, SecurityPermission.CACHE_CREATE, null); + ctx.security().authorize(null, SecurityPermission.CACHE_CREATE); GridSqlCreateTable cmd = (GridSqlCreateTable)stmt0; @@ -363,7 +363,7 @@ else if (stmt0 instanceof GridSqlCreateTable) { } } else if (stmt0 instanceof GridSqlDropTable) { - ctx.security().authorize(null, SecurityPermission.CACHE_DESTROY, null); + ctx.security().authorize(null, SecurityPermission.CACHE_DESTROY); GridSqlDropTable cmd = (GridSqlDropTable)stmt0; diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/AbstractSchemaSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/AbstractSchemaSelfTest.java index 3cb6de61b56ba..f0cb7101f38f3 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/AbstractSchemaSelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/AbstractSchemaSelfTest.java @@ -229,7 +229,7 @@ private static void assertInternalIndexParams(QueryTypeDescriptorImpl typeDesc, * @param node Node to connect to. * @return Thin JDBC connection to specified node. */ - static Connection connect(IgniteEx node) { + public static Connection connect(IgniteEx node) { Collection recs = node.context().ports().records(); GridPortRecord cliLsnrRec = null; @@ -573,16 +573,4 @@ public String field() { return field; } } - - /** - * Runnable which can throw checked exceptions. - */ - protected interface RunnableX { - /** - * Do run. - * - * @throws Exception If failed. - */ - public void run() throws Exception; - } } diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicColumnsAbstractConcurrentSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicColumnsAbstractConcurrentSelfTest.java index 3f090620287d2..19dbe33ec11d2 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicColumnsAbstractConcurrentSelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicColumnsAbstractConcurrentSelfTest.java @@ -59,6 +59,7 @@ import org.apache.ignite.internal.util.typedef.T3; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgnitePredicate; +import org.apache.ignite.testframework.GridTestUtils; import static org.apache.ignite.internal.IgniteClientReconnectAbstractTest.TestTcpDiscoverySpi; @@ -777,8 +778,8 @@ private void checkClientReconnect(final boolean restartCache, boolean dynamicCac new QueryField[] { c("age", Integer.class.getName()), c("city", String.class.getName()) }; // Check index create. - reconnectClientNode(srv, cli, restartCache, dynamicCache, new RunnableX() { - @Override public void run() throws Exception { + reconnectClientNode(srv, cli, restartCache, dynamicCache, new GridTestUtils.RunnableX() { + @Override public void runx() throws Exception { addCols(srv, schemaName, cols).get(); dropCols(srv, schemaName, "NAME").get(); @@ -799,7 +800,7 @@ private void checkClientReconnect(final boolean restartCache, boolean dynamicCac * @throws Exception If failed. */ private void reconnectClientNode(final Ignite srvNode, final Ignite cliNode, final boolean restart, - final boolean dynamicCache, final RunnableX clo) throws Exception { + final boolean dynamicCache, final GridTestUtils.RunnableX clo) throws Exception { IgniteClientReconnectAbstractTest.reconnectClientNode(log, cliNode, srvNode, new Runnable() { @Override public void run() { if (restart) { @@ -1201,19 +1202,6 @@ private IgniteConfiguration serverConfiguration(int nodeIdx, boolean filtered) t return cfg; } - /** - * Runnable which can throw checked exceptions. - */ - interface RunnableX { - /** - * Do run. - * - * @throws Exception If failed. - */ - @SuppressWarnings("UnnecessaryInterfaceModifier") - public void run() throws Exception; - } - /** * Node filter. */ diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicIndexAbstractBasicSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicIndexAbstractBasicSelfTest.java index 65c9454565770..8b6570a6ac88c 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicIndexAbstractBasicSelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicIndexAbstractBasicSelfTest.java @@ -25,6 +25,7 @@ import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteSystemProperties; +import org.apache.ignite.IgniteException; import org.apache.ignite.Ignition; import org.apache.ignite.cache.CacheAtomicityMode; import org.apache.ignite.cache.CacheMode; @@ -44,6 +45,8 @@ import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL; import static org.apache.ignite.cache.CacheMode.PARTITIONED; import static org.apache.ignite.cache.CacheMode.REPLICATED; +import static org.apache.ignite.testframework.GridTestUtils.RunnableX; +import static org.apache.ignite.testframework.GridTestUtils.assertThrows; /** * Tests for dynamic index creation. @@ -203,7 +206,7 @@ private void checkCreate(CacheMode mode, CacheAtomicityMode atomicityMode, boole assertIndex(CACHE_NAME, TBL_NAME, IDX_NAME_1, QueryIndex.DFLT_INLINE_SIZE, field(FIELD_NAME_1_ESCAPED)); assertIgniteSqlException(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { dynamicIndexCreate(CACHE_NAME, TBL_NAME, idx, false, 0); } }, IgniteQueryErrorCode.INDEX_ALREADY_EXISTS); @@ -446,7 +449,7 @@ private void checkCreateNoTable(CacheMode mode, CacheAtomicityMode atomicityMode final QueryIndex idx = index(IDX_NAME_1, field(FIELD_NAME_1_ESCAPED)); assertIgniteSqlException(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { dynamicIndexCreate(CACHE_NAME, randomString(), idx, false, 0); } }, IgniteQueryErrorCode.TABLE_NOT_FOUND); @@ -522,7 +525,7 @@ private void checkCreateIndexNoColumn(CacheMode mode, CacheAtomicityMode atomici final QueryIndex idx = index(IDX_NAME_1, field(randomString())); assertIgniteSqlException(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { dynamicIndexCreate(CACHE_NAME, TBL_NAME, idx, false, 0); } }, IgniteQueryErrorCode.COLUMN_NOT_FOUND); @@ -597,7 +600,7 @@ private void checkCreateIndexOnColumnWithAlias(CacheMode mode, CacheAtomicityMod initialize(mode, atomicityMode, near); assertIgniteSqlException(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { QueryIndex idx = index(IDX_NAME_1, field(FIELD_NAME_2_ESCAPED)); dynamicIndexCreate(CACHE_NAME, TBL_NAME, idx, false, 0); @@ -735,7 +738,7 @@ private void checkIndexCreatedForInlineSize(int inlineSize) throws Exception { */ private void checkNoIndexIsCreatedForInlineSize(final int inlineSize, int igniteQryErrorCode) throws Exception { assertIgniteSqlException(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { QueryIndex idx = index(IDX_NAME_1, field(FIELD_NAME_1_ESCAPED)); idx.setInlineSize(inlineSize); dynamicIndexCreate(CACHE_NAME, TBL_NAME, idx, false, 0); @@ -866,7 +869,7 @@ private void checkIndexCreatedForParallelism(int parallel) throws Exception { */ private void checkNoIndexIsCreatedForParallelism(final int parallel, int igniteQryErrorCode) throws Exception { assertIgniteSqlException(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { QueryIndex idx = index(IDX_NAME_1, field(FIELD_NAME_1_ESCAPED)); dynamicIndexCreate(CACHE_NAME, TBL_NAME, idx, false, parallel); } @@ -1037,7 +1040,7 @@ private void checkDropNoIndex(CacheMode mode, CacheAtomicityMode atomicityMode, initialize(mode, atomicityMode, near); assertIgniteSqlException(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { dynamicIndexDrop(CACHE_NAME, IDX_NAME_1, false); } }, IgniteQueryErrorCode.INDEX_NOT_FOUND); @@ -1146,7 +1149,7 @@ public void testFailOnLocalCache() throws Exception { final QueryIndex idx = index(IDX_NAME_1, field(FIELD_NAME_1_ESCAPED)); assertIgniteSqlException(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { dynamicIndexCreate(CACHE_NAME, TBL_NAME, idx, true, 0); } }, IgniteQueryErrorCode.UNSUPPORTED_OPERATION); @@ -1154,7 +1157,7 @@ public void testFailOnLocalCache() throws Exception { assertNoIndex(CACHE_NAME, TBL_NAME, IDX_NAME_1); assertIgniteSqlException(new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { dynamicIndexDrop(CACHE_NAME, IDX_NAME_LOCAL, true); } }, IgniteQueryErrorCode.UNSUPPORTED_OPERATION); @@ -1385,22 +1388,15 @@ private static void assertIgniteSqlException(RunnableX r, String msg, int expCod try { r.run(); } - catch (CacheException e) { - Throwable cause = e.getCause(); - - assertTrue(cause != null); - assertTrue("Unexpected cause: " + cause.getClass().getName(), cause instanceof IgniteSQLException); - - IgniteSQLException cause0 = (IgniteSQLException)cause; - - int code = cause0.statusCode(); + catch (IgniteException ie){ + assertTrue("Unexpected exception: " + ie, ie.getCause() instanceof CacheException); - assertEquals("Unexpected error code [expected=" + expCode + ", actual=" + code + - ", msg=" + cause.getMessage() + ']', expCode, code); + checkCacheException(msg, expCode, (CacheException)ie.getCause()); - if (msg != null) - assertEquals("Unexpected error message [expected=" + msg + ", actual=" + cause0.getMessage() + ']', - msg, cause0.getMessage()); + return; + } + catch (CacheException e) { + checkCacheException(msg, expCode, e); return; } @@ -1411,6 +1407,25 @@ private static void assertIgniteSqlException(RunnableX r, String msg, int expCod fail(IgniteSQLException.class.getSimpleName() + " is not thrown."); } + /** */ + private static void checkCacheException(String msg, int expCode, CacheException e) { + Throwable cause = e.getCause(); + + assertTrue(cause != null); + assertTrue("Unexpected cause: " + cause.getClass().getName(), cause instanceof IgniteSQLException); + + IgniteSQLException cause0 = (IgniteSQLException)cause; + + int code = cause0.statusCode(); + + assertEquals("Unexpected error code [expected=" + expCode + ", actual=" + code + + ", msg=" + cause.getMessage() + ']', expCode, code); + + if (msg != null) + assertEquals("Unexpected error message [expected=" + msg + ", actual=" + cause0.getMessage() + ']', + msg, cause0.getMessage()); + } + /** * Synchronously create index. * diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicIndexAbstractConcurrentSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicIndexAbstractConcurrentSelfTest.java index f8bb0cf84b713..d8999e4091288 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicIndexAbstractConcurrentSelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicIndexAbstractConcurrentSelfTest.java @@ -53,6 +53,7 @@ import org.jetbrains.annotations.NotNull; import static org.apache.ignite.internal.IgniteClientReconnectAbstractTest.TestTcpDiscoverySpi; +import static org.apache.ignite.testframework.GridTestUtils.RunnableX; /** * Concurrency tests for dynamic index create/drop. @@ -663,7 +664,7 @@ private void checkClientReconnect(final boolean restartCache) throws Exception { // Check index create. reconnectClientNode(srv, cli, restartCache, new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { final QueryIndex idx = index(IDX_NAME_1, field(FIELD_NAME_1)); queryProcessor(srv).dynamicIndexCreate(CACHE_NAME, CACHE_NAME, TBL_NAME, idx, false, 0).get(); @@ -676,7 +677,7 @@ private void checkClientReconnect(final boolean restartCache) throws Exception { // Check index drop. reconnectClientNode(srv, cli, restartCache, new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { if (!restartCache) queryProcessor(srv).dynamicIndexDrop(CACHE_NAME, CACHE_NAME, IDX_NAME_1, false).get(); } @@ -696,7 +697,7 @@ private void checkClientReconnect(final boolean restartCache) throws Exception { assertIndexUsed(IDX_NAME_2, SQL_SIMPLE_FIELD_2, SQL_ARG_2); reconnectClientNode(srv, cli, restartCache, new RunnableX() { - @Override public void run() throws Exception { + @Override public void runx() throws Exception { if (!restartCache) queryProcessor(srv).dynamicIndexDrop(CACHE_NAME, CACHE_NAME, IDX_NAME_2, false).get(); @@ -721,7 +722,7 @@ private void checkClientReconnect(final boolean restartCache) throws Exception { * @throws Exception If failed. */ private void reconnectClientNode(final Ignite srvNode, final Ignite cliNode, final boolean restart, - final RunnableX clo) throws Exception { + final Runnable clo) throws Exception { IgniteClientReconnectAbstractTest.reconnectClientNode(log, cliNode, srvNode, new Runnable() { @Override public void run() { if (restart) { diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicIndexAbstractSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicIndexAbstractSelfTest.java index 0684f7f6e8e69..69056a4698e46 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicIndexAbstractSelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicIndexAbstractSelfTest.java @@ -37,6 +37,7 @@ import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode; import org.apache.ignite.internal.processors.query.IgniteSQLException; import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.testframework.GridTestUtils; /** * Test that checks indexes handling on H2 side. @@ -130,8 +131,8 @@ public void testCreateIndexWithDuplicateName() { cache.query(new SqlFieldsQuery("CREATE INDEX \"" + IDX_NAME_1_ESCAPED + "\" ON \"" + TBL_NAME_ESCAPED + "\"(\"" + FIELD_NAME_1_ESCAPED + "\" ASC)")); - assertSqlException(new RunnableX() { - @Override public void run() throws Exception { + assertSqlException(new GridTestUtils.RunnableX() { + @Override public void runx() { cache.query(new SqlFieldsQuery("CREATE INDEX \"" + IDX_NAME_1_ESCAPED + "\" ON \"" + TBL_NAME_ESCAPED + "\"(\"id\" ASC)")); } @@ -192,8 +193,8 @@ public void testDropIndex() { public void testDropMissingIndex() { final IgniteCache cache = cache(); - assertSqlException(new RunnableX() { - @Override public void run() throws Exception { + assertSqlException(new GridTestUtils.RunnableX() { + @Override public void runx() { cache.query(new SqlFieldsQuery("DROP INDEX \"" + IDX_NAME_1_ESCAPED + "\"")); } }, IgniteQueryErrorCode.INDEX_NOT_FOUND); @@ -379,10 +380,10 @@ private CacheConfiguration cacheConfiguration() { * @param r Runnable. * @param expCode Error code. */ - private static void assertSqlException(DynamicIndexAbstractBasicSelfTest.RunnableX r, int expCode) { + private static void assertSqlException(GridTestUtils.RunnableX r, int expCode) { try { try { - r.run(); + r.runx(); } catch (CacheException e) { if (e.getCause() != null) diff --git a/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryImpl.java b/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryImpl.java index 260d5539f2e90..835e6f83077d0 100644 --- a/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryImpl.java +++ b/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryImpl.java @@ -57,11 +57,13 @@ import org.apache.ignite.internal.IgniteFutureTimeoutCheckedException; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.IgniteKernal; +import org.apache.ignite.internal.IgniteNodeAttributes; import org.apache.ignite.internal.IgnitionEx; import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; import org.apache.ignite.internal.events.DiscoveryCustomEvent; import org.apache.ignite.internal.managers.discovery.IgniteDiscoverySpiInternalListener; import org.apache.ignite.internal.processors.security.SecurityContext; +import org.apache.ignite.internal.processors.security.SecurityUtils; import org.apache.ignite.internal.util.GridLongList; import org.apache.ignite.internal.util.GridSpinBusyLock; import org.apache.ignite.internal.util.IgniteUtils; @@ -2093,6 +2095,18 @@ private ZkNodeValidateResult authenticateNode(ZookeeperClusterNode node) { return new ZkNodeValidateResult("Authentication failed"); } + try { + // Stick in authentication subject to node (use security-safe attributes for copy). + Map attrs = new HashMap<>(node.getAttributes()); + + attrs.put(IgniteNodeAttributes.ATTR_SECURITY_SUBJECT_V2, U.marshal(marsh, subj)); + attrs.put(IgniteNodeAttributes.ATTR_SECURITY_SUBJECT, marshalWithSecurityVersion(subj, 1)); + + node.setAttributes(attrs); + } catch (IgniteCheckedException e) { + U.warn(log, "Security subject cannot be created.", e); + } + if (!(subj instanceof Serializable)) { U.warn(log, "Authentication subject is not Serializable [nodeId=" + node.id() + ", addrs=" + U.addressesAsString(node) + ']'); @@ -2114,6 +2128,22 @@ private ZkNodeValidateResult authenticateNode(ZookeeperClusterNode node) { return new ZkNodeValidateResult(secSubjZipBytes); } + /** + * @param obj Object. + * @param ver Security serialize version. + * @return Marshaled object. + */ + private byte[] marshalWithSecurityVersion(Object obj, int ver) throws IgniteCheckedException { + try { + SecurityUtils.serializeVersion(ver); + + return U.marshal(marsh, obj); + } + finally { + SecurityUtils.restoreDefaultSerializeVersion(); + } + } + /** * @throws Exception If failed. */ From b8a547fdb7a79b6a3baf63387f5f209087a57e5d Mon Sep 17 00:00:00 2001 From: ktkalenko Date: Wed, 17 Jul 2019 11:54:50 +0300 Subject: [PATCH 45/62] GG-19117 GridCacheProcessor should add info about cache in exception message, if applicable. (cherry picked from commit 4b045f5a0f04ce89a3266f825bebd3136af5c0b0) --- .../processors/cache/GridCacheProcessor.java | 63 +++++++++++++++---- 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java index 2bf598e284a9d..230162ea3d010 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java @@ -35,6 +35,7 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; import java.util.stream.Collectors; import javax.management.MBeanServer; import org.apache.ignite.IgniteCheckedException; @@ -212,6 +213,12 @@ public class GridCacheProcessor extends GridProcessorAdapter { private static final String MERGE_OF_CONFIG_REQUIRED_MESSAGE = "Failed to join node to the active cluster " + "(the config of the cache '%s' has to be merged which is impossible on active grid). " + "Deactivate grid and retry node join or clean the joining node."; + /** */ + private static final String CACHE_NAME_AND_OPERATION_FORMAT = "[cacheName=%s, operation=%s]"; + + /** */ + private static final String CACHE_NAMES_AND_OPERATION_FORMAT = "[cacheNames=%s, operation=%s]"; + /** */ private final boolean startClientCaches = IgniteSystemProperties.getBoolean(IgniteSystemProperties.IGNITE_START_CACHES_ON_JOIN, false); @@ -3699,8 +3706,10 @@ public IgniteInternalFuture dynamicStartCache( ) { assert cacheName != null; - if (checkThreadTx) - checkEmptyTransactions(); + if (checkThreadTx) { + checkEmptyTransactionsEx(() -> String.format(CACHE_NAME_AND_OPERATION_FORMAT, cacheName, + "dynamicStartCache")); + } try { DynamicCacheChangeRequest req = prepareCacheChangeRequest( @@ -3794,8 +3803,16 @@ public IgniteInternalFuture dynamicStartCachesByStoredConf( boolean disabledAfterStart, IgniteUuid restartId ) { - if (checkThreadTx) - checkEmptyTransactions(); + if (checkThreadTx) { + checkEmptyTransactionsEx(() -> { + List cacheNames = storedCacheDataList.stream() + .map(StoredCacheData::config) + .map(CacheConfiguration::getName) + .collect(Collectors.toList()); + + return String.format(CACHE_NAMES_AND_OPERATION_FORMAT, cacheNames, "dynamicStartCachesByStoredConf"); + }); + } List srvReqs = null; Map clientReqs = null; @@ -3887,8 +3904,10 @@ public IgniteInternalFuture dynamicDestroyCache( ) { assert cacheName != null; - if (checkThreadTx) - checkEmptyTransactions(); + if (checkThreadTx) { + checkEmptyTransactionsEx(() -> String.format(CACHE_NAME_AND_OPERATION_FORMAT, cacheName, + "dynamicDestroyCache")); + } DynamicCacheChangeRequest req = DynamicCacheChangeRequest.stopRequest(ctx, cacheName, sql, true); @@ -3920,8 +3939,10 @@ public IgniteInternalFuture dynamicDestroyCaches( boolean checkThreadTx, boolean destroy ) { - if (checkThreadTx) - checkEmptyTransactions(); + if (checkThreadTx) { + checkEmptyTransactionsEx(() -> String.format(CACHE_NAMES_AND_OPERATION_FORMAT, cacheNames, + "dynamicDestroyCaches")); + } List reqs = new ArrayList<>(cacheNames.size()); @@ -4007,7 +4028,7 @@ IgniteInternalFuture dynamicCloseCache(String cacheName) { if (proxy == null || proxy.isProxyClosed()) return new GridFinishedFuture<>(); // No-op. - checkEmptyTransactions(); + checkEmptyTransactionsEx(() -> String.format(CACHE_NAME_AND_OPERATION_FORMAT, cacheName, "dynamicCloseCache")); if (proxy.context().isLocal()) return dynamicDestroyCache(cacheName, false, true, false, null); @@ -4022,11 +4043,14 @@ IgniteInternalFuture dynamicCloseCache(String cacheName) { * @return Future that will be completed when state is changed for all caches. */ public IgniteInternalFuture resetCacheState(Collection cacheNames) { - checkEmptyTransactions(); - if (F.isEmpty(cacheNames)) cacheNames = cachesInfo.registeredCaches().keySet(); + Collection forCheckCacheNames = cacheNames; + + checkEmptyTransactionsEx(() -> String.format(CACHE_NAME_AND_OPERATION_FORMAT, forCheckCacheNames, + "resetCacheState")); + Collection reqs = new ArrayList<>(cacheNames.size()); for (String cacheName : cacheNames) { @@ -5204,6 +5228,23 @@ public void checkEmptyTransactions() throws IgniteException { throw new IgniteException("Cannot start/stop cache within lock or transaction."); } + /** + * Method invoke {@link #checkEmptyTransactions()} and add message in case exception. + * + * @param eMsgSupplier supplier additional text message + * @throws IgniteException If {@link #checkEmptyTransactions()} throw {@link IgniteException} + * */ + private void checkEmptyTransactionsEx(final Supplier eMsgSupplier) throws IgniteException { + assert eMsgSupplier != null; + + try { + checkEmptyTransactions(); + } + catch (IgniteException e) { + throw new IgniteException(e.getMessage() + ' ' + eMsgSupplier.get(), e); + } + } + /** * @param val Object to check. * @return Configuration copy. From 60eda4fc6f6b817d08ade8a947a5194fa1bba16b Mon Sep 17 00:00:00 2001 From: ktkalenko Date: Wed, 17 Jul 2019 12:34:53 +0300 Subject: [PATCH 46/62] GG-21225 control.sh validate_indexes SQL Index issue add information about group and cache id. (cherry picked from commit f3017ea805e1334e2bdcf5a083aa830a28be3013) --- .../internal/visor/verify/ValidateIndexesClosure.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesClosure.java b/modules/indexing/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesClosure.java index 10591752058fd..02ddbaf451431 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesClosure.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesClosure.java @@ -738,7 +738,16 @@ else if (current++ % checkThrough > 0) } } - String uniqueIdxName = "[cacheGroup=" + ctx.group().name() + ", cache=" + ctx.name() + ", idx=" + idx.getName() + "]"; + CacheGroupContext group = ctx.group(); + + String uniqueIdxName = String.format( + "[cacheGroup=%s, cacheGroupId=%s, cache=%s, cacheId=%s, idx=%s]", + group.name(), + group.groupId(), + ctx.name(), + ctx.cacheId(), + idx.getName() + ); processedIndexes.incrementAndGet(); From 884f66139607f1db7e8f830cd94e2a41394a7c01 Mon Sep 17 00:00:00 2001 From: Dmitriy Govorukhin Date: Wed, 17 Jul 2019 12:50:00 +0300 Subject: [PATCH 47/62] GG-21472 [GG-21254] Fixed *.testFailAfterStart failed on TC (cherry picked from commit f7f0b89c947ac421c3e49a45a5357413198c59ba) --- ...lushMultiNodeFailoverAbstractSelfTest.java | 66 +++++++++---------- 1 file changed, 30 insertions(+), 36 deletions(-) diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushMultiNodeFailoverAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushMultiNodeFailoverAbstractSelfTest.java index 07fdb71fca68a..25da4cfeaf92b 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushMultiNodeFailoverAbstractSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushMultiNodeFailoverAbstractSelfTest.java @@ -25,9 +25,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; -import org.apache.ignite.IgniteSystemProperties; -import org.apache.ignite.cache.CacheAtomicityMode; -import org.apache.ignite.cache.CacheRebalanceMode; import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.DataRegionConfiguration; @@ -49,17 +46,15 @@ import org.apache.ignite.transactions.TransactionConcurrency; import org.apache.ignite.transactions.TransactionIsolation; -import static java.nio.file.StandardOpenOption.CREATE; -import static java.nio.file.StandardOpenOption.READ; -import static java.nio.file.StandardOpenOption.WRITE; +import static org.apache.ignite.IgniteSystemProperties.IGNITE_DISABLE_WAL_DURING_REBALANCING; +import static org.apache.ignite.IgniteSystemProperties.IGNITE_WAL_MMAP; +import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL; +import static org.apache.ignite.cache.CacheRebalanceMode.SYNC; /** * Tests error recovery while node flushing */ public abstract class IgniteWalFlushMultiNodeFailoverAbstractSelfTest extends GridCommonAbstractTest { - /** */ - private static final String TEST_CACHE = "testCache"; - /** */ private static final int ITRS = 2000; @@ -116,22 +111,23 @@ protected boolean mmap() { cfg.setConsistentId(gridName); - CacheConfiguration cacheCfg = new CacheConfiguration(TEST_CACHE) - .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL) + cfg.setCacheConfiguration( + new CacheConfiguration(DEFAULT_CACHE_NAME) + .setAtomicityMode(TRANSACTIONAL) .setBackups(1) - .setRebalanceMode(CacheRebalanceMode.SYNC) - .setAffinity(new RendezvousAffinityFunction(false, 32)); - - cfg.setCacheConfiguration(cacheCfg); + .setRebalanceMode(SYNC) + .setAffinity(new RendezvousAffinityFunction(false, 32)) + ); - DataStorageConfiguration memCfg = new DataStorageConfiguration() + cfg.setDataStorageConfiguration( + new DataStorageConfiguration() .setDefaultDataRegionConfiguration( - new DataRegionConfiguration().setMaxSize(2048L * 1024 * 1024).setPersistenceEnabled(true)) - .setWalMode(this.walMode()) - .setWalSegmentSize(50_000) - .setWalBufferSize(50_000); - - cfg.setDataStorageConfiguration(memCfg); + new DataRegionConfiguration() + .setMaxSize(2048L * 1024 * 1024) + .setPersistenceEnabled(true)) + .setWalMode(walMode()) + .setWalSegmentSize(512 * 1024) + .setWalBufferSize(512 * 1024)); cfg.setFailureHandler(new StopNodeFailureHandler()); @@ -159,17 +155,17 @@ public void testFailAfterStart() throws Exception { /** * @throws Exception if failed. */ - public void failWhilePut(boolean failWhileStart) throws Exception { - final Ignite grid = startGridsMultiThreaded(gridCount()); + private void failWhilePut(boolean failWhileStart) throws Exception { + Ignite ig = startGrids(gridCount()); - grid.cluster().active(true); + ig.cluster().active(true); - IgniteCache cache = grid.cache(TEST_CACHE); + IgniteCache cache = ig.cache(DEFAULT_CACHE_NAME); for (int i = 0; i < ITRS; i++) { - while (true) { - try (Transaction tx = grid.transactions().txStart( - TransactionConcurrency.PESSIMISTIC, TransactionIsolation.READ_COMMITTED)) { + while (!Thread.currentThread().isInterrupted()) { + try (Transaction tx = ig.transactions().txStart( + TransactionConcurrency.PESSIMISTIC, TransactionIsolation.REPEATABLE_READ)) { cache.put(i, "testValue" + i); tx.commit(); @@ -190,7 +186,7 @@ public void failWhilePut(boolean failWhileStart) throws Exception { setFileIOFactory(grid(gridCount()).context().cache().context().wal()); - grid.cluster().setBaselineTopology(grid.cluster().topologyVersion()); + ig.cluster().setBaselineTopology(ig.cluster().topologyVersion()); awaitPartitionMapExchange(); } @@ -206,7 +202,7 @@ public void failWhilePut(boolean failWhileStart) throws Exception { // We should await successful stop of node. GridTestUtils.waitForCondition(new GridAbsPredicate() { @Override public boolean apply() { - return grid.cluster().nodes().size() == gridCount(); + return ig.cluster().nodes().size() == gridCount(); } }, getTestTimeout()); @@ -216,11 +212,9 @@ public void failWhilePut(boolean failWhileStart) throws Exception { Ignite grid0 = startGrids(gridCount() + 1); - setFileIOFactory(grid(gridCount()).context().cache().context().wal()); - grid0.cluster().active(true); - cache = grid0.cache(TEST_CACHE); + cache = grid0.cache(DEFAULT_CACHE_NAME); for (int i = 0; i < ITRS; i++) assertEquals(cache.get(i), "testValue" + i); @@ -261,7 +255,7 @@ private static class FailingFileIOFactory implements FileIOFactory { return new FileIODecorator(delegate) { /** {@inheritDoc} */ @Override public int write(ByteBuffer srcBuf) throws IOException { - if (fail != null && fail.get()) + if (fail != null && file.getName().endsWith(".wal") && fail.get()) throw new IOException("No space left on device"); return super.write(srcBuf); @@ -269,7 +263,7 @@ private static class FailingFileIOFactory implements FileIOFactory { /** {@inheritDoc} */ @Override public MappedByteBuffer map(int sizeBytes) throws IOException { - if (fail != null && fail.get()) + if (fail != null && file.getName().endsWith(".wal") && fail.get()) throw new IOException("No space left on deive"); return delegate.map(sizeBytes); From f196f2cf4a5d3c33f57d1a7ddf391e3f2a88c3dd Mon Sep 17 00:00:00 2001 From: Dmitriy Govorukhin Date: Wed, 17 Jul 2019 13:28:57 +0300 Subject: [PATCH 48/62] GG-21472 [GG-21254] Fixed *.testFailAfterStart failed on TC (cherry picked from commit f7f0b89c947ac421c3e49a45a5357413198c59ba) --- .../IgniteWalFlushMultiNodeFailoverAbstractSelfTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushMultiNodeFailoverAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushMultiNodeFailoverAbstractSelfTest.java index 25da4cfeaf92b..2781b782fd5a7 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushMultiNodeFailoverAbstractSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushMultiNodeFailoverAbstractSelfTest.java @@ -74,7 +74,8 @@ public abstract class IgniteWalFlushMultiNodeFailoverAbstractSelfTest extends Gr cleanPersistenceDir(); - System.setProperty(IgniteSystemProperties.IGNITE_WAL_MMAP, Boolean.toString(mmap())); + System.setProperty(IGNITE_WAL_MMAP, Boolean.toString(mmap())); + System.setProperty(IGNITE_DISABLE_WAL_DURING_REBALANCING, "false"); } /** {@inheritDoc} */ @@ -83,7 +84,8 @@ public abstract class IgniteWalFlushMultiNodeFailoverAbstractSelfTest extends Gr cleanPersistenceDir(); - System.clearProperty(IgniteSystemProperties.IGNITE_WAL_MMAP); + System.clearProperty(IGNITE_WAL_MMAP); + System.clearProperty(IGNITE_DISABLE_WAL_DURING_REBALANCING); super.afterTest(); } From 6674af25ccf89b3bfd3cf4360c4e452166ceaf99 Mon Sep 17 00:00:00 2001 From: ktkalenko Date: Wed, 17 Jul 2019 15:09:21 +0300 Subject: [PATCH 49/62] GG-20905 Print warning if awaiting next wal segment it too long. (cherry picked from commit 4f05cd91e58a8d7fb266f2e0253d197c52b20b51) --- .../apache/ignite/IgniteSystemProperties.java | 18 ++++++++++++++ .../wal/FileWriteAheadLogManager.java | 24 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java index 7920a9cd6a572..c36bfe4f4283b 100644 --- a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java +++ b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java @@ -882,6 +882,24 @@ public final class IgniteSystemProperties { */ public static final String IGNITE_LOADED_PAGES_BACKWARD_SHIFT_MAP = "IGNITE_LOADED_PAGES_BACKWARD_SHIFT_MAP"; + /** + * Property for setup percentage of archive size for checkpoint trigger. Default value is 0.25 + */ + public static final String IGNITE_CHECKPOINT_TRIGGER_ARCHIVE_SIZE_PERCENTAGE = "IGNITE_CHECKPOINT_TRIGGER_ARCHIVE_SIZE_PERCENTAGE"; + + /** + * Property for setup percentage of WAL archive size to calculate threshold since which removing of old archive should be started. + * Default value is 0.5 + */ + public static final String IGNITE_THRESHOLD_WAL_ARCHIVE_SIZE_PERCENTAGE = "IGNITE_THRESHOLD_WAL_ARCHIVE_SIZE_PERCENTAGE"; + + /** + * Threshold time (in millis) to print warning to log if waiting for next wal segment took longer than the threshold. + * + * Default value is 1000 ms. + */ + public static final String IGNITE_THRESHOLD_WAIT_TIME_NEXT_WAL_SEGMENT = "IGNITE_THRESHOLD_WAIT_TIME_NEXT_WAL_SEGMENT"; + /** * Count of WAL compressor worker threads. Default value is 4. */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java index 8b166f3e9a0c6..5169ef64f7a22 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java @@ -134,6 +134,9 @@ import static java.nio.file.StandardOpenOption.CREATE; import static java.nio.file.StandardOpenOption.READ; import static java.nio.file.StandardOpenOption.WRITE; +import static org.apache.ignite.IgniteSystemProperties.IGNITE_CHECKPOINT_TRIGGER_ARCHIVE_SIZE_PERCENTAGE; +import static org.apache.ignite.IgniteSystemProperties.IGNITE_THRESHOLD_WAIT_TIME_NEXT_WAL_SEGMENT; +import static org.apache.ignite.IgniteSystemProperties.IGNITE_THRESHOLD_WAL_ARCHIVE_SIZE_PERCENTAGE; import static org.apache.ignite.IgniteSystemProperties.IGNITE_WAL_COMPRESSOR_WORKER_THREAD_CNT; import static org.apache.ignite.IgniteSystemProperties.IGNITE_WAL_MMAP; import static org.apache.ignite.IgniteSystemProperties.IGNITE_WAL_SEGMENT_SYNC_TIMEOUT; @@ -256,6 +259,12 @@ public class FileWriteAheadLogManager extends GridCacheSharedManagerAdapter impl private final int WAL_COMPRESSOR_WORKER_THREAD_CNT = IgniteSystemProperties.getInteger(IGNITE_WAL_COMPRESSOR_WORKER_THREAD_CNT, 4); + /** + * Threshold time to print warning to log if awaiting for next wal segment took too long (exceeded this threshold). + */ + private static final long THRESHOLD_WAIT_TIME_NEXT_WAL_SEGMENT = + IgniteSystemProperties.getLong(IGNITE_THRESHOLD_WAIT_TIME_NEXT_WAL_SEGMENT, 1000L); + /** */ private final boolean alwaysWriteFullPages; @@ -1528,9 +1537,24 @@ private File pollNextFile(long curIdx) throws StorageException, IgniteInterrupte return new File(walWorkDir, FileDescriptor.fileName(curIdx + 1)); } + long absNextIdxStartTime = System.nanoTime(); + // Signal to archiver that we are done with the segment and it can be archived. long absNextIdx = archiver0.nextAbsoluteSegmentIndex(); + long absNextIdxWaitTime = U.nanosToMillis(System.nanoTime() - absNextIdxStartTime); + + if (absNextIdxWaitTime > THRESHOLD_WAIT_TIME_NEXT_WAL_SEGMENT) { + log.warning( + String.format("Waiting for next wal segment was too long " + + "[waitingTime=%s, curIdx=%s, absNextIdx=%s, walSegments=%s]", + absNextIdxWaitTime, + curIdx, + absNextIdx, + dsCfg.getWalSegments()) + ); + } + long segmentIdx = absNextIdx % dsCfg.getWalSegments(); return new File(walWorkDir, FileDescriptor.fileName(segmentIdx)); From 143257c7a0143cf146ec050f2e35817c7b9db023 Mon Sep 17 00:00:00 2001 From: Ivan Bessonov Date: Wed, 17 Jul 2019 14:59:57 +0300 Subject: [PATCH 50/62] GG-21338 Fixed checkpointReadLock() may hang during node stop (cherry picked from commit fb2553a00aa4885280dcde883248742f9b753c07) --- .../GridDhtPartitionTopologyImpl.java | 23 +++++++++++++++---- .../GridCacheDatabaseSharedManager.java | 4 ++-- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java index 19ae255344f44..a202c996b9971 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java @@ -2237,6 +2237,8 @@ else if (plc != PartitionLossPolicy.IGNORE) { ctx.database().checkpointReadLock(); try { + Map> addToWaitGroups = new HashMap<>(); + lock.writeLock().lock(); try { @@ -2268,7 +2270,7 @@ else if (plc != PartitionLossPolicy.IGNORE) { GridDhtPartitionState state = partMap.get(part); - if (state == null || state != OWNING) + if (state != OWNING) continue; if (!newOwners.contains(remoteNodeId)) { @@ -2288,9 +2290,7 @@ else if (plc != PartitionLossPolicy.IGNORE) { UUID nodeId = entry.getKey(); Set rebalancedParts = entry.getValue(); - // Add to wait groups to ensure late assignment switch after all partitions are rebalanced. - for (Integer part : rebalancedParts) - ctx.cache().context().affinity().addToWaitGroup(groupId(), part, nodeId, topologyVersionFuture().initialVersion()); + addToWaitGroups.put(nodeId, new HashSet<>(rebalancedParts)); if (!rebalancedParts.isEmpty()) { Set historical = rebalancedParts.stream() @@ -2309,9 +2309,22 @@ else if (plc != PartitionLossPolicy.IGNORE) { } node2part = new GridDhtPartitionFullMap(node2part, updateSeq.incrementAndGet()); - } finally { + } + finally { lock.writeLock().unlock(); } + + for (Map.Entry> entry : addToWaitGroups.entrySet()) { + // Add to wait groups to ensure late assignment switch after all partitions are rebalanced. + for (Integer part : entry.getValue()) { + ctx.cache().context().affinity().addToWaitGroup( + groupId(), + part, + entry.getKey(), + topologyVersionFuture().initialVersion() + ); + } + } } finally { ctx.database().checkpointReadUnlock(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java index 7a317c82c9e5d..dff32723177fd 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java @@ -976,7 +976,7 @@ private void finishRecovery() throws IgniteCheckedException { long time = System.currentTimeMillis(); - checkpointReadLock(); + CHECKPOINT_LOCK_HOLD_COUNT.set(CHECKPOINT_LOCK_HOLD_COUNT.get() + 1); try { for (DatabaseLifecycleListener lsnr : getDatabaseListeners(cctx.kernalContext())) @@ -1008,7 +1008,7 @@ private void finishRecovery() throws IgniteCheckedException { throw e; } finally { - checkpointReadUnlock(); + CHECKPOINT_LOCK_HOLD_COUNT.set(CHECKPOINT_LOCK_HOLD_COUNT.get() - 1); } } From eab2af954ac8c52b311a8dc370a2f6c82275c0b7 Mon Sep 17 00:00:00 2001 From: denis-chudov Date: Thu, 13 Jun 2019 19:32:24 +0300 Subject: [PATCH 51/62] GG-17345 Reduce heap occupation by o.a.i.i.processors.cache.persistence.file.FilePageStore instances (cherry picked from commit 806b1b6d861dfa76980ba39970bb111ecaa15789) --- .../FileStoreHeapUtilizationJolBenchmark.java | 86 +++++++++++++++++++ .../cache/persistence/file/FilePageStore.java | 63 ++++++++------ .../file/FilePageStoreFactory.java | 24 +++++- .../file/FilePageStoreManager.java | 23 ++--- .../persistence/file/FilePageStoreV2.java | 13 +-- .../file/FileVersionCheckingFactory.java | 30 ++++--- .../IgnitePdsTaskCancelingTest.java | 2 +- 7 files changed, 182 insertions(+), 59 deletions(-) create mode 100644 modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jol/FileStoreHeapUtilizationJolBenchmark.java diff --git a/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jol/FileStoreHeapUtilizationJolBenchmark.java b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jol/FileStoreHeapUtilizationJolBenchmark.java new file mode 100644 index 0000000000000..7b529d88b6c9c --- /dev/null +++ b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jol/FileStoreHeapUtilizationJolBenchmark.java @@ -0,0 +1,86 @@ +/* + * Copyright 2019 GridGain Systems, Inc. and Contributors. + * + * Licensed under the GridGain Community Edition License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.gridgain.com/products/software/community-edition/gridgain-community-edition-license + * + * 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.benchmarks.jol; + +import java.io.File; +import java.nio.ByteBuffer; +import java.nio.file.Path; +import java.util.LinkedList; +import java.util.List; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.configuration.DataStorageConfiguration; +import org.apache.ignite.internal.pagemem.PageMemory; +import org.apache.ignite.internal.pagemem.store.PageStore; +import org.apache.ignite.internal.processors.cache.persistence.file.AsyncFileIOFactory; +import org.apache.ignite.internal.processors.cache.persistence.file.FilePageStoreFactory; +import org.apache.ignite.internal.processors.cache.persistence.file.FileVersionCheckingFactory; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.openjdk.jol.info.GraphLayout; + +import static org.apache.ignite.internal.processors.cache.persistence.file.FilePageStoreManager.PART_FILE_TEMPLATE; + +/** + * + */ +public class FileStoreHeapUtilizationJolBenchmark { + /** */ + private void benchmark() throws IgniteCheckedException { + FilePageStoreFactory factory = new FileVersionCheckingFactory( + new AsyncFileIOFactory(), + new AsyncFileIOFactory(), + new DataStorageConfiguration() + .setPageSize(4096) + ); + + List stores = new LinkedList<>(); + + File workDir = U.resolveWorkDirectory(U.defaultWorkDirectory(), "db", false); + + for (int i = 0; i < 10000; i++) { + final int p = i; + + PageStore ps = factory.createPageStore( + PageMemory.FLAG_DATA, + () -> getPartitionFilePath(workDir, p), + d -> { } + ); + + ps.ensure(); + + ps.write(0, ByteBuffer.allocate(256), 1, false); + + stores.add(ps); + } + + System.gc(); + + GraphLayout layout = GraphLayout.parseInstance(stores); + + System.out.println("heap usage: " + layout.totalSize()); + + U.delete(workDir); + } + + /** */ + private Path getPartitionFilePath(File cacheWorkDir, int partId) { + return new File(cacheWorkDir, String.format(PART_FILE_TEMPLATE, partId)).toPath(); + } + + /** */ + public static void main(String[] args) throws Exception { + new FileStoreHeapUtilizationJolBenchmark().benchmark(); + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java index a53d747fcf612..51ccfe85d2831 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java @@ -24,6 +24,7 @@ import java.nio.channels.ClosedByInterruptException; import java.nio.channels.ClosedChannelException; import java.nio.file.Files; +import java.nio.file.Path; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -39,6 +40,7 @@ import org.apache.ignite.internal.processors.cache.persistence.wal.crc.FastCrc; import org.apache.ignite.internal.processors.cache.persistence.wal.crc.IgniteDataIntegrityViolationException; import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgniteOutClosure; import static java.nio.file.StandardOpenOption.CREATE; import static java.nio.file.StandardOpenOption.READ; @@ -59,7 +61,7 @@ public class FilePageStore implements PageStore { public static final int HEADER_SIZE = 8/*SIGNATURE*/ + 4/*VERSION*/ + 1/*type*/ + 4/*page size*/; /** */ - private final File cfgFile; + private final IgniteOutClosure pathProvider; /** */ private final byte type; @@ -97,17 +99,15 @@ public class FilePageStore implements PageStore { /** */ private final ReadWriteLock lock = new ReentrantReadWriteLock(); - /** - * @param file File. - */ + /** */ public FilePageStore( byte type, - File file, + IgniteOutClosure pathProvider, FileIOFactory factory, DataStorageConfiguration cfg, AllocatedPageTracker allocatedTracker) { this.type = type; - this.cfgFile = file; + this.pathProvider = pathProvider; this.dbCfg = cfg; this.ioFactory = factory; this.allocated = new AtomicLong(); @@ -117,7 +117,7 @@ public FilePageStore( /** {@inheritDoc} */ @Override public boolean exists() { - return cfgFile.exists() && cfgFile.length() > headerSize(); + return Files.exists(pathProvider.apply()); } /** @@ -174,7 +174,7 @@ private long initFile(FileIO fileIO) throws IOException { } catch (ClosedByInterruptException e) { // If thread was interrupted written header can be inconsistent. - Files.delete(cfgFile.toPath()); + Files.delete(pathProvider.apply()); throw e; } @@ -186,7 +186,7 @@ private long initFile(FileIO fileIO) throws IOException { * @return Next available position in the file to store a data. * @throws IOException If check has failed. */ - private long checkFile(FileIO fileIO) throws IOException { + private long checkFile(FileIO fileIO, File cfgFile) throws IOException { ByteBuffer hdr = ByteBuffer.allocate(headerSize()).order(ByteOrder.LITTLE_ENDIAN); fileIO.readFully(hdr); @@ -246,8 +246,10 @@ public void stop(boolean delete) throws StorageException { if (fileIO != null) // Ensure the file is closed even if not initialized yet. fileIO.close(); - if (delete && cfgFile.exists()) - Files.delete(cfgFile.toPath()); + Path path = pathProvider.apply(); + + if (delete && Files.exists(path)) + Files.delete(path); return; } @@ -259,10 +261,10 @@ public void stop(boolean delete) throws StorageException { fileIO = null; if (delete) - Files.delete(cfgFile.toPath()); + Files.delete(pathProvider.apply()); } catch (IOException e) { - throw new StorageException("Failed to stop serving partition file [file=" + cfgFile.getPath() + throw new StorageException("Failed to stop serving partition file [file=" + getFileAbsolutePath() + ", delete=" + delete + "]", e); } finally { @@ -283,6 +285,8 @@ public void stop(boolean delete) throws StorageException { public void truncate(int tag) throws StorageException { init(); + Path filePath = pathProvider.apply(); + lock.writeLock().lock(); try { @@ -294,10 +298,10 @@ public void truncate(int tag) throws StorageException { fileIO = null; - Files.delete(cfgFile.toPath()); + Files.delete(filePath); } catch (IOException e) { - throw new StorageException("Failed to truncate partition file [file=" + cfgFile.getPath() + "]", e); + throw new StorageException("Failed to truncate partition file [file=" + filePath.toAbsolutePath() + "]", e); } finally { allocatedTracker.updateTotalAllocatedPages(-1L * allocated.getAndSet(0) / pageSize); @@ -343,7 +347,7 @@ public void finishRecover() throws StorageException { recover = false; } catch (IOException e) { - throw new StorageException("Failed to finish recover partition file [file=" + cfgFile.getAbsolutePath() + "]", e); + throw new StorageException("Failed to finish recover partition file [file=" + getFileAbsolutePath() + "]", e); } finally { lock.writeLock().unlock(); @@ -362,7 +366,8 @@ public void finishRecover() throws StorageException { assert pageBuf.position() == 0; assert pageBuf.order() == ByteOrder.nativeOrder(); assert off <= allocated.get() : "calculatedOffset=" + off + - ", allocated=" + allocated.get() + ", headerSize=" + headerSize() + ", cfgFile=" + cfgFile; + ", allocated=" + allocated.get() + ", headerSize=" + headerSize() + ", cfgFile=" + + pathProvider.apply().toAbsolutePath(); int n = readWithFailover(pageBuf, off); @@ -385,7 +390,7 @@ public void finishRecover() throws StorageException { if ((savedCrc32 ^ curCrc32) != 0) throw new IgniteDataIntegrityViolationException("Failed to read page (CRC validation failed) " + "[id=" + U.hexLong(pageId) + ", off=" + (off - pageSize) + - ", file=" + cfgFile.getAbsolutePath() + ", fileSize=" + fileIO.size() + + ", file=" + getFileAbsolutePath() + ", fileSize=" + fileIO.size() + ", savedCrc=" + U.hexInt(savedCrc32) + ", curCrc=" + U.hexInt(curCrc32) + ", page=" + U.toHexString(pageBuf) + "]"); @@ -397,7 +402,7 @@ public void finishRecover() throws StorageException { PageIO.setCrc(pageBuf, savedCrc32); } catch (IOException e) { - throw new StorageException("Failed to read page [file=" + cfgFile.getAbsolutePath() + ", pageId=" + pageId + "]", e); + throw new StorageException("Failed to read page [file=" + getFileAbsolutePath() + ", pageId=" + pageId + "]", e); } } @@ -411,7 +416,7 @@ public void finishRecover() throws StorageException { readWithFailover(buf, 0); } catch (IOException e) { - throw new StorageException("Failed to read header [file=" + cfgFile.getAbsolutePath() + "]", e); + throw new StorageException("Failed to read header [file=" + getFileAbsolutePath() + "]", e); } } @@ -435,9 +440,11 @@ private void init() throws StorageException { while (true) { try { + File cfgFile = pathProvider.apply().toFile(); + this.fileIO = fileIO = ioFactory.create(cfgFile, CREATE, READ, WRITE); - newSize = (cfgFile.length() == 0 ? initFile(fileIO) : checkFile(fileIO)) - headerSize(); + newSize = (cfgFile.length() == 0 ? initFile(fileIO) : checkFile(fileIO, cfgFile)) - headerSize(); if (interrupted) Thread.currentThread().interrupt(); @@ -463,7 +470,7 @@ private void init() throws StorageException { } catch (IOException e) { err = new StorageException( - "Failed to initialize partition file: " + cfgFile.getAbsolutePath(), e); + "Failed to initialize partition file: " + getFileAbsolutePath(), e); throw err; } @@ -509,9 +516,11 @@ private void reinit(FileIO fileIO) throws IOException { try { fileIO = null; + File cfgFile = pathProvider.apply().toFile(); + fileIO = ioFactory.create(cfgFile, CREATE, READ, WRITE); - checkFile(fileIO); + checkFile(fileIO, cfgFile); this.fileIO = fileIO; @@ -564,7 +573,7 @@ private void reinit(FileIO fileIO) throws IOException { assert (off >= 0 && off <= allocated.get()) || recover : "off=" + U.hexLong(off) + ", allocated=" + U.hexLong(allocated.get()) + - ", pageId=" + U.hexLong(pageId) + ", file=" + cfgFile.getPath(); + ", pageId=" + U.hexLong(pageId) + ", file=" + getFileAbsolutePath(); assert pageBuf.capacity() == pageSize; assert pageBuf.position() == 0; @@ -622,7 +631,7 @@ private void reinit(FileIO fileIO) throws IOException { } } - throw new StorageException("Failed to write page [file=" + cfgFile.getAbsolutePath() + throw new StorageException("Failed to write page [file=" + getFileAbsolutePath() + ", pageId=" + pageId + ", tag=" + tag + "]", e); } } @@ -661,7 +670,7 @@ private static int calcCrc32(ByteBuffer pageBuf, int pageSize) { fileIO.force(); } catch (IOException e) { - throw new StorageException("Failed to fsync partition file [file=" + cfgFile.getAbsolutePath() + ']', e); + throw new StorageException("Failed to fsync partition file [file=" + getFileAbsolutePath() + ']', e); } finally { lock.writeLock().unlock(); @@ -684,7 +693,7 @@ private static int calcCrc32(ByteBuffer pageBuf, int pageSize) { * @return File absolute path. */ public String getFileAbsolutePath() { - return cfgFile.getAbsolutePath(); + return pathProvider.apply().toAbsolutePath().toString(); } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreFactory.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreFactory.java index fe93d0743be07..6271b8b638269 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreFactory.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreFactory.java @@ -18,19 +18,39 @@ package org.apache.ignite.internal.processors.cache.persistence.file; import java.io.File; +import java.nio.file.Path; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.pagemem.PageIdAllocator; import org.apache.ignite.internal.processors.cache.persistence.AllocatedPageTracker; +import org.apache.ignite.lang.IgniteOutClosure; /** * */ public interface FilePageStoreFactory { /** - * Creates instance of FilePageStore based on given file. + * Creates instance of PageStore based on given file. * * @param type Data type, can be {@link PageIdAllocator#FLAG_IDX} or {@link PageIdAllocator#FLAG_DATA}. * @param file File Page store file. + * @param allocatedTracker metrics updater. + * @return page store + * @throws IgniteCheckedException if failed. */ - public FilePageStore createPageStore(byte type, File file, AllocatedPageTracker allocatedTracker) throws IgniteCheckedException; + default FilePageStore createPageStore(byte type, File file, AllocatedPageTracker allocatedTracker) + throws IgniteCheckedException { + return createPageStore(type, file::toPath, allocatedTracker); + } + + /** + * Creates instance of PageStore based on file path provider. + * + * @param type Data type, can be {@link PageIdAllocator#FLAG_IDX} or {@link PageIdAllocator#FLAG_DATA} + * @param pathProvider File Page store path provider. + * @param allocatedTracker metrics updater + * @return page store + * @throws IgniteCheckedException if failed + */ + FilePageStore createPageStore(byte type, IgniteOutClosure pathProvider, AllocatedPageTracker allocatedTracker) + throws IgniteCheckedException; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java index dee98da16666e..8463b947ced63 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java @@ -450,7 +450,7 @@ public FilePageStoreManager(GridKernalContext ctx) { } /** {@inheritDoc} */ - @Override public void onPartitionCreated(int grpId, int partId) throws IgniteCheckedException { + @Override public void onPartitionCreated(int grpId, int partId) { // No-op. } @@ -555,7 +555,7 @@ public PageStore writeInternal(int cacheId, long pageId, ByteBuffer pageBuf, int * */ public Path getPath(boolean isSharedGroup, String cacheOrGroupName, int partId) { - return getPartitionFile(cacheWorkDir(isSharedGroup, cacheOrGroupName), partId).toPath(); + return getPartitionFilePath(cacheWorkDir(isSharedGroup, cacheOrGroupName), partId); } /** @@ -617,14 +617,15 @@ private CacheStoreHolder initDir(File cacheWorkDir, FilePageStore[] partStores = new FilePageStore[partitions]; for (int partId = 0; partId < partStores.length; partId++) { - FilePageStore partStore = - pageStoreFactory.createPageStore( - PageMemory.FLAG_DATA, - getPartitionFile(cacheWorkDir, partId), - allocatedTracker); + final int p = partId; - partStores[partId] = partStore; - } + FilePageStore partStore = pageStoreFactory.createPageStore( + PageMemory.FLAG_DATA, + () -> getPartitionFilePath(cacheWorkDir, p), + allocatedTracker); + + partStores[partId] = partStore; + } return new CacheStoreHolder(idxStore, partStores); } @@ -640,8 +641,8 @@ private CacheStoreHolder initDir(File cacheWorkDir, * @param cacheWorkDir Cache work directory. * @param partId Partition id. */ - @NotNull private File getPartitionFile(File cacheWorkDir, int partId) { - return new File(cacheWorkDir, format(PART_FILE_TEMPLATE, partId)); + @NotNull private Path getPartitionFilePath(File cacheWorkDir, int partId) { + return new File(cacheWorkDir, String.format(PART_FILE_TEMPLATE, partId)).toPath(); } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreV2.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreV2.java index d8c800d39b9a6..4b0dc198109f6 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreV2.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreV2.java @@ -16,9 +16,10 @@ */ package org.apache.ignite.internal.processors.cache.persistence.file; -import java.io.File; +import java.nio.file.Path; import org.apache.ignite.configuration.DataStorageConfiguration; import org.apache.ignite.internal.processors.cache.persistence.AllocatedPageTracker; +import org.apache.ignite.lang.IgniteOutClosure; /** * @@ -31,19 +32,21 @@ public class FilePageStoreV2 extends FilePageStore { private final int hdrSize; /** + * Constructor which initializes file path provider closure, allowing to calculate file path in any time. + * * @param type Type. - * @param file File. + * @param pathProvider file path provider. * @param factory Factory. * @param cfg Config. - * @param allocatedTracker Metrics updater + * @param allocatedTracker Allocated tracker. */ public FilePageStoreV2( byte type, - File file, + IgniteOutClosure pathProvider, FileIOFactory factory, DataStorageConfiguration cfg, AllocatedPageTracker allocatedTracker) { - super(type, file, factory, cfg, allocatedTracker); + super(type, pathProvider, factory, cfg, allocatedTracker); hdrSize = cfg.getPageSize(); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileVersionCheckingFactory.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileVersionCheckingFactory.java index bc938a57912fc..62266392b5ada 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileVersionCheckingFactory.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileVersionCheckingFactory.java @@ -17,13 +17,15 @@ package org.apache.ignite.internal.processors.cache.persistence.file; -import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.nio.file.Files; +import java.nio.file.Path; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.configuration.DataStorageConfiguration; import org.apache.ignite.internal.processors.cache.persistence.AllocatedPageTracker; +import org.apache.ignite.lang.IgniteOutClosure; /** * Checks version in files if it's present on the disk, creates store with latest version otherwise. @@ -73,16 +75,18 @@ public FileVersionCheckingFactory(FileIOFactory fileIOFactory, DataStorageConfig /** {@inheritDoc} */ @Override public FilePageStore createPageStore( byte type, - File file, + IgniteOutClosure pathProvider, AllocatedPageTracker allocatedTracker) throws IgniteCheckedException { - if (!file.exists()) - return createPageStore(type, file, latestVersion(), allocatedTracker); + Path filePath = pathProvider.apply(); - try (FileIO fileIO = fileIOFactoryStoreV1.create(file)) { + if (!Files.exists(filePath)) + return createPageStore(type, pathProvider, latestVersion(), allocatedTracker); + + try (FileIO fileIO = fileIOFactoryStoreV1.create(filePath.toFile())) { int minHdr = FilePageStore.HEADER_SIZE; if (fileIO.size() < minHdr) - return createPageStore(type, file, latestVersion(), allocatedTracker); + return createPageStore(type, pathProvider, latestVersion(), allocatedTracker); ByteBuffer hdr = ByteBuffer.allocate(minHdr).order(ByteOrder.LITTLE_ENDIAN); @@ -94,10 +98,10 @@ public FileVersionCheckingFactory(FileIOFactory fileIOFactory, DataStorageConfig int ver = hdr.getInt(); - return createPageStore(type, file, ver, allocatedTracker); + return createPageStore(type, pathProvider, ver, allocatedTracker); } catch (IOException e) { - throw new IgniteCheckedException("Error while creating file page store [file=" + file + "]:", e); + throw new IgniteCheckedException("Error while creating file page store [file=" + filePath.toAbsolutePath() + "]:", e); } } @@ -120,24 +124,24 @@ public int latestVersion() { * Instantiates specific version of FilePageStore. * * @param type Type. - * @param file File. * @param ver Version. * @param allocatedTracker Metrics updater */ public FilePageStore createPageStore( byte type, - File file, + IgniteOutClosure pathProvider, int ver, AllocatedPageTracker allocatedTracker) { + switch (ver) { case FilePageStore.VERSION: - return new FilePageStore(type, file, fileIOFactoryStoreV1, memCfg, allocatedTracker); + return new FilePageStore(type, pathProvider, fileIOFactoryStoreV1, memCfg, allocatedTracker); case FilePageStoreV2.VERSION: - return new FilePageStoreV2(type, file, fileIOFactory, memCfg, allocatedTracker); + return new FilePageStoreV2(type, pathProvider, fileIOFactory, memCfg, allocatedTracker); default: - throw new IllegalArgumentException("Unknown version of file page store: " + ver + " for file [" + file.getAbsolutePath() + "]"); + throw new IllegalArgumentException("Unknown version of file page store: " + ver + " for file [" + pathProvider.apply().toAbsolutePath() + "]"); } } } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsTaskCancelingTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsTaskCancelingTest.java index 6b457ef47196f..5833fa5c2646f 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsTaskCancelingTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsTaskCancelingTest.java @@ -196,7 +196,7 @@ public void testFilePageStoreInterruptThreads() throws Exception { DataStorageConfiguration dbCfg = getDataStorageConfiguration(); - FilePageStore pageStore = new FilePageStore(PageMemory.FLAG_DATA, file, factory, dbCfg, + FilePageStore pageStore = new FilePageStore(PageMemory.FLAG_DATA, () -> file.toPath(), factory, dbCfg, AllocatedPageTracker.NO_OP); int pageSize = dbCfg.getPageSize(); From 347ae688a8539a90b1a51d104dd5f32cce7520b4 Mon Sep 17 00:00:00 2001 From: denis-chudov Date: Tue, 16 Jul 2019 12:28:16 +0300 Subject: [PATCH 52/62] GG-17345 Checking file length in FilePageStore#exists() (cherry picked from commit 0a17bb96b1d50d2fcf8c714979c74a9c4ec983c1) --- .../processors/cache/persistence/file/FilePageStore.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java index 51ccfe85d2831..5b302097ca323 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java @@ -117,7 +117,9 @@ public FilePageStore( /** {@inheritDoc} */ @Override public boolean exists() { - return Files.exists(pathProvider.apply()); + File file = pathProvider.apply().toFile(); + + return file.exists() && file.length() > headerSize(); } /** From 3fe68c276d15e7fd30ecee73da2ddfdc16c58f89 Mon Sep 17 00:00:00 2001 From: ktkalenko Date: Thu, 18 Jul 2019 08:50:49 +0300 Subject: [PATCH 53/62] GG-21232 control.sh if experimental command disabled - don't show help for experemental commands. (cherry picked from commit 86ee0b508e206cfcc325b4898c2732d511dfceff) --- bin/control.bat | 5 ++ .../internal/commandline/WalCommands.java | 48 +++++++++++-------- .../CommandHandlerParsingTest.java | 21 -------- .../ignite/util/GridCommandHandlerTest.java | 48 ++++++++++++++++--- 4 files changed, 74 insertions(+), 48 deletions(-) diff --git a/bin/control.bat b/bin/control.bat index 15d5e6fcb619b..4894cbc4322ad 100644 --- a/bin/control.bat +++ b/bin/control.bat @@ -156,6 +156,11 @@ if %ERRORLEVEL% equ 0 ( if "%JVM_OPTS%" == "" set JVM_OPTS=-Xms256m -Xmx1g ) +:: +:: Uncomment to enable experimental commands [--wal] +:: +:: set JVM_OPTS=%JVM_OPTS% -DIGNITE_ENABLE_EXPERIMENTAL_COMMAND=true + :: :: Uncomment the following GC settings if you see spikes in your throughput due to Garbage Collection. :: diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/WalCommands.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/WalCommands.java index f892e985b5065..2ac9c8794d896 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/WalCommands.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/WalCommands.java @@ -39,6 +39,7 @@ import static org.apache.ignite.IgniteSystemProperties.IGNITE_ENABLE_EXPERIMENTAL_COMMAND; import static org.apache.ignite.internal.commandline.CommandArgIterator.isCommandOrOption; +import static org.apache.ignite.internal.commandline.CommandHandler.UTILITY_NAME; import static org.apache.ignite.internal.commandline.CommandList.WAL; import static org.apache.ignite.internal.commandline.CommandLogger.DOUBLE_INDENT; import static org.apache.ignite.internal.commandline.CommandLogger.INDENT; @@ -71,12 +72,13 @@ public class WalCommands implements Command> { /** {@inheritDoc} */ @Override public void printUsage(Logger logger) { - if (enableExperimental()) { - Command.usage(logger, "Print absolute paths of unused archived wal segments on each node:", WAL, - WAL_PRINT, "[consistentId1,consistentId2,....,consistentIdN]"); - Command.usage(logger, "Delete unused archived wal segments on each node:", WAL, WAL_DELETE, - "[consistentId1,consistentId2,....,consistentIdN]", optional(CMD_AUTO_CONFIRMATION)); - } + if (!enableExperimental()) + return; + + Command.usage(logger, "Print absolute paths of unused archived wal segments on each node:", WAL, + WAL_PRINT, "[consistentId1,consistentId2,....,consistentIdN]"); + Command.usage(logger, "Delete unused archived wal segments on each node:", WAL, WAL_DELETE, + "[consistentId1,consistentId2,....,consistentIdN]", optional(CMD_AUTO_CONFIRMATION)); } /** @@ -86,21 +88,26 @@ public class WalCommands implements Command> { * @throws Exception If failed to execute wal action. */ @Override public Object execute(GridClientConfiguration clientCfg, Logger logger) throws Exception { - this.logger = logger; + if (enableExperimental()) { + this.logger = logger; - try (GridClient client = Command.startClient(clientCfg)) { - switch (walAct) { - case WAL_DELETE: - deleteUnusedWalSegments(client, walArgs, clientCfg); + try (GridClient client = Command.startClient(clientCfg)) { + switch (walAct) { + case WAL_DELETE: + deleteUnusedWalSegments(client, walArgs, clientCfg); - break; + break; - case WAL_PRINT: - default: - printUnusedWalSegments(client, walArgs, clientCfg); + case WAL_PRINT: + default: + printUnusedWalSegments(client, walArgs, clientCfg); - break; + break; + } } + } else { + logger.warning(String.format("For use experimental command add %s=true to JVM_OPTS in %s", + IGNITE_ENABLE_EXPERIMENTAL_COMMAND, UTILITY_NAME)); } return null; @@ -116,9 +123,6 @@ public class WalCommands implements Command> { /** {@inheritDoc} */ @Override public void parseArguments(CommandArgIterator argIter) { - if (!enableExperimental()) - throw new IllegalArgumentException("Experimental command is disabled."); - String str = argIter.nextArg("Expected arguments for " + WAL.text()); String walAct = str.toLowerCase(); @@ -128,8 +132,10 @@ public class WalCommands implements Command> { ? argIter.nextArg("Unexpected argument for " + WAL.text() + ": " + walAct) : ""; - this.walAct = walAct; - this.walArgs = walArgs; + if (enableExperimental()) { + this.walAct = walAct; + this.walArgs = walArgs; + } } else throw new IllegalArgumentException("Unexpected action " + walAct + " for " + WAL.text()); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java b/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java index 1d9df94b083f6..9378b046ceec8 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java @@ -270,27 +270,6 @@ private void generateAllCombinations(List res, List source, Predicate< } } - /** - * Test that experimental command (i.e. WAL command) is disabled by default. - */ - public void testExperimentalCommandIsDisabled() { - System.clearProperty(IGNITE_ENABLE_EXPERIMENTAL_COMMAND); - - GridTestUtils.assertThrows( - null, - () -> parseArgs(Arrays.asList(WAL.text(), WAL_PRINT)), - IllegalArgumentException.class, - null - ); - - GridTestUtils.assertThrows( - null, - () -> parseArgs(Arrays.asList(WAL.text(), WAL_DELETE)), - IllegalArgumentException.class, - null - ); - } - /** * Tests parsing and validation for the SSL arguments. */ diff --git a/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java b/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java index 089943f377c17..3a9b429f7d0ea 100644 --- a/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java +++ b/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java @@ -18,7 +18,6 @@ package org.apache.ignite.util; import java.io.File; -import java.io.FilenameFilter; import java.io.IOException; import java.io.RandomAccessFile; import java.io.Serializable; @@ -45,6 +44,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.cache.processor.EntryProcessor; import javax.cache.processor.EntryProcessorException; import javax.cache.processor.MutableEntry; @@ -52,10 +52,8 @@ import org.apache.ignite.IgniteAtomicSequence; import org.apache.ignite.IgniteCache; import org.apache.ignite.IgniteCheckedException; -import org.apache.ignite.IgniteCluster; import org.apache.ignite.IgniteDataStreamer; import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction; -import org.apache.ignite.cluster.BaselineNode; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.configuration.AtomicConfiguration; import org.apache.ignite.configuration.CacheConfiguration; @@ -114,10 +112,13 @@ import static java.io.File.separatorChar; import static java.util.Arrays.asList; +import static org.apache.ignite.IgniteSystemProperties.IGNITE_ENABLE_EXPERIMENTAL_COMMAND; import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL; import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC; import static org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_OK; import static org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_UNEXPECTED_ERROR; +import static org.apache.ignite.internal.commandline.CommandHandler.UTILITY_NAME; +import static org.apache.ignite.internal.commandline.CommandList.WAL; import static org.apache.ignite.internal.commandline.OutputFormat.MULTI_LINE; import static org.apache.ignite.internal.commandline.OutputFormat.SINGLE_LINE; import static org.apache.ignite.internal.commandline.cache.CacheSubcommands.HELP; @@ -133,6 +134,7 @@ * Command line handler test. */ public class GridCommandHandlerTest extends GridCommandHandlerAbstractTest { + /** */ private File defaultDiagnosticDir; /** */ @@ -319,21 +321,21 @@ public void testFindAndDeleteGarbage() throws Exception { assertEquals(EXIT_CODE_OK, execute("--cache", "find_garbage", "--port", "11212")); - assertTrue(testOut.toString().contains("garbage not found")); + assertContains(log, testOut.toString(), "garbage not found"); testOut.reset(); assertEquals(EXIT_CODE_OK, execute("--cache", "find_garbage", ignite(0).localNode().id().toString(), "--port", "11212")); - assertTrue(testOut.toString().contains("garbage not found")); + assertContains(log, testOut.toString(), "garbage not found"); testOut.reset(); assertEquals(EXIT_CODE_OK, execute("--cache", "find_garbage", "groupGarbage", "--port", "11212")); - assertTrue(testOut.toString().contains("garbage not found")); + assertContains(log, testOut.toString(), "garbage not found"); } /** @@ -2779,4 +2781,38 @@ private void corruptDataEntry( e.printStackTrace(); } } + + /** + * Don't show wal commands by --help in case + * {@link org.apache.ignite.IgniteSystemProperties#IGNITE_ENABLE_EXPERIMENTAL_COMMAND} = false or empty. + */ + @Test + public void testHideWalInHelpWhenDisableExperimentalCommand() { + System.clearProperty(IGNITE_ENABLE_EXPERIMENTAL_COMMAND); + + injectTestSystemOut(); + + execute("--help"); + + assertNotContains(log, testOut.toString(), WAL.text()); + } + + /** + * Wal commands should ignored and print warning in case + * {@link org.apache.ignite.IgniteSystemProperties#IGNITE_ENABLE_EXPERIMENTAL_COMMAND} = false or empty. + * */ + @Test + public void testWalCommandsInCaseDisableExperimentalCommand() { + System.clearProperty(IGNITE_ENABLE_EXPERIMENTAL_COMMAND); + + injectTestSystemOut(); + + String warning = String.format("For use experimental command add %s=true to JVM_OPTS in %s", + IGNITE_ENABLE_EXPERIMENTAL_COMMAND, UTILITY_NAME); + + Stream.of("print", "delete") + .peek(c -> testOut.reset()) + .peek(c -> assertEquals(EXIT_CODE_OK, execute(WAL.text(), c))) + .forEach(c -> assertContains(log, testOut.toString(), warning)); + } } From 7bbf4d018f33a5ba6fb15eb0bdff5f68521609a2 Mon Sep 17 00:00:00 2001 From: Evgeniy Rudenko Date: Fri, 19 Jul 2019 12:04:02 +1000 Subject: [PATCH 54/62] GG-20567 Removed outdated dependency from pom file --- pom.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8b7a50e35e6a1..620ef74fb0147 100644 --- a/pom.xml +++ b/pom.xml @@ -121,7 +121,6 @@ modules/scalar-2.10 modules/scalar - modules/spark-2.10 modules/spark modules/visor-console-2.10 modules/visor-console @@ -554,7 +553,6 @@ modules/scalar-2.10 - modules/spark-2.10 modules/visor-console-2.10 modules/visor-plugins From a5a2d852a68b6a47f65108aa7b29b7e1f51e157e Mon Sep 17 00:00:00 2001 From: Ivan Bessonov Date: Fri, 19 Jul 2019 11:19:20 +0300 Subject: [PATCH 55/62] GG-21630 [GG-20866] [IGNITE-11966] Fixed using AdaptiveLoadBalancingSpi without IgniteConfiguration.setIncludeEventTypes(EventType.EVT_TASK_FINISHED, EventType.EVT_TASK_FAILED) leads to memory leak - Fixed #6690. (#293) (cherry picked from commit e2d6632cd9e3c0f85a66f47b432c092f67b57167) --- .../eventstorage/GridEventStorageManager.java | 14 +++++++++++++- ...idEventStorageRuntimeConfigurationSelfTest.java | 10 +++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/eventstorage/GridEventStorageManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/eventstorage/GridEventStorageManager.java index 522a9faa846a5..c4ec2630c0537 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/eventstorage/GridEventStorageManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/eventstorage/GridEventStorageManager.java @@ -72,9 +72,12 @@ import static org.apache.ignite.events.EventType.EVTS_ALL; import static org.apache.ignite.events.EventType.EVTS_DISCOVERY_ALL; +import static org.apache.ignite.events.EventType.EVT_JOB_MAPPED; import static org.apache.ignite.events.EventType.EVT_NODE_FAILED; import static org.apache.ignite.events.EventType.EVT_NODE_LEFT; import static org.apache.ignite.events.EventType.EVT_NODE_METRICS_UPDATED; +import static org.apache.ignite.events.EventType.EVT_TASK_FAILED; +import static org.apache.ignite.events.EventType.EVT_TASK_FINISHED; import static org.apache.ignite.internal.GridTopic.TOPIC_EVENT; import static org.apache.ignite.internal.events.DiscoveryCustomEvent.EVT_DISCOVERY_CUSTOM_EVT; import static org.apache.ignite.internal.managers.communication.GridIoPolicy.PUBLIC_POOL; @@ -507,7 +510,16 @@ private boolean isHiddenEvent(int type) { * @return {@code true} if this is an internal event. */ private boolean isInternalEvent(int type) { - return type == EVT_DISCOVERY_CUSTOM_EVT || F.contains(EVTS_DISCOVERY_ALL, type); + switch (type) { + case EVT_DISCOVERY_CUSTOM_EVT: + case EVT_TASK_FINISHED: + case EVT_TASK_FAILED: + case EVT_JOB_MAPPED: + return true; + + default: + return F.contains(EVTS_DISCOVERY_ALL, type); + } } /** diff --git a/modules/core/src/test/java/org/apache/ignite/internal/GridEventStorageRuntimeConfigurationSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/GridEventStorageRuntimeConfigurationSelfTest.java index 97626c8e414e6..92455accc4355 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/GridEventStorageRuntimeConfigurationSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/GridEventStorageRuntimeConfigurationSelfTest.java @@ -135,7 +135,7 @@ public void testDisableWithIncludes() throws Exception { try { Ignite g = startGrid(); - g.events().enableLocal(EVT_TASK_STARTED, EVT_TASK_FINISHED, EVT_JOB_STARTED); + g.events().enableLocal(EVT_TASK_STARTED, EVT_JOB_STARTED); final AtomicInteger cnt = new AtomicInteger(); @@ -145,17 +145,17 @@ public void testDisableWithIncludes() throws Exception { return true; } - }, EVT_TASK_STARTED, EVT_TASK_FINISHED, EVT_JOB_STARTED); + }, EVT_TASK_STARTED, EVT_JOB_STARTED); g.compute().run(F.noop()); - assertEquals(3, cnt.get()); + assertEquals(2, cnt.get()); - g.events().disableLocal(EVT_TASK_STARTED, EVT_TASK_FINISHED, EVT_JOB_FAILED); + g.events().disableLocal(EVT_TASK_STARTED, EVT_JOB_FAILED); g.compute().run(F.noop()); - assertEquals(4, cnt.get()); + assertEquals(3, cnt.get()); } finally { stopAllGrids(); From d62c77d3b1c86d353d28353f7e0a6c251ed170f6 Mon Sep 17 00:00:00 2001 From: Alexey Goncharuk Date: Fri, 19 Jul 2019 18:48:00 +0300 Subject: [PATCH 56/62] GG-21395 Fixed unguarded log.info() usages --- .../session/CassandraSessionImpl.java | 60 +++++++++++----- .../DefaultCommunicationFailureResolver.java | 11 +-- .../apache/ignite/internal/IgnitionEx.java | 5 +- .../processors/cache/CacheGroupContext.java | 10 +-- .../GridDhtPartitionTopologyImpl.java | 12 ++-- .../dht/topology/PartitionsEvictManager.java | 8 ++- .../GridCacheDatabaseSharedManager.java | 70 ++++++++++--------- .../pagemem/PagesWriteSpeedBasedThrottle.java | 2 +- .../wal/scanner/PrintToLogHandler.java | 3 +- .../VerifyBackupPartitionsDumpTask.java | 6 +- .../cluster/GridClusterStateProcessor.java | 3 +- .../datastructures/GridCacheLockImpl.java | 5 +- .../diagnostic/PageHistoryDiagnoster.java | 6 +- .../odbc/ClientListenerProcessor.java | 6 +- .../ignite/internal/util/GridJavaProcess.java | 2 +- .../ignite/internal/util/IgniteStopwatch.java | 14 ++-- .../ignite/spi/discovery/tcp/ClientImpl.java | 3 +- .../pagemem/IgniteThrottlingUnitTest.java | 2 + .../wal/scanner/WalScannerTest.java | 4 ++ .../h2/twostep/GridMapQueryExecutor.java | 2 +- .../org/apache/ignite/ml/math/Tracer.java | 11 +-- .../IgniteAbstractOsgiContextActivator.java | 3 +- .../zk/internal/ZookeeperDiscoveryImpl.java | 2 +- 23 files changed, 154 insertions(+), 96 deletions(-) diff --git a/modules/cassandra/store/src/main/java/org/apache/ignite/cache/store/cassandra/session/CassandraSessionImpl.java b/modules/cassandra/store/src/main/java/org/apache/ignite/cache/store/cassandra/session/CassandraSessionImpl.java index 4fb0cb27d7c8f..4d59e54716115 100644 --- a/modules/cassandra/store/src/main/java/org/apache/ignite/cache/store/cassandra/session/CassandraSessionImpl.java +++ b/modules/cassandra/store/src/main/java/org/apache/ignite/cache/store/cassandra/session/CassandraSessionImpl.java @@ -648,17 +648,25 @@ private void createKeyspace(KeyValuePersistenceSettings settings) { while (attempt < CQL_EXECUTION_ATTEMPTS_COUNT) { try { - log.info("-----------------------------------------------------------------------"); - log.info("Creating Cassandra keyspace '" + settings.getKeyspace() + "'"); - log.info("-----------------------------------------------------------------------\n\n" + - settings.getKeyspaceDDLStatement() + "\n"); - log.info("-----------------------------------------------------------------------"); + if (log.isInfoEnabled()) { + log.info("-----------------------------------------------------------------------"); + log.info("Creating Cassandra keyspace '" + settings.getKeyspace() + "'"); + log.info("-----------------------------------------------------------------------\n\n" + + settings.getKeyspaceDDLStatement() + "\n"); + log.info("-----------------------------------------------------------------------"); + } + session().execute(settings.getKeyspaceDDLStatement()); - log.info("Cassandra keyspace '" + settings.getKeyspace() + "' was successfully created"); + + if (log.isInfoEnabled()) + log.info("Cassandra keyspace '" + settings.getKeyspace() + "' was successfully created"); + return; } catch (AlreadyExistsException ignored) { - log.info("Cassandra keyspace '" + settings.getKeyspace() + "' already exist"); + if (log.isInfoEnabled()) + log.info("Cassandra keyspace '" + settings.getKeyspace() + "' already exist"); + return; } catch (Throwable e) { @@ -689,17 +697,25 @@ private void createTable(String table, KeyValuePersistenceSettings settings) { while (attempt < CQL_EXECUTION_ATTEMPTS_COUNT) { try { - log.info("-----------------------------------------------------------------------"); - log.info("Creating Cassandra table '" + tableFullName + "'"); - log.info("-----------------------------------------------------------------------\n\n" + + if (log.isInfoEnabled()) { + log.info("-----------------------------------------------------------------------"); + log.info("Creating Cassandra table '" + tableFullName + "'"); + log.info("-----------------------------------------------------------------------\n\n" + settings.getTableDDLStatement(table) + "\n"); - log.info("-----------------------------------------------------------------------"); + log.info("-----------------------------------------------------------------------"); + } + session().execute(settings.getTableDDLStatement(table)); - log.info("Cassandra table '" + tableFullName + "' was successfully created"); + + if (log.isInfoEnabled()) + log.info("Cassandra table '" + tableFullName + "' was successfully created"); + return; } catch (AlreadyExistsException ignored) { - log.info("Cassandra table '" + tableFullName + "' already exist"); + if (log.isInfoEnabled()) + log.info("Cassandra table '" + tableFullName + "' already exist"); + return; } catch (Throwable e) { @@ -741,14 +757,19 @@ private void createTableIndexes(String table, KeyValuePersistenceSettings settin while (attempt < CQL_EXECUTION_ATTEMPTS_COUNT) { try { - log.info("-----------------------------------------------------------------------"); - log.info("Creating indexes for Cassandra table '" + tableFullName + "'"); - log.info("-----------------------------------------------------------------------"); + if (log.isInfoEnabled()) { + log.info("-----------------------------------------------------------------------"); + log.info("Creating indexes for Cassandra table '" + tableFullName + "'"); + log.info("-----------------------------------------------------------------------"); + } for (String statement : indexDDLStatements) { try { - log.info(statement); - log.info("-----------------------------------------------------------------------"); + if (log.isInfoEnabled()) { + log.info(statement); + log.info("-----------------------------------------------------------------------"); + } + session().execute(statement); } catch (AlreadyExistsException ignored) { @@ -759,7 +780,8 @@ private void createTableIndexes(String table, KeyValuePersistenceSettings settin } } - log.info("Indexes for Cassandra table '" + tableFullName + "' were successfully created"); + if (log.isInfoEnabled()) + log.info("Indexes for Cassandra table '" + tableFullName + "' were successfully created"); return; } diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/DefaultCommunicationFailureResolver.java b/modules/core/src/main/java/org/apache/ignite/configuration/DefaultCommunicationFailureResolver.java index 7db42d3b239cf..46c79cb41cb25 100644 --- a/modules/core/src/main/java/org/apache/ignite/configuration/DefaultCommunicationFailureResolver.java +++ b/modules/core/src/main/java/org/apache/ignite/configuration/DefaultCommunicationFailureResolver.java @@ -49,11 +49,12 @@ public class DefaultCommunicationFailureResolver implements CommunicationFailure if (largestCluster == null) return; - log.info("Communication problem resolver found fully connected independent cluster [" - + "serverNodesCnt=" + largestCluster.srvNodesCnt + ", " - + "clientNodesCnt=" + largestCluster.connectedClients.size() + ", " - + "totalAliveNodes=" + ctx.topologySnapshot().size() + ", " - + "serverNodesIds=" + clusterNodeIds(largestCluster.srvNodesSet, ctx.topologySnapshot(), 1000) + "]"); + if (log.isInfoEnabled()) + log.info("Communication problem resolver found fully connected independent cluster [" + + "serverNodesCnt=" + largestCluster.srvNodesCnt + ", " + + "clientNodesCnt=" + largestCluster.connectedClients.size() + ", " + + "totalAliveNodes=" + ctx.topologySnapshot().size() + ", " + + "serverNodesIds=" + clusterNodeIds(largestCluster.srvNodesSet, ctx.topologySnapshot(), 1000) + "]"); keepCluster(ctx, largestCluster); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java b/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java index 766f3973b79aa..8428aab53aec5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java @@ -1736,8 +1736,9 @@ synchronized void start(GridStartContext startCtx) throws IgniteCheckedException start0(startCtx, myCfg, startNodeTimer); - log.info("Node started : " - + startNodeTimer.stagesTimings().stream().collect(joining(",", "[", "]"))); + if (log.isInfoEnabled()) + log.info("Node started : " + + startNodeTimer.stagesTimings().stream().collect(joining(",", "[", "]"))); } catch (Exception e) { if (log != null) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java index 3206bae3c100f..77911caf551f8 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java @@ -1192,8 +1192,9 @@ public boolean globalWalEnabled() { */ public void globalWalEnabled(boolean enabled) { if (globalWalEnabled != enabled) { - log.info("Global WAL state for group=" + cacheOrGroupName() + - " changed from " + globalWalEnabled + " to " + enabled); + if (log.isInfoEnabled()) + log.info("Global WAL state for group=" + cacheOrGroupName() + + " changed from " + globalWalEnabled + " to " + enabled); persistGlobalWalState(enabled); @@ -1206,8 +1207,9 @@ public void globalWalEnabled(boolean enabled) { */ public void localWalEnabled(boolean enabled) { if (localWalEnabled != enabled){ - log.info("Local WAL state for group=" + cacheOrGroupName() + - " changed from " + localWalEnabled + " to " + enabled); + if (log.isInfoEnabled()) + log.info("Local WAL state for group=" + cacheOrGroupName() + + " changed from " + localWalEnabled + " to " + enabled); persistLocalWalState(enabled); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java index a202c996b9971..e964c0b2ee1e9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java @@ -2640,14 +2640,14 @@ private void removeNode(UUID nodeId) { @Override public void ownMoving(AffinityTopologyVersion rebFinishedTopVer) { lock.writeLock().lock(); - AffinityTopologyVersion lastAffChangeVer = ctx.exchange().lastAffinityChangedTopologyVersion(lastTopChangeVer); + try { + AffinityTopologyVersion lastAffChangeVer = ctx.exchange().lastAffinityChangedTopologyVersion(lastTopChangeVer); - if (lastAffChangeVer.compareTo(rebFinishedTopVer) > 0) - log.info("Affinity topology changed, no MOVING partitions will be owned " + - "[rebFinishedTopVer=" + rebFinishedTopVer + - ", lastAffChangeVer=" + lastAffChangeVer + "]"); + if (lastAffChangeVer.compareTo(rebFinishedTopVer) > 0 && log.isInfoEnabled()) + log.info("Affinity topology changed, no MOVING partitions will be owned " + + "[rebFinishedTopVer=" + rebFinishedTopVer + + ", lastAffChangeVer=" + lastAffChangeVer + "]"); - try { for (GridDhtLocalPartition locPart : grp.topology().currentLocalPartitions()) { if (locPart.state() == MOVING) { boolean reserved = locPart.reserve(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/PartitionsEvictManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/PartitionsEvictManager.java index 704c7db3887f7..1abb6abc671b7 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/PartitionsEvictManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/PartitionsEvictManager.java @@ -245,7 +245,8 @@ private void showProgress() { if (threads == 0) threads = permits = 1; - log.info("Evict partition permits=" + permits); + if (log.isInfoEnabled()) + log.info("Evict partition permits=" + permits); evictionQueue = new BucketQueue(threads); } @@ -349,8 +350,9 @@ private void awaitFinishAll(){ private void awaitFinish(Integer part, IgniteInternalFuture fut) { // Wait for last offered partition eviction completion try { - log.info("Await partition evict, grpName=" + grp.cacheOrGroupName() + - ", grpId=" + grp.groupId() + ", partId=" + part); + if (log.isInfoEnabled()) + log.info("Await partition evict, grpName=" + grp.cacheOrGroupName() + + ", grpId=" + grp.groupId() + ", partId=" + part); fut.get(); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java index dff32723177fd..aed87de10e6dc 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java @@ -1579,8 +1579,8 @@ private void prepareIndexRebuildFuture(int cacheId) { CacheConfiguration ccfg = cacheCtx.config(); - if (ccfg != null) { - log().info("Finished indexes rebuilding for cache [name=" + ccfg.getName() + if (ccfg != null && log.isInfoEnabled()) { + log.info("Finished indexes rebuilding for cache [name=" + ccfg.getName() + ", grpName=" + ccfg.getGroupName() + ']'); } } @@ -2267,8 +2267,9 @@ private WALPointer performBinaryMemoryRestore( WALPointer cpMark = ((CheckpointRecord)rec).checkpointMark(); if (cpMark != null) { - log.info("Restoring checkpoint after logical recovery, will start physical recovery from " + - "back pointer: " + cpMark); + if (log.isInfoEnabled()) + log.info("Restoring checkpoint after logical recovery, will start physical recovery from " + + "back pointer: " + cpMark); recPtr = cpMark; } @@ -2413,8 +2414,9 @@ private WALPointer performBinaryMemoryRestore( "on disk, but checkpoint record is missed in WAL) " + "[cpStatus=" + status + ", lastRead=" + lastReadPtr + "]"); - log.info("Finished applying memory changes [changesApplied=" + applied + - ", time=" + (U.currentTimeMillis() - start) + " ms]"); + if (log.isInfoEnabled()) + log.info("Finished applying memory changes [changesApplied=" + applied + + ", time=" + (U.currentTimeMillis() - start) + " ms]"); assert applied.get() > 0; @@ -4122,21 +4124,22 @@ private Checkpoint markCheckpointBegin(CheckpointMetricsTracker tracker) throws if (printCheckpointStats && log.isInfoEnabled()) { long possibleJvmPauseDur = possibleLongJvmPauseDuration(tracker); - log.info( - String.format( - CHECKPOINT_STARTED_LOG_FORMAT, - cpRec.checkpointId(), - cp.checkpointMark(), - tracker.beforeLockDuration(), - tracker.lockWaitDuration(), - tracker.listenersExecuteDuration(), - tracker.lockHoldDuration(), - tracker.walCpRecordFsyncDuration(), - possibleJvmPauseDur > 0 ? "possibleJvmPauseDuration=" + possibleJvmPauseDur + "ms," : "", - cpPages.size(), - curr.reason - ) - ); + if (log.isInfoEnabled()) + log.info( + String.format( + CHECKPOINT_STARTED_LOG_FORMAT, + cpRec.checkpointId(), + cp.checkpointMark(), + tracker.beforeLockDuration(), + tracker.lockWaitDuration(), + tracker.listenersExecuteDuration(), + tracker.lockHoldDuration(), + tracker.walCpRecordFsyncDuration(), + possibleJvmPauseDur > 0 ? "possibleJvmPauseDuration=" + possibleJvmPauseDur + "ms," : "", + cpPages.size(), + curr.reason + ) + ); } return new Checkpoint(cp, cpPages, curr); @@ -5391,11 +5394,12 @@ private static void dumpPartitionsInfo(CacheGroupContext grp, IgniteLogger log) GridDhtLocalPartition part = grp.topology().localPartition(p); if (part != null) { - log.info("Partition [grp=" + grp.cacheOrGroupName() - + ", id=" + p - + ", state=" + part.state() - + ", counter=" + part.dataStore().partUpdateCounter() - + ", size=" + part.fullSize() + "]"); + if (log.isInfoEnabled()) + log.info("Partition [grp=" + grp.cacheOrGroupName() + + ", id=" + p + + ", state=" + part.state() + + ", counter=" + part.dataStore().partUpdateCounter() + + ", size=" + part.fullSize() + "]"); continue; } @@ -5406,7 +5410,8 @@ private static void dumpPartitionsInfo(CacheGroupContext grp, IgniteLogger log) pageStore.ensure(grp.groupId(), p); if (pageStore.pages(grp.groupId(), p) <= 1) { - log.info("Partition [grp=" + grp.cacheOrGroupName() + ", id=" + p + ", state=N/A (only file header) ]"); + if (log.isInfoEnabled()) + log.info("Partition [grp=" + grp.cacheOrGroupName() + ", id=" + p + ", state=N/A (only file header) ]"); continue; } @@ -5427,11 +5432,12 @@ private static void dumpPartitionsInfo(CacheGroupContext grp, IgniteLogger log) long updateCntr = io.getUpdateCounter(pageAddr); long size = io.getSize(pageAddr); - log.info("Partition [grp=" + grp.cacheOrGroupName() - + ", id=" + p - + ", state=" + state - + ", counter=" + updateCntr - + ", size=" + size + "]"); + if (log.isInfoEnabled()) + log.info("Partition [grp=" + grp.cacheOrGroupName() + + ", id=" + p + + ", state=" + state + + ", counter=" + updateCntr + + ", size=" + size + "]"); } finally { pageMem.readUnlock(grp.groupId(), partMetaId, partMetaPage); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PagesWriteSpeedBasedThrottle.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PagesWriteSpeedBasedThrottle.java index 2dd81275d108e..d497bdafa5e4b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PagesWriteSpeedBasedThrottle.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PagesWriteSpeedBasedThrottle.java @@ -288,7 +288,7 @@ private void recurrentLogIfNeed() { if (weight <= WARN_THRESHOLD) return; - if (prevWarnTime.compareAndSet(prevWarningNs, curNs)) { + if (prevWarnTime.compareAndSet(prevWarningNs, curNs) && log.isInfoEnabled()) { String msg = String.format("Throttling is applied to page modifications " + "[percentOfPartTime=%.2f, markDirty=%d pages/sec, checkpointWrite=%d pages/sec, " + "estIdealMarkDirty=%d pages/sec, curDirty=%.2f, maxDirty=%.2f, avgParkTime=%d ns, " + diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/scanner/PrintToLogHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/scanner/PrintToLogHandler.java index 848acb913d2f1..551e4df97aade 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/scanner/PrintToLogHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/scanner/PrintToLogHandler.java @@ -63,7 +63,8 @@ public PrintToLogHandler(IgniteLogger log) { resultString = null; - log.info(msg); + if (log.isInfoEnabled()) + log.info(msg); } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/VerifyBackupPartitionsDumpTask.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/VerifyBackupPartitionsDumpTask.java index 4066acf78d40e..a6a3bf12664e5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/VerifyBackupPartitionsDumpTask.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/VerifyBackupPartitionsDumpTask.java @@ -178,14 +178,16 @@ private String writeHashes( File out = new File(workDir, IDLE_DUMP_FILE_PREFIX + LocalDateTime.now().format(TIME_FORMATTER) + ".txt"); - ignite.log().info("IdleVerifyDumpTask will write output to " + out.getAbsolutePath()); + if (ignite.log().isInfoEnabled()) + ignite.log().info("IdleVerifyDumpTask will write output to " + out.getAbsolutePath()); try (PrintWriter writer = new PrintWriter(new FileWriter(out))) { writeResult(partitions, conflictRes, skippedRecords, writer); writer.flush(); - ignite.log().info("IdleVerifyDumpTask successfully written dump to '" + out.getAbsolutePath() + "'"); + if (ignite.log().isInfoEnabled()) + ignite.log().info("IdleVerifyDumpTask successfully written dump to '" + out.getAbsolutePath() + "'"); } catch (IOException | IgniteException e) { ignite.log().error("Failed to write dump file: " + out.getAbsolutePath(), e); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java index df9a38110ecfe..b974d803d2e83 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java @@ -413,7 +413,8 @@ private boolean isBaselineSatisfied(BaselineTopology blt, List serv DiscoveryDataClusterState state = globalState; if (msg.requestId().equals(state.transitionRequestId())) { - log.info("Received state change finish message: " + msg.clusterActive()); + if (log.isInfoEnabled()) + log.info("Received state change finish message: " + msg.clusterActive()); globalState = state.finish(msg.success()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/GridCacheLockImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/GridCacheLockImpl.java index f677ff55c7b0b..a5f7c1f844752 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/GridCacheLockImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/GridCacheLockImpl.java @@ -637,8 +637,9 @@ boolean synchronizeQueue(final boolean cancelled, final Thread thread) { } catch (Exception e) { if (interruptAll) { - log.info("Node is stopped (or lock is broken in non-failover safe mode)," + - " aborting transaction."); + if (log.isInfoEnabled()) + log.info("Node is stopped (or lock is broken in non-failover safe mode)," + + " aborting transaction."); // Abort this attempt to synchronize queue and start another one, // that will return immediately. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/diagnostic/PageHistoryDiagnoster.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/diagnostic/PageHistoryDiagnoster.java index 59a5b7af2ca08..8d0ccd8f3b7ab 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/diagnostic/PageHistoryDiagnoster.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/diagnostic/PageHistoryDiagnoster.java @@ -114,7 +114,8 @@ public void dumpPageHistory( @NotNull PageHistoryDiagnoster.DiagnosticPageBuilder builder ) throws IgniteCheckedException { if (walFolders == null) { - log.info("Skipping dump page history due to WAL not configured"); + if (log.isInfoEnabled()) + log.info("Skipping dump page history due to WAL not configured"); return; } @@ -150,7 +151,8 @@ public void dumpPageHistory( } if (descIdx == -1) { - log.info("Skipping dump page history due to can not reserve WAL segments: " + descToString(descs)); + if (log.isInfoEnabled()) + log.info("Skipping dump page history due to can not reserve WAL segments: " + descToString(descs)); return; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerProcessor.java index c8c026039ac77..7a810e46e4e38 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerProcessor.java @@ -479,7 +479,8 @@ private class ClientProcessorMXBeanImpl implements ClientProcessorMXBean { srv.close(ses); - log.info("Client session has been dropped: " + clientConnectionDescription(ses, connCtx)); + if (log.isInfoEnabled()) + log.info("Client session has been dropped: " + clientConnectionDescription(ses, connCtx)); } } @@ -504,7 +505,8 @@ private class ClientProcessorMXBeanImpl implements ClientProcessorMXBean { srv.close(ses); - log.info("Client session has been dropped: " + clientConnectionDescription(ses, connCtx)); + if (log.isInfoEnabled()) + log.info("Client session has been dropped: " + clientConnectionDescription(ses, connCtx)); return true; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/GridJavaProcess.java b/modules/core/src/main/java/org/apache/ignite/internal/util/GridJavaProcess.java index 3f05e13cfe502..32ce861247323 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/GridJavaProcess.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/GridJavaProcess.java @@ -193,7 +193,7 @@ public void kill() throws Exception { int exitVal = killProc.exitValue(); - if (exitVal != 0) + if (exitVal != 0 && log.isInfoEnabled()) log.info(String.format("Abnormal exit value of %s for pid %s", exitVal, pid)); if (procKilledC != null) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteStopwatch.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteStopwatch.java index cf7a186b57086..b55fe1ab99bb6 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteStopwatch.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteStopwatch.java @@ -135,19 +135,23 @@ public static void logTime( ) throws IgniteCheckedException { long start = System.currentTimeMillis(); - log.info("Operation was started: operation = " + operationName); + if (log.isInfoEnabled()) + log.info("Operation was started: " + operationName); + try { operation.run(); } catch (Throwable ex) { - log.info("Operation was failed: operation = " + operationName - + ", elapsedTime = " + (System.currentTimeMillis() - start) + " ms"); + if (log.isInfoEnabled()) + log.info("Operation failed [operation=" + operationName + + ", elapsedTime=" + (System.currentTimeMillis() - start) + "ms]"); throw ex; } - log.info("Operation was success: operation = " + operationName - + ", elapsedTime = " + (System.currentTimeMillis() - start) + " ms"); + if (log.isInfoEnabled()) + log.info("Operation succeeded [operation=" + operationName + + ", elapsedTime=" + (System.currentTimeMillis() - start) + "ms]"); } /** diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java index 58a09223c1130..4392a471fe03e 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java @@ -2194,7 +2194,8 @@ private void processNodeAddFinishedMessage(TcpDiscoveryNodeAddFinishedMessage ms if (log.isInfoEnabled()) { for (ClusterNode node : getRemoteNodes()) { if (node.id().equals(locNode.clientRouterNodeId())) { - log.info("Router node: " + node); + if (log.isInfoEnabled()) + log.info("Router node: " + node); break; } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/IgniteThrottlingUnitTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/IgniteThrottlingUnitTest.java index bc07ae19f3789..75baea2161dbe 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/IgniteThrottlingUnitTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/IgniteThrottlingUnitTest.java @@ -288,6 +288,8 @@ public void warningInCaseTooMuchThrottling() { AtomicInteger warnings = new AtomicInteger(0); IgniteLogger log = mock(IgniteLogger.class); + when(log.isInfoEnabled()).thenReturn(true); + doAnswer(invocation -> { Object[] args = invocation.getArguments(); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/wal/scanner/WalScannerTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/wal/scanner/WalScannerTest.java index 95d8016e4cf67..58dcdf91a1917 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/wal/scanner/WalScannerTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/wal/scanner/WalScannerTest.java @@ -176,6 +176,8 @@ public void testShouldDumpToLogFoundRecord() throws Exception { IgniteLogger log = mock(IgniteLogger.class); + when(log.isInfoEnabled()).thenReturn(true); + ArgumentCaptor valCapture = ArgumentCaptor.forClass(String.class); doNothing().when(log).info(valCapture.capture()); @@ -264,6 +266,8 @@ public void testShouldDumpToFileAndLogFoundRecord() throws Exception { IgniteLogger log = mock(IgniteLogger.class); + when(log.isInfoEnabled()).thenReturn(true); + ArgumentCaptor valCapture = ArgumentCaptor.forClass(String.class); doNothing().when(log).info(valCapture.capture()); diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java index 290d146f45bb0..b92d8d7a580eb 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java @@ -744,7 +744,7 @@ private void sendError(ClusterNode node, long qryReqId, Throwable err) { if (log.isDebugEnabled()) U.warn(log, errMsg, err); - else + else if (log.isInfoEnabled()) log.info(errMsg); } else diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/Tracer.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/Tracer.java index b73ee3e9d9489..acc8f9d97c342 100644 --- a/modules/ml/src/main/java/org/apache/ignite/ml/math/Tracer.java +++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/Tracer.java @@ -97,7 +97,8 @@ static private ColorMapper mkMatrixColorMapper(Matrix mtx) { public static void showAscii(Vector vec, IgniteLogger log, String fmt) { String cls = vec.getClass().getSimpleName(); - log.info(String.format(LOCALE, "%s(%d) [%s]", cls, vec.size(), mkString(vec, fmt))); + if (log.isInfoEnabled()) + log.info(String.format(LOCALE, "%s(%d) [%s]", cls, vec.size(), mkString(vec, fmt))); } /** @@ -179,10 +180,12 @@ public static void showAscii(Matrix mtx, IgniteLogger log, String fmt) { int rows = mtx.rowSize(); int cols = mtx.columnSize(); - log.info(String.format(LOCALE, "%s(%dx%d)", cls, rows, cols)); + if (log.isInfoEnabled()) { + log.info(String.format(LOCALE, "%s(%dx%d)", cls, rows, cols)); - for (int row = 0; row < rows; row++) - log.info(rowStr(mtx, row, fmt)); + for (int row = 0; row < rows; row++) + log.info(rowStr(mtx, row, fmt)); + } } /** diff --git a/modules/osgi/src/main/java/org/apache/ignite/osgi/IgniteAbstractOsgiContextActivator.java b/modules/osgi/src/main/java/org/apache/ignite/osgi/IgniteAbstractOsgiContextActivator.java index dc491e998b955..289d86f26729a 100644 --- a/modules/osgi/src/main/java/org/apache/ignite/osgi/IgniteAbstractOsgiContextActivator.java +++ b/modules/osgi/src/main/java/org/apache/ignite/osgi/IgniteAbstractOsgiContextActivator.java @@ -117,7 +117,8 @@ public abstract class IgniteAbstractOsgiContextActivator implements BundleActiva log = ignite.log(); - log.info("Started Ignite from OSGi Activator [name=" + ignite.name() + ']'); + if (log.isInfoEnabled()) + log.info("Started Ignite from OSGi Activator [name=" + ignite.name() + ']'); // Add into Ignite's OSGi registry. IgniteOsgiUtils.classloaders().put(ignite, clsLdr); diff --git a/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryImpl.java b/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryImpl.java index 835e6f83077d0..61483f09d0844 100644 --- a/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryImpl.java +++ b/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryImpl.java @@ -1358,7 +1358,7 @@ private void checkIsCoordinator(final List aliveNodes) throws Exception log.info("Discovery coordinator already exists, watch for previous server node [" + "locId=" + locNode.id() + ", watchPath=" + prevE.getValue() + ']'); - } + } PreviousNodeWatcher watcher = new ServerPreviousNodeWatcher(rtState); From 9a3b007b9da697ac158ce23922a7a3a56f5cc22a Mon Sep 17 00:00:00 2001 From: Dmitriy Govorukhin Date: Mon, 22 Jul 2019 13:34:43 +0300 Subject: [PATCH 57/62] GG-21696 [GG-21389] Flush records on cache stop (cherry picked from commit d8753aea2f9fe8712553a7bee0551830768e9808) --- .../processors/cache/GridCacheProcessor.java | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java index 230162ea3d010..3baf8ae26a7c0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java @@ -1321,16 +1321,26 @@ private void stopCache(GridCacheAdapter cache, boolean cancel, boolean des U.stopLifecycleAware(log, lifecycleAwares(ctx.group(), cache.configuration(), ctx.store().configuredStore())); - IgnitePageStoreManager pageStore; + try { + IgniteWriteAheadLogManager wal; - if (destroy && (pageStore = sharedCtx.pageStore()) != null) { - try { + if ((wal = sharedCtx.wal()) != null) + wal.flush(null, false); + } + catch (IgniteCheckedException e) { + U.error(log, "Failed to flush WAL data while destroying cache" + + "[cache=" + ctx.name() + "]", e); + } + + try { + IgnitePageStoreManager pageStore; + + if (destroy && (pageStore = sharedCtx.pageStore()) != null) pageStore.removeCacheData(new StoredCacheData(ctx.config())); - } - catch (IgniteCheckedException e) { - U.error(log, "Failed to delete cache configuration data while destroying cache" + - "[cache=" + ctx.name() + "]", e); - } + } + catch (IgniteCheckedException e) { + U.error(log, "Failed to delete cache configuration data while destroying cache" + + "[cache=" + ctx.name() + "]", e); } if (log.isInfoEnabled()) { From 8d83dbcf921ed96e923f65a067d7c3af225b15a9 Mon Sep 17 00:00:00 2001 From: Yury Gerzhedovich Date: Mon, 22 Jul 2019 18:01:01 +0300 Subject: [PATCH 58/62] GG-21461: improve algorithm of detecting use of java objects for inlining --- .../processors/query/h2/IgniteH2Indexing.java | 2 +- .../processors/query/h2/database/H2Tree.java | 21 ++++- .../query/h2/database/H2TreeIndex.java | 8 +- .../database/H2TreeInlineObjectDetector.java | 91 ++++++++++++++++--- 4 files changed, 107 insertions(+), 15 deletions(-) diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index d946eb251a1c3..55ed331d186e8 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -714,7 +714,7 @@ GridH2IndexBase createSortedIndex(String name, GridH2Table tbl, boolean pk, List H2RowCache cache = rowCache.forGroup(cctx.groupId()); - return new H2TreeIndex(cctx, cache, tbl, name, pk, cols, inlineSize, segments); + return new H2TreeIndex(cctx, cache, tbl, name, pk, cols, inlineSize, segments, log); } catch (IgniteCheckedException e) { throw new IgniteException(e); diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java index 0525f437dd3ac..3abe981bedaf1 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java @@ -23,6 +23,7 @@ import java.util.stream.Collectors; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteException; +import org.apache.ignite.IgniteLogger; import org.apache.ignite.internal.pagemem.FullPageId; import org.apache.ignite.internal.pagemem.PageIdUtils; import org.apache.ignite.internal.pagemem.PageMemory; @@ -69,6 +70,15 @@ public abstract class H2Tree extends BPlusTree { /** */ private final int[] columnIds; + /** */ + private final IgniteLogger log; + + /** */ + private final String tblName; + + /** */ + private final String idxName; + /** */ private final IoStatisticsHolder stats; @@ -89,6 +99,8 @@ public abstract class H2Tree extends BPlusTree { * Constructor. * * @param name Tree name. + * @param tblName Table name. + * @param idxName Index name. * @param reuseList Reuse list. * @param grpId Cache group ID. * @param pageMem Page memory. @@ -98,11 +110,14 @@ public abstract class H2Tree extends BPlusTree { * @param initNew Initialize new index. * @param rowCache Row cache. * @param failureProcessor if the tree is corrupted. + * @param log Logger. * @param stats Statistics holder. * @throws IgniteCheckedException If failed. */ protected H2Tree( String name, + String tblName, + String idxName, ReuseList reuseList, int grpId, PageMemory pageMem, @@ -116,6 +131,7 @@ protected H2Tree( int inlineSize, @Nullable H2RowCache rowCache, @Nullable FailureProcessor failureProcessor, + IgniteLogger log, IoStatisticsHolder stats ) throws IgniteCheckedException { super( @@ -130,8 +146,11 @@ protected H2Tree( null ); + this.log = log; this.stats = stats; this.rowCache = rowCache; + this.tblName = tblName; + this.idxName = idxName; this.rowStore = rowStore; this.cols = cols; @@ -190,7 +209,7 @@ private boolean inlineObjectSupported(MetaPageInfo metaInfo, List colsList, int inlineSize, - int segmentsCnt + int segmentsCnt, + IgniteLogger log ) throws IgniteCheckedException { assert segmentsCnt > 0 : segmentsCnt; @@ -135,6 +138,8 @@ public H2TreeIndex( RootPage page = getMetaPage(i); segments[i] = new H2Tree( + name, + tbl.getName(), name, cctx.offheap().reuseListForIndex(name), cctx.groupId(), @@ -149,6 +154,7 @@ public H2TreeIndex( computeInlineSize(inlineIdxs, inlineSize), rowCache, cctx.kernalContext().failure(), + log, stats) { @Override public int compareValues(Value v1, Value v2) { return v1 == v2 ? 0 : table.compareTypeSafe(v1, v2); diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java index 83a3872f625a4..5367648c6e894 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java @@ -18,6 +18,7 @@ import java.util.List; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.IgniteLogger; import org.apache.ignite.internal.pagemem.PageUtils; import org.apache.ignite.internal.processors.cache.persistence.tree.BPlusTree; import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusIO; @@ -40,13 +41,29 @@ public class H2TreeInlineObjectDetector implements BPlusTree.TreeRowClosure inlineHelpers) { + H2TreeInlineObjectDetector(int inlineSize, List inlineHelpers, String tblName, String idxName, + IgniteLogger log) { this.inlineSize = inlineSize; this.inlineHelpers = inlineHelpers; + this.tblName = tblName; + this.idxName = idxName; + this.log = log; } /** {@inheritDoc} */ @@ -68,26 +85,61 @@ public class H2TreeInlineObjectDetector implements BPlusTree.TreeRowClosure inlineSize - fieldOff - 3 || len > originalObjBytes.length){ + + inlineObjectSupportedDecision(false, "lenght is big " + len); + + return true; + } + + // compare full object + if(isFull) { + int compRes = ih.compare(pageAddr, off + fieldOff, inlineSize - fieldOff, val, (o1, o2) -> 0); + + inlineObjectSupportedDecision(compRes == 0, "full compare"); + + return true; + } + + + // try compare byte by byte for partial inlined object. + byte[] inlineBytes = PageUtils.getBytes(pageAddr, off + fieldOff + 3, len); + + for (int i = 0; i < len; i++) { + if(inlineBytes[i] == originalObjBytes[i]) + continue; + + inlineObjectSupportedDecision(false, i + " byte compare"); + + return true; + } + + inlineObjectSupportedDecision(true, len + " bytes compared"); return true; } - else { - assert type == Value.UNKNOWN; - return false; - } + inlineObjectSupportedDecision(false, "inline type " + type); + + return true; } return true; @@ -122,4 +174,19 @@ public static boolean objectMayBeInlined(int inlineSize, List return remainSize >= 4; } + + /** + * @param inlineObjSupported {@code true} if inline object is supported on current tree. + * @param reason Reason why has been made decision. + */ + private void inlineObjectSupportedDecision(boolean inlineObjSupported, String reason){ + this.inlineObjSupported = inlineObjSupported; + + if (inlineObjSupported) + log.info("Index support JAVA_OBJECT type inlining [tblName=" + tblName +", idxName=" + + idxName + ", reason='" + reason + "']"); + else + log.info("Index doesn't support JAVA_OBJECT type inlining [tblName=" + tblName +", idxName=" + + idxName + ", reason='" + reason + "']"); + } } From 8a70bd04637e2f676440ffae8f00bbcbdbaefa70 Mon Sep 17 00:00:00 2001 From: Yury Gerzhedovich Date: Tue, 23 Jul 2019 11:26:28 +0300 Subject: [PATCH 59/62] GG-21461: fixes after review. --- .../query/h2/database/H2TreeIndex.java | 2 ++ .../database/H2TreeInlineObjectDetector.java | 21 ++++--------------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java index a724d274ff9f9..505a351efae56 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java @@ -82,11 +82,13 @@ public class H2TreeIndex extends GridH2IndexBase { /** * @param cctx Cache context. + * @param rowCache Row cache. * @param tbl Table. * @param name Index name. * @param pk Primary key. * @param colsList Index columns. * @param inlineSize Inline size. + * @param segmentsCnt number of tree's segments. * @param log Logger. * @throws IgniteCheckedException If failed. */ diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java index 5367648c6e894..6ac007aac6304 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java @@ -96,35 +96,22 @@ public class H2TreeInlineObjectDetector implements BPlusTree.TreeRowClosure inlineSize - fieldOff - 3 || len > originalObjBytes.length){ - + if (len > inlineSize - fieldOff - 3 || len > originalObjBytes.length) { inlineObjectSupportedDecision(false, "lenght is big " + len); return true; } - // compare full object - if(isFull) { - int compRes = ih.compare(pageAddr, off + fieldOff, inlineSize - fieldOff, val, (o1, o2) -> 0); - - inlineObjectSupportedDecision(compRes == 0, "full compare"); - - return true; - } - - - // try compare byte by byte for partial inlined object. + // try compare byte by byte for fully or partial inlined object. byte[] inlineBytes = PageUtils.getBytes(pageAddr, off + fieldOff + 3, len); for (int i = 0; i < len; i++) { - if(inlineBytes[i] == originalObjBytes[i]) + if (inlineBytes[i] == originalObjBytes[i]) continue; inlineObjectSupportedDecision(false, i + " byte compare"); @@ -183,7 +170,7 @@ private void inlineObjectSupportedDecision(boolean inlineObjSupported, String re this.inlineObjSupported = inlineObjSupported; if (inlineObjSupported) - log.info("Index support JAVA_OBJECT type inlining [tblName=" + tblName +", idxName=" + + log.info("Index supports JAVA_OBJECT type inlining [tblName=" + tblName +", idxName=" + idxName + ", reason='" + reason + "']"); else log.info("Index doesn't support JAVA_OBJECT type inlining [tblName=" + tblName +", idxName=" + From 67a599b41a29897b4ed4c2645dbb61825f38a25f Mon Sep 17 00:00:00 2001 From: Yury Gerzhedovich Date: Wed, 24 Jul 2019 12:59:43 +0300 Subject: [PATCH 60/62] GG-21461: Corrupt index tree fix --- .../processors/query/h2/database/H2Tree.java | 4 +++- .../h2/database/H2TreeInlineObjectDetector.java | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java index 3abe981bedaf1..b91934f58439f 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2Tree.java @@ -167,7 +167,9 @@ protected H2Tree( if (metaInfo.useUnwrappedPk()) throw new IgniteCheckedException("Unwrapped PK is not supported by current version"); - this.inlineSize = metaInfo.inlineSize(); + inlineSize = metaInfo.inlineSize(); + + this.inlineSize = inlineSize; setIos( H2ExtrasInnerIO.getVersions(inlineSize), diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java index 6ac007aac6304..164c2ba349e76 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java @@ -75,11 +75,16 @@ public class H2TreeInlineObjectDetector implements BPlusTree.TreeRowClosure= inlineSize) return false; if (ih.type() != Value.JAVA_OBJECT) { + if(ih.size() < 0) + varLenPresents=true; + fieldOff += ih.fullSize(pageAddr, off + fieldOff); continue; @@ -124,11 +129,20 @@ public class H2TreeInlineObjectDetector implements BPlusTree.TreeRowClosure Date: Wed, 24 Jul 2019 18:44:47 +0300 Subject: [PATCH 61/62] GG-21461: fixes after review --- .../database/H2TreeInlineObjectDetector.java | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java index 164c2ba349e76..4faac8271fb45 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java @@ -82,8 +82,8 @@ public class H2TreeInlineObjectDetector implements BPlusTree.TreeRowClosure inlineHelpers) { @@ -180,14 +177,14 @@ public static boolean objectMayBeInlined(int inlineSize, List * @param inlineObjSupported {@code true} if inline object is supported on current tree. * @param reason Reason why has been made decision. */ - private void inlineObjectSupportedDecision(boolean inlineObjSupported, String reason){ + private void inlineObjectSupportedDecision(boolean inlineObjSupported, String reason) { this.inlineObjSupported = inlineObjSupported; if (inlineObjSupported) - log.info("Index supports JAVA_OBJECT type inlining [tblName=" + tblName +", idxName=" + + log.info("Index supports JAVA_OBJECT type inlining [tblName=" + tblName + ", idxName=" + idxName + ", reason='" + reason + "']"); else - log.info("Index doesn't support JAVA_OBJECT type inlining [tblName=" + tblName +", idxName=" + + log.info("Index doesn't support JAVA_OBJECT type inlining [tblName=" + tblName + ", idxName=" + idxName + ", reason='" + reason + "']"); } } From 27f7124e91d64f98c1999dd0e4ef9b3048bf2360 Mon Sep 17 00:00:00 2001 From: Yury Gerzhedovich Date: Thu, 25 Jul 2019 11:54:24 +0300 Subject: [PATCH 62/62] GG-21461: fixes after review --- .../query/h2/database/H2TreeInlineObjectDetector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java index 4faac8271fb45..291111a8de64b 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeInlineObjectDetector.java @@ -167,7 +167,7 @@ public static boolean objectMayBeInlined(int inlineSize, List if (ih.type() == Value.JAVA_OBJECT) break; - remainSize -= ih.size() > 0 ? 1 + ih.size() : 4; + remainSize -= ih.size() > 0 ? 1 + ih.size() : 1; } return remainSize >= 4;