From 26d8c8347cecf6b8ae1abf99a6f2581675fd8e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=80=D0=B0=D0=B6=D0=BD=D0=B8=D0=BA=D0=BE=D0=B2=20?= =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20=D0=A1?= =?UTF-8?q?=D0=B5=D1=80=D0=B3=D0=B5=D0=B5=D0=B2=D0=B8=D1=87?= Date: Thu, 2 Jul 2020 17:59:09 +0300 Subject: [PATCH 01/15] IGN-1049 Backup filter for RendezvousAffinityFunction Squashed commit of the following: commit f7a3fad02662615e47c90220240fa8418765283a Author: Aleksey Plekhanov Date: Thu Jul 2 19:47:20 2020 +0500 IGN-1049 Backup filter for RendezvousAffinityFunction --- modules/core/pom.xml | 1 + ...terNodeAttributeColocatedBackupFilter.java | 102 ++++++++++++++++++ ...ttributeColocatedBackupFilterSelfTest.java | 91 ++++++++++++++++ .../testsuites/IgniteCacheMvccTestSuite2.java | 1 + .../testsuites/IgniteCacheTestSuite2.java | 2 + 5 files changed, 197 insertions(+) create mode 100644 modules/core/src/main/java/com/sbt/sbergrid/extras/ClusterNodeAttributeColocatedBackupFilter.java create mode 100644 modules/core/src/test/java/com/sbt/sbergrid/extras/ClusterNodeAttributeColocatedBackupFilterSelfTest.java diff --git a/modules/core/pom.xml b/modules/core/pom.xml index 0035912ee5ebd..acc5474461a2e 100644 --- a/modules/core/pom.xml +++ b/modules/core/pom.xml @@ -501,6 +501,7 @@ + **/com/sbt/sbergrid/**/*Test.java **/org/apache/ignite/**/*.java **/annotation/*Test.java **/ClientServerTest.java diff --git a/modules/core/src/main/java/com/sbt/sbergrid/extras/ClusterNodeAttributeColocatedBackupFilter.java b/modules/core/src/main/java/com/sbt/sbergrid/extras/ClusterNodeAttributeColocatedBackupFilter.java new file mode 100644 index 0000000000000..bc0e33411b31c --- /dev/null +++ b/modules/core/src/main/java/com/sbt/sbergrid/extras/ClusterNodeAttributeColocatedBackupFilter.java @@ -0,0 +1,102 @@ +/* + * 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 com.sbt.sbergrid.extras; + +import java.util.List; +import java.util.Objects; +import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.lang.IgniteBiPredicate; + +/** + * This class can be used as a {@link RendezvousAffinityFunction#setAffinityBackupFilter } to create + * cache templates in Spring that force each partition's primary and backup to be co-located on nodes with the same + * attribute value. + *

+ * This implementation will discard backups rather than place copies on nodes with different attribute values. This + * avoids trying to cram more data onto remaining nodes when some have failed. + *

+ * A node attribute to compare is provided on construction. Note: "All cluster nodes, + * on startup, automatically register all the environment and system properties as node attributes." + *

+ * This class is constructed with a node attribute name, and a candidate node will be rejected if previously selected + * nodes for a partition have a different value for attribute on the candidate node. + * + *

Spring Example

+ * Create a partitioned cache template plate with 1 backup, where the backup will be placed in the same cell + * as the primary. Note: This example requires that the environment variable "CELL" be set appropriately on + * each node via some means external to Ignite. + *
+ * <property name="cacheConfiguration">
+ *     <list>
+ *         <bean id="cache-template-bean" abstract="true" class="org.apache.ignite.configuration.CacheConfiguration">
+ *             <property name="name" value="JobcaseDefaultCacheConfig*"/>
+ *             <property name="cacheMode" value="PARTITIONED" />
+ *             <property name="backups" value="1" />
+ *             <property name="affinity">
+ *                 <bean class="org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction">
+ *                     <property name="affinityBackupFilter">
+ *                         <bean class="com.sbt.sbergrid.extras.ClusterNodeAttributeColocatedBackupFilter">
+ *                             <!-- Backups must go to the same CELL as primary -->
+ *                             <constructor-arg value="CELL" />
+ *                         </bean>
+ *                     </property>
+ *                 </bean>
+ *             </property>
+ *         </bean>
+ *     </list>
+ * </property>
+ * 
+ *

+ * + * @deprecated Use {@link org.apache.ignite.cache.affinity.rendezvous.ClusterNodeAttributeColocatedBackupFilter} + * instead. + */ +@Deprecated +public class ClusterNodeAttributeColocatedBackupFilter implements IgniteBiPredicate> { + /** */ + private static final long serialVersionUID = 1L; + + /** Attribute name. */ + private final String attributeName; + + /** + * @param attributeName The attribute name for the attribute to compare. + */ + public ClusterNodeAttributeColocatedBackupFilter(String attributeName) { + this.attributeName = attributeName; + } + + /** + * Defines a predicate which returns {@code true} if a node is acceptable for a backup + * or {@code false} otherwise. An acceptable node is one where its attribute value + * is exact match with previously selected nodes. If an attribute does not + * exist on exactly one node of a pair, then the attribute does not match. If the attribute + * does not exist both nodes of a pair, then the attribute matches. + * + * @param candidate A node that is a candidate for becoming a backup node for a partition. + * @param previouslySelected A list of primary/backup nodes already chosen for a partition. + * The primary is first. + */ + @Override public boolean apply(ClusterNode candidate, List previouslySelected) { + for (ClusterNode node : previouslySelected) + return Objects.equals(candidate.attribute(attributeName), node.attribute(attributeName)); + + return true; + } +} diff --git a/modules/core/src/test/java/com/sbt/sbergrid/extras/ClusterNodeAttributeColocatedBackupFilterSelfTest.java b/modules/core/src/test/java/com/sbt/sbergrid/extras/ClusterNodeAttributeColocatedBackupFilterSelfTest.java new file mode 100644 index 0000000000000..7ea7b06612c8b --- /dev/null +++ b/modules/core/src/test/java/com/sbt/sbergrid/extras/ClusterNodeAttributeColocatedBackupFilterSelfTest.java @@ -0,0 +1,91 @@ +/* + * 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 com.sbt.sbergrid.extras; + +import java.util.Collection; +import java.util.Map; +import org.apache.ignite.IgniteCache; +import org.apache.ignite.cache.affinity.AffinityFunction; +import org.apache.ignite.cache.affinity.AffinityFunctionBackupFilterAbstractSelfTest; +import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction; +import org.apache.ignite.cluster.ClusterNode; + +/** + * Partitioned affinity test. + */ +public class ClusterNodeAttributeColocatedBackupFilterSelfTest extends AffinityFunctionBackupFilterAbstractSelfTest { + /** {@inheritDoc} */ + @Override protected AffinityFunction affinityFunction() { + RendezvousAffinityFunction aff = new RendezvousAffinityFunction(false); + + aff.setBackupFilter(backupFilter); + + return aff; + } + + /** {@inheritDoc} */ + @Override protected AffinityFunction affinityFunctionWithAffinityBackupFilter(String attributeName) { + RendezvousAffinityFunction aff = new RendezvousAffinityFunction(false); + + aff.setAffinityBackupFilter(new ClusterNodeAttributeColocatedBackupFilter(attributeName)); + + return aff; + } + + /** {@inheritDoc} */ + @Override protected void checkPartitionsWithAffinityBackupFilter() throws Exception { + AffinityFunction aff = cacheConfiguration(grid(0).configuration(), DEFAULT_CACHE_NAME).getAffinity(); + + int partCnt = aff.partitions(); + + int iter = grid(0).cluster().nodes().size() / 4; + + IgniteCache cache = grid(0).cache(DEFAULT_CACHE_NAME); + + for (int i = 0; i < partCnt; i++) { + Collection nodes = affinity(cache).mapKeyToPrimaryAndBackups(i); + + Map stat = getAttributeStatistic(nodes); + + if (stat.get(FIRST_NODE_GROUP) > 0) { + assertEquals((Integer)Math.min(backups + 1, iter * 2), stat.get(FIRST_NODE_GROUP)); + assertEquals((Integer)0, stat.get("B")); + assertEquals((Integer)0, stat.get("C")); + } + else if (stat.get("B") > 0) { + assertEquals((Integer)0, stat.get(FIRST_NODE_GROUP)); + assertEquals((Integer)iter, stat.get("B")); + assertEquals((Integer)0, stat.get("C")); + } + else if (stat.get("C") > 0) { + assertEquals((Integer)0, stat.get(FIRST_NODE_GROUP)); + assertEquals((Integer)0, stat.get("B")); + assertEquals((Integer)iter, stat.get("C")); + } + else + fail("Unexpected partition assignment"); + } + } + + /** {@inheritDoc} */ + @Override public void testPartitionDistributionWithAffinityBackupFilter() throws Exception { + backups = 2; + + super.testPartitionDistributionWithAffinityBackupFilter(); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite2.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite2.java index 49a1779c653fb..e552f98b71f66 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite2.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheMvccTestSuite2.java @@ -170,6 +170,7 @@ public static List> suite() { ignoredTests.add(RendezvousAffinityFunctionBackupFilterSelfTest.class); ignoredTests.add(ClusterNodeAttributeAffinityBackupFilterSelfTest.class); ignoredTests.add(ClusterNodeAttributeColocatedBackupFilterSelfTest.class); + ignoredTests.add(com.sbt.sbergrid.extras.ClusterNodeAttributeColocatedBackupFilterSelfTest.class); ignoredTests.add(NonAffinityCoordinatorDynamicStartStopTest.class); ignoredTests.add(NoneRebalanceModeSelfTest.class); diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite2.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite2.java index 87ef5917f3078..7c95e0a93883c 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite2.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite2.java @@ -380,6 +380,8 @@ public static List> suite(Collection ignoredTests) { GridTestUtils.addTestIfNeeded(suite, RendezvousAffinityFunctionBackupFilterSelfTest.class, ignoredTests); GridTestUtils.addTestIfNeeded(suite, ClusterNodeAttributeAffinityBackupFilterSelfTest.class, ignoredTests); GridTestUtils.addTestIfNeeded(suite, ClusterNodeAttributeColocatedBackupFilterSelfTest.class, ignoredTests); + GridTestUtils.addTestIfNeeded(suite, + com.sbt.sbergrid.extras.ClusterNodeAttributeColocatedBackupFilterSelfTest.class, ignoredTests); GridTestUtils.addTestIfNeeded(suite, CachePartitionStateTest.class, ignoredTests); GridTestUtils.addTestIfNeeded(suite, CacheComparatorTest.class, ignoredTests); From 051d72776a554e839e4b34120ab81f10c8fedb5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D0=B0=D1=80=D1=83=D1=81=20=D0=94=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=81=20=D0=93=D1=80=D0=B8=D0=B3=D0=BE=D1=80=D1=8C=D0=B5=D0=B2?= =?UTF-8?q?=D0=B8=D1=87?= Date: Wed, 3 Jun 2020 14:34:50 +0300 Subject: [PATCH 02/15] IGN-627 Fix incorrect subject identifier for thin client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Squashed commit of the following: commit 72f75465a94fc3121f55e0472a5a96defddc742b Author: sbt-garus-dg Date: Wed Jun 3 14:16:52 2020 +0300 fix comments commit f37bd70b40b3a6f424f1458ea8adfcd0de4517c6 Author: sbt-garus-dg Date: Wed May 27 17:35:21 2020 +0300 rework tests commit 970a8f87cda473541e381800b8f03e51701c60cc Author: sbt-garus-dg Date: Mon May 25 15:57:22 2020 +0300 fix comments commit 3f7e76870256312bbe200a7b1ea7d5f967ff9fd7 Merge: 675bbac8445 a2dbfc170f0 Author: sbt-garus-dg Date: Fri May 22 16:24:43 2020 +0300 Merge branch 'master-se-4.281' into IGN-627-1 commit a2dbfc170f01c1002a825c52a9423dc7094b3b13 Merge: 108fd7ec7d4 3549f250d7b Author: sbt-garus-dg Date: Fri May 22 16:22:00 2020 +0300 Merge remote-tracking branch 'origin/master-se-4.281' into master-se-4.281 commit 675bbac84456cbcbfae27e0f4c9ff49b0ff0f5fe Author: sbt-garus-dg Date: Thu May 21 10:15:19 2020 +0300 fix comments commit 23f54e407d787e77db24e7efc2449a076cf4825e Author: sbt-garus-dg Date: Wed May 20 15:47:44 2020 +0300 fix comments commit 6b09b64b0401b4b195bf42f7554ef164b241a3d5 Author: sbt-garus-dg Date: Mon May 18 16:56:44 2020 +0300 activate/deactivate the cluster commit 16cc7d5d3cce3f06c5a199fd30d5e4f83b39e495 Author: sbt-garus-dg Date: Mon May 18 16:00:01 2020 +0300 activate/deactivate the cluster commit 7900fc370d8f152ace46c564be4af93a7bec22ab Author: sbt-garus-dg Date: Mon May 18 15:47:46 2020 +0300 activate/deactivate the cluster commit 8e0b6433569364c28e085c54d3f9e532256cfd88 Author: sbt-garus-dg Date: Mon May 18 15:31:59 2020 +0300 activate/deactivate the cluster commit 73d4d35de367b4d613a5ce64deef160bcfeb1335 Merge: 555e3ac7bb5 108fd7ec7d4 Author: sbt-garus-dg Date: Fri May 15 13:46:10 2020 +0300 Merge branch 'master-se-4.281' into IGN-627 commit 108fd7ec7d47ee77c594481df8113bd10b0c23bd Merge: c601f0a50ba 5073636d478 Author: sbt-garus-dg Date: Fri May 15 13:42:38 2020 +0300 Merge remote-tracking branch 'origin/master-se-4.281' into master-se-4.281 commit 5073636d478d3cb9bfdf3fb039bd53970baee47e Author: Бражников Александр Сергеевич Date: Wed Apr 15 17:29:37 2020 +0300 IGN-600: added request password from console to keystore for userAttributes Squashed commit of the following: commit 1a7dba7e8a0db41c57745f9a7426ff3edeb446d3 Author: Ryzhov Sergei Date: Wed Apr 15 15:51:34 2020 +0300 IGN-600: fix comments: getting keyStorePath to userAttributes from sslCtxFactory commit 7d5b3ca99a11a3885c6c4b46318918a22adcbe9d Author: Ryzhov Sergei Date: Tue Apr 14 23:53:34 2020 +0300 IGN-600: fix comments commit 5baee15f71404f716c8784ba0ce80c98ae5c4076 Author: Ryzhov Sergei Date: Tue Apr 14 23:33:06 2020 +0300 IGN-600: getting password from sslContextFactory to keystore for userAttributes commit 83c7b250a9e04cc8a56c736a179b194c4b1d997f Author: Ryzhov Sergei Date: Tue Apr 14 21:06:28 2020 +0300 IGN-600: added request password from console to keystore for userAttributes commit 8df62fa401d19ae6feaaa3a9f2637f373ec8841a Author: olegostanin Date: Wed Apr 1 15:15:03 2020 +0300 IGN-527 Add JKS path and password attributes support to control.sh IGN-527 Added Base64 encoding for userAttrs in CommandHandler. commit fae8b3a859da6fbb8f0600f185561a0a1929278c Author: Andrey Kuznetsov Date: Tue Apr 7 01:38:12 2020 +0300 IGN-559 Added userAttrs to authentication message. commit ea2dea11778ea34f907b811568eaef293fe785f1 Author: Бражников Александр Сергеевич Date: Fri May 15 13:18:13 2020 +0300 IGN-348 added GridSecurityProcessor#securityContext(UUID subjId) Squashed commit of the following: commit fd97c238fa2ea9b1a608f17377b47c638c70768b Merge: fc83c39c155 7c357305ad3 Author: Бражников Александр Сергеевич Date: Fri May 15 13:17:27 2020 +0300 Merge branch 'master-se-4.281' of https://sbtatlas.sigma.sbrf.ru/stash/scm/ospt/ignite into IGN-348 commit fc83c39c155cdf6767636b61ef7ae376f99f66c8 Author: sbt-garus-dg Date: Tue Apr 14 10:37:40 2020 +0300 code style commit 094f3b61031b1e0d64451d513acd4cb1f5dc118d Author: sbt-garus-dg Date: Tue Mar 31 16:50:43 2020 +0300 IGN-348 revert commit b8f56bcdef7979e7a3a9f5a2121f98f30a1398e0 Author: sbt-garus-dg Date: Tue Mar 31 16:19:47 2020 +0300 IGN-348 revert commit e162c412ef31cbbeaace0404a956feedbcef1723 Author: sbt-garus-dg Date: Tue Mar 31 16:08:25 2020 +0300 IGN-348 revert commit 1cbccc0fa1693e681c0dfa57c24dbd7d45cd0389 Author: sbt-garus-dg Date: Tue Mar 31 13:41:47 2020 +0300 IGN-348 revert commit 3a8a1a33e66272a9601aff67172b6b25b906e436 Author: sbt-garus-dg Date: Tue Mar 31 13:32:04 2020 +0300 IGN-348 revert commit 73eb5adf585dc9e818915f02fc335359c7cbf2c3 Author: sbt-garus-dg Date: Tue Mar 31 12:00:22 2020 +0300 IGN-348 revert commit c5053268e3c0d37ea63ffd122b308c24c0d77913 Author: sbt-garus-dg Date: Tue Mar 31 11:50:21 2020 +0300 IGN-348 revert commit e583157144bdf552d8c30eba071aeb9357d65de7 Author: sbt-garus-dg Date: Tue Mar 31 11:35:50 2020 +0300 IGN-348 revert commit b7dc6679b791fc162a42b92eed5fc515f36a1e8e Author: sbt-garus-dg Date: Tue Mar 31 11:20:04 2020 +0300 IGN-348 revert commit e2e755d56d7aea4445c65d6574db3f95e08548cd Author: sbt-garus-dg Date: Sun Mar 29 17:29:53 2020 +0300 IGN-348 added GridSecurityProcessor#securityContext(UUID subjId) commit 41577c04a5173a73b4a9ad9e490e5f34a8791c81 Merge: 2be8b1e309b 6824edd1b10 Author: Бражников Александр Сергеевич Date: Thu Mar 19 15:00:05 2020 +0300 Merge pull request #9 in OSPT/ignite from IGN-308 to master-se-3.280 * commit '6824edd1b1044f272512f46737ad46a66895c865': IGNITE-12734 Backport test fix IGNITE-12734 Backport test fix GNITE-12734 Fixed scan query over evicted partition - Fixes #7494. IGNITE-12734 Fixed scan query over evicted partition - Fixes #7494. Delete /.gradle IGNITE-12734 Fixed scan query over evicted partition - Fixes #7494. IGNITE-12734 Fixed scan query over evicted partition - Fixes #7494. commit 6824edd1b1044f272512f46737ad46a66895c865 Author: Aleksey Plekhanov Date: Thu Mar 19 14:28:43 2020 +0300 IGNITE-12734 Backport test fix commit 043034d445ad435835dedd88584fc1e33e6c3bba Author: Aleksey Plekhanov Date: Thu Mar 19 14:26:20 2020 +0300 IGNITE-12734 Backport test fix commit 88ceb9c138f6d8b69a7e9e986e9ec695a1e14afc Author: Aleksandr B Date: Thu Mar 19 13:41:07 2020 +0300 GNITE-12734 Fixed scan query over evicted partition - Fixes #7494. commit bbb71cafb86e11bfafbdc4878e49373b0ccf016d Author: Aleksandr B Date: Thu Mar 19 13:08:51 2020 +0300 IGNITE-12734 Fixed scan query over evicted partition - Fixes #7494. commit fc2b3e2b52784c8023a071d6def087325d808215 Author: Aleksandr B Date: Wed Mar 18 17:50:24 2020 +0300 Delete /.gradle commit 1aa3727eb375ac7284338cdced3d9cfbbb0a993c Author: Aleksey Plekhanov Date: Wed Mar 18 13:12:47 2020 +0300 IGNITE-12734 Fixed scan query over evicted partition - Fixes #7494. commit 4a56a6079eac2eb985e61c73fb50ff22e4e20524 Author: Aleksey Plekhanov Date: Wed Mar 18 13:12:47 2020 +0300 IGNITE-12734 Fixed scan query over evicted partition - Fixes #7494. ... and 11 more commits commit 7c357305ad393288b9b90c46b1b8b47239c03950 Author: Dmitrii Ryabov Date: Mon Feb 10 19:25:55 2020 +0300 IGNITE-12049 Support of user attributes on thin clients. commit 555e3ac7bb585cd5bc6aab7c8c4f085097902b49 Author: sbt-garus-dg Date: Fri May 15 11:26:28 2020 +0300 ign-627 commit 53ad6d785461c34902557c44fb74ec889ebdd276 Merge: 423f70d7ae6 c601f0a50ba Author: sbt-garus-dg Date: Fri May 15 11:07:38 2020 +0300 Merge branch 'master-se-4.281' into IGN-627 # Conflicts: # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PageMemoryImpl.java # modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java # modules/core/src/main/java/org/apache/ignite/internal/processors/security/GridSecurityProcessor.java # modules/core/src/main/java/org/apache/ignite/internal/processors/security/IgniteSecurityProcessor.java # modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsWithTtlDeactivateOnHighloadTest.java # modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/CacheScanQueryFailoverTest.java # modules/core/src/test/java/org/apache/ignite/testsuites/SecurityTestSuite.java ... and 49 more commits IGN-1981 Fix ThinClientSslPermissionCheckTest#testSysOperation Merge in OSPT/ignite from IGN-1981 to master Squashed commit of the following: commit 2e671c9c0a9484ef27d6501dc02a9cd1a45cc004 Author: Shishkov Ilya Date: Mon Nov 9 22:40:45 2020 +0300 IGN-1981 Fix ThinClientSslPermissionCheckTest#testSysOperation --- .../cache/CacheAffinitySharedManager.java | 4 +- .../cache/DynamicCacheChangeBatch.java | 21 ++ .../processors/cache/ExchangeActions.java | 17 ++ .../cache/GridCacheEventManager.java | 7 +- .../processors/cache/GridCacheProcessor.java | 33 ++- .../cluster/ChangeGlobalStateMessage.java | 19 ++ .../cluster/GridClusterStateProcessor.java | 10 + .../processors/security/SecurityUtils.java | 71 ++++++ .../AbstractSecurityCacheEventTest.java | 203 ++++++++++++++++++ ...tivateDeactivateClusterCacheEventTest.java | 94 ++++++++ .../events/CacheCreateDestroyEventsTest.java | 182 ++++++++++++++++ ...hinClientCacheCreateDestroyEventsTest.java | 111 ++++++++++ .../TestCertificateSecurityProcessor.java | 20 +- .../security/impl/TestSecurityProcessor.java | 8 +- .../ignite/testsuites/SecurityTestSuite.java | 9 +- 15 files changed, 794 insertions(+), 15 deletions(-) create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/events/AbstractSecurityCacheEventTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/events/ActivateDeactivateClusterCacheEventTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/events/CacheCreateDestroyEventsTest.java create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/events/ThinClientCacheCreateDestroyEventsTest.java diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java index 199c5e4e7bfde..3c2d93d85873d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java @@ -87,6 +87,7 @@ import static org.apache.ignite.events.EventType.EVT_NODE_JOINED; import static org.apache.ignite.events.EventType.EVT_NODE_LEFT; import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState.OWNING; +import static org.apache.ignite.internal.processors.security.SecurityUtils.withContextIfNeed; import static org.apache.ignite.internal.processors.tracing.SpanType.AFFINITY_CALCULATION; /** @@ -882,7 +883,8 @@ public IgniteInternalFuture onCacheChangeRequest( fut.timeBag().finishGlobalStage("Update caches registry"); - processCacheStartRequests(fut, crd, exchActions); + withContextIfNeed(exchActions.securitySubjectId(), cctx.kernalContext(), + () -> processCacheStartRequests(fut, crd, exchActions)); Set stoppedGrps = processCacheStopRequests(fut, crd, exchActions, false); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeBatch.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeBatch.java index 6b89424462b0d..bd39b11f11574 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeBatch.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeBatch.java @@ -19,6 +19,7 @@ import java.util.Collection; import java.util.Set; +import java.util.UUID; import org.apache.ignite.internal.managers.discovery.DiscoCache; import org.apache.ignite.internal.managers.discovery.DiscoveryCustomMessage; import org.apache.ignite.internal.managers.discovery.GridDiscoveryManager; @@ -58,6 +59,9 @@ public class DynamicCacheChangeBatch implements DiscoveryCustomMessage { @GridToStringExclude @Nullable private transient ServiceDeploymentActions serviceDeploymentActions; + /** Security subject id. */ + private UUID secSubjId; + /** * @param reqs Requests. */ @@ -115,6 +119,8 @@ public ExchangeActions exchangeActions() { void exchangeActions(ExchangeActions exchangeActions) { assert exchangeActions != null && !exchangeActions.empty() : exchangeActions; + exchangeActions.securitySubjectId(securitySubjectId()); + this.exchangeActions = exchangeActions; } @@ -155,6 +161,21 @@ public Set restartingCaches() { return restartingCaches; } + /** + * Sets Security subject id. + * @param id + */ + public void securitySubjectId(UUID id) { + secSubjId = id; + } + + /** + * @return Security subject id. + */ + public UUID securitySubjectId() { + return secSubjId; + } + /** * @param startCaches {@code True} if required to start all caches on client node. */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ExchangeActions.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ExchangeActions.java index 8736a88d53c66..69e3e904d3676 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ExchangeActions.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ExchangeActions.java @@ -62,6 +62,9 @@ public class ExchangeActions { /** */ private StateChangeRequest stateChangeReq; + /** Security subject id. */ + private UUID secSubjId; + /** * @param grpId Group ID. * @return Always {@code true}, fails with assert error if inconsistent. @@ -110,6 +113,20 @@ public Collection cacheStopRequests() { return cachesToStop != null ? cachesToStop.values() : Collections.emptyList(); } + /** + * @return Security subject id. + */ + public UUID securitySubjectId() { + return secSubjId; + } + + /** + * Sets Security subject id. + */ + public void securitySubjectId(UUID secSubjId) { + this.secSubjId = secSubjId; + } + /** * @param ctx Context. * @param err Error if any. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEventManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEventManager.java index e17d4cd16742c..238d7a9094f7e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEventManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEventManager.java @@ -24,6 +24,7 @@ import org.apache.ignite.events.CacheEvent; import org.apache.ignite.internal.managers.eventstorage.GridLocalEventListener; import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx; +import org.apache.ignite.internal.processors.security.IgniteSecurity; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.X; import org.apache.ignite.internal.util.typedef.internal.LT; @@ -144,6 +145,10 @@ public void addEvent(int part, * @param type Event type (start or stop). */ public void addEvent(int type) { + IgniteSecurity security = cctx.kernalContext().security(); + + UUID subjId = security.enabled() ? security.securityContext().subject().id() : null; + addEvent( 0, null, @@ -156,7 +161,7 @@ public void addEvent(int type) { false, null, false, - null, + subjId, null, null, false); 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 5d129f0a6ef3f..b8f087bf909b8 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 @@ -185,6 +185,7 @@ import org.apache.ignite.mxbean.IgniteMBeanAware; 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.apache.ignite.spi.discovery.DiscoveryDataBag.GridDiscoveryData; @@ -220,6 +221,7 @@ import static org.apache.ignite.internal.processors.cache.GridCacheUtils.isPersistentCache; import static org.apache.ignite.internal.processors.cache.ValidationOnNodeJoinUtils.validateHashIdResolvers; import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition.DFLT_CACHE_REMOVE_ENTRIES_TTL; +import static org.apache.ignite.internal.processors.security.SecurityUtils.withContextIfNeed; import static org.apache.ignite.internal.util.IgniteUtils.doInParallel; /** @@ -1762,7 +1764,7 @@ public Collection startReceivedCaches(UUID nodeId, Affin .map(desc -> new StartCacheInfo(desc, null, exchTopVer, false)) .collect(toList()); - prepareStartCaches(startCacheInfos); + withContextIfNeed(nodeId, ctx, () -> prepareStartCaches(startCacheInfos)); return receivedCaches; } @@ -1825,6 +1827,8 @@ private void prepareStartCaches( Collection startCacheInfos, StartCacheFailHandler cacheStartFailHandler ) throws IgniteCheckedException { + final UUID secSubjId = ctx.security().enabled() ? ctx.security().securityContext().subject().id() : null; + if (!IGNITE_ALLOW_START_CACHES_IN_PARALLEL || startCacheInfos.size() <= 1) { for (StartCacheInfo startCacheInfo : startCacheInfos) { cacheStartFailHandler.handle( @@ -1859,12 +1863,12 @@ private void prepareStartCaches( cacheStartFailHandler.handle( startCacheInfo, cacheInfo -> { - GridCacheContext cacheCtx = prepareCacheContext( + GridCacheContext cacheCtx = withContextIfNeed(secSubjId, ctx, () -> prepareCacheContext( cacheInfo.getCacheDescriptor(), cacheInfo.getReqNearCfg(), cacheInfo.getExchangeTopVer(), cacheInfo.isDisabledAfterStart() - ); + )); cacheContexts.put(cacheInfo, cacheCtx); context().exchange().exchangerUpdateHeartbeat(); @@ -1926,7 +1930,7 @@ private void prepareStartCaches( if (cacheContext.isRecoveryMode()) finishRecovery(cacheInfo.getExchangeTopVer(), cacheContext); else - onCacheStarted(cacheCtxEntry.getValue()); + withContextIfNeed(secSubjId, ctx, () -> onCacheStarted(cacheCtxEntry.getValue())); context().exchange().exchangerUpdateHeartbeat(); @@ -2812,10 +2816,13 @@ private void processCacheStopRequestOnExchangeDone(ExchangeActions exchActions) try { boolean destroyCache = action.request().destroy(); - prepareCacheStop(cacheName, destroyCache); + withContextIfNeed(exchActions.securitySubjectId(), ctx, + () -> { + prepareCacheStop(cacheName, destroyCache); - if (destroyCache || grpIdToDestroy.contains(cachesToStopByGrp.getKey())) - ctx.query().completeRebuildIndexes(cacheName); + if (destroyCache || grpIdToDestroy.contains(cachesToStopByGrp.getKey())) + ctx.query().completeRebuildIndexes(cacheName); + }); } finally { sharedCtx.database().checkpointReadUnlock(); @@ -4108,7 +4115,17 @@ private Collection initiateCacheChanges( if (!sndReqs.isEmpty()) { try { - ctx.discovery().sendCustomEvent(new DynamicCacheChangeBatch(sndReqs)); + DynamicCacheChangeBatch batch = new DynamicCacheChangeBatch(sndReqs); + + IgniteSecurity security = ctx.security(); + + if (security.enabled()) { + SecuritySubject subj = security.securityContext().subject(); + + batch.securitySubjectId(subj.id()); + } + + ctx.discovery().sendCustomEvent(batch); err = checkNodeState(); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/ChangeGlobalStateMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/ChangeGlobalStateMessage.java index 19049695dcf1a..b238e0eddc892 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/ChangeGlobalStateMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/ChangeGlobalStateMessage.java @@ -51,6 +51,9 @@ public class ChangeGlobalStateMessage implements DiscoveryCustomMessage { /** Cluster state */ private ClusterState state; + /** Security subject id. */ + private UUID secSubjId; + /** Configurations read from persistent store. */ private List storedCfgs; @@ -114,6 +117,20 @@ public ChangeGlobalStateMessage( return storedCfgs; } + /** + * @return Security subject id. + */ + public UUID securitySubjectId() { + return secSubjId; + } + + /** + * Sets security subject id. + */ + public void securitySubjectId(UUID secSubjId) { + this.secSubjId = secSubjId; + } + /** * @return Cache updates to be executed on exchange. If {@code null} exchange is not needed. */ @@ -127,6 +144,8 @@ public ChangeGlobalStateMessage( void exchangeActions(ExchangeActions exchangeActions) { assert exchangeActions != null && !exchangeActions.empty() : exchangeActions; + exchangeActions.securitySubjectId(securitySubjectId()); + this.exchangeActions = exchangeActions; } 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 f99555fd1ed7e..a99dc9ae89025 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 @@ -73,6 +73,7 @@ import org.apache.ignite.internal.processors.cluster.baseline.autoadjust.BaselineAutoAdjustStatus; import org.apache.ignite.internal.processors.cluster.baseline.autoadjust.BaselineTopologyUpdater; import org.apache.ignite.internal.processors.configuration.distributed.DistributePropertyListener; +import org.apache.ignite.internal.processors.security.IgniteSecurity; import org.apache.ignite.internal.processors.service.GridServiceProcessor; import org.apache.ignite.internal.util.future.GridFinishedFuture; import org.apache.ignite.internal.util.future.GridFutureAdapter; @@ -93,6 +94,7 @@ import org.apache.ignite.lang.IgniteProductVersion; import org.apache.ignite.lang.IgniteUuid; import org.apache.ignite.marshaller.jdk.JdkMarshaller; +import org.apache.ignite.plugin.security.SecuritySubject; import org.apache.ignite.spi.IgniteNodeValidationResult; import org.apache.ignite.spi.discovery.DiscoveryDataBag; import org.apache.ignite.spi.systemview.view.BaselineNodeAttributeView; @@ -1192,6 +1194,14 @@ public IgniteInternalFuture changeGlobalState( System.currentTimeMillis() ); + IgniteSecurity security = ctx.security(); + + if (security.enabled()) { + SecuritySubject subj = security.securityContext().subject(); + + msg.securitySubjectId(subj.id()); + } + IgniteInternalFuture resFut = wrapStateChangeFuture(startedFut, msg); try { 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 10970a633a6ba..23dd57f8d8e18 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 @@ -35,6 +35,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; +import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -285,4 +286,74 @@ public SandboxInvocationHandler(IgniteSandbox sandbox, Object original) { }); } } + + /** + * Runs passed {@code runnable} with the security context associated + * with passed {@code secSubjId} if security is enabled. + * + * @param secSubjId Security subject id. + * @param ctx Grid kernal context. + * @param r Runnable. + */ + public static void withContextIfNeed(UUID secSubjId, GridKernalContext ctx, RunnableX r) + throws IgniteCheckedException { + withContextIfNeed(secSubjId, ctx, () -> { + r.run(); + + return null; + }); + } + + /** + * Calls passed {@code callable} with the security context associated + * with passed {@code secSubjId} if security is enabled. + * + * @param secSubjId Security subject id. + * @param ctx Grid kernal context. + * @param c Callable. + * @return Result of passed callable. + */ + public static T withContextIfNeed(UUID secSubjId, GridKernalContext ctx, Callable c) + throws IgniteCheckedException { + IgniteSecurity security = ctx.security(); + + try { + if (security.enabled() && secSubjId != null) { + try (OperationSecurityContext s = security.withContext(secSubjId)) { + return c.call(); + } + } + + return c.call(); + } + catch (Exception e) { + if (e instanceof IgniteCheckedException) + throw (IgniteCheckedException)e; + + throw new IgniteCheckedException(e); + } + } + + /** + * Runnable that can throw exceptions. + */ + @FunctionalInterface + public static 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); + } + } + } } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/events/AbstractSecurityCacheEventTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/events/AbstractSecurityCacheEventTest.java new file mode 100644 index 0000000000000..37ac3b69f400b --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/events/AbstractSecurityCacheEventTest.java @@ -0,0 +1,203 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.processors.security.events; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import com.google.common.collect.Iterators; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.IgniteException; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.events.CacheEvent; +import org.apache.ignite.events.Event; +import org.apache.ignite.events.EventType; +import org.apache.ignite.internal.IgnitionEx; +import org.apache.ignite.internal.processors.security.AbstractSecurityTest; +import org.apache.ignite.lang.IgniteBiPredicate; +import org.apache.ignite.lang.IgnitePredicate; +import org.apache.ignite.plugin.security.SecuritySubject; + +import static org.apache.ignite.events.EventType.EVT_CACHE_STOPPED; + +/** + * Abstract class to test correctness of {@link CacheEvent#subjectId}. + */ +@SuppressWarnings("rawtypes") +public abstract class AbstractSecurityCacheEventTest extends AbstractSecurityTest { + /** Counter. */ + protected static final AtomicInteger COUNTER = new AtomicInteger(); + + /** Node that registers event listeners. */ + private static final String LISTENER_NODE = "listener_node"; + + /** Events latch. */ + private static volatile CountDownLatch evtsLatch; + + /** Logins in remote filters. */ + private static final Collection rmtLogins = new ConcurrentLinkedQueue<>(); + + /** Logins in a local listener. */ + private static final Collection locLogins = new ConcurrentLinkedQueue<>(); + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + super.beforeTestsStarted(); + + startGridAllowAll(LISTENER_NODE); + } + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + return super.getConfiguration(igniteInstanceName).setIncludeEventTypes(EventType.EVTS_CACHE_LIFECYCLE); + } + + /** */ + protected void testCacheEvents(int expTimes, String expLogin, int evtType, Collection ccfgs, + Consumer> op) throws Exception { + // For the EVT_CACHE_STOPPED event count of local listener should be 1 due to IGNITE-13010. + evtsLatch = new CountDownLatch(expTimes + (evtType == EVT_CACHE_STOPPED ? 1 : expTimes)); + + rmtLogins.clear(); + locLogins.clear(); + + UUID lsnrId = grid(LISTENER_NODE) + .events() + .remoteListen( + new TestPredicate(ccfgs) { + @Override void register(String login) { + locLogins.add(login); + } + }, + new TestPredicate(ccfgs) { + @Override void register(String login) { + rmtLogins.add(login); + } + }, evtType); + + try { + // Execute tested operation. + op.accept(ccfgs); + + // Waiting for events. + evtsLatch.await(10, TimeUnit.SECONDS); + + // Check results. + checkResult(expLogin, rmtLogins, expTimes, "Remote filter."); + // For the EVT_CACHE_STOPPED event expected times of calling local listener should be 0 (ignored) + // due to IGNITE-13010. + checkResult(expLogin, locLogins, evtType == EVT_CACHE_STOPPED ? 0 : expTimes, "Local listener."); + } + finally { + grid(LISTENER_NODE).events().stopRemoteListen(lsnrId); + } + } + + /** */ + private void checkResult(String expLogin, Collection logins, int expTimes, String msgPrefix) { + Set set = new HashSet<>(logins); + + if (set.size() != 1) { + fail(msgPrefix + " Expected subject: " + expLogin + + ". Actual subjects: " + Iterators.toString(set.iterator())); + } + else + assertEquals(msgPrefix, expLogin, logins.iterator().next()); + + if (expTimes > 0) + assertEquals(msgPrefix, expTimes, logins.size()); + } + + /** */ + protected Collection cacheConfigurations(int num, boolean needCreateCaches) { + Collection res; + + if (num == 1) + res = Collections.singletonList(new CacheConfiguration("test_cache_" + COUNTER.incrementAndGet())); + else { + res = new ArrayList<>(num); + + for (int i = 0; i < num; i++) + res.add(new CacheConfiguration("test_cache_" + COUNTER.incrementAndGet())); + } + + if (needCreateCaches) + res.forEach(c -> grid(LISTENER_NODE).createCache(c.getName())); + + return res; + } + + /** + * Remote filter or local listener predicate. + */ + private abstract static class TestPredicate implements IgniteBiPredicate, IgnitePredicate { + /** Expected cache names. */ + private final Set cacheNames; + + /** */ + private TestPredicate(Collection ccfgs) { + cacheNames = ccfgs.stream().map(CacheConfiguration::getName).collect(Collectors.toSet()); + } + + /** */ + private void body(Event evt) { + try { + CacheEvent cacheEvt = (CacheEvent)evt; + + if (cacheNames.contains(cacheEvt.cacheName())) { + SecuritySubject subj = IgnitionEx.localIgnite().context().security() + .authenticatedSubject(cacheEvt.subjectId()); + + evtsLatch.countDown(); + + register(subj.login().toString()); + } + } + catch (IgniteCheckedException e) { + throw new IgniteException(e); + } + } + + /** */ + abstract void register(String login); + + /** {@inheritDoc} */ + @Override public boolean apply(UUID uuid, Event evt) { + body(evt); + + return true; + } + + /** {@inheritDoc} */ + @Override public boolean apply(Event evt) { + body(evt); + + return true; + } + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/events/ActivateDeactivateClusterCacheEventTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/events/ActivateDeactivateClusterCacheEventTest.java new file mode 100644 index 0000000000000..a99bf081e4d4a --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/events/ActivateDeactivateClusterCacheEventTest.java @@ -0,0 +1,94 @@ +/* + * 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.events; + +import java.util.Arrays; +import java.util.Collection; +import org.apache.ignite.configuration.CacheConfiguration; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import static org.apache.ignite.events.EventType.EVT_CACHE_STARTED; +import static org.apache.ignite.events.EventType.EVT_CACHE_STOPPED; + +/** + * Test that an event's local listener and an event's remote filter get correct subjectId when + * a server (client) node activates/deactivates the cluster. + */ +@RunWith(Parameterized.class) +@SuppressWarnings({"rawtypes"}) +public class ActivateDeactivateClusterCacheEventTest extends AbstractSecurityCacheEventTest { + /** Server. */ + private static final String SRV = "server"; + + /** Client. */ + private static final String CLNT = "client"; + + /** Parameters. */ + @Parameterized.Parameters(name = "node={0}") + public static Iterable data() { + return Arrays.asList(new String[] {SRV}, new String[] {CLNT}); + } + + /** Initiate node name. */ + @Parameterized.Parameter + public String node; + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + super.beforeTestsStarted(); + + startClientAllowAll(CLNT); + + startGridAllowAll(SRV).cluster().active(true); + } + + /** */ + @Test + public void testActivateCluster() throws Exception { + clusterShouldBeActive(); + + Collection configurations = cacheConfigurations(2, false); + + configurations.forEach(c -> grid(CLNT).createCache(c.getName())); + + grid(SRV).cluster().active(false); + + testCacheEvents(6, node, EVT_CACHE_STARTED, configurations, + ccfgs -> grid(node).cluster().active(true)); + } + + /** */ + @Test + public void testDeactivateCluster() throws Exception { + clusterShouldBeActive(); + + testCacheEvents(6, node, EVT_CACHE_STOPPED, cacheConfigurations(2, true), ccfgs -> { + ccfgs.forEach(c -> grid(CLNT).cache(c.getName())); + + grid(node).cluster().active(false); + }); + } + + /** */ + private void clusterShouldBeActive() { + if (!grid(SRV).cluster().active()) + grid(SRV).cluster().active(true); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/events/CacheCreateDestroyEventsTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/events/CacheCreateDestroyEventsTest.java new file mode 100644 index 0000000000000..fc8c479ebfbc5 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/events/CacheCreateDestroyEventsTest.java @@ -0,0 +1,182 @@ +/* + * 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.events; + +import java.util.stream.Collectors; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.internal.processors.security.impl.TestSecurityPluginProvider; +import org.junit.Test; + +import static org.apache.ignite.events.EventType.EVT_CACHE_STARTED; +import static org.apache.ignite.events.EventType.EVT_CACHE_STOPPED; +import static org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.ALLOW_ALL; + +/** + * Test that an event's local listener and an event's remote filter get correct subjectId + * when a server (client) node create or destroy a cache. + */ +@SuppressWarnings({"rawtypes", "unchecked", "ZeroLengthArrayAllocation"}) +public class CacheCreateDestroyEventsTest extends AbstractSecurityCacheEventTest { + /** Client node. */ + private static final String CLNT = "client"; + + /** Server node. */ + private static final String SRV = "server"; + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + super.beforeTestsStarted(); + + startGridAllowAll(SRV); + + startClientAllowAll(CLNT).cluster().active(true); + } + + /** */ + @Test + public void testCreateCacheSrvEvt() throws Exception { + testDynamicCreateDestroyCache(2, SRV, EVT_CACHE_STARTED); + } + + /** */ + @Test + public void testCreateCacheClntEvt() throws Exception { + testDynamicCreateDestroyCache(3, CLNT, EVT_CACHE_STARTED); + } + + /** */ + @Test + public void testGetOrCreateCacheSrvEvt() throws Exception { + testDynamicCreateDestroyCache(2, SRV, EVT_CACHE_STARTED, true); + } + + /** */ + @Test + public void testGetOrCreateCacheClntEvt() throws Exception { + testDynamicCreateDestroyCache(3, CLNT, EVT_CACHE_STARTED, true); + } + + /** */ + @Test + public void testCreateBatchCachesSrvEvt() throws Exception { + testDynamicCreateDestroyCacheBatch(4, SRV, EVT_CACHE_STARTED); + } + + /** */ + @Test + public void testCreateBatchCachesClntEvt() throws Exception { + testDynamicCreateDestroyCacheBatch(6, CLNT, EVT_CACHE_STARTED); + } + + /** */ + @Test + public void testDestroyCacheSrvEvt() throws Exception { + testDynamicCreateDestroyCache(2, SRV, EVT_CACHE_STOPPED); + } + + /** */ + @Test + public void testDestroyCacheClntEvt() throws Exception { + testDynamicCreateDestroyCache(2, CLNT, EVT_CACHE_STOPPED); + } + + /** */ + @Test + public void testDestroyBatchCachesSrvEvt() throws Exception { + testDynamicCreateDestroyCacheBatch(4, SRV, EVT_CACHE_STOPPED); + } + + /** */ + @Test + public void testDestroyBatchCachesClntEvt() throws Exception { + testDynamicCreateDestroyCacheBatch(4, CLNT, EVT_CACHE_STOPPED); + } + + /** */ + @Test + public void testCreateCacheOnNodeJoinAsServer() throws Exception { + testCreateCacheOnNodeJoin(false); + } + + /** */ + @Test + public void testCreateCacheOnNodeJoinAsClient() throws Exception { + testCreateCacheOnNodeJoin(true); + } + + /** */ + private void testCreateCacheOnNodeJoin(boolean isClient) throws Exception { + final String login = "new_node_" + COUNTER.incrementAndGet(); + + try { + testCacheEvents(6, login, EVT_CACHE_STARTED, cacheConfigurations(2, false), + ccfgs -> { + try { + startGrid( + getConfiguration(login, + new TestSecurityPluginProvider(login, "", ALLOW_ALL, globalAuth)) + .setClientMode(isClient) + .setCacheConfiguration(ccfgs.toArray(new CacheConfiguration[] {})) + ); + } + catch (Exception e) { + throw new RuntimeException(e); + } + }); + } + finally { + stopGrid(login); + } + } + + /** */ + private void testDynamicCreateDestroyCacheBatch(int expTimes, String evtNode, int evtType) throws Exception { + testCacheEvents(expTimes, evtNode, evtType, cacheConfigurations(2, evtType == EVT_CACHE_STOPPED), + ccfgs -> { + if (evtType == EVT_CACHE_STARTED) + grid(evtNode).createCaches(ccfgs); + else { + grid(evtNode).destroyCaches(ccfgs.stream().map(CacheConfiguration::getName) + .collect(Collectors.toSet())); + } + }); + } + + /** */ + private void testDynamicCreateDestroyCache(int expTimes, String evtNode, int evtType) throws Exception { + testDynamicCreateDestroyCache(expTimes, evtNode, evtType, false); + } + + /** */ + private void testDynamicCreateDestroyCache(int expTimes, String evtNode, int evtType, boolean isGetOrCreate) + throws Exception { + testCacheEvents(expTimes, evtNode, evtType, cacheConfigurations(1, evtType == EVT_CACHE_STOPPED), + ccfgs -> { + CacheConfiguration cfg = ccfgs.stream().findFirst().orElseThrow(IllegalStateException::new); + + if (evtType == EVT_CACHE_STARTED) { + if (isGetOrCreate) + grid(evtNode).getOrCreateCache(cfg); + else + grid(evtNode).createCache(cfg); + } + else + grid(evtNode).destroyCache(cfg.getName()); + }); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/events/ThinClientCacheCreateDestroyEventsTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/events/ThinClientCacheCreateDestroyEventsTest.java new file mode 100644 index 0000000000000..f4cb31cdd5eea --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/events/ThinClientCacheCreateDestroyEventsTest.java @@ -0,0 +1,111 @@ +/* + * 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.events; + +import java.util.Collection; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import org.apache.ignite.Ignition; +import org.apache.ignite.client.ClientCacheConfiguration; +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.internal.processors.security.impl.TestSecurityData; +import org.apache.ignite.internal.processors.security.impl.TestSecurityPluginProvider; +import org.apache.ignite.plugin.security.SecurityPermissionSetBuilder; +import org.junit.Test; + +import static org.apache.ignite.events.EventType.EVT_CACHE_STARTED; +import static org.apache.ignite.events.EventType.EVT_CACHE_STOPPED; +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.SecurityPermissionSetBuilder.ALLOW_ALL; + +/** + * Test that an event's local listener and an event's remote filter get correct subjectId when + * a thin client create or destroy a cache. + */ +@SuppressWarnings("rawtypes") +public class ThinClientCacheCreateDestroyEventsTest extends AbstractSecurityCacheEventTest { + /** Client. */ + private static final String CLIENT = "client"; + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + super.beforeTestsStarted(); + + startGrid(getConfiguration("srv", new TestSecurityPluginProvider("srv", null, ALLOW_ALL, false, + new TestSecurityData(CLIENT, + SecurityPermissionSetBuilder.create().defaultAllowAll(false) + .appendSystemPermissions(CACHE_CREATE, CACHE_DESTROY) + .build())) + )).cluster().active(true); + } + + /** */ + @Test + public void testCreateCacheEvent() throws Exception { + testCacheEvents(EVT_CACHE_STARTED, operation(IgniteClient::createCache)); + } + + /** */ + @Test + public void testGetOrCreateCacheEvent() throws Exception { + testCacheEvents(EVT_CACHE_STARTED, operation(IgniteClient::getOrCreateCache)); + } + + /** */ + @Test + public void testDestroyCacheEvent() throws Exception { + testCacheEvents(EVT_CACHE_STOPPED, operation((clnt, cfg) -> clnt.destroyCache(cfg.getName()))); + } + + /** */ + private void testCacheEvents(int evtType, Consumer> op) throws Exception { + testCacheEvents(2, CLIENT, evtType, + cacheConfigurations(1, evtType == EVT_CACHE_STOPPED), op); + } + + /** */ + private Consumer> operation(BiConsumer c) { + return ccfgs -> { + try (IgniteClient clnt = startClient()) { + ClientCacheConfiguration ccfg = ccfgs.stream().findFirst() + .map(cfg -> new ClientCacheConfiguration().setName(cfg.getName())) + .orElseThrow(IllegalStateException::new); + + c.accept(clnt, ccfg); + } + catch (Exception e) { + throw new RuntimeException(e); + } + }; + } + + /** + * @return Thin client for specified user. + */ + private IgniteClient startClient() { + return Ignition.startClient( + new ClientConfiguration().setAddresses(Config.SERVER) + .setUserName(CLIENT) + .setUserPassword("") + ); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestCertificateSecurityProcessor.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestCertificateSecurityProcessor.java index a59f64417fb9d..f9e0aa0c17cf7 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestCertificateSecurityProcessor.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/impl/TestCertificateSecurityProcessor.java @@ -54,6 +54,9 @@ public class TestCertificateSecurityProcessor extends GridProcessorAdapter imple /** Permissions. */ public static final Map PERMS = new ConcurrentHashMap<>(); + /** */ + private static final Map SECURITY_CONTEXTS = new ConcurrentHashMap<>(); + /** Users security data. */ private final Collection predefinedAuthData; @@ -70,7 +73,7 @@ public TestCertificateSecurityProcessor(GridKernalContext ctx, Collection Date: Tue, 2 Feb 2021 13:00:32 +0300 Subject: [PATCH 03/15] IGNITE-14071 .NET: RegisterSameJavaType mode enabled for messaging --- .../platform/PlatformDeployServiceTask.java | 100 +++++++++++++++--- .../org/apache/ignite/platform/model/V5.java | 34 ++++++ .../org/apache/ignite/platform/model/V6.java | 34 ++++++ .../org/apache/ignite/platform/model/V7.java | 34 ++++++ .../org/apache/ignite/platform/model/V8.java | 34 ++++++ .../Services/IJavaService.cs | 9 ++ .../Services/JavaServiceDynamicProxy.cs | 18 ++++ .../Services/Model.cs | 20 ++++ .../Services/PlatformTestService.cs | 18 ++++ .../Services/ServicesTypeAutoResolveTest.cs | 55 ++++++++++ .../Impl/Messaging/Messaging.cs | 53 ++++++++-- 11 files changed, 385 insertions(+), 24 deletions(-) create mode 100644 modules/core/src/test/java/org/apache/ignite/platform/model/V5.java create mode 100644 modules/core/src/test/java/org/apache/ignite/platform/model/V6.java create mode 100644 modules/core/src/test/java/org/apache/ignite/platform/model/V7.java create mode 100644 modules/core/src/test/java/org/apache/ignite/platform/model/V8.java diff --git a/modules/core/src/test/java/org/apache/ignite/platform/PlatformDeployServiceTask.java b/modules/core/src/test/java/org/apache/ignite/platform/PlatformDeployServiceTask.java index 449de1229659c..363e335c0fe3a 100644 --- a/modules/core/src/test/java/org/apache/ignite/platform/PlatformDeployServiceTask.java +++ b/modules/core/src/test/java/org/apache/ignite/platform/PlatformDeployServiceTask.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; import org.apache.ignite.IgniteException; @@ -39,6 +40,7 @@ import org.apache.ignite.compute.ComputeJobAdapter; import org.apache.ignite.compute.ComputeJobResult; import org.apache.ignite.compute.ComputeTaskAdapter; +import org.apache.ignite.internal.IgniteInterruptedCheckedException; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.platform.model.ACL; @@ -50,10 +52,15 @@ import org.apache.ignite.platform.model.Parameter; import org.apache.ignite.platform.model.Role; import org.apache.ignite.platform.model.User; +import org.apache.ignite.platform.model.V5; +import org.apache.ignite.platform.model.V6; +import org.apache.ignite.platform.model.V7; +import org.apache.ignite.platform.model.V8; import org.apache.ignite.platform.model.Value; import org.apache.ignite.resources.IgniteInstanceResource; import org.apache.ignite.services.Service; import org.apache.ignite.services.ServiceContext; +import org.apache.ignite.testframework.GridTestUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -467,26 +474,26 @@ public int testOverload(Integer count, Employee[] emps) { /** */ public int testOverload(int count, Parameter[] params) { - assertNotNull(params); - assertEquals(count, params.length); + assert params != null; + assert count == params.length; - assertEquals(1, params[0].getId()); - assertEquals(2, params[0].getValues().length); + assert 1 == params[0].getId(); + assert 2 == params[0].getValues().length; - assertEquals(1, params[0].getValues()[0].getId()); - assertEquals(42, params[0].getValues()[0].getVal()); + assert 1 == params[0].getValues()[0].getId(); + assert 42 == params[0].getValues()[0].getVal(); - assertEquals(2, params[0].getValues()[1].getId()); - assertEquals(43, params[0].getValues()[1].getVal()); + assert 2 == params[0].getValues()[1].getId(); + assert 43 == params[0].getValues()[1].getVal(); - assertEquals(2, params[1].getId()); - assertEquals(2, params[1].getValues().length); + assert 2 == params[1].getId(); + assert 2 == params[1].getValues().length; - assertEquals(3, params[1].getValues()[0].getId()); - assertEquals(44, params[1].getValues()[0].getVal()); + assert 3 == params[1].getValues()[0].getId(); + assert 44 == params[1].getValues()[0].getVal(); - assertEquals(4, params[1].getValues()[1].getId()); - assertEquals(45, params[1].getValues()[1].getVal()); + assert 4 == params[1].getValues()[1].getId(); + assert 45 == params[1].getValues()[1].getVal(); return 43; } @@ -621,6 +628,71 @@ public void testLocalDateFromCache() { cache.put(8, ts2); } + /** */ + private final AtomicInteger cntMsgs = new AtomicInteger(0); + + /** */ + public void startReceiveMessage() { + ignite.message().localListen("test-topic-2", (node, obj) -> { + assert obj instanceof BinaryObject; + + V6 v6 = ((BinaryObject)obj).deserialize(); + + assert "Sarah Connor".equals(v6.getName()) || + "John Connor".equals(v6.getName()) || + "Kyle Reese".equals(v6.getName()); + + cntMsgs.incrementAndGet(); + + return true; + }); + + ignite.message().localListen("test-topic-3", (node, obj) -> { + assert obj instanceof BinaryObject; + + V7 v7 = ((BinaryObject)obj).deserialize(); + + assert "V7-1".equals(v7.getName()) || + "V7-2".equals(v7.getName()) || + "V7-3".equals(v7.getName()); + + cntMsgs.incrementAndGet(); + + return true; + }); + + ignite.message().localListen("test-topic-4", (node, obj) -> { + assert obj instanceof BinaryObject; + + V8 v8 = ((BinaryObject)obj).deserialize(); + + assert "V8".equals(v8.getName()) || + "V9".equals(v8.getName()) || + "V10".equals(v8.getName()); + + cntMsgs.incrementAndGet(); + + return true; + }); + } + + /** */ + public boolean testMessagesReceived() { + try { + return GridTestUtils.waitForCondition(() -> cntMsgs.get() == 9, 1_000 * 5); + } + catch (IgniteInterruptedCheckedException e) { + return false; + } + } + + /** */ + public void testSendMessage() { + ignite.message().sendOrdered("test-topic", new V5("1"), 1_000 * 5); + ignite.message().sendOrdered("test-topic", new V5("2"), 1_000 * 5); + ignite.message().sendOrdered("test-topic", new V5("3"), 1_000 * 5); + } + /** */ public void testException(String exCls) throws Exception { switch (exCls) { diff --git a/modules/core/src/test/java/org/apache/ignite/platform/model/V5.java b/modules/core/src/test/java/org/apache/ignite/platform/model/V5.java new file mode 100644 index 0000000000000..4cb788671126c --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/model/V5.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.platform.model; + +/** Test V5 object. */ +public class V5 { + /** */ + private final String name; + + /** */ + public V5(String name) { + this.name = name; + } + + /** */ + public String getName() { + return name; + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/platform/model/V6.java b/modules/core/src/test/java/org/apache/ignite/platform/model/V6.java new file mode 100644 index 0000000000000..08c670c3f68e9 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/model/V6.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.platform.model; + +/** Test V6 object. */ +public class V6 { + /** */ + private final String name; + + /** */ + public V6(String name) { + this.name = name; + } + + /** */ + public String getName() { + return name; + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/platform/model/V7.java b/modules/core/src/test/java/org/apache/ignite/platform/model/V7.java new file mode 100644 index 0000000000000..8b32beca3bb8e --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/model/V7.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.platform.model; + +/** Test V7 object. */ +public class V7 { + /** */ + private final String name; + + /** */ + public V7(String name) { + this.name = name; + } + + /** */ + public String getName() { + return name; + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/platform/model/V8.java b/modules/core/src/test/java/org/apache/ignite/platform/model/V8.java new file mode 100644 index 0000000000000..d4fde95831fc8 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/model/V8.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.platform.model; + +/** Test V8 object. */ +public class V8 { + /** */ + private final String name; + + /** */ + public V8(String name) { + this.name = name; + } + + /** */ + public String getName() { + return name; + } +} diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/IJavaService.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/IJavaService.cs index fe714c17d73a6..5c4ea13038fa7 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/IJavaService.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/IJavaService.cs @@ -209,5 +209,14 @@ public interface IJavaService /** */ void sleep(long delayMs); + + /** */ + void startReceiveMessage(); + + /** */ + bool testMessagesReceived(); + + /** */ + void testSendMessage(); } } diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/JavaServiceDynamicProxy.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/JavaServiceDynamicProxy.cs index e5840e0b16c80..9ce5b631e0faf 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/JavaServiceDynamicProxy.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/JavaServiceDynamicProxy.cs @@ -394,5 +394,23 @@ public void sleep(long delayMs) { _svc.sleep(delayMs); } + + /** */ + public void startReceiveMessage() + { + _svc.startReceiveMessage(); + } + + /** */ + public bool testMessagesReceived() + { + return _svc.testMessagesReceived(); + } + + /** */ + public void testSendMessage() + { + _svc.testSendMessage(); + } } } diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/Model.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/Model.cs index 9c1a9feb307e6..6210fd2be4017 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/Model.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/Model.cs @@ -189,4 +189,24 @@ public class V3 { public String Name { get; set; } } /// A class is a clone of Java class V4 with the same namespace. /// public class V4 { public String Name { get; set; } } + + ///

+ /// A class is a clone of Java class V5 with the same namespace. + /// + public class V5 { public String Name { get; set; } } + + /// + /// A class is a clone of Java class V6 with the same namespace. + /// + public class V6 { public String Name { get; set; } } + + /// + /// A class is a clone of Java class V6 with the same namespace. + /// + public class V7 { public String Name { get; set; } } + + /// + /// A class is a clone of Java class V6 with the same namespace. + /// + public class V8 { public String Name { get; set; } } } diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/PlatformTestService.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/PlatformTestService.cs index 1ed48fec5fa45..5a579b21c49d0 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/PlatformTestService.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/PlatformTestService.cs @@ -617,5 +617,23 @@ public void sleep(long delayMs) { throw new NotImplementedException(); } + + /** */ + public void startReceiveMessage() + { + throw new NotImplementedException(); + } + + /** */ + public bool testMessagesReceived() + { + throw new NotImplementedException(); + } + + /** */ + public void testSendMessage() + { + throw new NotImplementedException(); + } } } diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTypeAutoResolveTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTypeAutoResolveTest.cs index 09ce3c574e300..acf707f03e1a3 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTypeAutoResolveTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTypeAutoResolveTest.cs @@ -244,6 +244,61 @@ private static void DoTestService(IJavaService svc) Assert.AreEqual("user", users[1].Role.Name); } + /// + /// Tests Java service invocation. + /// Types should be resolved implicitly. + /// + [Test] + public void TestMessagingJavaService() + { + // Deploy Java service. + var javaSvcName = TestUtils.DeployJavaService(_grid1); + + var svc = _grid1.GetServices().GetServiceProxy(javaSvcName, true); + + var msgng = _grid1.GetMessaging(); + + var rcvd = new List(); + + var lsnr = new MessageListener((guid, v) => + { + rcvd.Add(v); + + return true; + }); + + msgng.LocalListen(lsnr, "test-topic"); + + svc.testSendMessage(); + + TestUtils.WaitForTrueCondition(() => rcvd.Count == 3, timeout: 2500); + + Assert.IsNotNull(rcvd.Find(v => v.Name == "1")); + Assert.IsNotNull(rcvd.Find(v => v.Name == "2")); + Assert.IsNotNull(rcvd.Find(v => v.Name == "3")); + + msgng.StopLocalListen(lsnr, "test-topic"); + + svc.startReceiveMessage(); + + msgng.Send(new V6 {Name = "Sarah Connor"}, "test-topic-2"); + msgng.Send(new V6 {Name = "John Connor"}, "test-topic-2"); + msgng.Send(new V6 {Name = "Kyle Reese"}, "test-topic-2"); + + msgng.SendAll(new[] + { + new V7 {Name = "V7-1"}, + new V7 {Name = "V7-2"}, + new V7 {Name = "V7-3"} + }, "test-topic-3"); + + msgng.SendOrdered(new V8 {Name = "V8"}, "test-topic-4"); + msgng.SendOrdered(new V8 {Name = "V9"}, "test-topic-4"); + msgng.SendOrdered(new V8 {Name = "V10"}, "test-topic-4"); + + Assert.IsTrue(svc.testMessagesReceived()); + } + /// /// Starts the grids. /// diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Messaging/Messaging.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Messaging/Messaging.cs index e17bcbfaeda0a..51b8e796031c3 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Messaging/Messaging.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Messaging/Messaging.cs @@ -87,8 +87,19 @@ public IClusterGroup ClusterGroup public void Send(object message, object topic = null) { IgniteArgumentCheck.NotNull(message, "message"); + + bool locRegisterSameJavaType = Marshaller.RegisterSameJavaTypeTl.Value; - DoOutOp((int) Op.Send, topic, message); + Marshaller.RegisterSameJavaTypeTl.Value = true; + + try + { + DoOutOp((int) Op.Send, topic, message); + } + finally + { + Marshaller.RegisterSameJavaTypeTl.Value = locRegisterSameJavaType; + } } /** */ @@ -96,12 +107,23 @@ public void SendAll(IEnumerable messages, object topic = null) { IgniteArgumentCheck.NotNull(messages, "messages"); - DoOutOp((int) Op.SendMulti, writer => + bool locRegisterSameJavaType = Marshaller.RegisterSameJavaTypeTl.Value; + + Marshaller.RegisterSameJavaTypeTl.Value = true; + + try { - writer.Write(topic); + DoOutOp((int) Op.SendMulti, writer => + { + writer.Write(topic); - writer.WriteEnumerable(messages.OfType()); - }); + writer.WriteEnumerable(messages.OfType()); + }); + } + finally + { + Marshaller.RegisterSameJavaTypeTl.Value = locRegisterSameJavaType; + } } /** */ @@ -109,13 +131,24 @@ public void SendOrdered(object message, object topic = null, TimeSpan? timeout = { IgniteArgumentCheck.NotNull(message, "message"); - DoOutOp((int) Op.SendOrdered, writer => + bool locRegisterSameJavaType = Marshaller.RegisterSameJavaTypeTl.Value; + + Marshaller.RegisterSameJavaTypeTl.Value = true; + + try { - writer.Write(topic); - writer.Write(message); + DoOutOp((int) Op.SendOrdered, writer => + { + writer.Write(topic); + writer.Write(message); - writer.WriteLong((long)(timeout == null ? 0 : timeout.Value.TotalMilliseconds)); - }); + writer.WriteLong((long) (timeout == null ? 0 : timeout.Value.TotalMilliseconds)); + }); + } + finally + { + Marshaller.RegisterSameJavaTypeTl.Value = locRegisterSameJavaType; + } } /** */ From 8b83dd7ed2e5c47623d36d5339d42b0cdd84d0a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B6=D0=B8=D0=BA=D0=BE=D0=B2=20=D0=9D=D0=B8=D0=BA?= =?UTF-8?q?=D0=BE=D0=BB=D0=B0=D0=B9=20=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B8=D1=87?= Date: Thu, 4 Feb 2021 17:59:07 +0300 Subject: [PATCH 04/15] IGN-2583 .NET: RegisterSameJavaType mode enabled when reading message Merge in OSPT/ignite from IGN-2583 to master Squashed commit of the following: commit e3b64a3f77c9abb1e6796f3a818a961acacad19f Author: Nikolay Izhikov Date: Thu Feb 4 15:18:59 2021 +0300 IGN-2583: RegisterSameJavaType mode enabled when reading message. --- .../Services/ServicesTypeAutoResolveTest.cs | 21 +++++++++------- .../Impl/Messaging/MessageListenerHolder.cs | 24 +++++++++++++++---- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTypeAutoResolveTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTypeAutoResolveTest.cs index acf707f03e1a3..e7e08a7900c42 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTypeAutoResolveTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTypeAutoResolveTest.cs @@ -267,17 +267,22 @@ public void TestMessagingJavaService() return true; }); - msgng.LocalListen(lsnr, "test-topic"); - - svc.testSendMessage(); + try + { + msgng.LocalListen(lsnr, "test-topic"); - TestUtils.WaitForTrueCondition(() => rcvd.Count == 3, timeout: 2500); + svc.testSendMessage(); - Assert.IsNotNull(rcvd.Find(v => v.Name == "1")); - Assert.IsNotNull(rcvd.Find(v => v.Name == "2")); - Assert.IsNotNull(rcvd.Find(v => v.Name == "3")); + TestUtils.WaitForTrueCondition(() => rcvd.Count == 3, timeout: 2500); - msgng.StopLocalListen(lsnr, "test-topic"); + Assert.IsNotNull(rcvd.Find(v => v.Name == "1")); + Assert.IsNotNull(rcvd.Find(v => v.Name == "2")); + Assert.IsNotNull(rcvd.Find(v => v.Name == "3")); + } + finally + { + msgng.StopLocalListen(lsnr, "test-topic"); + } svc.startReceiveMessage(); diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Messaging/MessageListenerHolder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Messaging/MessageListenerHolder.cs index 457533ad3078d..1091cdce4abee 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Messaging/MessageListenerHolder.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Messaging/MessageListenerHolder.cs @@ -73,13 +73,29 @@ private MessageListenerHolder(Ignite grid, object filter, Func public int Invoke(IBinaryStream input) { - var rawReader = _ignite.Marshaller.StartUnmarshal(input).GetRawReader(); + Guid? nodeId; + object msg; - var nodeId = rawReader.ReadGuid(); + bool locRegisterSameJavaType = Marshaller.RegisterSameJavaTypeTl.Value; - Debug.Assert(nodeId != null); + Marshaller.RegisterSameJavaTypeTl.Value = true; - return _invoker(nodeId.Value, rawReader.ReadObject()) ? 1 : 0; + try + { + var rawReader = _ignite.Marshaller.StartUnmarshal(input).GetRawReader(); + + nodeId = rawReader.ReadGuid(); + + Debug.Assert(nodeId != null); + + msg = rawReader.ReadObject(); + } + finally + { + Marshaller.RegisterSameJavaTypeTl.Value = locRegisterSameJavaType; + } + + return _invoker(nodeId.Value, msg) ? 1 : 0; } /// From a0a5321bc781576fa3bca538ba5ffb08d399bdc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B6=D0=B8=D0=BA=D0=BE=D0=B2=20=D0=9D=D0=B8=D0=BA?= =?UTF-8?q?=D0=BE=D0=BB=D0=B0=D0=B9=20=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B8=D1=87?= Date: Wed, 17 Feb 2021 19:35:18 +0300 Subject: [PATCH 05/15] IGN-2681 .NET: Enable RegisterSameJavaType for Cache API Merge in OSPT/ignite from IGN-2681 to master Squashed commit of the following: commit 52c96c308aca0e2baeb7a1c476d990a215d69810 Author: Nikolay Izhikov Date: Wed Feb 17 18:42:57 2021 +0300 IGN-2681: Enable RegisterSameJavaType mode for a cache operations. --- .../platform/PlatformDeployServiceTask.java | 21 +++ .../org/apache/ignite/platform/model/V10.java | 34 ++++ .../org/apache/ignite/platform/model/V11.java | 34 ++++ .../org/apache/ignite/platform/model/V12.java | 34 ++++ .../org/apache/ignite/platform/model/V9.java | 34 ++++ .../Services/IJavaService.cs | 3 + .../Services/JavaServiceDynamicProxy.cs | 6 + .../Services/Model.cs | 24 ++- .../Services/PlatformTestService.cs | 17 ++ .../Services/ServicesTypeAutoResolveTest.cs | 32 +++- .../Impl/Cache/CacheImpl.cs | 68 ++++---- .../Impl/Compute/ComputeImpl.cs | 12 +- .../Impl/PlatformTargetAdapter.cs | 160 +++++++++++------- 13 files changed, 378 insertions(+), 101 deletions(-) create mode 100644 modules/core/src/test/java/org/apache/ignite/platform/model/V10.java create mode 100644 modules/core/src/test/java/org/apache/ignite/platform/model/V11.java create mode 100644 modules/core/src/test/java/org/apache/ignite/platform/model/V12.java create mode 100644 modules/core/src/test/java/org/apache/ignite/platform/model/V9.java diff --git a/modules/core/src/test/java/org/apache/ignite/platform/PlatformDeployServiceTask.java b/modules/core/src/test/java/org/apache/ignite/platform/PlatformDeployServiceTask.java index 363e335c0fe3a..c6cda5dce78a4 100644 --- a/modules/core/src/test/java/org/apache/ignite/platform/PlatformDeployServiceTask.java +++ b/modules/core/src/test/java/org/apache/ignite/platform/PlatformDeployServiceTask.java @@ -52,10 +52,14 @@ import org.apache.ignite.platform.model.Parameter; import org.apache.ignite.platform.model.Role; import org.apache.ignite.platform.model.User; +import org.apache.ignite.platform.model.V10; +import org.apache.ignite.platform.model.V11; +import org.apache.ignite.platform.model.V12; import org.apache.ignite.platform.model.V5; import org.apache.ignite.platform.model.V6; import org.apache.ignite.platform.model.V7; import org.apache.ignite.platform.model.V8; +import org.apache.ignite.platform.model.V9; import org.apache.ignite.platform.model.Value; import org.apache.ignite.resources.IgniteInstanceResource; import org.apache.ignite.services.Service; @@ -628,6 +632,23 @@ public void testLocalDateFromCache() { cache.put(8, ts2); } + /** */ + public void putValsForCache() { + ignite.getOrCreateCache("V9").put(1, new V9("1")); + + IgniteCache v10 = ignite.getOrCreateCache("V10"); + + v10.put(1, new V10("1")); + v10.put(2, new V10("2")); + + ignite.getOrCreateCache("V11").put(1, new V11("1")); + + IgniteCache v12 = ignite.getOrCreateCache("V12"); + + v12.put(1, new V12("1")); + v12.put(2, new V12("2")); + } + /** */ private final AtomicInteger cntMsgs = new AtomicInteger(0); diff --git a/modules/core/src/test/java/org/apache/ignite/platform/model/V10.java b/modules/core/src/test/java/org/apache/ignite/platform/model/V10.java new file mode 100644 index 0000000000000..4cdac5725e3ba --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/model/V10.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.platform.model; + +/** Test V10 object. */ +public class V10 { + /** */ + private final String name; + + /** */ + public V10(String name) { + this.name = name; + } + + /** */ + public String getName() { + return name; + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/platform/model/V11.java b/modules/core/src/test/java/org/apache/ignite/platform/model/V11.java new file mode 100644 index 0000000000000..b1e880ba0cbbc --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/model/V11.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.platform.model; + +/** Test V11 object. */ +public class V11 { + /** */ + private final String name; + + /** */ + public V11(String name) { + this.name = name; + } + + /** */ + public String getName() { + return name; + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/platform/model/V12.java b/modules/core/src/test/java/org/apache/ignite/platform/model/V12.java new file mode 100644 index 0000000000000..a0b6a0cbd6a62 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/model/V12.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.platform.model; + +/** Test V12 object. */ +public class V12 { + /** */ + private final String name; + + /** */ + public V12(String name) { + this.name = name; + } + + /** */ + public String getName() { + return name; + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/platform/model/V9.java b/modules/core/src/test/java/org/apache/ignite/platform/model/V9.java new file mode 100644 index 0000000000000..67f856235eb82 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/model/V9.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.platform.model; + +/** Test V9 object. */ +public class V9 { + /** */ + private final String name; + + /** */ + public V9(String name) { + this.name = name; + } + + /** */ + public String getName() { + return name; + } +} diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/IJavaService.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/IJavaService.cs index 5c4ea13038fa7..168b2b2757ef7 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/IJavaService.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/IJavaService.cs @@ -210,6 +210,9 @@ public interface IJavaService /** */ void sleep(long delayMs); + /** */ + void putValsForCache(); + /** */ void startReceiveMessage(); diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/JavaServiceDynamicProxy.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/JavaServiceDynamicProxy.cs index 9ce5b631e0faf..55906033e6e79 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/JavaServiceDynamicProxy.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/JavaServiceDynamicProxy.cs @@ -412,5 +412,11 @@ public void testSendMessage() { _svc.testSendMessage(); } + + /** */ + public void putValsForCache() + { + _svc.putValsForCache(); + } } } diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/Model.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/Model.cs index 6210fd2be4017..b7b8e4fc9efee 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/Model.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/Model.cs @@ -201,12 +201,32 @@ public class V5 { public String Name { get; set; } } public class V6 { public String Name { get; set; } } /// - /// A class is a clone of Java class V6 with the same namespace. + /// A class is a clone of Java class V7 with the same namespace. /// public class V7 { public String Name { get; set; } } /// - /// A class is a clone of Java class V6 with the same namespace. + /// A class is a clone of Java class V8 with the same namespace. /// public class V8 { public String Name { get; set; } } + + /// + /// A class is a clone of Java class V9 with the same namespace. + /// + public class V9 { public String Name { get; set; } } + + /// + /// A class is a clone of Java class V10 with the same namespace. + /// + public class V10 { public String Name { get; set; } } + + /// + /// A class is a clone of Java class V11 with the same namespace. + /// + public class V11 { public String Name { get; set; } } + + /// + /// A class is a clone of Java class V12 with the same namespace. + /// + public class V12 { public String Name { get; set; } } } diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/PlatformTestService.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/PlatformTestService.cs index 5a579b21c49d0..5892915ce786a 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/PlatformTestService.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/PlatformTestService.cs @@ -635,5 +635,22 @@ public void testSendMessage() { throw new NotImplementedException(); } + + public void putValsForCache() + { + _ignite.GetOrCreateCache("V9").Put(1, new V9 {Name = "1"}); + + var v10 = _ignite.GetOrCreateCache("V10"); + + v10.Put(1, new V10 {Name = "1"}); + v10.Put(2, new V10 {Name = "2"}); + + _ignite.GetOrCreateCache("V11").Put(1, new V11 {Name = "1"}); + + var v12 = _ignite.GetOrCreateCache("V12"); + + v12.Put(1, new V12 {Name = "1"}); + v12.Put(2, new V12 {Name = "2"}); + } } } diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTypeAutoResolveTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTypeAutoResolveTest.cs index e7e08a7900c42..6f4a5f084279f 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTypeAutoResolveTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTypeAutoResolveTest.cs @@ -186,7 +186,7 @@ private void DoTestDepartments(IJavaService svc) /// /// Tests java service instance. /// - private static void DoTestService(IJavaService svc) + private void DoTestService(IJavaService svc) { Assert.IsNull(svc.testAddress(null)); @@ -242,6 +242,36 @@ private static void DoTestService(IJavaService svc) Assert.AreEqual(2, users[1].Id); Assert.AreEqual(ACL.Deny, users[1].Acl); Assert.AreEqual("user", users[1].Role.Name); + + svc.putValsForCache(); + + Assert.AreEqual("1", _grid1.GetCache("V9").Get(1).Name); + + var v10 = _grid1.GetCache("V10").GetAll(new List {1, 2}); + + Assert.AreEqual(2, v10.Count); + + foreach (var entry in v10) + { + if (entry.Key == 1) + Assert.AreEqual("1", entry.Value.Name); + else + Assert.AreEqual("2", entry.Value.Name); + } + + Assert.AreEqual("1", _grid1.GetCache("V11").GetAsync(1).Result.Name); + + var v12 = _grid1.GetCache("V12").GetAllAsync(new List {1, 2}).Result; + + Assert.AreEqual(2, v12.Count); + + foreach (var entry in v12) + { + if (entry.Key == 1) + Assert.AreEqual("1", entry.Value.Name); + else + Assert.AreEqual("2", entry.Value.Name); + } } /// diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs index cb96d2e0566b3..6919fc7486196 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs @@ -137,7 +137,7 @@ private bool CanUsePlatformCache /// private Task DoOutOpAsync(CacheOp op, T1 val1) { - return DoOutOpAsync((int) op, val1); + return DoOutOpAsync((int) op, val1, IsKeepBinary); } /// @@ -145,7 +145,7 @@ private Task DoOutOpAsync(CacheOp op, T1 val1) /// private Task DoOutOpAsync(CacheOp op, T1 val1) { - return DoOutOpAsync((int) op, val1); + return DoOutOpAsync((int) op, val1, IsKeepBinary); } /// @@ -153,7 +153,7 @@ private Task DoOutOpAsync(CacheOp op, T1 val1) /// private Task DoOutOpAsync(CacheOp op, T1 val1, T2 val2) { - return DoOutOpAsync((int) op, val1, val2); + return DoOutOpAsync((int) op, val1, val2, IsKeepBinary); } /// @@ -161,7 +161,7 @@ private Task DoOutOpAsync(CacheOp op, T1 val1, T2 val2) /// private Task DoOutOpAsync(CacheOp op, T1 val1, T2 val2) { - return DoOutOpAsync((int) op, val1, val2); + return DoOutOpAsync((int) op, val1, val2, IsKeepBinary); } /// @@ -192,7 +192,7 @@ public string Name public CacheConfiguration GetConfiguration() { return DoInOp((int) CacheOp.GetConfig, stream => new CacheConfiguration( - BinaryUtils.Marshaller.StartUnmarshal(stream))); + BinaryUtils.Marshaller.StartUnmarshal(stream)), IsKeepBinary); } /** */ @@ -265,7 +265,7 @@ public ICache WithExpiryPolicy(IExpiryPolicy plc) { IgniteArgumentCheck.NotNull(plc, "plc"); - var cache0 = DoOutOpObject((int)CacheOp.WithExpiryPolicy, w => ExpiryPolicySerializer.WritePolicy(w, plc)); + var cache0 = DoOutOpObject((int)CacheOp.WithExpiryPolicy, w => ExpiryPolicySerializer.WritePolicy(w, plc), IsKeepBinary); return new CacheImpl( cache0, @@ -290,7 +290,7 @@ public bool IsAllowAtomicOpsInTx /** */ public void LoadCache(ICacheEntryFilter p, params object[] args) { - DoOutInOpX((int) CacheOp.LoadCache, writer => WriteLoadCacheData(writer, p, args), _readException); + DoOutInOpX((int) CacheOp.LoadCache, writer => WriteLoadCacheData(writer, p, args), _readException, IsKeepBinary); } /** */ @@ -302,7 +302,7 @@ public Task LoadCacheAsync(ICacheEntryFilter p, params object[] args) /** */ public void LocalLoadCache(ICacheEntryFilter p, params object[] args) { - DoOutInOpX((int) CacheOp.LocLoadCache, writer => WriteLoadCacheData(writer, p, args), _readException); + DoOutInOpX((int) CacheOp.LocLoadCache, writer => WriteLoadCacheData(writer, p, args), _readException, IsKeepBinary); } /** */ @@ -506,7 +506,7 @@ public bool TryLocalPeek(TK key, out TV value, params CachePeekMode[] modes) w.WriteInt(peekModes); }, (s, r) => r == True ? new CacheResult(Unmarshal(s)) : new CacheResult(), - _readException); + _readException, IsKeepBinary); value = res.Success ? res.Value : default(TV); @@ -547,7 +547,7 @@ public TV Get(TK key) throw GetKeyNotFoundException(key); return Unmarshal(stream); - }, _readException); + }, _readException, IsKeepBinary); } /** */ @@ -652,7 +652,7 @@ public ICollection> GetAll(IEnumerable keys) (s, r) => r == True ? ReadGetAllDictionary(Marshaller.StartUnmarshal(s, _flagKeepBinary), res) : res, - _readException); + _readException, IsKeepBinary); // ReSharper restore AccessToDisposedClosure } } @@ -662,7 +662,7 @@ public ICollection> GetAll(IEnumerable keys) (s, r) => r == True ? ReadGetAllDictionary(Marshaller.StartUnmarshal(s, _flagKeepBinary)) : null, - _readException); + _readException, IsKeepBinary); } /** */ @@ -1204,7 +1204,7 @@ private long Size0(bool loc, int? part, params CachePeekMode[] modes) { writer.WriteBoolean(false); } - }) + platformCacheSize; + }, IsKeepBinary) + platformCacheSize; } /// @@ -1310,7 +1310,7 @@ public TRes Invoke(TK key, ICacheEntryProcessor writer.WriteObjectDetached(holder); }, (input, res) => res == True ? Unmarshal(input) : default(TRes), - _readException); + _readException, IsKeepBinary); } finally { @@ -1390,7 +1390,7 @@ public ICollection> InvokeAll(I }, (input, res) => res == True ? ReadInvokeAllResults(Marshaller.StartUnmarshal(input, IsKeepBinary)) - : null, _readException); + : null, _readException, IsKeepBinary); } finally { @@ -1451,7 +1451,7 @@ public T DoOutInOpExtension(int extensionId, int opCode, Action res == True ? readFunc(Marshaller.StartUnmarshal(input)) - : default(T), _readException); + : default(T), _readException, IsKeepBinary); } /** */ @@ -1460,7 +1460,7 @@ public ICacheLock Lock(TK key) IgniteArgumentCheck.NotNull(key, "key"); return DoOutInOpX((int) CacheOp.Lock, w => w.Write(key), - (stream, res) => new CacheLock(stream.ReadInt(), this), _readException); + (stream, res) => new CacheLock(stream.ReadInt(), this), _readException, IsKeepBinary); } /** */ @@ -1469,7 +1469,7 @@ public ICacheLock LockAll(IEnumerable keys) IgniteArgumentCheck.NotNull(keys, "keys"); return DoOutInOpX((int) CacheOp.LockAll, w => w.WriteEnumerable(keys), - (stream, res) => new CacheLock(stream.ReadInt(), this), _readException); + (stream, res) => new CacheLock(stream.ReadInt(), this), _readException, IsKeepBinary); } /** */ @@ -1492,7 +1492,7 @@ public ICacheMetrics GetMetrics() IBinaryRawReader reader = Marshaller.StartUnmarshal(stream, false); return new CacheMetricsImpl(reader); - }); + }, IsKeepBinary); } /** */ @@ -1516,7 +1516,7 @@ public ICacheMetrics GetLocalMetrics() IBinaryRawReader reader = Marshaller.StartUnmarshal(stream, false); return new CacheMetricsImpl(reader); - }); + }, IsKeepBinary); } /** */ @@ -1587,7 +1587,7 @@ public ICollection GetLostPartitions() } return res; - }); + }, IsKeepBinary); } #region Queries @@ -1633,7 +1633,7 @@ public IQueryCursor> Query(QueryBase qry) } } - var cursor = DoOutOpObject((int) qry.OpId, writer => qry.Write(writer, IsKeepBinary)); + var cursor = DoOutOpObject((int) qry.OpId, writer => qry.Write(writer, IsKeepBinary), IsKeepBinary); return new QueryCursor(cursor, _flagKeepBinary); } @@ -1661,7 +1661,7 @@ public IContinuousQueryHandleFields QueryContinuous(ContinuousQuery qry, qry.Validate(); return new ContinuousQueryHandleImpl(qry, Marshaller, _flagKeepBinary, - writeAction => DoOutOpObject((int) CacheOp.QryContinuous, writeAction), initialQry); + writeAction => DoOutOpObject((int) CacheOp.QryContinuous, writeAction, IsKeepBinary), initialQry); } /// @@ -1673,7 +1673,7 @@ private IContinuousQueryHandle> QueryContinuousImpl(Continuo qry.Validate(); return new ContinuousQueryHandleImpl(qry, Marshaller, _flagKeepBinary, - writeAction => DoOutOpObject((int) CacheOp.QryContinuous, writeAction), initialQry); + writeAction => DoOutOpObject((int) CacheOp.QryContinuous, writeAction, IsKeepBinary), initialQry); } #endregion @@ -1728,7 +1728,7 @@ internal CacheEnumerator CreateEnumerator(bool loc, int peekModes) { if (loc) { - var target = DoOutOpObject((int) CacheOp.LocIterator, (IBinaryStream s) => s.WriteInt(peekModes)); + var target = DoOutOpObject((int) CacheOp.LocIterator, (IBinaryStream s) => s.WriteInt(peekModes), IsKeepBinary); return new CacheEnumerator(target, _flagKeepBinary); } @@ -1855,7 +1855,7 @@ private bool DoOutOp(CacheOp op, T1 x) return DoOutInOpX((int) op, w => { w.Write(x); - }, _readException); + }, _readException, IsKeepBinary); } /// @@ -1867,7 +1867,7 @@ private bool DoOutOp(CacheOp op, T1 x, T2 y) { w.WriteObjectDetached(x); w.WriteObjectDetached(y); - }, _readException); + }, _readException, IsKeepBinary); } /// @@ -1880,7 +1880,7 @@ private bool DoOutOp(CacheOp op, T1 x, T2 y, T3 z) w.WriteObjectDetached(x); w.WriteObjectDetached(y); w.WriteObjectDetached(z); - }, _readException); + }, _readException, IsKeepBinary); } /// @@ -1888,7 +1888,7 @@ private bool DoOutOp(CacheOp op, T1 x, T2 y, T3 z) /// private bool DoOutOp(CacheOp op, Action write) { - return DoOutInOpX((int) op, write, _readException); + return DoOutInOpX((int) op, write, _readException, IsKeepBinary); } /// @@ -1899,7 +1899,7 @@ private CacheResult DoOutInOpNullable(CacheOp cacheOp, TK x) return DoOutInOpX((int)cacheOp, w => w.Write(x), (stream, res) => res == True ? new CacheResult(Unmarshal(stream)) : new CacheResult(), - _readException); + _readException, IsKeepBinary); } /// @@ -1914,7 +1914,7 @@ private CacheResult DoOutInOpNullable(CacheOp cacheOp, T1 x, T2 y) w.WriteObjectDetached(y); }, (stream, res) => res == True ? new CacheResult(Unmarshal(stream)) : new CacheResult(), - _readException); + _readException, IsKeepBinary); } /** */ @@ -1930,7 +1930,7 @@ public bool TryEnter(long id, TimeSpan timeout) { s.WriteLong(id); s.WriteLong((long) timeout.TotalMilliseconds); - }) == True; + }, IsKeepBinary) == True; } /** */ @@ -1953,7 +1953,7 @@ public IQueryMetrics GetQueryMetrics() IBinaryRawReader reader = Marshaller.StartUnmarshal(stream, false); return new QueryMetricsImpl(reader); - }); + }, IsKeepBinary); } /** */ @@ -2103,7 +2103,7 @@ private IPlatformTargetInternal QueryFieldsInternal(SqlFieldsQuery qry) if (string.IsNullOrEmpty(qry.Sql)) throw new ArgumentException("Sql cannot be null or empty"); - return DoOutOpObject((int) CacheOp.QrySqlFields, writer => qry.Write(writer)); + return DoOutOpObject((int) CacheOp.QrySqlFields, writer => qry.Write(writer), IsKeepBinary); } } } diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeImpl.cs index 153775c4f1ba6..ac85e5332dfa6 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeImpl.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeImpl.cs @@ -159,7 +159,7 @@ public void WithKeepBinary() /// New instance associated with a specified executor. public ComputeImpl WithExecutor(string executorName) { - var target = DoOutOpObject(OpWithExecutor, w => w.WriteString(executorName)); + var target = DoOutOpObject(OpWithExecutor, w => w.WriteString(executorName), _keepBinary.Value); return new ComputeImpl(target, _prj, _keepBinary.Value); } @@ -180,7 +180,7 @@ public TReduceRes ExecuteJavaTask(string taskName, object taskArg) try { - return DoOutInOp(OpExec, writer => WriteTask(writer, taskName, taskArg, nodes)); + return DoOutInOp(OpExec, writer => WriteTask(writer, taskName, taskArg, nodes), _keepBinary.Value); } finally { @@ -206,7 +206,7 @@ public Future ExecuteJavaTaskAsync(string taskName, obje try { - return DoOutOpObjectAsync(OpExecAsync, w => WriteTask(w, taskName, taskArg, nodes)); + return DoOutOpObjectAsync(OpExecAsync, w => WriteTask(w, taskName, taskArg, nodes), _keepBinary.Value); } finally { @@ -235,7 +235,7 @@ public Future Execute(IComputeTask DoAffinityOp(object cacheNames, int? partition, w.WriteWithPeerDeployment(func); w.WriteLong(handle); - }); + }, _keepBinary.Value); fut.Task.ContWith(_ => handleRegistry.Release(handle), TaskContinuationOptions.ExecuteSynchronously); @@ -653,7 +653,7 @@ private Future ExecuteClosures0( if (writeAction != null) writeAction(writer); - }); + }, _keepBinary.Value); holder.Future.SetTarget(new Listenable(futTarget)); } diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/PlatformTargetAdapter.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/PlatformTargetAdapter.cs index d56656ec0aac2..92b4ea68ab81d 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/PlatformTargetAdapter.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/PlatformTargetAdapter.cs @@ -93,15 +93,41 @@ public Marshaller Marshaller #region OUT operations + /// + /// Enables Register Same Java Type mode is keepBinary = false. + /// + /// Action. + /// Keep binary flag. + /// + private static T WithReg(Func action, bool keepBinary) + { + if (keepBinary) + return action.Invoke(); + + bool locRegisterSameJavaType = Marshaller.RegisterSameJavaTypeTl.Value; + + Marshaller.RegisterSameJavaTypeTl.Value = true; + + try + { + return action.Invoke(); + } + finally + { + Marshaller.RegisterSameJavaTypeTl.Value = locRegisterSameJavaType; + } + } + /// /// Perform out operation. /// /// Operation type. /// Action to be performed on the stream. + /// Keep binary flag. /// - protected long DoOutOp(int type, Action action) + protected long DoOutOp(int type, Action action, bool keepBinary = false) { - return _target.InStreamOutLong(type, action); + return WithReg(() => _target.InStreamOutLong(type, action), keepBinary); } /// @@ -109,10 +135,11 @@ protected long DoOutOp(int type, Action action) /// /// Operation type. /// Action to be performed on the stream. + /// Keep binary flag. /// - protected long DoOutOp(int type, Action action) + protected long DoOutOp(int type, Action action, bool keepBinary = false) { - return DoOutOp(type, stream => WriteToStream(action, stream, _marsh)); + return DoOutOp(type, stream => WriteToStream(action, stream, _marsh), keepBinary); } /// @@ -120,10 +147,11 @@ protected long DoOutOp(int type, Action action) /// /// Operation type. /// Action to be performed on the stream. + /// Keep binary flag. /// Resulting object. - protected IPlatformTargetInternal DoOutOpObject(int type, Action action) + protected IPlatformTargetInternal DoOutOpObject(int type, Action action, bool keepBinary = false) { - return _target.InStreamOutObject(type, stream => WriteToStream(action, stream, _marsh)); + return WithReg(() => _target.InStreamOutObject(type, stream => WriteToStream(action, stream, _marsh)), keepBinary); } /// @@ -131,10 +159,11 @@ protected IPlatformTargetInternal DoOutOpObject(int type, Action a /// /// Operation type. /// Action to be performed on the stream. + /// Keep binary flag. /// Resulting object. - protected IPlatformTargetInternal DoOutOpObject(int type, Action action) + protected IPlatformTargetInternal DoOutOpObject(int type, Action action, bool keepBinary = false) { - return _target.InStreamOutObject(type, action); + return WithReg(() => _target.InStreamOutObject(type, action), keepBinary); } /// @@ -152,13 +181,14 @@ protected IPlatformTargetInternal DoOutOpObject(int type) /// /// Operation type. /// Value. + /// Keep binary flag. /// Result. - protected long DoOutOp(int type, T1 val1) + protected long DoOutOp(int type, T1 val1, bool keepBinary = false) { return DoOutOp(type, writer => { writer.Write(val1); - }); + }, keepBinary); } /// @@ -167,14 +197,15 @@ protected long DoOutOp(int type, T1 val1) /// Operation type. /// Value 1. /// Value 2. + /// Keep binary flag. /// Result. - protected long DoOutOp(int type, T1 val1, T2 val2) + protected long DoOutOp(int type, T1 val1, T2 val2, bool keepBinary = false) { return DoOutOp(type, writer => { writer.Write(val1); writer.Write(val2); - }); + }, keepBinary); } #endregion @@ -186,10 +217,11 @@ protected long DoOutOp(int type, T1 val1, T2 val2) /// /// Type. /// Action. + /// Keep binary flag. /// Result. - protected T DoInOp(int type, Func action) + protected T DoInOp(int type, Func action, bool keepBinary = false) { - return _target.OutStream(type, action); + return WithReg(() => _target.OutStream(type, action), keepBinary); } /// @@ -213,10 +245,11 @@ protected T DoInOp(int type) /// Out action. /// In action. /// Error action. + /// Keep binary flag. /// Result. - protected TR DoOutInOp(int type, Action outAction, Func inAction, Func errorAction = null) + protected TR DoOutInOp(int type, Action outAction, Func inAction, Func errorAction = null, bool keepBinary = false) { - return _target.InStreamOutStream(type, stream => WriteToStream(outAction, stream, _marsh), inAction, errorAction); + return WithReg(() => _target.InStreamOutStream(type, stream => WriteToStream(outAction, stream, _marsh), inAction, errorAction), keepBinary); } /// @@ -227,14 +260,15 @@ protected TR DoOutInOp(int type, Action outAction, FuncOut action. /// In action. /// The action to read an error. + /// Keep binary flag. /// /// Result. /// protected TR DoOutInOpX(int type, Action outAction, Func inAction, - Func inErrorAction) + Func inErrorAction, bool keepBinary = false) { - return _target.InStreamOutLong(type, stream => WriteToStream(outAction, stream, _marsh), - inAction, inErrorAction); + return WithReg(() => _target.InStreamOutLong(type, stream => WriteToStream(outAction, stream, _marsh), + inAction, inErrorAction), keepBinary); } /// @@ -243,14 +277,15 @@ protected TR DoOutInOpX(int type, Action outAction, FuncOperation type. /// Out action. /// The action to read an error. + /// Keep binary flag. /// /// Result. /// protected bool DoOutInOpX(int type, Action outAction, - Func inErrorAction) + Func inErrorAction, bool keepBinary = false) { - return _target.InStreamOutLong(type, stream => WriteToStream(outAction, stream, _marsh), - (stream, res) => res == True, inErrorAction); + return WithReg(() => _target.InStreamOutLong(type, stream => WriteToStream(outAction, stream, _marsh), + (stream, res) => res == True, inErrorAction), keepBinary); } /// @@ -260,12 +295,13 @@ protected bool DoOutInOpX(int type, Action outAction, /// Out action. /// In action. /// Argument. + /// Keep binary flag. /// Result. protected TR DoOutInOp(int type, Action outAction, - Func inAction, IPlatformTargetInternal arg) + Func inAction, IPlatformTargetInternal arg, bool keepBinary = false) { - return _target.InObjectStreamOutObjectStream(type, stream => WriteToStream(outAction, stream, _marsh), - inAction, arg); + return WithReg(() => _target.InObjectStreamOutObjectStream(type, stream => WriteToStream(outAction, stream, _marsh), + inAction, arg), keepBinary); } /// @@ -273,11 +309,12 @@ protected TR DoOutInOp(int type, Action outAction, /// /// Operation type. /// Out action. + /// Keep binary flag. /// Result. - protected TR DoOutInOp(int type, Action outAction) + protected TR DoOutInOp(int type, Action outAction, bool keepBinary = false) { - return _target.InStreamOutStream(type, stream => WriteToStream(outAction, stream, _marsh), - stream => Unmarshal(stream)); + return WithReg(() => _target.InStreamOutStream(type, stream => WriteToStream(outAction, stream, _marsh), + stream => Unmarshal(stream)), keepBinary); } /// @@ -285,11 +322,12 @@ protected TR DoOutInOp(int type, Action outAction) /// /// Operation type. /// Value. + /// Keep binary flag. /// Result. - protected TR DoOutInOp(int type, T1 val) + protected TR DoOutInOp(int type, T1 val, bool keepBinary = false) { - return _target.InStreamOutStream(type, stream => WriteToStream(val, stream, _marsh), - stream => Unmarshal(stream)); + return WithReg(() => _target.InStreamOutStream(type, stream => WriteToStream(val, stream, _marsh), + stream => Unmarshal(stream)), keepBinary); } /// @@ -312,10 +350,11 @@ protected long DoOutInOp(int type, long val = 0) /// /// The type code. /// The write action. + /// Keep binary flag. /// Task for async operation - protected Task DoOutOpAsync(int type, Action writeAction = null) + protected Task DoOutOpAsync(int type, Action writeAction = null, bool keepBinary = false) { - return DoOutOpAsync(type, writeAction); + return DoOutOpAsync(type, writeAction, keepBinary); } /// @@ -338,7 +377,7 @@ protected Task DoOutOpAsync(int type, Action writeAction = n } w.WriteLong(futId); w.WriteInt(futType); - }), keepBinary, convertFunc).Task; + }, keepBinary), keepBinary, convertFunc).Task; } /// @@ -347,15 +386,16 @@ protected Task DoOutOpAsync(int type, Action writeAction = n /// Type of the result. /// The type code. /// The write action. + /// Keep binary flag. /// Future for async operation - protected Future DoOutOpObjectAsync(int type, Action writeAction) + protected Future DoOutOpObjectAsync(int type, Action writeAction, bool keepBinary = false) { return GetFuture((futId, futType) => DoOutOpObject(type, w => { writeAction(w); w.WriteLong(futId); w.WriteInt(futType); - })); + }, keepBinary), keepBinary); } /// @@ -365,17 +405,18 @@ protected Future DoOutOpObjectAsync(int type, Action writeAc /// The type of the first arg. /// The type code. /// First arg. + /// Keep binary flag. /// /// Task for async operation /// - protected Task DoOutOpAsync(int type, T1 val1) + protected Task DoOutOpAsync(int type, T1 val1, bool keepBinary = false) { return GetFuture((futId, futType) => DoOutOp(type, w => { w.WriteObject(val1); w.WriteLong(futId); w.WriteInt(futType); - })).Task; + }, keepBinary), keepBinary).Task; } /// @@ -387,10 +428,11 @@ protected Task DoOutOpAsync(int type, T1 val1) /// The type code. /// First arg. /// Second arg. + /// Keep binary flag. /// /// Task for async operation /// - protected Task DoOutOpAsync(int type, T1 val1, T2 val2) + protected Task DoOutOpAsync(int type, T1 val1, T2 val2, bool keepBinary = false) { return GetFuture((futId, futType) => DoOutOp(type, w => { @@ -398,7 +440,7 @@ protected Task DoOutOpAsync(int type, T1 val1, T2 val2) w.WriteObjectDetached(val2); w.WriteLong(futId); w.WriteInt(futType); - })).Task; + }, keepBinary), keepBinary).Task; } #endregion @@ -468,31 +510,33 @@ private Future GetFuture(Func listenAc private Future GetFuture(Action listenAction, bool keepBinary = false, Func convertFunc = null) { - var futType = FutureType.Object; + return WithReg(() => { + var futType = FutureType.Object; - var type = typeof(T); + var type = typeof(T); - if (type.IsPrimitive) - IgniteFutureTypeMap.TryGetValue(type, out futType); + if (type.IsPrimitive) + IgniteFutureTypeMap.TryGetValue(type, out futType); - var fut = convertFunc == null && futType != FutureType.Object - ? new Future() - : new Future(new FutureConverter(_marsh, keepBinary, convertFunc)); + var fut = convertFunc == null && futType != FutureType.Object + ? new Future() + : new Future(new FutureConverter(_marsh, keepBinary, convertFunc)); - var futHnd = _marsh.Ignite.HandleRegistry.Allocate(fut); + var futHnd = _marsh.Ignite.HandleRegistry.Allocate(fut); - try - { - listenAction(futHnd, (int)futType); - } - catch (Exception) - { - _marsh.Ignite.HandleRegistry.Release(futHnd); + try + { + listenAction(futHnd, (int)futType); + } + catch (Exception) + { + _marsh.Ignite.HandleRegistry.Release(futHnd); - throw; - } + throw; + } - return fut; + return fut; + }, keepBinary); } /// From 3cc5c5d2a55997571498e4a78bf77d8e79f71506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B6=D0=B8=D0=BA=D0=BE=D0=B2=20=D0=9D=D0=B8=D0=BA?= =?UTF-8?q?=D0=BE=D0=BB=D0=B0=D0=B9=20=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B8=D1=87?= Date: Thu, 25 Feb 2021 18:09:18 +0300 Subject: [PATCH 06/15] IGN-2745 .NET: RegisterSameJavaType mode for Scan Query Merge in OSPT/ignite from IGN-2745 to master Squashed commit of the following: commit b0634120190db4f0c20dbbb92d7a047b8738bca8 Author: Nikolay Izhikov Date: Thu Feb 25 16:53:22 2021 +0300 IGN-2745: RegisterSameJavaType mode for SQLFields Query. commit af43837ec19bd5032284a625a469e707d893b124 Author: Nikolay Izhikov Date: Thu Feb 25 15:45:15 2021 +0300 IGN-2745: RegisterSameJavaType mode for Scan Query. commit 57289aabdb64b4d0306b84ebb47a48a88d525183 Author: Nikolay Izhikov Date: Thu Feb 25 15:40:14 2021 +0300 IGN-2745: WIP. IGN-2783 .NET: Compilation fix Merge in OSPT/ignite from IGN-2783 to master Squashed commit of the following: commit 9ef10fb21dd887d23fbda1ae87b77d77d36aea93 Author: Nikolay Izhikov Date: Mon Mar 1 12:09:42 2021 +0300 IGN-2783: Compilation fix. --- .../platform/PlatformDeployServiceTask.java | 29 +++++++++ .../org/apache/ignite/platform/model/V13.java | 34 +++++++++++ .../org/apache/ignite/platform/model/V14.java | 34 +++++++++++ .../org/apache/ignite/platform/model/V15.java | 34 +++++++++++ .../org/apache/ignite/platform/model/V16.java | 34 +++++++++++ .../Services/Model.cs | 20 ++++++ .../Services/ServicesTypeAutoResolveTest.cs | 61 +++++++++++++++++++ .../Impl/Cache/Query/QueryCursorBase.cs | 38 ++++++++++++ 8 files changed, 284 insertions(+) create mode 100644 modules/core/src/test/java/org/apache/ignite/platform/model/V13.java create mode 100644 modules/core/src/test/java/org/apache/ignite/platform/model/V14.java create mode 100644 modules/core/src/test/java/org/apache/ignite/platform/model/V15.java create mode 100644 modules/core/src/test/java/org/apache/ignite/platform/model/V16.java diff --git a/modules/core/src/test/java/org/apache/ignite/platform/PlatformDeployServiceTask.java b/modules/core/src/test/java/org/apache/ignite/platform/PlatformDeployServiceTask.java index c6cda5dce78a4..d2d645371eae1 100644 --- a/modules/core/src/test/java/org/apache/ignite/platform/PlatformDeployServiceTask.java +++ b/modules/core/src/test/java/org/apache/ignite/platform/PlatformDeployServiceTask.java @@ -40,6 +40,7 @@ import org.apache.ignite.compute.ComputeJobAdapter; import org.apache.ignite.compute.ComputeJobResult; import org.apache.ignite.compute.ComputeTaskAdapter; +import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.internal.IgniteInterruptedCheckedException; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.U; @@ -55,6 +56,10 @@ import org.apache.ignite.platform.model.V10; import org.apache.ignite.platform.model.V11; import org.apache.ignite.platform.model.V12; +import org.apache.ignite.platform.model.V13; +import org.apache.ignite.platform.model.V14; +import org.apache.ignite.platform.model.V15; +import org.apache.ignite.platform.model.V16; import org.apache.ignite.platform.model.V5; import org.apache.ignite.platform.model.V6; import org.apache.ignite.platform.model.V7; @@ -647,6 +652,30 @@ public void putValsForCache() { v12.put(1, new V12("1")); v12.put(2, new V12("2")); + + IgniteCache v13 = ignite.getOrCreateCache("V13"); + + v13.put(1, new V13("1")); + v13.put(2, new V13("2")); + + IgniteCache v14 = ignite.getOrCreateCache("V14"); + + v14.put(1, new V14("1")); + v14.put(2, new V14("2")); + + IgniteCache v15 = ignite.getOrCreateCache("V15"); + + v15.put(1, new V15("1")); + v15.put(2, new V15("2")); + + CacheConfiguration ccfg = new CacheConfiguration<>("V16"); + + ccfg.setIndexedTypes(Integer.class, V16.class); + + IgniteCache v16 = ignite.getOrCreateCache(ccfg); + + v16.put(1, new V16("1")); + v16.put(2, new V16("2")); } /** */ diff --git a/modules/core/src/test/java/org/apache/ignite/platform/model/V13.java b/modules/core/src/test/java/org/apache/ignite/platform/model/V13.java new file mode 100644 index 0000000000000..a82cd573dbfca --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/model/V13.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.platform.model; + +/** Test V13 object. */ +public class V13 { + /** */ + private final String name; + + /** */ + public V13(String name) { + this.name = name; + } + + /** */ + public String getName() { + return name; + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/platform/model/V14.java b/modules/core/src/test/java/org/apache/ignite/platform/model/V14.java new file mode 100644 index 0000000000000..075c2430cd9cd --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/model/V14.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.platform.model; + +/** Test V14 object. */ +public class V14 { + /** */ + private final String name; + + /** */ + public V14(String name) { + this.name = name; + } + + /** */ + public String getName() { + return name; + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/platform/model/V15.java b/modules/core/src/test/java/org/apache/ignite/platform/model/V15.java new file mode 100644 index 0000000000000..b9a29f16a4f97 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/model/V15.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.platform.model; + +/** Test V15 object. */ +public class V15 { + /** */ + private final String name; + + /** */ + public V15(String name) { + this.name = name; + } + + /** */ + public String getName() { + return name; + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/platform/model/V16.java b/modules/core/src/test/java/org/apache/ignite/platform/model/V16.java new file mode 100644 index 0000000000000..bf70834d99ebc --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/model/V16.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.platform.model; + +/** Test V15 object. */ +public class V16 { + /** */ + private final String name; + + /** */ + public V16(String name) { + this.name = name; + } + + /** */ + public String getName() { + return name; + } +} diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/Model.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/Model.cs index b7b8e4fc9efee..63315c3c696af 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/Model.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/Model.cs @@ -229,4 +229,24 @@ public class V11 { public String Name { get; set; } } /// A class is a clone of Java class V12 with the same namespace. /// public class V12 { public String Name { get; set; } } + + /// + /// A class is a clone of Java class V13 with the same namespace. + /// + public class V13 { public String Name { get; set; } } + + /// + /// A class is a clone of Java class V14 with the same namespace. + /// + public class V14 { public String Name { get; set; } } + + /// + /// A class is a clone of Java class V15 with the same namespace. + /// + public class V15 { public String Name { get; set; } } + + /// + /// A class is a clone of Java class V16 with the same namespace. + /// + public class V16 { public String Name { get; set; } } } diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTypeAutoResolveTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTypeAutoResolveTest.cs index 6f4a5f084279f..7833f6a6dc08d 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTypeAutoResolveTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTypeAutoResolveTest.cs @@ -24,6 +24,8 @@ namespace Apache.Ignite.Core.Tests.Services using System.Linq; using System.Reflection; using Apache.Ignite.Core.Binary; + using Apache.Ignite.Core.Cache; + using Apache.Ignite.Core.Cache.Query; using NUnit.Framework; using Apache.Ignite.Platform.Model; @@ -272,6 +274,53 @@ private void DoTestService(IJavaService svc) else Assert.AreEqual("2", entry.Value.Name); } + + var v13 = _grid1.GetCache("V13").Query(new ScanQuery()).GetAll(); + + Assert.AreEqual(2, v13.Count); + + foreach (var entry in v13) + { + if (entry.Key == 1) + Assert.AreEqual("1", entry.Value.Name); + else + Assert.AreEqual("2", entry.Value.Name); + } + + var v14 = _grid1.GetCache("V14").Query(new ScanQuery()); + + foreach (var entry in v14) + { + if (entry.Key == 1) + Assert.AreEqual("1", entry.Value.Name); + else + Assert.AreEqual("2", entry.Value.Name); + } + + var v15 = _grid1.GetCache("V15") + .Query(new ScanQuery(new CacheEntryFilter())).GetAll(); + + Assert.AreEqual(1, v15.Count); + + foreach (var entry in v15) + { + Assert.AreEqual("1", entry.Value.Name); + } + + var v16 = _grid1.GetCache("V16").Query(new SqlFieldsQuery("SELECT _KEY, _VAL FROM V16")); + + var cnt = 0; + + foreach (var entry in v16) + { + cnt++; + if ((int) entry[0] == 1) + Assert.AreEqual("1", ((V16) entry[1]).Name); + else + Assert.AreEqual("2", ((V16) entry[1]).Name); + } + + Assert.AreEqual(2, cnt); } /// @@ -383,4 +432,16 @@ private IgniteConfiguration GetConfiguration(string springConfigUrl) }; } } + + /// + /// Cache entry filter. + /// + class CacheEntryFilter : ICacheEntryFilter + { + /** */ + public bool Invoke(ICacheEntry entry) + { + return entry.Value.Name.Equals("1"); + } + } } diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Query/QueryCursorBase.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Query/QueryCursorBase.cs index 058027c1bf73a..3e6244a29806c 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Query/QueryCursorBase.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Query/QueryCursorBase.cs @@ -87,6 +87,11 @@ protected QueryCursorBase(Marshaller marsh, bool keepBinary, Func */ public IList GetAll() + { + return WithReg(() => GetAll0(), _keepBinary); + } + + private IList GetAll0() { if (_getAllCalled) throw new InvalidOperationException("Failed to get all entries because GetAll() " + @@ -257,6 +262,14 @@ protected IList ConvertGetAll(IBinaryStream stream) /// Stream. /// Result. protected T[] ConvertGetBatch(IBinaryStream stream) + { + return WithReg(() => ConvertGetBatch0(stream), _keepBinary); + } + + /// + /// Converter for GET_BATCH operation. + /// + private T[] ConvertGetBatch0(IBinaryStream stream) { var reader = _marsh.StartUnmarshal(stream, _keepBinary); @@ -326,5 +339,30 @@ private void ThrowIfDisposed() throw new ObjectDisposedException(GetType().Name, "Object has been disposed."); } } + + /// + /// Enables Register Same Java Type mode is keepBinary = false. + /// + /// Action. + /// Keep binary flag. + /// + private static TK WithReg(Func action, bool keepBinary) + { + if (keepBinary) + return action.Invoke(); + + bool locRegisterSameJavaType = Marshaller.RegisterSameJavaTypeTl.Value; + + Marshaller.RegisterSameJavaTypeTl.Value = true; + + try + { + return action.Invoke(); + } + finally + { + Marshaller.RegisterSameJavaTypeTl.Value = locRegisterSameJavaType; + } + } } } From a818bc9cae56c93465d0bca3aff2a72e195aeedc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B6=D0=B8=D0=BA=D0=BE=D0=B2=20=D0=9D=D0=B8=D0=BA?= =?UTF-8?q?=D0=BE=D0=BB=D0=B0=D0=B9=20=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B8=D1=87?= Date: Fri, 5 Mar 2021 12:24:32 +0300 Subject: [PATCH 07/15] IGN-2810 .Net: Enable RegisterSameJavaType mode for platform cache update Merge in OSPT/ignite from IGN-2810 to master Squashed commit of the following: commit 4c97a66ae0ed7f264b66e7f798bad548807b0503 Author: Nikolay Izhikov Date: Fri Mar 5 11:09:03 2021 +0300 IGN-2810 Fix. commit 2313da33c5d83a0185abb8cf8e66aa66ec4f42e2 Author: Nikolay Izhikov Date: Thu Mar 4 19:39:36 2021 +0300 IGN-2810 Fix. commit a19b9798c3902f5270e171def552152cca1c2a23 Author: Nikolay Izhikov Date: Wed Mar 3 22:48:29 2021 +0300 IGN-2810 .Net test to reproduce LoadCache issue. commit 875362740de6238ea20d25094f8f2e7e65eb79eb Author: Nikolay Izhikov Date: Wed Mar 3 22:30:37 2021 +0300 IGN-2810 .Net test to reproduce LoadCache issue. commit a041b1a1b7d1a5d2a12cbe8bfc1a9813e711a176 Author: Nikolay Izhikov Date: Wed Mar 3 21:58:30 2021 +0300 IGN-2810 .Net test to reproduce LoadCache issue. --- .../ignite/platform/V17CacheStoreFactory.java | 37 ++++ .../ignite/platform/V18CacheStoreFactory.java | 37 ++++ .../apache/ignite/platform/VCacheStore.java | 88 +++++++++ .../org/apache/ignite/platform/model/V16.java | 2 +- ...Apache.Ignite.Core.Tests.DotNetCore.csproj | 1 + .../Apache.Ignite.Core.Tests.csproj | 4 + .../Cache/LoadCacheTest.cs | 186 ++++++++++++++++++ .../Config/Cache/load-cache-config.xml | 69 +++++++ .../Services/Model.cs | 18 ++ .../Impl/Cache/Platform/PlatformCache.cs | 22 +++ 10 files changed, 463 insertions(+), 1 deletion(-) create mode 100644 modules/core/src/test/java/org/apache/ignite/platform/V17CacheStoreFactory.java create mode 100644 modules/core/src/test/java/org/apache/ignite/platform/V18CacheStoreFactory.java create mode 100644 modules/core/src/test/java/org/apache/ignite/platform/VCacheStore.java create mode 100644 modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/LoadCacheTest.cs create mode 100644 modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Cache/load-cache-config.xml diff --git a/modules/core/src/test/java/org/apache/ignite/platform/V17CacheStoreFactory.java b/modules/core/src/test/java/org/apache/ignite/platform/V17CacheStoreFactory.java new file mode 100644 index 0000000000000..8fcdf30507756 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/V17CacheStoreFactory.java @@ -0,0 +1,37 @@ +/* + * 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.platform; + +import javax.cache.configuration.Factory; + +/** + * Cache store factory for .Net tests. + * + * @param + * @param + */ +public class V17CacheStoreFactory implements Factory> { + /** */ + private static final long serialVersionUID = 0L; + + /** {@inheritDoc} */ + @Override public VCacheStore create() { + return new VCacheStore<>("apache.ignite.platform.model.V17"); + } +} + diff --git a/modules/core/src/test/java/org/apache/ignite/platform/V18CacheStoreFactory.java b/modules/core/src/test/java/org/apache/ignite/platform/V18CacheStoreFactory.java new file mode 100644 index 0000000000000..250ec85ad0fbc --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/V18CacheStoreFactory.java @@ -0,0 +1,37 @@ +/* + * 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.platform; + +import javax.cache.configuration.Factory; + +/** + * Cache store factory for .Net tests. + * + * @param + * @param + */ +public class V18CacheStoreFactory implements Factory> { + /** */ + private static final long serialVersionUID = 0L; + + /** {@inheritDoc} */ + @Override public VCacheStore create() { + return new VCacheStore<>("apache.ignite.platform.model.V18"); + } +} + diff --git a/modules/core/src/test/java/org/apache/ignite/platform/VCacheStore.java b/modules/core/src/test/java/org/apache/ignite/platform/VCacheStore.java new file mode 100644 index 0000000000000..71dde5cacbaec --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/VCacheStore.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.platform; + +import java.util.Collection; +import java.util.Map; +import javax.cache.Cache; +import javax.cache.integration.CacheLoaderException; +import javax.cache.integration.CacheWriterException; +import org.apache.ignite.Ignite; +import org.apache.ignite.cache.store.CacheStore; +import org.apache.ignite.lang.IgniteBiInClosure; +import org.apache.ignite.resources.IgniteInstanceResource; +import org.jetbrains.annotations.Nullable; + +public class VCacheStore implements CacheStore { + @IgniteInstanceResource + protected Ignite ignite; + + /** */ + private final String typeName; + + /** */ + public VCacheStore(String typeName) { + this.typeName = typeName; + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + @Override public void loadCache(IgniteBiInClosure clo, @Nullable Object... args) throws CacheLoaderException { + Integer key = 1; + + clo.apply((K)key, (V)ignite.binary().builder(typeName) + .setField("id", key, Integer.class) + .setField("name", "v1", String.class) + .build()); + } + + /** {@inheritDoc} */ + @Override public void sessionEnd(boolean commit) throws CacheWriterException { + // No-op. + } + + /** {@inheritDoc} */ + @Override public V load(K k) throws CacheLoaderException { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @Override public Map loadAll(Iterable iterable) throws CacheLoaderException { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @Override public void write(Cache.Entry entry) throws CacheWriterException { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @Override public void writeAll(Collection> collection) throws CacheWriterException { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @Override public void delete(Object o) throws CacheWriterException { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @Override public void deleteAll(Collection collection) throws CacheWriterException { + throw new UnsupportedOperationException(); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/platform/model/V16.java b/modules/core/src/test/java/org/apache/ignite/platform/model/V16.java index bf70834d99ebc..014d7ec3bd5aa 100644 --- a/modules/core/src/test/java/org/apache/ignite/platform/model/V16.java +++ b/modules/core/src/test/java/org/apache/ignite/platform/model/V16.java @@ -17,7 +17,7 @@ package org.apache.ignite.platform.model; -/** Test V15 object. */ +/** Test V16 object. */ public class V16 { /** */ private final String name; diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.DotNetCore.csproj b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.DotNetCore.csproj index f32f5bcfc8db1..4bdf13610b85f 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.DotNetCore.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.DotNetCore.csproj @@ -93,6 +93,7 @@ + PreserveNewest diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj index b0154cfabe7da..9260f30f29e6d 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj @@ -323,6 +323,7 @@ + @@ -472,6 +473,9 @@ PreserveNewest Designer + + PreserveNewest + PreserveNewest diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/LoadCacheTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/LoadCacheTest.cs new file mode 100644 index 0000000000000..9e7739ef78481 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/LoadCacheTest.cs @@ -0,0 +1,186 @@ +/* + * 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. + */ + +namespace Apache.Ignite.Core.Tests.Cache +{ + using System; + using System.IO; + using System.Reflection; + using Apache.Ignite.Core.Binary; + using Apache.Ignite.Core.Cache; + using Apache.Ignite.Core.Cache.Configuration; + using Apache.Ignite.Platform.Model; + using NUnit.Framework; + + /// + /// Tests checks ability to execute loadCache method without explicit registration of binary type. + /// + public class LoadCacheTest + { + /** */ + private IIgnite _grid1; + + /** */ + private IIgnite _client; + + [TestFixtureTearDown] + public void FixtureTearDown() + { + StopGrids(); + } + + /// + /// Executes before each test. + /// + [SetUp] + public void SetUp() + { + StartGrids(); + } + + /// + /// Executes after each test. + /// + [TearDown] + public void TearDown() + { + try + { + TestUtils.AssertHandleRegistryIsEmpty(1000, _grid1); + } + catch (Exception) + { + // Restart grids to cleanup + StopGrids(); + + throw; + } + finally + { + if (TestContext.CurrentContext.Test.Name.StartsWith("TestEventTypes")) + StopGrids(); // clean events for other tests + } + } + + /// + /// Starts the grids. + /// + private void StartGrids() + { + if (_grid1 != null) + return; + + var path = Path.Combine("Config", "Cache", "load-cache-config.xml"); + + _grid1 = Ignition.Start(GetConfiguration(path)); + + var clientWorkDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + "client_work"); + + _client = Ignition.Start(new IgniteConfiguration(TestUtils.GetTestConfiguration()) + { + WorkDirectory = clientWorkDir, + ClientMode = true, + IgniteInstanceName = "client", + BinaryConfiguration = new BinaryConfiguration + { + NameMapper = new BinaryBasicNameMapper {NamespaceToLower = true} + } + }); + } + + /// + /// Gets the Ignite configuration. + /// + private IgniteConfiguration GetConfiguration(string springConfigUrl) + { + springConfigUrl = ReplaceFooterSetting(springConfigUrl); + + return new IgniteConfiguration(TestUtils.GetTestConfiguration()) + { + IgniteInstanceName = "server", + SpringConfigUrl = springConfigUrl, + BinaryConfiguration = new BinaryConfiguration + { + NameMapper = new BinaryBasicNameMapper {NamespaceToLower = true} + } + }; + } + + /// + /// Replaces the footer setting. + /// + internal static string ReplaceFooterSetting(string path) + { + var text = File.ReadAllText(path).Replace( + "property name=\"compactFooter\" value=\"true\"", + "property name=\"compactFooter\" value=\"false\""); + + path += "_fullFooter"; + + File.WriteAllText(path, text); + + Assert.IsTrue(File.Exists(path)); + + return path; + } + + /// + /// Stops the grids. + /// + private void StopGrids() + { + _grid1 = null; + + Ignition.StopAll(true); + } + + [Test] + public void LoadCacheOnServer() + { + var cache = _grid1.GetCache("V17"); + + cache.LoadCache(null); + + var v = cache.LocalPeek(1, CachePeekMode.Platform); + + Assert.AreEqual(1, v.Id); + Assert.AreEqual("v1", v.Name); + } + + [Test] + public void LoadCacheOnClient() + { + var cache = _client.GetOrCreateNearCache( + "V18", + new NearCacheConfiguration(), + new PlatformCacheConfiguration + { + KeyTypeName = typeof(int).FullName, + ValueTypeName = typeof(V18).FullName + } + ); + + cache.LoadCache(null); + + var v = cache.Get(1); + + Assert.AreEqual(1, v.Id); + Assert.AreEqual("v1", v.Name); + } + } +} diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Cache/load-cache-config.xml b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Cache/load-cache-config.xml new file mode 100644 index 0000000000000..41f97284803f5 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Cache/load-cache-config.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 127.0.0.1:47500 + + + + + + + + diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/Model.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/Model.cs index 63315c3c696af..efdcc11af0bbd 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/Model.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/Model.cs @@ -249,4 +249,22 @@ public class V15 { public String Name { get; set; } } /// A class is a clone of Java class V16 with the same namespace. /// public class V16 { public String Name { get; set; } } + + /// + /// V17. + /// + public class V17 + { + public int Id { get; set; } + public String Name { get; set; } + } + + /// + /// V18. + /// + public class V18 + { + public int Id { get; set; } + public String Name { get; set; } + } } diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Platform/PlatformCache.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Platform/PlatformCache.cs index c7bb09fafe522..7de9cef4b79b3 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Platform/PlatformCache.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Platform/PlatformCache.cs @@ -127,6 +127,28 @@ public int GetSize(int? partition) /** */ public void Update(IBinaryStream stream, Marshaller marshaller) + { + if (_keepBinary) + Update0(stream, marshaller); + + bool locRegisterSameJavaType = Marshaller.RegisterSameJavaTypeTl.Value; + + Marshaller.RegisterSameJavaTypeTl.Value = true; + + try + { + Update0(stream, marshaller); + } + finally + { + Marshaller.RegisterSameJavaTypeTl.Value = locRegisterSameJavaType; + } + } + + /// + /// Updates entry in platform cache. + /// + private void Update0(IBinaryStream stream, Marshaller marshaller) { Debug.Assert(stream != null); Debug.Assert(marshaller != null); From f1e280ca9b6f2e786af91ced0931096cdce4c45c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A8=D0=B8=D1=88=D0=BA=D0=BE=D0=B2=20=D0=98=D0=BB=D1=8C?= =?UTF-8?q?=D1=8F=20=D0=92=D0=B0=D0=BB=D0=B5=D1=80=D1=8C=D0=B5=D0=B2=D0=B8?= =?UTF-8?q?=D1=87?= Date: Wed, 17 Mar 2021 14:30:44 +0300 Subject: [PATCH 08/15] IGN-2851 Add thin client compatibility for 4.281.3 and 4.290 (both server and client) Merge in OSPT/ignite from IGN-2851 to master Squashed commit of the following: commit e09af126a5438b4e2f0237739e96d0dae1c8318a Author: Shishkov Ilya Date: Tue Mar 16 15:23:18 2021 +0300 IGN-2581 Fix potential NPE during protocol versions comparison commit c562149112c96946287de7ab3265313503f836a5 Author: Shishkov Ilya Date: Tue Mar 16 15:13:06 2021 +0300 IGN-2581 Make ProtocolContext#ise281Compatible non-static commit 71def878633380ae1da663154521116147be1cda Author: Shishkov Ilya Date: Tue Mar 16 14:26:11 2021 +0300 IGN-2581 Make ProtocolContext#ise281Compatible non-static commit f23ef32089f53e6c05c1204a34bea2c1e35f9efc Author: Shishkov Ilya Date: Mon Mar 15 17:50:07 2021 +0300 IGN-2581 Add ThinClientPermissionCheckSecurityWith281CompatibilityTest to SecurityTestSuite commit 72de08b29680cdfaf0d8d6bc6a9bbf7eedcfc099 Author: Shishkov Ilya Date: Mon Mar 15 15:20:44 2021 +0300 IGN-2851 Fix code-style commit 128e98796278eb3924234c6486b4a63d96f484eb Author: Shishkov Ilya Date: Mon Mar 15 13:58:25 2021 +0300 IGN-2851 Add client compatibility flag to IgniteSystemProperties, add extra test commit ae3fc31dda92fea456d35c06830c2f55a6bb7006 Author: Shishkov Ilya Date: Mon Mar 15 12:09:48 2021 +0300 IGN-2851 Replace ClientProtocolContext#setIse281Compatible() to constructor parameter commit 2bdc44bb9cec9a74f928573be8b1df9cbf29c1d7 Author: Shishkov Ilya Date: Sat Mar 13 11:45:25 2021 +0300 IGN-2851 Fix backward compatibility of 4.290 client with 4.281.3 server commit ab7d5158cb9531b8d9b424c4e50a5972124e2036 Author: Shishkov Ilya Date: Fri Mar 12 10:14:08 2021 +0300 IGN-2851 Fix backward compatibility of 4.290 server with 4.281.3 thin client --- .../apache/ignite/IgniteSystemProperties.java | 10 ++++++ .../internal/client/thin/ProtocolContext.java | 29 ++++++++++++++++ .../client/thin/TcpClientChannel.java | 29 +++++++++++----- .../client/ClientConnectionContext.java | 21 +++++++++--- .../client/ClientProtocolContext.java | 19 +++++++++++ .../platform/client/ClientRequestHandler.java | 2 +- ...CheckSecurityWith281CompatibilityTest.java | 33 +++++++++++++++++++ .../ignite/testsuites/SecurityTestSuite.java | 2 ++ 8 files changed, 132 insertions(+), 13 deletions(-) create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/client/ThinClientPermissionCheckSecurityWith281CompatibilityTest.java 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 64d4ac7b544d2..22b726aa76aea 100644 --- a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java +++ b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java @@ -2012,6 +2012,16 @@ public final class IgniteSystemProperties { "stopped when the threshold is exceeded", type = Integer.class, defaults = "" + DFLT_CACHED_STRINGS_THRESHOLD) public static final String IGNITE_PERF_STAT_CACHED_STRINGS_THRESHOLD = "IGNITE_PERF_STAT_CACHED_STRINGS_THRESHOLD"; + /** + * Flag for compatibility of Ignite SE 4.290+ thin clients with Ignite SE 4.280/4.281 servers. + * NOTE: in order to enable client compatibility mode, this option must be set to true only + * on the thin client side. Default value is false. + */ + @SystemProperty(value = "Flag for compatibility of Ignite SE 4.290+ thin clients with " + + "Ignite SE 4.280/4.281 servers. In order to enable client compatibility mode, this option must be set to " + + "'true' only on the thin client side", defaults = "false") + public static final String IGNITE_SE_281_THIN_CLIENT_COMPATIBLE = "IGNITE_SE_281_THIN_CLIENT_COMPATIBLE"; + /** * Enforces singleton. */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ProtocolContext.java b/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ProtocolContext.java index ec8fb6e2f51bf..749cec4413b35 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ProtocolContext.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ProtocolContext.java @@ -18,8 +18,11 @@ package org.apache.ignite.internal.client.thin; import java.util.EnumSet; +import org.apache.ignite.IgniteSystemProperties; import org.apache.ignite.client.ClientFeatureNotSupportedByServerException; +import static org.apache.ignite.IgniteSystemProperties.IGNITE_SE_281_THIN_CLIENT_COMPATIBLE; + /** * Protocol Context. */ @@ -30,13 +33,26 @@ public class ProtocolContext { /** Features. */ private final EnumSet features; + /** */ + private final boolean ise281Compatible; + /** * @param ver Protocol version. * @param features Supported features. */ public ProtocolContext(ProtocolVersion ver, EnumSet features) { + this(ver, features, false); + } + + /** + * @param ver Protocol version. + * @param features Supported features. + * @param ise281Compatible Ignite SE 4.281 compatibility flag. + */ + public ProtocolContext(ProtocolVersion ver, EnumSet features, boolean ise281Compatible) { this.ver = ver; this.features = features != null ? features : EnumSet.noneOf(ProtocolBitmaskFeature.class); + this.ise281Compatible = ise281Compatible; } /** @@ -87,4 +103,17 @@ public ProtocolVersion version() { public static boolean isFeatureSupported(ProtocolVersion ver, ProtocolVersionFeature feature) { return ver.compareTo(feature.verIntroduced()) >= 0; } + + /** */ + public boolean isIse281Compatible() { + return ise281Compatible; + } + + /** + * @param ver Protocol version. + */ + public static boolean isIse281Compatible(ProtocolVersion ver) { + return IgniteSystemProperties.getBoolean(IGNITE_SE_281_THIN_CLIENT_COMPATIBLE, false) && + ProtocolVersion.V1_7_0.equals(ver); + } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/client/thin/TcpClientChannel.java b/modules/core/src/main/java/org/apache/ignite/internal/client/thin/TcpClientChannel.java index 4246b0788b02e..7538187e12340 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/client/thin/TcpClientChannel.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/client/thin/TcpClientChannel.java @@ -588,7 +588,7 @@ private void handshakeReq(ProtocolVersion proposedVer, String user, String pwd, writer.writeByte(ClientListenerNioListener.THIN_CLIENT); - if (protocolCtx.isFeatureSupported(BITMAP_FEATURES)) { + if (protocolCtx.isFeatureSupported(BITMAP_FEATURES) && !protocolCtx.isIse281Compatible()) { byte[] features = ProtocolBitmaskFeature.featuresAsBytes(protocolCtx.features()); writer.writeByteArray(features); } @@ -615,10 +615,17 @@ private void handshakeReq(ProtocolVersion proposedVer, String user, String pwd, */ private ProtocolContext protocolContextFromVersion(ProtocolVersion ver) { EnumSet features = null; - if (ProtocolContext.isFeatureSupported(ver, BITMAP_FEATURES)) - features = ProtocolBitmaskFeature.allFeaturesAsEnumSet(); - return new ProtocolContext(ver, features); + final boolean isIse281Compatible = ProtocolContext.isIse281Compatible(ver); + + if (ProtocolContext.isFeatureSupported(ver, BITMAP_FEATURES)) { + if (isIse281Compatible) + features = EnumSet.of(USER_ATTRIBUTES); + else + features = ProtocolBitmaskFeature.allFeaturesAsEnumSet(); + } + + return new ProtocolContext(ver, features, isIse281Compatible); } /** Receive and handle handshake response. */ @@ -630,12 +637,18 @@ private void handshakeRes(ByteBuffer buf, ProtocolVersion proposedVer, String us boolean success = res.readBoolean(); if (success) { - byte[] features = EMPTY_BYTES; + EnumSet features = null; - if (ProtocolContext.isFeatureSupported(proposedVer, BITMAP_FEATURES)) - features = reader.readByteArray(); + final boolean ise281Compatible = ProtocolContext.isIse281Compatible(proposedVer); + + if (ProtocolContext.isFeatureSupported(proposedVer, BITMAP_FEATURES)) { + if (ise281Compatible) + features = EnumSet.of(USER_ATTRIBUTES); + else + features = ProtocolBitmaskFeature.enumSet(reader.readByteArray()); + } - protocolCtx = new ProtocolContext(proposedVer, ProtocolBitmaskFeature.enumSet(features)); + protocolCtx = new ProtocolContext(proposedVer, features, ise281Compatible); if (protocolCtx.isFeatureSupported(PARTITION_AWARENESS)) { // Reading server UUID diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientConnectionContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientConnectionContext.java index eb765bdf5edd1..a55e3450566b5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientConnectionContext.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientConnectionContext.java @@ -30,6 +30,8 @@ import org.apache.ignite.configuration.ThinClientConfiguration; import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.binary.BinaryReaderExImpl; +import org.apache.ignite.internal.binary.GridBinaryMarshaller; +import org.apache.ignite.internal.binary.streams.BinaryInputStream; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.odbc.ClientListenerAbstractConnectionContext; import org.apache.ignite.internal.processors.odbc.ClientListenerMessageParser; @@ -196,13 +198,24 @@ public ClientProtocolContext currentProtocolContext() { EnumSet features = null; + boolean ise281Compatible = false; if (ClientProtocolContext.isFeatureSupported(ver, BITMAP_FEATURES)) { - byte[] cliFeatures = reader.readByteArray(); - - features = ClientBitmaskFeature.enumSet(cliFeatures); + BinaryInputStream stream = reader.in(); + int initPos = stream.position(); + byte flag = stream.readByte(); + stream.position(initPos); + if (flag == GridBinaryMarshaller.BYTE_ARR) { + byte[] cliFeatures = reader.readByteArray(); + + features = ClientBitmaskFeature.enumSet(cliFeatures); + } + else { + features = EnumSet.of(USER_ATTRIBUTES); + ise281Compatible = true; + } } - currentProtocolContext = new ClientProtocolContext(ver, features); + currentProtocolContext = new ClientProtocolContext(ver, features, ise281Compatible); String user = null; String pwd = null; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientProtocolContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientProtocolContext.java index 51bf7b8405251..d2b66167ec8b7 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientProtocolContext.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientProtocolContext.java @@ -31,13 +31,27 @@ public class ClientProtocolContext { /** Features. */ private final EnumSet features; + /** */ + private boolean ise281Compatible; + /** * @param ver Protocol version. * @param features Supported features. */ public ClientProtocolContext(ClientListenerProtocolVersion ver, EnumSet features) { + this(ver, features, false); + } + + /** + * @param ver Protocol version. + * @param features Supported features. + * @param ise281Compatible Ignite SE 4.281.3 compatibility flag. + */ + public ClientProtocolContext(ClientListenerProtocolVersion ver, + EnumSet features, boolean ise281Compatible) { this.ver = ver; this.features = features != null ? features : EnumSet.noneOf(ClientBitmaskFeature.class); + this.ise281Compatible = ise281Compatible; } /** @@ -84,4 +98,9 @@ public ClientListenerProtocolVersion version() { public static boolean isFeatureSupported(ClientListenerProtocolVersion ver, ClientProtocolVersionFeature feature) { return ver.compareTo(feature.verIntroduced()) >= 0; } + + /** */ + public boolean isIse281Compatible() { + return ise281Compatible; + } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientRequestHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientRequestHandler.java index 55a151aa00660..f1a5f3dad4d1a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientRequestHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientRequestHandler.java @@ -116,7 +116,7 @@ public class ClientRequestHandler implements ClientListenerRequestHandler { @Override public void writeHandshake(BinaryWriterExImpl writer) { writer.writeBoolean(true); - if (protocolCtx.isFeatureSupported(BITMAP_FEATURES)) + if (protocolCtx.isFeatureSupported(BITMAP_FEATURES) && !protocolCtx.isIse281Compatible()) writer.writeByteArray(protocolCtx.featureBytes()); if (protocolCtx.isFeatureSupported(PARTITION_AWARENESS)) diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/client/ThinClientPermissionCheckSecurityWith281CompatibilityTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/client/ThinClientPermissionCheckSecurityWith281CompatibilityTest.java new file mode 100644 index 0000000000000..c60dd80ae98a5 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/client/ThinClientPermissionCheckSecurityWith281CompatibilityTest.java @@ -0,0 +1,33 @@ +/* + * 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 org.apache.ignite.testframework.junits.WithSystemProperty; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static org.apache.ignite.IgniteSystemProperties.IGNITE_SE_281_THIN_CLIENT_COMPATIBLE; + +/** + * Security tests for thin client with turned on ISE 4.281 compatibility mode. + */ +@RunWith(JUnit4.class) +@WithSystemProperty(key = IGNITE_SE_281_THIN_CLIENT_COMPATIBLE, value = "true") +public class ThinClientPermissionCheckSecurityWith281CompatibilityTest extends ThinClientPermissionCheckSecurityTest { + // NO-OP +} 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 index 2db8011370d58..eed89c7800067 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/SecurityTestSuite.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/SecurityTestSuite.java @@ -34,6 +34,7 @@ import org.apache.ignite.internal.processors.security.client.AttributeSecurityCheckTest; import org.apache.ignite.internal.processors.security.client.IgniteClientContainSubjectAddressTest; import org.apache.ignite.internal.processors.security.client.ThinClientPermissionCheckSecurityTest; +import org.apache.ignite.internal.processors.security.client.ThinClientPermissionCheckSecurityWith281CompatibilityTest; import org.apache.ignite.internal.processors.security.client.ThinClientPermissionCheckTest; import org.apache.ignite.internal.processors.security.client.ThinClientSecurityContextOnRemoteNodeTest; import org.apache.ignite.internal.processors.security.client.ThinClientSslPermissionCheckTest; @@ -84,6 +85,7 @@ ComputePermissionCheckTest.class, ThinClientPermissionCheckTest.class, ThinClientPermissionCheckSecurityTest.class, + ThinClientPermissionCheckSecurityWith281CompatibilityTest.class, ContinuousQueryPermissionCheckTest.class, IgniteClientContainSubjectAddressTest.class, SnapshotPermissionCheckTest.class, From ee621ec0e6d593651c88786f1ea3dd073ed47078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B6=D0=B8=D0=BA=D0=BE=D0=B2=20=D0=9D=D0=B8=D0=BA?= =?UTF-8?q?=D0=BE=D0=BB=D0=B0=D0=B9=20=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B8=D1=87?= Date: Fri, 2 Apr 2021 11:55:42 +0300 Subject: [PATCH 09/15] =?UTF-8?q?IGN-3030=20=D0=97=D0=B0=D0=BF=D1=83=D1=81?= =?UTF-8?q?=D0=BA=20ducktape=20=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20ISE.=20=D0=98=D1=81=D0=BA=D0=BB=D1=8E?= =?UTF-8?q?=D1=87=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BD=D0=B5=D0=BD=D1=83=D0=B6?= =?UTF-8?q?=D0=BD=D1=8B=D1=85=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merge in OSPT/ignite from IGN-3030 to master Squashed commit of the following: commit 354dd7beeef1b942f0991f00a6fee53cbdf3d78f Author: Nikolay Izhikov Date: Fri Apr 2 07:52:01 2021 +0300 IGN-3030 Скрипт запуска ducktape тестов для ISE. commit 4f8592a298af61297cd0f0f0d338f498b1c70e9a Author: Nikolay Izhikov Date: Fri Apr 2 07:49:11 2021 +0300 IGN-3030 Скрипт запуска ducktape тестов для ISE. commit ecff6c815ec24ffb7bd5663ec0ff804f2dc1374a Author: Nikolay Izhikov Date: Thu Apr 1 16:54:46 2021 +0300 IGN-3030 Скрипт запуска ducktape тестов для ISE. --- bin/include/build-classpath.sh | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/bin/include/build-classpath.sh b/bin/include/build-classpath.sh index dbcd81e24e861..a92d6a356356e 100644 --- a/bin/include/build-classpath.sh +++ b/bin/include/build-classpath.sh @@ -47,18 +47,24 @@ includeToClassPath() { for file in $1/* do - if [ -d ${file} ] && [ -d "${file}/target" ]; then - if [ -d "${file}/target/classes" ]; then - IGNITE_LIBS=${IGNITE_LIBS}${SEP}${file}/target/classes - fi + if [[ -z "${EXCLUDE_MODULES:-}" ]] || [[ ${EXCLUDE_MODULES:-} != *"`basename $file`"* ]]; then + if [ -d ${file} ] && [ -d "${file}/target" ]; then + if [ -d "${file}/target/classes" ]; then + IGNITE_LIBS=${IGNITE_LIBS}${SEP}${file}/target/classes + fi - if [ -d "${file}/target/test-classes" ]; then - IGNITE_LIBS=${IGNITE_LIBS}${SEP}${file}/target/test-classes - fi + if [[ -z "${EXCLUDE_TEST_CLASSES:-}" ]]; then + if [ -d "${file}/target/test-classes" ]; then + IGNITE_LIBS=${IGNITE_LIBS}${SEP}${file}/target/test-classes + fi + fi - if [ -d "${file}/target/libs" ]; then - IGNITE_LIBS=${IGNITE_LIBS}${SEP}${file}/target/libs/* - fi + if [ -d "${file}/target/libs" ]; then + IGNITE_LIBS=${IGNITE_LIBS}${SEP}${file}/target/libs/* + fi + fi + else + echo "$file excluded by EXCLUDE_MODULES settings" fi done From 23c8a9d869961d9381898e5da48ad11bc8870570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D1=83=D0=B7=D0=BD=D0=B5=D1=86=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=81=20=D0=93=D0=B5=D0=BD=D0=BD=D0=B0=D0=B4?= =?UTF-8?q?=D1=8C=D0=B5=D0=B2=D0=B8=D1=87?= Date: Fri, 13 Aug 2021 14:07:13 +0300 Subject: [PATCH 10/15] IGNITE-15099 Fix concurrent heartbeat update while in blocking section for system workers - Fixes #9259. Merge in OSPT/ignite from ign-3593 to maint/2110 Squashed commit of the following: commit 97c2ae029049c13f746eb5e7ad424a966ca00a4d Author: Aleksey Plekhanov Date: Fri Jul 16 09:32:54 2021 +0300 IGNITE-15099 Fix concurrent heartbeat update while in blocking section for system workers - Fixes #9259. Signed-off-by: Aleksey Plekhanov (cherry picked from commit a47ff44f40a1dbdeaa03289966ce8055e5b0127f) --- .../internal/util/worker/GridWorker.java | 18 ++++++- .../failure/SystemWorkersBlockingTest.java | 52 +++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/worker/GridWorker.java b/modules/core/src/main/java/org/apache/ignite/internal/util/worker/GridWorker.java index 5926b9ca3552d..615d5062a9439 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/worker/GridWorker.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/worker/GridWorker.java @@ -19,6 +19,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicLongFieldUpdater; import org.apache.ignite.IgniteInterruptedException; import org.apache.ignite.IgniteLogger; import org.apache.ignite.internal.IgniteInterruptedCheckedException; @@ -56,6 +57,10 @@ public abstract class GridWorker implements Runnable, WorkProgressDispatcher { /** Timestamp to be updated by this worker periodically to indicate it's up and running. */ private volatile long heartbeatTs; + /** Atomic field updater to change heartbeat. */ + private static final AtomicLongFieldUpdater HEARTBEAT_UPDATER = + AtomicLongFieldUpdater.newUpdater(GridWorker.class, "heartbeatTs"); + /** Mutex for finish awaiting. */ private final Object mux = new Object(); @@ -273,7 +278,16 @@ public boolean isDone() { /** {@inheritDoc} */ @Override public void updateHeartbeat() { - heartbeatTs = U.currentTimeMillis(); + long curTs = U.currentTimeMillis(); + long hbTs = heartbeatTs; + + // Avoid heartbeat update while in the blocking section. + while (hbTs < curTs) { + if (HEARTBEAT_UPDATER.compareAndSet(this, hbTs, curTs)) + return; + + hbTs = heartbeatTs; + } } /** {@inheritDoc} */ @@ -283,7 +297,7 @@ public boolean isDone() { /** {@inheritDoc} */ @Override public void blockingSectionEnd() { - updateHeartbeat(); + heartbeatTs = U.currentTimeMillis(); } /** Can be called from {@link #runner()} thread to perform idleness handling. */ diff --git a/modules/core/src/test/java/org/apache/ignite/failure/SystemWorkersBlockingTest.java b/modules/core/src/test/java/org/apache/ignite/failure/SystemWorkersBlockingTest.java index ccfc50750d6b7..57495daec0a7a 100644 --- a/modules/core/src/test/java/org/apache/ignite/failure/SystemWorkersBlockingTest.java +++ b/modules/core/src/test/java/org/apache/ignite/failure/SystemWorkersBlockingTest.java @@ -30,6 +30,7 @@ import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.IgniteInterruptedCheckedException; +import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.internal.util.worker.GridWorker; import org.apache.ignite.internal.worker.WorkersRegistry; import org.apache.ignite.testframework.GridTestUtils; @@ -126,6 +127,57 @@ public void testBlockingWorker() throws Exception { e -> LatchingGridWorker.class.getName().equals(e.getClassName()))); } + /** + * @throws Exception If failed. + */ + @Test + public void testBlockingSection() throws Exception { + IgniteEx ignite = startGrid(0); + + CountDownLatch startLatch = new CountDownLatch(1); + CountDownLatch blockingSectionLatch = new CountDownLatch(1); + CountDownLatch endLatch = new CountDownLatch(1); + + GridWorker worker = new GridWorker(ignite.name(), "test-worker", log) { + @Override protected void body() { + blockingSectionBegin(); + + try { + startLatch.countDown(); + + blockingSectionLatch.await(); + } + catch (Exception ignore) { + // No-op. + } + finally { + blockingSectionEnd(); + + endLatch.countDown(); + } + } + }; + + runWorker(worker); + + ignite.context().workersRegistry().register(worker); + + startLatch.await(); + + // Check that concurrent heartbeat update doesn't affect the blocking section. + worker.updateHeartbeat(); + + Thread.sleep(2 * SYSTEM_WORKER_BLOCKED_TIMEOUT); + + blockingSectionLatch.countDown(); + + endLatch.await(); + + assertNull(failureError.get()); + + assertTrue(worker.heartbeatTs() <= U.currentTimeMillis()); + } + /** * Tests that repeatedly calling {@link WorkersRegistry#onIdle} in single registered {@link GridWorker} * doesn't lead to infinite loop. From aac933f1c117fdee35e78c75f374c7a97cbf9fdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B6=D0=B8=D0=BA=D0=BE=D0=B2=20=D0=9D=D0=B8=D0=BA?= =?UTF-8?q?=D0=BE=D0=BB=D0=B0=D0=B9=20=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B8=D1=87?= Date: Mon, 27 Sep 2021 09:10:49 +0300 Subject: [PATCH 11/15] IGNITE-14292 Change permissions required to create/destroy caches in GridRestProcessor (#9098) Merge in OSPT/ignite from IGNITE-14292_2110 to maint/2110 Squashed commit of the following: commit 2fb4b531cb94529be41e0294872acb3f35c0c23f Author: Sergei Ryzhov Date: Fri Sep 24 20:22:50 2021 +0300 IGNITE-14292 Change permissions required to create/destroy caches in GridRestProcessor (#9098) (cherry picked from commit 0d711422edaf2971f3990316e22121be043b8c30) --- .../processors/rest/GridRestProcessor.java | 7 +- .../protocols/http/jetty/GridRestSuite.java | 1 + .../jetty/RestProcessorAuthorizationTest.java | 139 ++++++++++++++++++ 3 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 modules/rest-http/src/test/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/RestProcessorAuthorizationTest.java 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 4df9e31517d9f..e8add311a06f6 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 @@ -885,8 +885,13 @@ private void authorize(GridRestRequest req) throws SecurityException { break; case GET_OR_CREATE_CACHE: + perm = SecurityPermission.CACHE_CREATE; + name = ((GridRestCacheRequest)req).cacheName(); + + break; + case DESTROY_CACHE: - perm = SecurityPermission.ADMIN_CACHE; + perm = SecurityPermission.CACHE_DESTROY; name = ((GridRestCacheRequest)req).cacheName(); break; diff --git a/modules/rest-http/src/test/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridRestSuite.java b/modules/rest-http/src/test/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridRestSuite.java index 069726c1ec18a..06371c494a03f 100644 --- a/modules/rest-http/src/test/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridRestSuite.java +++ b/modules/rest-http/src/test/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridRestSuite.java @@ -24,6 +24,7 @@ */ @RunWith(Suite.class) @Suite.SuiteClasses({ + RestProcessorAuthorizationTest.class, RestSetupSimpleTest.class }) public class GridRestSuite { diff --git a/modules/rest-http/src/test/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/RestProcessorAuthorizationTest.java b/modules/rest-http/src/test/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/RestProcessorAuthorizationTest.java new file mode 100644 index 0000000000000..28281177bd0a0 --- /dev/null +++ b/modules/rest-http/src/test/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/RestProcessorAuthorizationTest.java @@ -0,0 +1,139 @@ +/* + * 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.rest.protocols.http.jetty; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.security.Permissions; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.apache.ignite.cluster.ClusterState; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.processors.rest.GridRestCommand; +import org.apache.ignite.internal.processors.security.GridSecurityProcessor; +import org.apache.ignite.internal.processors.security.SecurityContext; +import org.apache.ignite.internal.processors.security.client.CommonSecurityCheckTest; +import org.apache.ignite.internal.processors.security.impl.TestSecurityData; +import org.apache.ignite.internal.processors.security.impl.TestSecurityPluginProvider; +import org.apache.ignite.internal.processors.security.impl.TestSecurityProcessor; +import org.apache.ignite.internal.util.lang.GridTuple3; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.plugin.PluginProvider; +import org.apache.ignite.plugin.security.SecurityException; +import org.apache.ignite.plugin.security.SecurityPermission; +import org.junit.Test; + +import static org.apache.ignite.internal.processors.cache.CacheGetRemoveSkipStoreTest.TEST_CACHE; +import static org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.ALLOW_ALL; + +/** + * Tests REST processor authorization commands GET_OR_CREATE_CACHE / DESTROY_CACHE. + */ +public class RestProcessorAuthorizationTest extends CommonSecurityCheckTest { + /** */ + private static final String LOGIN = "login"; + + /** */ + private static final String PWD = "pwd"; + + /** */ + private final List> authorizationCtxList = new ArrayList<>(); + + /** {@inheritDoc} */ + @Override protected PluginProvider getPluginProvider(String name) { + return new TestSecurityPluginProvider( + name, + null, + ALLOW_ALL, + globalAuth, + clientData() + ) { + /** {@inheritDoc} */ + @Override protected GridSecurityProcessor securityProcessor(GridKernalContext ctx) { + return new TestSecurityProcessor( + ctx, + new TestSecurityData(login, pwd, perms, new Permissions()), + Arrays.asList(clientData), + globalAuth + ) { + /** {@inheritDoc} */ + @Override public void authorize( + String name, + SecurityPermission perm, + SecurityContext securityCtx + ) throws SecurityException { + authorizationCtxList.add(F.t(name, perm, securityCtx)); + + super.authorize(name, perm, securityCtx); + } + }; + } + }; + } + + /** @throws Exception if failed. */ + @Test + public void testCacheCreateDestroyPermission() throws Exception { + IgniteEx ignite = startGrid(0); + + ignite.cluster().state(ClusterState.ACTIVE); + + assertNull(ignite.cache(TEST_CACHE)); + + executeCommand(GridRestCommand.GET_OR_CREATE_CACHE, LOGIN, PWD); + + GridTuple3 ctx = authorizationCtxList.get(0); + + assertEquals(TEST_CACHE, ctx.get1()); + assertEquals(SecurityPermission.CACHE_CREATE, ctx.get2()); + assertEquals(LOGIN, ctx.get3().subject().login()); + + assertNotNull(ignite.cache(TEST_CACHE)); + + authorizationCtxList.clear(); + + executeCommand(GridRestCommand.DESTROY_CACHE, LOGIN, PWD); + + ctx = authorizationCtxList.get(0); + + assertEquals(TEST_CACHE, ctx.get1()); + assertEquals(SecurityPermission.CACHE_DESTROY, ctx.get2()); + assertEquals(LOGIN, ctx.get3().subject().login()); + + assertNull(ignite.cache(TEST_CACHE)); + } + + /** */ + private void executeCommand(GridRestCommand cmd, String login, String pwd) throws IOException { + String addr = "http://localhost:8080/ignite?cmd=" + cmd.key() + + "&cacheName=" + TEST_CACHE + + "&ignite.login=" + login + "&ignite.password=" + pwd; + + URL url = new URL(addr); + + URLConnection conn = url.openConnection(); + + conn.connect(); + + assertEquals(200, ((HttpURLConnection)conn).getResponseCode()); + } +} From 69b5f2aeb217cd59876620d8ac5ec52158a1c82b Mon Sep 17 00:00:00 2001 From: Mikhail Petrov <32207922+ololo3000@users.noreply.github.com> Date: Tue, 23 Nov 2021 15:59:24 +0300 Subject: [PATCH 12/15] IGNITE-15951 Fixes preconfigured service deployment authorization. (#9582) (cherry picked from commit 83b517afcd6b7f138b7a00f6e225e70f9f2d1ba1) --- .../service/IgniteServiceProcessor.java | 17 +- .../service/ServiceAuthorizationTest.java | 424 ++++++++++++++++++ .../ignite/testsuites/SecurityTestSuite.java | 2 + 3 files changed, 441 insertions(+), 2 deletions(-) create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/security/service/ServiceAuthorizationTest.java diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java index e3ad553720f38..63e7937078bdb 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java @@ -65,6 +65,7 @@ import org.apache.ignite.internal.processors.cluster.DiscoveryDataClusterState; import org.apache.ignite.internal.processors.cluster.IgniteChangeGlobalStateSupport; import org.apache.ignite.internal.processors.platform.services.PlatformService; +import org.apache.ignite.internal.processors.security.OperationSecurityContext; import org.apache.ignite.internal.util.future.GridCompoundFuture; import org.apache.ignite.internal.util.future.GridFinishedFuture; import org.apache.ignite.internal.util.future.GridFutureAdapter; @@ -76,6 +77,7 @@ import org.apache.ignite.lang.IgniteUuid; import org.apache.ignite.marshaller.Marshaller; import org.apache.ignite.marshaller.jdk.JdkMarshaller; +import org.apache.ignite.plugin.security.SecurityException; import org.apache.ignite.plugin.security.SecurityPermission; import org.apache.ignite.services.Service; import org.apache.ignite.services.ServiceConfiguration; @@ -95,6 +97,7 @@ import static org.apache.ignite.configuration.DeploymentMode.PRIVATE; import static org.apache.ignite.events.EventType.EVT_NODE_JOINED; import static org.apache.ignite.internal.GridComponent.DiscoveryDataExchangeType.SERVICE_PROC; +import static org.apache.ignite.plugin.security.SecurityPermission.SERVICE_DEPLOY; /** * Ignite service processor. @@ -370,6 +373,16 @@ private void cancelDeployedServices() { for (ServiceInfo desc : joinData.services()) { assert desc.topologySnapshot().isEmpty(); + try (OperationSecurityContext ignored = ctx.security().withContext(data.joiningNodeId())) { + if (checkPermissions(desc.name(), SERVICE_DEPLOY) != null) { + U.warn(log, "Failed to register service configuration received from joining node :" + + " [nodeId=" + data.joiningNodeId() + ", cfgName=" + desc.name() + "]." + + " Joining node is not authorized to deploy the service."); + + continue; + } + } + ServiceInfo oldDesc = registeredServices.get(desc.serviceId()); if (oldDesc != null) { // In case of a collision of IgniteUuid.randomUuid() (almost impossible case) @@ -586,8 +599,8 @@ private PreparedConfigurations prepareServiceConfigurations(Collecti err = e; } - if (err == null) - err = checkPermissions(cfg.getName(), SecurityPermission.SERVICE_DEPLOY); + if (err == null && (isLocalNodeCoordinator() || ctx.discovery().localJoinFuture().isDone())) + err = checkPermissions(cfg.getName(), SERVICE_DEPLOY); if (err == null) { try { diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/service/ServiceAuthorizationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/service/ServiceAuthorizationTest.java new file mode 100644 index 0000000000000..af5cbcb3418aa --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/service/ServiceAuthorizationTest.java @@ -0,0 +1,424 @@ +/* + * 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.service; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.function.Function; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteServices; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.processors.security.AbstractSecurityTest; +import org.apache.ignite.internal.processors.security.AbstractTestSecurityPluginProvider; +import org.apache.ignite.internal.processors.security.impl.TestSecurityPluginProvider; +import org.apache.ignite.internal.util.typedef.G; +import org.apache.ignite.internal.util.typedef.X; +import org.apache.ignite.plugin.security.SecurityException; +import org.apache.ignite.plugin.security.SecurityPermission; +import org.apache.ignite.services.Service; +import org.apache.ignite.services.ServiceConfiguration; +import org.apache.ignite.services.ServiceContext; +import org.apache.ignite.services.ServiceDeploymentException; +import org.apache.ignite.testframework.GridTestUtils.RunnableX; +import org.apache.ignite.testframework.ListeningTestLogger; +import org.apache.ignite.testframework.LogListener; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import static org.apache.ignite.plugin.security.SecurityPermission.CACHE_CREATE; +import static org.apache.ignite.plugin.security.SecurityPermission.JOIN_AS_SERVER; +import static org.apache.ignite.plugin.security.SecurityPermission.SERVICE_CANCEL; +import static org.apache.ignite.plugin.security.SecurityPermission.SERVICE_DEPLOY; +import static org.apache.ignite.plugin.security.SecurityPermission.SERVICE_INVOKE; +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.plugin.security.SecurityPermissionSetBuilder.create; +import static org.apache.ignite.testframework.GridTestUtils.assertThrowsAnyCause; +import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause; +import static org.apache.ignite.testframework.GridTestUtils.waitForCondition; +import static org.apache.ignite.testframework.LogListener.matches; + +/** Tests permissions that are required to perform service operations. */ +@RunWith(Parameterized.class) +public class ServiceAuthorizationTest extends AbstractSecurityTest { + /** Name of the test service.*/ + private static final String TEST_SERVICE_NAME = "test-service-name"; + + /** Error that occurs in case service deployment fails. */ + private static final String DEPLOYMENT_AUTHORIZATION_FAILED_ERR = + "Authorization failed [perm=SERVICE_DEPLOY, name=" + TEST_SERVICE_NAME; + + /** Index of the node that is allowed to perform test operation. */ + private static final int ALLOWED_NODE_IDX = 1; + + /** Index of the node that is forbidden to perform test operation. */ + private static final int FORBIDDEN_NODE_IDX = 2; + + /** Instance of the test logger to check logged messages. */ + private static ListeningTestLogger listeningLog; + + /** Whether a client node is an initiator of the test operations. */ + @Parameterized.Parameter() + public boolean isClient; + + /** */ + @Parameterized.Parameters(name = "isClient={0}") + public static Iterable data() { + return Arrays.asList(new Object[] {true}, new Object[] {false}); + } + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration( + String instanceName, + AbstractTestSecurityPluginProvider pluginProv + ) throws Exception { + return super.getConfiguration(instanceName, pluginProv) + .setGridLogger(listeningLog); + } + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + listeningLog = new ListeningTestLogger(log); + } + + /** {@inheritDoc} */ + @Override protected void beforeTest() throws Exception { + super.beforeTest(); + + startGridAllowAll(getTestIgniteInstanceName(0)); + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + super.afterTest(); + + stopAllGrids(); + } + + /** Tests that all service cancel calls require {@link SecurityPermission#SERVICE_CANCEL} permission. */ + @Test + public void testServiceCancel() throws Exception { + startGrid(configuration(ALLOWED_NODE_IDX, SERVICE_DEPLOY, SERVICE_INVOKE, SERVICE_CANCEL)); + startGrid(configuration(FORBIDDEN_NODE_IDX, SERVICE_DEPLOY, SERVICE_INVOKE)); + + checkCancel(srvcs -> srvcs.cancel(TEST_SERVICE_NAME)); + checkCancel(srvcs -> srvcs.cancelAsync(TEST_SERVICE_NAME).get()); + + checkCancel(srvcs -> srvcs.cancelAll(Collections.singleton(TEST_SERVICE_NAME))); + checkCancel(srvcs -> srvcs.cancelAllAsync(Collections.singleton(TEST_SERVICE_NAME)).get()); + + checkCancel(IgniteServices::cancelAll); + checkCancel(srvcs -> srvcs.cancelAllAsync().get()); + } + + /** Tests that all calls to obtain service instance require {@link SecurityPermission#SERVICE_INVOKE} permission. */ + @Test + public void testServiceInvoke() throws Exception { + startGrid(configuration(ALLOWED_NODE_IDX, SERVICE_DEPLOY, SERVICE_INVOKE)); + startGrid(configuration(FORBIDDEN_NODE_IDX, SERVICE_DEPLOY)); + + grid(ALLOWED_NODE_IDX).services().deploy(serviceConfiguration()); + + if (!isClient) { + checkInvoke(srvcs -> srvcs.service(TEST_SERVICE_NAME), false); + checkInvoke(srvcs -> srvcs.services(TEST_SERVICE_NAME), false); + } + + checkInvoke(srvcs -> srvcs.serviceProxy(TEST_SERVICE_NAME, TestService.class, false), true); + checkInvoke(srvcs -> srvcs.serviceProxy(TEST_SERVICE_NAME, TestService.class, false, getTestTimeout()), true); + } + + /** Tests that all service deploy calls require {@link SecurityPermission#SERVICE_DEPLOY} permission. */ + @Test + public void testServiceDeploy() throws Exception { + startGrid(configuration(ALLOWED_NODE_IDX, SERVICE_DEPLOY, SERVICE_INVOKE, SERVICE_CANCEL)); + startGrid(configuration(FORBIDDEN_NODE_IDX, SERVICE_INVOKE)); + + checkDeploy(srvcs -> srvcs.deploy(serviceConfiguration()), false); + checkDeploy(srvcs -> srvcs.deployAsync(serviceConfiguration()).get(), false); + + checkDeploy(srvcs -> srvcs.deployAll(Collections.singleton(serviceConfiguration())), false); + checkDeploy(srvcs -> srvcs.deployAllAsync(Collections.singleton(serviceConfiguration())).get(), false); + + checkDeploy(srvcs -> srvcs.deployMultiple(TEST_SERVICE_NAME, new TestServiceImpl(), isClient ? 1 : 3, 1), false); + checkDeploy(srvcs -> + srvcs.deployMultipleAsync(TEST_SERVICE_NAME, new TestServiceImpl(), isClient ? 1 : 3, 1).get(), + false + ); + + checkDeploy(srvcs -> srvcs.deployNodeSingleton(TEST_SERVICE_NAME, new TestServiceImpl()), false); + checkDeploy(srvcs -> srvcs.deployNodeSingletonAsync(TEST_SERVICE_NAME, new TestServiceImpl()).get(), false); + + checkDeploy(srvcs -> srvcs.deployClusterSingleton(TEST_SERVICE_NAME, new TestServiceImpl()), true); + checkDeploy(srvcs -> srvcs.deployClusterSingletonAsync(TEST_SERVICE_NAME, new TestServiceImpl()).get(), true); + + grid(0).createCache(DEFAULT_CACHE_NAME); + + int key = keyForNode(grid(0).affinity(DEFAULT_CACHE_NAME), new AtomicInteger(0), grid(0).cluster().localNode()); + + checkDeploy(srvcs -> + srvcs.deployKeyAffinitySingleton(TEST_SERVICE_NAME, new TestServiceImpl(), DEFAULT_CACHE_NAME, key), + true + ); + + checkDeploy(srvcs -> + srvcs.deployKeyAffinitySingletonAsync(TEST_SERVICE_NAME, new TestServiceImpl(), DEFAULT_CACHE_NAME, key).get(), + true + ); + } + + /** + * Tests that service deployment that was initiated during new node join process requires + * {@link SecurityPermission#SERVICE_DEPLOY} permission. + */ + @Test + public void testPreconfiguredServiceDeployment() throws Exception { + startClientAllowAll(getTestIgniteInstanceName(1)); + + LogListener srvcDeploymentFailedLogLsnr = matches(DEPLOYMENT_AUTHORIZATION_FAILED_ERR).times(2).build(); + + listeningLog.registerListener(srvcDeploymentFailedLogLsnr); + + startGrid(configuration(2, SERVICE_INVOKE).setServiceConfiguration(serviceConfiguration())); + + srvcDeploymentFailedLogLsnr.check(getTestTimeout()); + + checkServiceOnAllNodes(TEST_SERVICE_NAME, false); + + startGrid(configuration(3, SERVICE_DEPLOY, SERVICE_INVOKE).setServiceConfiguration(serviceConfiguration())); + + waitForCondition(() -> { + for (Ignite node : G.allGrids()) { + if (!node.cluster().localNode().isClient() && node.services().service(TEST_SERVICE_NAME) == null) + return false; + } + + return true; + }, getTestTimeout()); + + // Tests preconfigured service deployment on coordinator. + if (!isClient) { + stopAllGrids(); + + startGrid(configuration(0, SERVICE_DEPLOY, SERVICE_INVOKE).setServiceConfiguration(serviceConfiguration())); + + assertTrue(waitForCondition(() -> grid(0).services().service(TEST_SERVICE_NAME) != null, getTestTimeout())); + + stopGrid(0); + + srvcDeploymentFailedLogLsnr = matches(DEPLOYMENT_AUTHORIZATION_FAILED_ERR).times(1).build(); + + listeningLog.registerListener(srvcDeploymentFailedLogLsnr); + + startGrid(configuration(0, SERVICE_INVOKE).setServiceConfiguration(serviceConfiguration())); + + srvcDeploymentFailedLogLsnr.check(getTestTimeout()); + + checkServiceOnAllNodes(TEST_SERVICE_NAME, false); + } + } + + /** @return Test service configuration. */ + private ServiceConfiguration serviceConfiguration() { + ServiceConfiguration srvcCfg = new ServiceConfiguration(); + + srvcCfg.setMaxPerNodeCount(1); + srvcCfg.setName(TEST_SERVICE_NAME); + srvcCfg.setService(new TestServiceImpl()); + + return srvcCfg; + } + + /** @return Ignite node configuration. */ + private IgniteConfiguration configuration(int idx, SecurityPermission... perms) throws Exception { + String name = getTestIgniteInstanceName(idx); + + return getConfiguration( + name, + new TestSecurityPluginProvider( + name, + "", + create() + .defaultAllowAll(false) + .appendSystemPermissions(JOIN_AS_SERVER) + .appendCachePermissions(DEFAULT_CACHE_NAME, CACHE_CREATE) + .appendTaskPermissions( + "org.apache.ignite.internal.processors.affinity.GridAffinityUtils$AffinityJob", + TASK_EXECUTE, TASK_CANCEL) + .appendServicePermissions(TEST_SERVICE_NAME, perms) + .build(), + null, + false + ) + ).setClientMode(isClient); + } + + /** Checks that service with specified service name is deployed or not on all nodes. */ + private void checkServiceOnAllNodes(String name, boolean deployed) { + for (Ignite node : G.allGrids()) { + if (!node.cluster().localNode().isClient()) { + Object srvc = node.services().service(name); + + if (deployed) + assertNotNull(srvc); + else + assertNull(srvc); + } + } + } + + /** + * Checks that execution of the specified {@link Runnable} failed and that the exception was caused by the lack of + * the specified permission. + */ + private void checkFailed(SecurityPermission perm, RunnableX r) { + if (perm == SERVICE_DEPLOY) { + Throwable e = assertThrowsWithCause(r, ServiceDeploymentException.class); + + assertEquals(1, X.getSuppressedList(e).stream() + .filter(t -> + t.getMessage().contains("Authorization failed [perm=SERVICE_DEPLOY, name=" + TEST_SERVICE_NAME)) + .count()); + } + else { + assertThrowsAnyCause( + log, + () -> { + r.run(); + + return null; + }, + SecurityException.class, + "Authorization failed [perm=" + perm + ", name=" + TEST_SERVICE_NAME + ); + } + } + + /** + * Uses the specified consumer to perform a service cancellation operation on a node that has the required + * permissions to perform this operation and on a node that does not. And checks that in the second case operation + * is aborted. + */ + private void checkCancel(Consumer c) { + grid(ALLOWED_NODE_IDX).services().deploy(serviceConfiguration()); + + checkServiceOnAllNodes(TEST_SERVICE_NAME, true); + + checkFailed(SERVICE_CANCEL, () -> c.accept(grid(FORBIDDEN_NODE_IDX).services())); + + checkServiceOnAllNodes(TEST_SERVICE_NAME, true); + + c.accept(grid(ALLOWED_NODE_IDX).services()); + + checkServiceOnAllNodes(TEST_SERVICE_NAME, false); + } + + /** + * Uses the specified function to perform a service obtaining operation on a node that has the required + * permissions to perform this operation and on a node that does not. And checks that in the second case operation + * is aborted. Note that {@link SecurityPermission#SERVICE_INVOKE} is checked once before returning service + * instance to the user. + * + * @param f Function to perform a service obtaining operation. + * @param isProxy Whether invocation result is service proxy. + */ + private void checkInvoke(Function f, boolean isProxy) throws Exception { + checkFailed(SERVICE_INVOKE, () -> f.apply(grid(FORBIDDEN_NODE_IDX).services())); + + Object res = f.apply(grid(ALLOWED_NODE_IDX).services()); + + if (!isProxy) { + TestService srvc; + + if (res instanceof Collection) { + Collection srvcs = (Collection)res; + + assertFalse(srvcs.isEmpty()); + + srvc = srvcs.iterator().next(); + } + else { + assertTrue(res instanceof TestService); + + srvc = (TestService)res; + } + + assertTrue(srvc.doWork()); + } + else + assertTrue(((TestService)res).doWork()); + } + + /** + * Uses the specified consumer to perform a service deployment operation on a node that has the required + * permissions to perform this operation and on a node that does not. And checks that in the second case operation + * is aborted. + * + * @param c Consumer to perform a service deployment operation. + * @param isSingleton Whether deployed service is singleton. + */ + private void checkDeploy(Consumer c, boolean isSingleton) { + grid(ALLOWED_NODE_IDX).services().cancel(TEST_SERVICE_NAME); + + checkServiceOnAllNodes(TEST_SERVICE_NAME, false); + + checkFailed(SERVICE_DEPLOY, () -> c.accept(grid(FORBIDDEN_NODE_IDX).services())); + + checkServiceOnAllNodes(TEST_SERVICE_NAME, false); + + c.accept(grid(ALLOWED_NODE_IDX).services()); + + if (!isSingleton) + checkServiceOnAllNodes(TEST_SERVICE_NAME, true); + else + assertTrue(G.allGrids().stream().anyMatch(ignite -> ignite.services().service(TEST_SERVICE_NAME) != null)); + } + + /** Test service interface. */ + public static interface TestService extends Service { + /** Dummy test service method. */ + public boolean doWork(); + } + + /** Test service implementation. */ + public static class TestServiceImpl implements TestService { + /** {@inheritDoc} */ + @Override public boolean doWork() { + return true; + } + + /** {@inheritDoc} */ + @Override public void cancel(ServiceContext ctx) { + + } + + /** {@inheritDoc} */ + @Override public void init(ServiceContext ctx) throws Exception { + + } + + /** {@inheritDoc} */ + @Override public void execute(ServiceContext ctx) throws Exception { + + } + } +} 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 index eed89c7800067..ceaa8e4550500 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/SecurityTestSuite.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/SecurityTestSuite.java @@ -65,6 +65,7 @@ import org.apache.ignite.internal.processors.security.sandbox.SchedulerSandboxTest; import org.apache.ignite.internal.processors.security.sandbox.SecuritySubjectPermissionsTest; import org.apache.ignite.internal.processors.security.scheduler.SchedulerRemoteSecurityContextCheckTest; +import org.apache.ignite.internal.processors.security.service.ServiceAuthorizationTest; import org.apache.ignite.internal.processors.security.snapshot.SnapshotPermissionCheckTest; import org.apache.ignite.ssl.MultipleSSLContextsTest; import org.apache.ignite.tools.junit.JUnitTeamcityReporter; @@ -128,6 +129,7 @@ IgniteSecurityProcessorTest.class, MultipleSSLContextsTest.class, + ServiceAuthorizationTest.class, CacheCreateDestroyEventsTest.class, ActivateDeactivateClusterCacheEventTest.class, From c88d6995cf52b482d7be64b99245bfefb48713ad Mon Sep 17 00:00:00 2001 From: ibessonov Date: Tue, 23 Nov 2021 12:54:37 +0300 Subject: [PATCH 13/15] IGNITE-15767 Fixed spontaneous SocketTimeoutException in server socket accept (JDK-8247750). (#9498) (cherry picked from commit 7eb396c18db3b9ddf501f6554f9f7b5d330db0bc) --- .../ignite/internal/util/IgniteUtils.java | 23 +++++++++++++++++++ .../ipc/loopback/IpcServerTcpEndpoint.java | 3 ++- .../shmem/IpcSharedMemoryServerEndpoint.java | 3 ++- .../ignite/spi/discovery/tcp/ServerImpl.java | 2 +- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java index 3ddea5d081b3f..2a78ee1db6d37 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java @@ -65,8 +65,10 @@ import java.net.InetSocketAddress; import java.net.MalformedURLException; import java.net.NetworkInterface; +import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; +import java.net.SocketTimeoutException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; @@ -12106,4 +12108,25 @@ public static long uncompressedSize(File zip) throws IOException { return size; } } + + /** + * Invokes {@link ServerSocket#accept()} method on the passed server socked, working around the + * https://bugs.openjdk.java.net/browse/JDK-8247750 in the process. + * + * @param srvrSock Server socket. + * @return New socket. + * @throws IOException If an I/O error occurs when waiting for a connection. + * @see ServerSocket#accept() + */ + public static Socket acceptServerSocket(ServerSocket srvrSock) throws IOException { + while (true) { + try { + return srvrSock.accept(); + } + catch (SocketTimeoutException e) { + if (srvrSock.getSoTimeout() > 0) + throw e; + } + } + } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/ipc/loopback/IpcServerTcpEndpoint.java b/modules/core/src/main/java/org/apache/ignite/internal/util/ipc/loopback/IpcServerTcpEndpoint.java index 2b193eebd0d9e..b4e9965f5ebc1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/ipc/loopback/IpcServerTcpEndpoint.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/ipc/loopback/IpcServerTcpEndpoint.java @@ -24,6 +24,7 @@ import java.util.Map; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteLogger; +import org.apache.ignite.internal.util.IgniteUtils; import org.apache.ignite.internal.util.ipc.IpcEndpoint; import org.apache.ignite.internal.util.ipc.IpcEndpointBindException; import org.apache.ignite.internal.util.ipc.IpcServerEndpoint; @@ -81,7 +82,7 @@ public class IpcServerTcpEndpoint implements IpcServerEndpoint { /** {@inheritDoc} */ @Override public IpcEndpoint accept() throws IgniteCheckedException { try { - Socket sock = srvSock.accept(); + Socket sock = IgniteUtils.acceptServerSocket(srvSock); return new IpcClientTcpEndpoint(sock); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/ipc/shmem/IpcSharedMemoryServerEndpoint.java b/modules/core/src/main/java/org/apache/ignite/internal/util/ipc/shmem/IpcSharedMemoryServerEndpoint.java index b85228c0c4668..2b0ff94cf3253 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/ipc/shmem/IpcSharedMemoryServerEndpoint.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/ipc/shmem/IpcSharedMemoryServerEndpoint.java @@ -40,6 +40,7 @@ import org.apache.ignite.internal.IgniteInterruptedCheckedException; import org.apache.ignite.internal.processors.resource.GridResourceProcessor; import org.apache.ignite.internal.util.GridConcurrentHashSet; +import org.apache.ignite.internal.util.IgniteUtils; import org.apache.ignite.internal.util.ipc.IpcEndpoint; import org.apache.ignite.internal.util.ipc.IpcEndpointBindException; import org.apache.ignite.internal.util.ipc.IpcServerEndpoint; @@ -225,7 +226,7 @@ public void omitOutOfResourcesWarning(boolean omitOutOfResourcesWarn) { boolean accepted = false; try { - sock = srvSock.accept(); + sock = IgniteUtils.acceptServerSocket(srvSock); accepted = 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 7fe93d4e5dd06..e1591e5d85270 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 @@ -6662,7 +6662,7 @@ private class TcpServer extends GridWorker { blockingSectionBegin(); try { - sock = srvrSock.accept(); + sock = IgniteUtils.acceptServerSocket(srvrSock); } finally { blockingSectionEnd(); From 20f24e48c89d5dd4da12cb389ffcf6911b82e6a4 Mon Sep 17 00:00:00 2001 From: Nikolay Date: Mon, 22 Nov 2021 11:03:06 +0300 Subject: [PATCH 14/15] IGNITE-15924 Thin client cache for OptimizedMarshaller class names (#9576) (cherry picked from commit 620ee3f26832b092e41bcaec6fbc992c040d2463) --- .../internal/client/thin/TcpIgniteClient.java | 3 + .../OptimizedMarshallerClassesCachedTest.java | 86 +++++++++++++++++++ .../apache/ignite/client/ClientTestSuite.java | 4 +- 3 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/client/thin/OptimizedMarshallerClassesCachedTest.java diff --git a/modules/core/src/main/java/org/apache/ignite/internal/client/thin/TcpIgniteClient.java b/modules/core/src/main/java/org/apache/ignite/internal/client/thin/TcpIgniteClient.java index 617948d0fdd27..b640d589aac94 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/client/thin/TcpIgniteClient.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/client/thin/TcpIgniteClient.java @@ -600,6 +600,9 @@ public ClientMarshallerContext() { catch (ClientException e) { throw new IgniteCheckedException(e); } + + if (clsName != null) + cache.putIfAbsent(typeId, clsName); } if (clsName == null) diff --git a/modules/core/src/test/java/org/apache/ignite/internal/client/thin/OptimizedMarshallerClassesCachedTest.java b/modules/core/src/test/java/org/apache/ignite/internal/client/thin/OptimizedMarshallerClassesCachedTest.java new file mode 100644 index 0000000000000..e3a7cd51a0990 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/client/thin/OptimizedMarshallerClassesCachedTest.java @@ -0,0 +1,86 @@ +/* + * 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.client.thin; + +import java.time.LocalDateTime; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.function.Function; +import org.apache.ignite.Ignite; +import org.apache.ignite.client.ClientException; +import org.apache.ignite.client.Config; +import org.apache.ignite.client.IgniteClient; +import org.apache.ignite.configuration.ClientConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.marshaller.optimized.OptimizedMarshaller; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.junit.Test; + +/** */ +public class OptimizedMarshallerClassesCachedTest extends GridCommonAbstractTest { + /** */ + private final AtomicInteger cnt = new AtomicInteger(); + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + return super.getConfiguration(igniteInstanceName); + } + + /** Test check that meta for classes serialized by {@link OptimizedMarshaller} are cached on client. */ + @Test + public void testLocalDateTimeMetaCached() throws Exception { + try (Ignite srv = startGrid(0)) { + srv.getOrCreateCache(Config.DEFAULT_CACHE_NAME).put(1, LocalDateTime.now()); + + IgniteClient cli = new TcpIgniteClient((cfg0, hnd) -> new TcpClientChannel(cfg0, hnd) { + @Override public T service( + ClientOperation op, + Consumer payloadWriter, + Function payloadReader + ) throws ClientException { + if (op == ClientOperation.GET_BINARY_TYPE_NAME) + cnt.incrementAndGet(); + + return super.service(op, payloadWriter, payloadReader); + } + + @Override public CompletableFuture serviceAsync( + ClientOperation op, + Consumer payloadWriter, + Function payloadReader + ) { + if (op == ClientOperation.GET_BINARY_TYPE_NAME) + cnt.incrementAndGet(); + + return super.serviceAsync(op, payloadWriter, payloadReader); + } + }, new ClientConfiguration().setAddresses(Config.SERVER)); + + try { + cli.cache(Config.DEFAULT_CACHE_NAME).get(1); + cli.cache(Config.DEFAULT_CACHE_NAME).get(1); + } + finally { + cli.close(); + } + + assertEquals(1, cnt.get()); + } + } +} diff --git a/modules/indexing/src/test/java/org/apache/ignite/client/ClientTestSuite.java b/modules/indexing/src/test/java/org/apache/ignite/client/ClientTestSuite.java index 85255ce0dc3d5..7da1a83d0ba24 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/client/ClientTestSuite.java +++ b/modules/indexing/src/test/java/org/apache/ignite/client/ClientTestSuite.java @@ -22,6 +22,7 @@ import org.apache.ignite.internal.client.thin.ClusterApiTest; import org.apache.ignite.internal.client.thin.ClusterGroupTest; import org.apache.ignite.internal.client.thin.ComputeTaskTest; +import org.apache.ignite.internal.client.thin.OptimizedMarshallerClassesCachedTest; import org.apache.ignite.internal.client.thin.ReliableChannelTest; import org.apache.ignite.internal.client.thin.ServicesTest; import org.apache.ignite.internal.client.thin.ThinClientPartitionAwarenessDiscoveryTest; @@ -64,7 +65,8 @@ ThinClientPartitionAwarenessDiscoveryTest.class, ReliableChannelTest.class, CacheAsyncTest.class, - TimeoutTest.class + TimeoutTest.class, + OptimizedMarshallerClassesCachedTest.class, }) public class ClientTestSuite { // No-op. From fe59797b7937214c4d39335fdd401acf1698b93b Mon Sep 17 00:00:00 2001 From: Maksim Timonin Date: Fri, 19 Nov 2021 00:18:49 +0300 Subject: [PATCH 15/15] IGNITE-15781 GridDhtPartitionMap#get use primitive int (#9518) (cherry picked from commit 5cebca6420a9bbad02495411354e897da39abe52) --- .../cache/distributed/dht/preloader/GridDhtPartitionMap.java | 4 ++-- .../apache/ignite/internal/util/GridPartitionStateMap.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionMap.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionMap.java index 5cbf61070d7f9..3cbf75767e7fa 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionMap.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionMap.java @@ -157,8 +157,8 @@ public boolean hasMovingPartitions() { * @param part Partition. * @return Partition state. */ - public GridDhtPartitionState get(Integer part) { - return map.get(part); + public GridDhtPartitionState get(int part) { + return map.state(part); } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/GridPartitionStateMap.java b/modules/core/src/main/java/org/apache/ignite/internal/util/GridPartitionStateMap.java index 5ae5c5cad0839..855d3c79ef4a5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/GridPartitionStateMap.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/GridPartitionStateMap.java @@ -215,7 +215,7 @@ private GridDhtPartitionState setState(int part, GridDhtPartitionState st) { } /** */ - private GridDhtPartitionState state(int part) { + public GridDhtPartitionState state(int part) { int off = part * BITS; int st = 0;