You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by pt...@apache.org on 2020/05/12 09:45:23 UTC
[ignite] branch master updated: IGNITE-12932 .NET: Add Thin Client
Discovery
This is an automated email from the ASF dual-hosted git repository.
ptupitsyn pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new 3cadf45 IGNITE-12932 .NET: Add Thin Client Discovery
3cadf45 is described below
commit 3cadf45eef31d31a23928aee6af508406c305e75
Author: Pavel Tupitsyn <pt...@apache.org>
AuthorDate: Tue May 12 12:45:04 2020 +0300
IGNITE-12932 .NET: Add Thin Client Discovery
Add thin client discovery: client retrieves a list of server nodes with client connector endpoints and keeps this list up to date by reacting to topology change notifications in response flags.
IEP: https://cwiki.apache.org/confluence/display/IGNITE/IEP-44%3A+Thin+client+cluster+discovery
---
.../platform/client/ClientBitmaskFeature.java | 5 +-
.../platform/client/ClientMessageParser.java | 17 +-
...ClientClusterGroupGetNodesEndpointsRequest.java | 50 +++
...lientClusterGroupGetNodesEndpointsResponse.java | 170 +++++++++
.../Apache.Ignite.Core.Tests.DotNetCore.csproj | 66 +++-
.../Common/TestUtils.DotNetCore.cs | 4 +-
.../Apache.Ignite.Core.Tests.csproj | 7 +-
.../Cache/Affinity/AffinityFunctionSpringTest.cs | 5 +-
.../Cache/Affinity/AffinityTest.cs | 3 +-
.../Cache/Query/Linq/CacheLinqTest.Misc.cs | 3 +-
.../Client/Cache/CacheTest.cs | 16 +
.../Client/Cache/CacheTestSsl.cs | 38 +-
.../Client/Cache/ClientCacheConfigurationTest.cs | 4 +-
.../Client/Cache/PartitionAwarenessTest.cs | 39 +-
.../Client/ClientConnectionTest.cs | 6 +-
.../Client/ClientFeaturesTest.cs | 86 +++++
.../Client/ClientOpExtensionsTest.cs | 59 ---
.../Client/ClientProtocolCompatibilityTest.cs | 11 +-
.../Client/ClientReconnectCompatibilityTest.cs | 5 +-
.../Client/ClientTestBase.cs | 37 +-
.../Client/Cluster/ClientClusterDiscoveryTests.cs | 176 +++++++++
.../Cluster/ClientClusterDiscoveryTestsBase.cs | 149 ++++++++
.../ClientClusterDiscoveryTestsBaselineTopology.cs | 74 ++++
.../ClientClusterDiscoveryTestsNoLocalhost.cs} | 29 +-
.../Cluster/ClientClusterDiscoveryTestsSsl.cs} | 29 +-
.../Apache.Ignite.Core/Apache.Ignite.Core.csproj | 8 +-
.../Client/Cache/CacheClientConfiguration.cs | 8 +-
.../IClientConnection.cs} | 37 +-
.../Apache.Ignite.Core/Client/IIgniteClient.cs | 6 +
.../Impl/Client/Cache/CacheClient.cs | 8 +-
.../Cache/ClientCacheConfigurationSerializer.cs | 29 +-
...VersionAttribute.cs => ClientBitmaskFeature.cs} | 31 +-
.../Impl/Client/ClientConnection.cs | 71 ++++
.../Impl/Client/ClientContextBase.cs | 14 +-
...entRequestContext.cs => ClientDiscoveryNode.cs} | 56 +--
.../Impl/Client/ClientFailoverSocket.cs | 395 +++++++++++++++++----
.../Impl/Client/ClientFeatures.cs | 227 ++++++++++++
.../Apache.Ignite.Core/Impl/Client/ClientOp.cs | 14 +-
.../Impl/Client/ClientOpExtensions.cs | 71 ----
.../Impl/Client/ClientRequestContext.cs | 6 +-
.../Impl/Client/ClientResponseContext.cs | 6 +-
.../Apache.Ignite.Core/Impl/Client/ClientSocket.cs | 65 ++--
.../Apache.Ignite.Core/Impl/Client/ClientUtils.cs | 58 ---
.../Apache.Ignite.Core/Impl/Client/Endpoint.cs | 43 ++-
.../Apache.Ignite.Core/Impl/Client/IgniteClient.cs | 17 +-
modules/platforms/dotnet/DEVNOTES.txt | 4 +-
46 files changed, 1714 insertions(+), 548 deletions(-)
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientBitmaskFeature.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientBitmaskFeature.java
index 57e314f..fc09214 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientBitmaskFeature.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientBitmaskFeature.java
@@ -31,7 +31,10 @@ public enum ClientBitmaskFeature implements ThinProtocolFeature {
EXECUTE_TASK_BY_NAME(1),
/** Cluster operations (state and WAL). */
- CLUSTER_API(2);
+ CLUSTER_API(2),
+
+ /** Client discovery. */
+ CLUSTER_GROUP_GET_NODES_ENDPOINTS(3);
/** */
private static final EnumSet<ClientBitmaskFeature> ALL_FEATURES_AS_ENUM_SET =
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientMessageParser.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientMessageParser.java
index 69e1e5f..37ef131 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientMessageParser.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientMessageParser.java
@@ -67,15 +67,16 @@ import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheRe
import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheScanQueryRequest;
import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheSqlFieldsQueryRequest;
import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheSqlQueryRequest;
-import org.apache.ignite.internal.processors.platform.client.compute.ClientExecuteTaskRequest;
-import org.apache.ignite.internal.processors.platform.client.tx.ClientTxEndRequest;
-import org.apache.ignite.internal.processors.platform.client.tx.ClientTxStartRequest;
import org.apache.ignite.internal.processors.platform.client.cluster.ClientClusterChangeStateRequest;
import org.apache.ignite.internal.processors.platform.client.cluster.ClientClusterGetStateRequest;
-import org.apache.ignite.internal.processors.platform.client.cluster.ClientClusterWalChangeStateRequest;
-import org.apache.ignite.internal.processors.platform.client.cluster.ClientClusterWalGetStateRequest;
import org.apache.ignite.internal.processors.platform.client.cluster.ClientClusterGroupGetNodeIdsRequest;
import org.apache.ignite.internal.processors.platform.client.cluster.ClientClusterGroupGetNodesDetailsRequest;
+import org.apache.ignite.internal.processors.platform.client.cluster.ClientClusterGroupGetNodesEndpointsRequest;
+import org.apache.ignite.internal.processors.platform.client.cluster.ClientClusterWalChangeStateRequest;
+import org.apache.ignite.internal.processors.platform.client.cluster.ClientClusterWalGetStateRequest;
+import org.apache.ignite.internal.processors.platform.client.compute.ClientExecuteTaskRequest;
+import org.apache.ignite.internal.processors.platform.client.tx.ClientTxEndRequest;
+import org.apache.ignite.internal.processors.platform.client.tx.ClientTxStartRequest;
/**
* Thin client message parser.
@@ -239,6 +240,9 @@ public class ClientMessageParser implements ClientListenerMessageParser {
/** */
private static final short OP_CLUSTER_GROUP_GET_NODE_INFO = 5101;
+ /** */
+ private static final short OP_CLUSTER_GROUP_GET_NODE_ENDPOINTS = 5102;
+
/* Compute operations. */
/** */
private static final short OP_COMPUTE_TASK_EXECUTE = 6000;
@@ -441,6 +445,9 @@ public class ClientMessageParser implements ClientListenerMessageParser {
case OP_CLUSTER_GROUP_GET_NODE_INFO:
return new ClientClusterGroupGetNodesDetailsRequest(reader);
+ case OP_CLUSTER_GROUP_GET_NODE_ENDPOINTS:
+ return new ClientClusterGroupGetNodesEndpointsRequest(reader);
+
case OP_COMPUTE_TASK_EXECUTE:
return new ClientExecuteTaskRequest(reader);
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cluster/ClientClusterGroupGetNodesEndpointsRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cluster/ClientClusterGroupGetNodesEndpointsRequest.java
new file mode 100644
index 0000000..9d889da
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cluster/ClientClusterGroupGetNodesEndpointsRequest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.platform.client.cluster;
+
+import org.apache.ignite.binary.BinaryRawReader;
+import org.apache.ignite.internal.processors.platform.client.ClientConnectionContext;
+import org.apache.ignite.internal.processors.platform.client.ClientRequest;
+import org.apache.ignite.internal.processors.platform.client.ClientResponse;
+
+/**
+ * Cluster group get nodes endpoints request.
+ */
+public class ClientClusterGroupGetNodesEndpointsRequest extends ClientRequest {
+ /** Start topology version. -1 for earliest. */
+ private final long startTopVer;
+
+ /** End topology version. -1 for latest. */
+ private final long endTopVer;
+
+ /**
+ * Constructor.
+ *
+ * @param reader Reader.
+ */
+ public ClientClusterGroupGetNodesEndpointsRequest(BinaryRawReader reader) {
+ super(reader);
+ startTopVer = reader.readLong();
+ endTopVer = reader.readLong();
+ }
+
+ /** {@inheritDoc} */
+ @Override public ClientResponse process(ClientConnectionContext ctx) {
+ return new ClientClusterGroupGetNodesEndpointsResponse(requestId(), startTopVer, endTopVer);
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cluster/ClientClusterGroupGetNodesEndpointsResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cluster/ClientClusterGroupGetNodesEndpointsResponse.java
new file mode 100644
index 0000000..204451f
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cluster/ClientClusterGroupGetNodesEndpointsResponse.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.platform.client.cluster;
+
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.internal.binary.BinaryRawWriterEx;
+import org.apache.ignite.internal.cluster.IgniteClusterEx;
+import org.apache.ignite.internal.processors.odbc.ClientListenerProcessor;
+import org.apache.ignite.internal.processors.platform.client.ClientConnectionContext;
+import org.apache.ignite.internal.processors.platform.client.ClientResponse;
+
+import java.util.*;
+
+/**
+ * Cluster group get nodes endpoints response.
+ */
+public class ClientClusterGroupGetNodesEndpointsResponse extends ClientResponse {
+ /** Indicates unknown topology version. */
+ private static final long UNKNOWN_TOP_VER = -1;
+
+ /** Start topology version. -1 for earliest. */
+ private final long startTopVer;
+
+ /** End topology version. -1 for latest. */
+ private final long endTopVer;
+
+ /**
+ * Constructor.
+ *
+ * @param reqId Request identifier.
+ * @param startTopVer Start topology version.
+ * @param endTopVer End topology version.
+ */
+ public ClientClusterGroupGetNodesEndpointsResponse(long reqId,
+ long startTopVer,
+ long endTopVer) {
+ super(reqId);
+
+ this.startTopVer = startTopVer;
+ this.endTopVer = endTopVer;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void encode(ClientConnectionContext ctx, BinaryRawWriterEx writer) {
+ super.encode(ctx, writer);
+
+ IgniteClusterEx cluster = ctx.kernalContext().grid().cluster();
+
+ long endTopVer0 = endTopVer == UNKNOWN_TOP_VER ? cluster.topologyVersion() : endTopVer;
+
+ Collection<ClusterNode> topology = cluster.topology(endTopVer0);
+
+ writer.writeLong(endTopVer0);
+
+ if (startTopVer == UNKNOWN_TOP_VER) {
+ int pos = writer.reserveInt();
+ int size = 0;
+
+ for (ClusterNode node : topology) {
+ if (writeNode(writer, node))
+ size++;
+ }
+
+ writer.writeInt(pos, size);
+ writer.writeInt(0);
+
+ return;
+ }
+
+ Map<UUID, ClusterNode> startNodes = toMap(cluster.topology(startTopVer));
+ Map<UUID, ClusterNode> endNodes = toMap(topology);
+
+ int pos = writer.reserveInt();
+ int cnt = 0;
+
+ for (Map.Entry<UUID, ClusterNode> endNode : endNodes.entrySet()) {
+ if (!startNodes.containsKey(endNode.getKey())) {
+ if (writeNode(writer, endNode.getValue()))
+ cnt++;
+ }
+ }
+
+ writer.writeInt(pos, cnt);
+
+ pos = writer.reserveInt();
+ cnt = 0;
+
+ for (Map.Entry<UUID, ClusterNode> startNode : startNodes.entrySet()) {
+ if (!endNodes.containsKey(startNode.getKey()) && !startNode.getValue().isClient()) {
+ writeUuid(writer, startNode.getKey());
+ cnt++;
+ }
+ }
+
+ writer.writeInt(pos, cnt);
+ }
+
+ /**
+ * Writes node info.
+ *
+ * @param writer Writer.
+ * @param node Node.
+ */
+ private static boolean writeNode(BinaryRawWriterEx writer, ClusterNode node) {
+ if (node.isClient())
+ return false;
+
+ Object port = node.attribute(ClientListenerProcessor.CLIENT_LISTENER_PORT);
+
+ if (!(port instanceof Integer))
+ return false; // No client connector.
+
+ writeUuid(writer, node.id());
+ writer.writeInt((int) port);
+
+ Collection<String> addrs = node.addresses();
+ Collection<String> hosts = node.hostNames();
+
+ writer.writeInt(addrs.size() + hosts.size());
+
+ for (String addr : addrs)
+ writer.writeString(addr);
+
+ for (String host : hosts)
+ writer.writeString(host);
+
+ return true;
+ }
+
+ /**
+ * Writes UUID.
+ *
+ * @param writer Writer.
+ * @param id id.
+ */
+ private static void writeUuid(BinaryRawWriterEx writer, UUID id) {
+ writer.writeLong(id.getMostSignificantBits());
+ writer.writeLong(id.getLeastSignificantBits());
+ }
+
+ /**
+ * Converts collection to a set of node ids.
+ *
+ * @param nodes Nodes.
+ * @return Set of node ids.
+ */
+ private static Map<UUID, ClusterNode> toMap(Collection<ClusterNode> nodes) {
+ Map<UUID, ClusterNode> res = new HashMap<>(nodes.size());
+
+ for (ClusterNode node : nodes)
+ res.put(node.id(), node);
+
+ return res;
+ }
+}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Apache.Ignite.Core.Tests.DotNetCore.csproj b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Apache.Ignite.Core.Tests.DotNetCore.csproj
index 5facd32..ccf7b28 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Apache.Ignite.Core.Tests.DotNetCore.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Apache.Ignite.Core.Tests.DotNetCore.csproj
@@ -92,6 +92,27 @@
<Link>Binary\TypeNameParserTest.cs</Link>
</Compile>
<Compile Include="..\Apache.Ignite.Core.Tests\Cache\AddArgCacheEntryProcessor.cs" Link="Cache\AddArgCacheEntryProcessor.cs" />
+ <Compile Include="..\Apache.Ignite.Core.Tests\Cache\Affinity\AffinityAttributeTest.cs">
+ <Link>Cache\Affinity\AffinityAttributeTest.cs</Link>
+ </Compile>
+ <Compile Include="..\Apache.Ignite.Core.Tests\Cache\Affinity\AffinityFieldTest.cs">
+ <Link>Cache\Affinity\AffinityFieldTest.cs</Link>
+ </Compile>
+ <Compile Include="..\Apache.Ignite.Core.Tests\Cache\Affinity\AffinityFunctionSpringTest.cs">
+ <Link>Cache\Affinity\AffinityFunctionSpringTest.cs</Link>
+ </Compile>
+ <Compile Include="..\Apache.Ignite.Core.Tests\Cache\Affinity\AffinityFunctionTest.cs">
+ <Link>Cache\Affinity\AffinityFunctionTest.cs</Link>
+ </Compile>
+ <Compile Include="..\Apache.Ignite.Core.Tests\Cache\Affinity\AffinityKeyTest.cs">
+ <Link>Cache\Affinity\AffinityKeyTest.cs</Link>
+ </Compile>
+ <Compile Include="..\Apache.Ignite.Core.Tests\Cache\Affinity\AffinityTest.cs">
+ <Link>Cache\Affinity\AffinityTest.cs</Link>
+ </Compile>
+ <Compile Include="..\Apache.Ignite.Core.Tests\Cache\Affinity\AffinityTopologyVersionTest.cs">
+ <Link>Cache\Affinity\AffinityTopologyVersionTest.cs</Link>
+ </Compile>
<Compile Include="..\Apache.Ignite.Core.Tests\Cache\BinarizableAddArgCacheEntryProcessor.cs" Link="Cache\BinarizableAddArgCacheEntryProcessor.cs" />
<Compile Include="..\Apache.Ignite.Core.Tests\Cache\BinarizableTestException.cs" Link="Cache\BinarizableTestException.cs" />
<Compile Include="..\Apache.Ignite.Core.Tests\Cache\CacheAbstractTest.cs" Link="Cache\CacheAbstractTest.cs" />
@@ -200,13 +221,13 @@
<Compile Include="..\Apache.Ignite.Core.Tests\Client\Cache\TestKeyWithAffinity.cs">
<Link>ThinClient\Cache\TestKeyWithAffinity.cs</Link>
</Compile>
+ <Compile Include="..\Apache.Ignite.Core.Tests\Client\ClientFeaturesTest.cs">
+ <Link>ThinClient\ClientFeaturesTest.cs</Link>
+ </Compile>
<Compile Include="..\Apache.Ignite.Core.Tests\Client\ClientProtocolCompatibilityTest.cs">
<Link>ThinClient\ClientProtocolCompatibilityTest.cs</Link>
</Compile>
<Compile Include="..\Apache.Ignite.Core.Tests\Client\ClientConnectionTest.cs" Link="ThinClient\ClientConnectionTest.cs" />
- <Compile Include="..\Apache.Ignite.Core.Tests\Client\ClientOpExtensionsTest.cs">
- <Link>ThinClient\ClientOpExtensionsTest.cs</Link>
- </Compile>
<Compile Include="..\Apache.Ignite.Core.Tests\Client\ClientProtocolVersionTest.cs">
<Link>ThinClient\ClientProtocolVersionTest.cs</Link>
</Compile>
@@ -217,6 +238,21 @@
<Link>ThinClient\ClientServerCacheAdapterExtensions.cs</Link>
</Compile>
<Compile Include="..\Apache.Ignite.Core.Tests\Client\ClientTestBase.cs" Link="ThinClient\ClientTestBase.cs" />
+ <Compile Include="..\Apache.Ignite.Core.Tests\Client\Cluster\ClientClusterDiscoveryTests.cs">
+ <Link>ThinClient\Cluster\ClientClusterDiscoveryTests.cs</Link>
+ </Compile>
+ <Compile Include="..\Apache.Ignite.Core.Tests\Client\Cluster\ClientClusterDiscoveryTestsBase.cs">
+ <Link>ThinClient\Cluster\ClientClusterDiscoveryTestsBase.cs</Link>
+ </Compile>
+ <Compile Include="..\Apache.Ignite.Core.Tests\Client\Cluster\ClientClusterDiscoveryTestsBaselineTopology.cs">
+ <Link>ThinClient\Cluster\ClientClusterDiscoveryTestsBaselineTopology.cs</Link>
+ </Compile>
+ <Compile Include="..\Apache.Ignite.Core.Tests\Client\Cluster\ClientClusterDiscoveryTestsNoLocalhost.cs">
+ <Link>ThinClient\Cluster\ClientClusterDiscoveryTestsNoLocalhost.cs</Link>
+ </Compile>
+ <Compile Include="..\Apache.Ignite.Core.Tests\Client\Cluster\ClientClusterDiscoveryTestsSsl.cs">
+ <Link>ThinClient\Cluster\ClientClusterDiscoveryTestsSsl.cs</Link>
+ </Compile>
<Compile Include="..\Apache.Ignite.Core.Tests\Client\Cluster\ClientClusterGroupTests.cs" Link="ThinClient\Cluster\ClientClusterGroupTests.cs" />
<Compile Include="..\Apache.Ignite.Core.Tests\Client\Cluster\ClientClusterTests.cs" Link="ThinClient\Cluster\ClientClusterTests.cs" />
<Compile Include="..\Apache.Ignite.Core.Tests\Client\EndpointTest.cs" Link="ThinClient\EndpointTest.cs" />
@@ -298,6 +334,22 @@
<Content Include="..\Apache.Ignite.Core.Tests\Config\cache-query.xml" Link="Config\cache-query.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="..\Apache.Ignite.Core.Tests\Config\Cache\Affinity\affinity-function.xml">
+ <Link>Config\Cache\Affinity\affinity-function.xml</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\Apache.Ignite.Core.Tests\Config\Cache\Affinity\affinity-function2.xml">
+ <Link>Config\Cache\Affinity\affinity-function2.xml</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\Apache.Ignite.Core.Tests\Config\Cache\Store\cache-store-session-shared-factory.xml">
+ <Link>Config\Cache\Store\cache-store-session-shared-factory.xml</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\Apache.Ignite.Core.Tests\Config\Cache\Store\cache-store-session.xml">
+ <Link>Config\Cache\Store\cache-store-session.xml</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="..\Apache.Ignite.Core.Tests\Config\Client\IgniteClientConfiguration.xml" Link="Config\Client\IgniteClientConfiguration.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -316,6 +368,10 @@
<Content Include="..\Apache.Ignite.Core.Tests\Config\Compute\compute-grid-custom-executor.xml" Link="Config\Compute\compute-grid-custom-executor.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="..\Apache.Ignite.Core.Tests\Config\native-client-test-cache-affinity.xml">
+ <Link>Config\native-client-test-cache-affinity.xml</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="..\Apache.Ignite.Core.Tests\Config\native-client-test-cache-store.xml">
<Link>Config\native-client-test-cache-store.xml</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
@@ -339,9 +395,9 @@
<ItemGroup>
<PackageReference Include="log4net" Version="2.0.5" />
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
- <PackageReference Include="NUnit3TestAdapter" Version="3.9.0" />
+ <PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.4.0" />
<ProjectReference Include="..\Apache.Ignite.Core\Apache.Ignite.Core.DotNetCore.csproj" />
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Common/TestUtils.DotNetCore.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Common/TestUtils.DotNetCore.cs
index f524878..b38dca7 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Common/TestUtils.DotNetCore.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Common/TestUtils.DotNetCore.cs
@@ -21,6 +21,7 @@ namespace Apache.Ignite.Core.Tests
using System.Diagnostics;
using System.IO;
using System.Linq;
+ using Apache.Ignite.Core.Failure;
using Apache.Ignite.Core.Log;
using Apache.Ignite.Core.Tests.DotNetCore.Common;
@@ -43,7 +44,8 @@ namespace Apache.Ignite.Core.Tests
JvmOptions = TestJavaOptions(),
IgniteInstanceName = name,
Logger = TestLogger.Instance,
- WorkDirectory = WorkDir
+ WorkDirectory = WorkDir,
+ FailureHandler = new NoOpFailureHandler()
};
}
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 a1aa484..17caff8 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
@@ -165,13 +165,18 @@
<Compile Include="Client\Cache\TestKey.cs" />
<Compile Include="Client\Cache\TestKeyWithAffinity.cs" />
<Compile Include="Client\ClientProtocolCompatibilityTest.cs" />
- <Compile Include="Client\ClientOpExtensionsTest.cs" />
+ <Compile Include="Client\ClientFeaturesTest.cs" />
<Compile Include="Client\ClientProtocolVersionTest.cs" />
<Compile Include="Client\ClientReconnectCompatibilityTest.cs" />
<Compile Include="Client\ClientServerCacheAdapter.cs" />
<Compile Include="Client\ClientServerCacheAdapterExtensions.cs" />
<Compile Include="Client\ClientServerCompatibilityTest.cs" />
<Compile Include="Client\ClientTestBase.cs" />
+ <Compile Include="Client\Cluster\ClientClusterDiscoveryTests.cs" />
+ <Compile Include="Client\Cluster\ClientClusterDiscoveryTestsBase.cs" />
+ <Compile Include="Client\Cluster\ClientClusterDiscoveryTestsBaselineTopology.cs" />
+ <Compile Include="Client\Cluster\ClientClusterDiscoveryTestsNoLocalhost.cs" />
+ <Compile Include="Client\Cluster\ClientClusterDiscoveryTestsSsl.cs" />
<Compile Include="Client\Cluster\ClientClusterGroupTests.cs" />
<Compile Include="Client\Cluster\ClientClusterTests.cs" />
<Compile Include="Client\EndpointTest.cs" />
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFunctionSpringTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFunctionSpringTest.cs
index 14b5a60..2edb31e 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFunctionSpringTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFunctionSpringTest.cs
@@ -21,6 +21,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Affinity
{
using System;
using System.Collections.Generic;
+ using System.IO;
using System.Linq;
using Apache.Ignite.Core.Cache;
using Apache.Ignite.Core.Cache.Affinity;
@@ -38,8 +39,8 @@ namespace Apache.Ignite.Core.Tests.Cache.Affinity
/// Initializes a new instance of the <see cref="AffinityFunctionSpringTest"/> class.
/// </summary>
public AffinityFunctionSpringTest() : base(6,
- "config\\cache\\affinity\\affinity-function.xml",
- "config\\cache\\affinity\\affinity-function2.xml")
+ Path.Combine("Config", "Cache", "Affinity", "affinity-function.xml"),
+ Path.Combine("Config", "Cache", "Affinity", "affinity-function2.xml"))
{
// No-op.
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityTest.cs
index a3b8c03..d62c0b1 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityTest.cs
@@ -17,6 +17,7 @@
namespace Apache.Ignite.Core.Tests.Cache.Affinity
{
+ using System.IO;
using Apache.Ignite.Core.Binary;
using Apache.Ignite.Core.Cache;
using Apache.Ignite.Core.Cluster;
@@ -37,7 +38,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Affinity
{
var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
{
- SpringConfigUrl = "config\\native-client-test-cache-affinity.xml",
+ SpringConfigUrl = Path.Combine("Config", "native-client-test-cache-affinity.xml"),
IgniteInstanceName = "grid-" + i
};
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Misc.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Misc.cs
index 3341200..6d26131 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Misc.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Misc.cs
@@ -346,7 +346,8 @@ namespace Apache.Ignite.Core.Tests.Cache.Query.Linq
{
for (var i = 0; i < 100; i++)
{
- persons.SelectMany(p => GetRoleCache().AsCacheQueryable()).ToArray();
+ persons.SelectMany(p => GetRoleCache().AsCacheQueryable())
+ .Where(p => p.Value.Name.Contains("e")).ToArray();
}
});
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CacheTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CacheTest.cs
index eb8c985..7ccb688 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CacheTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CacheTest.cs
@@ -34,6 +34,22 @@ namespace Apache.Ignite.Core.Tests.Client.Cache
public class CacheTest : ClientTestBase
{
/// <summary>
+ /// Initializes a new instance of the <see cref="CacheTest"/> class.
+ /// </summary>
+ public CacheTest()
+ {
+ // No-op.
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="CacheTest"/> class.
+ /// </summary>
+ public CacheTest(int gridCount, bool enableSsl = false) : base(gridCount, enableSsl)
+ {
+ // No-op.
+ }
+
+ /// <summary>
/// Tests the cache put / get with primitive data types.
/// </summary>
[Test]
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CacheTestSsl.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CacheTestSsl.cs
index 92a0737..8875117 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CacheTestSsl.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CacheTestSsl.cs
@@ -17,50 +17,20 @@
namespace Apache.Ignite.Core.Tests.Client.Cache
{
- using System.IO;
- using System.Net;
- using System.Security.Authentication;
- using Apache.Ignite.Core.Client;
using NUnit.Framework;
/// <summary>
- /// Async cache test.
+ /// SSL cache test.
/// </summary>
[TestFixture]
public sealed class CacheTestSsl : CacheTest
{
/// <summary>
- /// Gets the Ignite configuration.
+ /// Initializes a new instance of the <see cref="CacheTestSsl"/> class.
/// </summary>
- protected override IgniteConfiguration GetIgniteConfiguration()
+ public CacheTestSsl() : base(1, true)
{
- return new IgniteConfiguration(base.GetIgniteConfiguration())
- {
- SpringConfigUrl = Path.Combine("Config", "Client", "server-with-ssl.xml")
- };
- }
-
- /// <summary>
- /// Gets the client configuration.
- /// </summary>
- protected override IgniteClientConfiguration GetClientConfiguration()
- {
- return new IgniteClientConfiguration(base.GetClientConfiguration())
- {
- Endpoints = new[] {IPAddress.Loopback + ":11110"},
- SslStreamFactory = new SslStreamFactory
- {
- CertificatePath = Path.Combine("Config", "Client", "thin-client-cert.pfx"),
- CertificatePassword = "123456",
- SkipServerCertificateValidation = true,
- CheckCertificateRevocation = true,
-#if !NETCOREAPP2_0 && !NETCOREAPP2_1 && !NETCOREAPP3_0
- SslProtocols = SslProtocols.Tls
-#else
- SslProtocols = SslProtocols.Tls12
-#endif
- }
- };
+ //No-op.
}
}
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/ClientCacheConfigurationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/ClientCacheConfigurationTest.cs
index 2314d2e..6a5f079 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/ClientCacheConfigurationTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/ClientCacheConfigurationTest.cs
@@ -176,9 +176,9 @@ namespace Apache.Ignite.Core.Tests.Client.Cache
{
using (var stream = new BinaryHeapStream(128))
{
- ClientCacheConfigurationSerializer.Write(stream, cfg, ClientSocket.CurrentProtocolVersion, true);
+ ClientCacheConfigurationSerializer.Write(stream, cfg, ClientFeatures.CurrentFeatures, true);
stream.Seek(0, SeekOrigin.Begin);
- return new CacheClientConfiguration(stream, ClientSocket.CurrentProtocolVersion);
+ return new CacheClientConfiguration(stream, ClientFeatures.CurrentFeatures);
}
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/PartitionAwarenessTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/PartitionAwarenessTest.cs
index 6ffb473..04cb6c5 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/PartitionAwarenessTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/PartitionAwarenessTest.cs
@@ -28,7 +28,6 @@ namespace Apache.Ignite.Core.Tests.Client.Cache
using Apache.Ignite.Core.Client;
using Apache.Ignite.Core.Client.Cache;
using Apache.Ignite.Core.Common;
- using Apache.Ignite.Core.Events;
using NUnit.Framework;
/// <summary>
@@ -152,7 +151,7 @@ namespace Apache.Ignite.Core.Tests.Client.Cache
}
[Test]
- public void CacheGet_NewNodeEnteredTopology_RequestIsRoutedToDefaultNode()
+ public void CacheGet_NewNodeEnteredTopology_RequestIsRoutedToNewNode()
{
// Warm-up.
Assert.AreEqual(1, _cache.Get(1));
@@ -168,28 +167,22 @@ namespace Apache.Ignite.Core.Tests.Client.Cache
var cfg = GetIgniteConfiguration();
cfg.AutoGenerateIgniteInstanceName = true;
- using (var ignite = Ignition.Start(cfg))
+ using (Ignition.Start(cfg))
{
- // Wait for rebalance.
- var events = ignite.GetEvents();
- events.EnableLocal(EventType.CacheRebalanceStopped);
- events.WaitForLocal(EventType.CacheRebalanceStopped);
-
- // Warm-up.
- Assert.AreEqual(1, _cache.Get(1));
-
- // Get default node index by performing non-partition-aware operation.
- _cache.GetAll(Enumerable.Range(1, 10));
- var defaultNodeIdx = GetClientRequestGridIndex("GetAll");
- Assert.Greater(defaultNodeIdx, -1);
-
- // Assert: keys 12 and 14 belong to a new node now, but we don't have the new node in the server list.
- // Requests are routed to default node.
- Assert.AreEqual(12, _cache.Get(12));
- Assert.AreEqual(defaultNodeIdx, GetClientRequestGridIndex());
-
- Assert.AreEqual(14, _cache.Get(14));
- Assert.AreEqual(defaultNodeIdx, GetClientRequestGridIndex());
+ TestUtils.WaitForTrueCondition(() =>
+ {
+ // Keys 12 and 14 belong to a new node now (-1).
+ Assert.AreEqual(12, _cache.Get(12));
+ if (GetClientRequestGridIndex() != -1)
+ {
+ return false;
+ }
+
+ Assert.AreEqual(14, _cache.Get(14));
+ Assert.AreEqual(-1, GetClientRequestGridIndex());
+
+ return true;
+ }, 3000);
}
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
index ec90b6f..a37f2e3 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
@@ -200,6 +200,9 @@ namespace Apache.Ignite.Core.Tests.Client
Assert.AreNotEqual(clientCfg, client.GetConfiguration());
Assert.AreNotEqual(client.GetConfiguration(), client.GetConfiguration());
Assert.AreEqual(clientCfg.ToXml(), client.GetConfiguration().ToXml());
+
+ var conn = client.GetConnections().Single();
+ Assert.AreEqual(servCfg.ClientConnectorConfiguration.Port, ((IPEndPoint) conn.RemoteEndPoint).Port);
}
}
@@ -340,8 +343,7 @@ namespace Apache.Ignite.Core.Tests.Client
ignite.Dispose();
var ex = Assert.Throws<AggregateException>(() => putGetTask.Wait());
- var baseEx = ex.GetBaseException();
- var socketEx = baseEx as SocketException;
+ var socketEx = ex.GetInnermostException() as SocketException;
if (socketEx != null)
{
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientFeaturesTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientFeaturesTest.cs
new file mode 100644
index 0000000..7b690b2
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientFeaturesTest.cs
@@ -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.
+ */
+
+namespace Apache.Ignite.Core.Tests.Client
+{
+ using System;
+ using System.Linq;
+ using Apache.Ignite.Core.Impl.Client;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Tests for <see cref="ClientFeatures"/> class.
+ /// </summary>
+ public class ClientFeaturesTest
+ {
+ /// <summary>
+ /// Tests that <see cref="ClientFeatures.GetMinVersion"/> returns a version
+ /// for every valid <see cref="ClientOp"/>.
+ /// </summary>
+ [Test]
+ public void TestGetMinVersionReturnsValueForEveryValidOp()
+ {
+ foreach (ClientOp clientOp in Enum.GetValues(typeof(ClientOp)))
+ {
+ var minVersion = ClientFeatures.GetMinVersion(clientOp);
+
+ Assert.IsTrue(minVersion >= ClientSocket.Ver100);
+ Assert.IsTrue(minVersion <= ClientSocket.CurrentProtocolVersion);
+ }
+ }
+
+ /// <summary>
+ /// Tests that <see cref="ClientFeatures.GetMinVersion"/> returns a specific version for known new features.
+ /// </summary>
+ [Test]
+ public void TestGetMinVersionReturnsSpecificVersionForNewFeatures()
+ {
+ Assert.AreEqual(ClientSocket.Ver140, ClientFeatures.GetMinVersion(ClientOp.CachePartitions));
+
+ Assert.AreEqual(ClientSocket.Ver150, ClientFeatures.GetMinVersion(ClientOp.ClusterIsActive));
+ Assert.AreEqual(ClientSocket.Ver150, ClientFeatures.GetMinVersion(ClientOp.ClusterChangeState));
+ Assert.AreEqual(ClientSocket.Ver150, ClientFeatures.GetMinVersion(ClientOp.ClusterChangeWalState));
+ Assert.AreEqual(ClientSocket.Ver150, ClientFeatures.GetMinVersion(ClientOp.ClusterGetWalState));
+ }
+
+ /// <summary>
+ /// Tests <see cref="ClientFeatures.AllFeatures"/>.
+ /// </summary>
+ [Test]
+ public void TestAllFeatures()
+ {
+ var expected = Enum.GetValues(typeof(ClientBitmaskFeature))
+ .Cast<int>()
+ .Aggregate(0, (a, b) => a | (1 << b));
+
+ Assert.AreEqual(expected, ClientFeatures.AllFeatures.Single());
+ }
+
+ /// <summary>
+ /// Tests <see cref="ClientFeatures.HasFeature"/>.
+ /// </summary>
+ [Test]
+ public void TestHasFeature()
+ {
+ var features = ClientFeatures.CurrentFeatures;
+
+ Assert.IsTrue(features.HasFeature(ClientBitmaskFeature.ClusterGroupGetNodesEndpoints));
+ Assert.IsFalse(features.HasFeature((ClientBitmaskFeature) (-1)));
+ Assert.IsFalse(features.HasFeature((ClientBitmaskFeature) 12345));
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientOpExtensionsTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientOpExtensionsTest.cs
deleted file mode 100644
index 664d413..0000000
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientOpExtensionsTest.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-namespace Apache.Ignite.Core.Tests.Client
-{
- using System;
- using Apache.Ignite.Core.Impl.Client;
- using NUnit.Framework;
-
- /// <summary>
- /// Tests for <see cref="ClientOpExtensions"/> class.
- /// </summary>
- public class ClientOpExtensionsTest
- {
- /// <summary>
- /// Tests that <see cref="ClientOpExtensions.GetMinVersion"/> returns a version
- /// for every valid <see cref="ClientOp"/>.
- /// </summary>
- [Test]
- public void TestGetMinVersionReturnsValueForEveryValidOp()
- {
- foreach (ClientOp clientOp in Enum.GetValues(typeof(ClientOp)))
- {
- var minVersion = clientOp.GetMinVersion();
-
- Assert.IsTrue(minVersion >= ClientSocket.Ver100);
- Assert.IsTrue(minVersion <= ClientSocket.CurrentProtocolVersion);
- }
- }
-
- /// <summary>
- /// Tests that <see cref="ClientOpExtensions.GetMinVersion"/> returns a specific version for known new features.
- /// </summary>
- [Test]
- public void TestGetMinVersionReturnsSpecificVersionForNewFeatures()
- {
- Assert.AreEqual(ClientSocket.Ver140, ClientOp.CachePartitions.GetMinVersion());
-
- Assert.AreEqual(ClientSocket.Ver150, ClientOp.ClusterIsActive.GetMinVersion());
- Assert.AreEqual(ClientSocket.Ver150, ClientOp.ClusterChangeState.GetMinVersion());
- Assert.AreEqual(ClientSocket.Ver150, ClientOp.ClusterChangeWalState.GetMinVersion());
- Assert.AreEqual(ClientSocket.Ver150, ClientOp.ClusterGetWalState.GetMinVersion());
- }
- }
-}
\ No newline at end of file
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientProtocolCompatibilityTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientProtocolCompatibilityTest.cs
index dad33b2..4ba7392 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientProtocolCompatibilityTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientProtocolCompatibilityTest.cs
@@ -83,10 +83,13 @@ namespace Apache.Ignite.Core.Tests.Client
cache.Put(1, 2);
Assert.AreEqual(2, cache.Get(1));
- var log = GetLogs(client).Last();
- var expectedMessage = string.Format("Partition awareness has been disabled: server protocol version " +
- "{0} is lower than required 1.4.0", version);
+ var log = GetLogs(client).FirstOrDefault(e => e.Message.StartsWith("Partition"));
+
+ var expectedMessage = string.Format(
+ "Partition awareness has been disabled: server protocol version " +
+ "{0} is lower than required 1.4.0", version);
+ Assert.IsNotNull(log);
Assert.AreEqual(expectedMessage, log.Message);
Assert.AreEqual(LogLevel.Warn, log.Level);
Assert.AreEqual(typeof(ClientFailoverSocket).Name, log.Category);
@@ -131,7 +134,7 @@ namespace Apache.Ignite.Core.Tests.Client
{
Assert.AreEqual(version, client.Socket.CurrentProtocolVersion);
- var lastLog = GetLogs(client).Last();
+ var lastLog = GetLogs(client).Last(e => e.Level == LogLevel.Debug);
var expectedLog = string.Format(
"Handshake completed on 127.0.0.1:10800, protocol version = {0}", version);
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientReconnectCompatibilityTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientReconnectCompatibilityTest.cs
index d9cec91..742f59a 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientReconnectCompatibilityTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientReconnectCompatibilityTest.cs
@@ -64,7 +64,10 @@ namespace Apache.Ignite.Core.Tests.Client
Assert.AreEqual(42, cache.Get(1));
Assert.IsFalse(client.GetConfiguration().EnablePartitionAwareness);
- var log = ((ListLogger) client.GetConfiguration().Logger).Entries.Last();
+ var log = ((ListLogger) client.GetConfiguration().Logger).Entries
+ .FirstOrDefault(e => e.Message.StartsWith("Partition"));
+
+ Assert.IsNotNull(log);
Assert.AreEqual("Partition awareness has been disabled: " +
"server protocol version 1.0.0 is lower than required 1.4.0", log.Message);
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientTestBase.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientTestBase.cs
index c94eb54..c9f2b0e 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientTestBase.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientTestBase.cs
@@ -19,8 +19,10 @@ namespace Apache.Ignite.Core.Tests.Client
{
using System;
using System.Collections.Generic;
+ using System.IO;
using System.Linq;
using System.Net;
+ using System.Security.Authentication;
using System.Text.RegularExpressions;
using Apache.Ignite.Core.Binary;
using Apache.Ignite.Core.Cache;
@@ -48,6 +50,9 @@ namespace Apache.Ignite.Core.Tests.Client
/** Grid count. */
private readonly int _gridCount = 1;
+ /** SSL. */
+ private readonly bool _enableSsl;
+
/// <summary>
/// Initializes a new instance of the <see cref="ClientTestBase"/> class.
/// </summary>
@@ -59,9 +64,10 @@ namespace Apache.Ignite.Core.Tests.Client
/// <summary>
/// Initializes a new instance of the <see cref="ClientTestBase"/> class.
/// </summary>
- public ClientTestBase(int gridCount)
+ public ClientTestBase(int gridCount, bool enableSsl = false)
{
_gridCount = gridCount;
+ _enableSsl = enableSsl;
}
/// <summary>
@@ -106,7 +112,7 @@ namespace Apache.Ignite.Core.Tests.Client
Assert.AreEqual(0, cache.GetSize(CachePeekMode.All));
Assert.AreEqual(0, GetClientCache<int>().GetSize(CachePeekMode.All));
-
+
ClearLoggers();
}
@@ -120,7 +126,7 @@ namespace Apache.Ignite.Core.Tests.Client
/// </summary>
protected static ICache<int, T> GetCache<T>()
{
- return Ignition.GetIgnite().GetOrCreateCache<int, T>(CacheName);
+ return Ignition.GetAll().First().GetOrCreateCache<int, T>(CacheName);
}
/// <summary>
@@ -152,11 +158,27 @@ namespace Apache.Ignite.Core.Tests.Client
/// </summary>
protected virtual IgniteClientConfiguration GetClientConfiguration()
{
+ var port = _enableSsl ? 11110 : IgniteClientConfiguration.DefaultPort;
+
return new IgniteClientConfiguration
{
- Endpoints = new List<string> {IPAddress.Loopback.ToString()},
+ Endpoints = new List<string> {IPAddress.Loopback + ":" + port},
SocketTimeout = TimeSpan.FromSeconds(15),
- Logger = new ListLogger(new ConsoleLogger {MinLevel = LogLevel.Trace})
+ Logger = new ListLogger(new ConsoleLogger {MinLevel = LogLevel.Trace}),
+ SslStreamFactory = _enableSsl
+ ? new SslStreamFactory
+ {
+ CertificatePath = Path.Combine("Config", "Client", "thin-client-cert.pfx"),
+ CertificatePassword = "123456",
+ SkipServerCertificateValidation = true,
+ CheckCertificateRevocation = true,
+#if !NETCOREAPP
+ SslProtocols = SslProtocols.Tls
+#else
+ SslProtocols = SslProtocols.Tls12
+#endif
+ }
+ : null
};
}
@@ -167,14 +189,15 @@ namespace Apache.Ignite.Core.Tests.Client
{
return new IgniteConfiguration(TestUtils.GetTestConfiguration())
{
- Logger = new ListLogger()
+ Logger = new ListLogger(),
+ SpringConfigUrl = _enableSsl ? Path.Combine("Config", "Client", "server-with-ssl.xml") : null
};
}
/// <summary>
/// Converts object to binary form.
/// </summary>
- protected IBinaryObject ToBinary(object o)
+ private IBinaryObject ToBinary(object o)
{
return Client.GetBinary().ToBinary<IBinaryObject>(o);
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cluster/ClientClusterDiscoveryTests.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cluster/ClientClusterDiscoveryTests.cs
new file mode 100644
index 0000000..76662e6
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cluster/ClientClusterDiscoveryTests.cs
@@ -0,0 +1,176 @@
+/*
+ * 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.Client.Cluster
+{
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Net;
+ using Apache.Ignite.Core.Tests.Client.Cache;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Tests for client cluster discovery.
+ /// </summary>
+ public class ClientClusterDiscoveryTests : ClientClusterDiscoveryTestsBase
+ {
+ /// <summary>
+ /// Initializes a new instance of <see cref="ClientClusterDiscoveryTests"/>.
+ /// </summary>
+ public ClientClusterDiscoveryTests() : this(false, false)
+ {
+ // No-op.
+ }
+
+ /// <summary>
+ /// Initializes a new instance of <see cref="ClientClusterDiscoveryTests"/>.
+ /// </summary>
+ public ClientClusterDiscoveryTests(bool noLocalhost, bool enableSsl) : base(noLocalhost, enableSsl)
+ {
+ // No-op.
+ }
+
+ /// <summary>
+ /// Tests random topology changes.
+ /// </summary>
+ [Test]
+ public void TestClientDiscoveryWithRandomTopologyChanges()
+ {
+ var nodes = new Stack<IIgnite>();
+
+ using (var client = GetClient())
+ {
+ AssertClientConnectionCount(client, 3);
+
+ for (int i = 0; i < 20; i++)
+ {
+ if (nodes.Count == 0 || TestUtils.Random.Next(2) == 0)
+ {
+ nodes.Push(Ignition.Start(GetIgniteConfiguration()));
+ }
+ else
+ {
+ nodes.Pop().Dispose();
+ }
+
+ AssertClientConnectionCount(client, 3 + nodes.Count);
+ }
+ }
+
+ foreach (var node in nodes)
+ {
+ node.Dispose();
+ }
+ }
+
+ /// <summary>
+ /// Tests that originally known node can leave and client maintains connections to other cluster nodes.
+ /// </summary>
+ [Test]
+ public void TestClientMaintainsConnectionWhenOriginalNodeLeaves()
+ {
+ // Client knows about single server node initially.
+ var ignite = Ignition.Start(GetIgniteConfiguration());
+ var cfg = GetClientConfiguration();
+ cfg.Endpoints = new[] {IPAddress.Loopback + ":10803"};
+
+ // Client starts and discovers other server nodes.
+ var client = Ignition.StartClient(cfg);
+ AssertClientConnectionCount(client, 4);
+
+ // Original node leaves. Client is still connected.
+ ignite.Dispose();
+ AssertClientConnectionCount(client, 3);
+
+ // Perform any operation to verify that client works.
+ Assert.AreEqual(3, client.GetCluster().GetNodes().Count);
+ }
+
+ /// <summary>
+ /// Tests that thin client discovery does not include thick client nodes.
+ /// </summary>
+ [Test]
+ public void TestThinClientDoesNotDiscoverThickClientNodes()
+ {
+ var cfg = GetIgniteConfiguration();
+ cfg.ClientMode = true;
+
+ using (Ignition.Start(cfg))
+ {
+ var client = GetClient();
+ AssertClientConnectionCount(client, 3);
+ }
+ }
+
+ /// <summary>
+ /// Tests that server nodes without client connector are ignored by thin client discovery.
+ /// </summary>
+ [Test]
+ public void TestDiscoveryWithoutClientConnectorOnServer()
+ {
+ var cfg = GetIgniteConfiguration();
+ cfg.ClientConnectorConfigurationEnabled = false;
+
+ using (Ignition.Start(cfg))
+ {
+ var client = GetClient();
+ AssertClientConnectionCount(client, 3);
+ }
+ }
+
+ /// <summary>
+ /// Tests that Partition Awareness feature works together with Cluster Discovery.
+ /// </summary>
+ [Test]
+ public void TestPartitionAwarenessRoutesRequestsToNewlyJoinedNodes()
+ {
+ if (GetType() == typeof(ClientClusterDiscoveryTestsBaselineTopology))
+ {
+ // Fixed baseline means that rebalance to a new node won't happen.
+ return;
+ }
+
+ var ignite = Ignition.GetAll().First();
+ var cache = ignite.CreateCache<int, int>("c");
+
+ using (var ignite2 = Ignition.Start(GetIgniteConfiguration()))
+ {
+ var client = GetClient();
+ AssertClientConnectionCount(client, 4);
+
+ var clientCache = client.GetCache<int, int>(cache.Name);
+ var logger = (ListLogger) ignite2.Logger;
+ var aff = ignite2.GetAffinity(cache.Name);
+ var localNode = ignite2.GetCluster().GetLocalNode();
+
+ TestUtils.WaitForTrueCondition(() => aff.GetAllPartitions(localNode).Length > 0, 5000);
+
+ var key = TestUtils.GetPrimaryKey(ignite2, cache.Name);
+
+ TestUtils.WaitForTrueCondition(() =>
+ {
+ clientCache.Put(key, key);
+
+ var log = logger.Entries.LastOrDefault(
+ e => e.Message.Contains("client.cache.ClientCachePutRequest"));
+
+ return log != null;
+ }, 3000);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cluster/ClientClusterDiscoveryTestsBase.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cluster/ClientClusterDiscoveryTestsBase.cs
new file mode 100644
index 0000000..8c81561
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cluster/ClientClusterDiscoveryTestsBase.cs
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Tests.Client.Cluster
+{
+ using System;
+ using System.Linq;
+ using System.Net;
+ using Apache.Ignite.Core.Client;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Basic class for client cluster discovery tests.
+ /// </summary>
+ public abstract class ClientClusterDiscoveryTestsBase : ClientTestBase
+ {
+ /** Flag indicating whether IgniteConfiguration.Localhost should be set. */
+ private readonly bool _noLocalhost;
+
+ /// <summary>
+ /// Initializes a new instance of <see cref="ClientClusterDiscoveryTests"/>.
+ /// </summary>
+ public ClientClusterDiscoveryTestsBase() : this(false, false)
+ {
+ // No-op.
+ }
+
+ /// <summary>
+ /// Initializes a new instance of <see cref="ClientClusterDiscoveryTests"/>.
+ /// </summary>
+ public ClientClusterDiscoveryTestsBase(bool noLocalhost, bool enableSsl) : base(3, enableSsl)
+ {
+ _noLocalhost = noLocalhost;
+ }
+
+ /// <summary>
+ /// Tests that client with one initial endpoint discovers all servers.
+ /// </summary>
+ [Test]
+ public void TestClientWithOneEndpointDiscoversAllServers()
+ {
+ using (var client = GetClient())
+ {
+ AssertClientConnectionCount(client, 3);
+ }
+ }
+
+ /// <summary>
+ /// Tests that client discovers new servers automatically when they join the cluster, and removes
+ /// disconnected servers.
+ /// </summary>
+ [Test]
+ public void TestClientDiscoversJoinedServersAndRemovesDisconnected()
+ {
+ using (var client = GetClient())
+ {
+ AssertClientConnectionCount(client, 3);
+
+ using (Ignition.Start(GetIgniteConfiguration()))
+ {
+ AssertClientConnectionCount(client, 4);
+ }
+
+ AssertClientConnectionCount(client, 3);
+ }
+ }
+
+ /** <inheritdoc /> */
+ protected override IgniteClientConfiguration GetClientConfiguration()
+ {
+ return new IgniteClientConfiguration(base.GetClientConfiguration())
+ {
+ EnablePartitionAwareness = true
+ };
+ }
+
+ /** <inheritdoc /> */
+ protected override IgniteConfiguration GetIgniteConfiguration()
+ {
+ return new IgniteConfiguration(base.GetIgniteConfiguration())
+ {
+ Localhost = _noLocalhost ? null : "127.0.0.1",
+ AutoGenerateIgniteInstanceName = true
+ };
+ }
+
+ /// <summary>
+ /// Asserts client connection count.
+ /// </summary>
+ protected static void AssertClientConnectionCount(IIgniteClient client, int count)
+ {
+ var res = TestUtils.WaitForCondition(() =>
+ {
+ // Perform any operation to cause topology update.
+ try
+ {
+ client.GetCacheNames();
+ }
+ catch (Exception)
+ {
+ // Ignore.
+ }
+
+ return count == client.GetConnections().Count();
+ }, 1000);
+
+ if (!res)
+ {
+ Assert.Fail("Client connection count mismatch: expected {0}, but was {1}",
+ count, client.GetConnections().Count());
+ }
+
+ var cluster = Ignition.GetAll().First().GetCluster();
+
+ foreach (var connection in client.GetConnections())
+ {
+ var server = cluster.GetNode(connection.NodeId);
+ Assert.IsNotNull(server);
+
+ var remoteEndPoint = (IPEndPoint) connection.RemoteEndPoint;
+ Assert.AreEqual(server.GetAttribute<int>("clientListenerPort"), remoteEndPoint.Port);
+
+ var ipAddresses = server.Addresses
+ .Select(a => a.Split('%').First()) // Trim IPv6 scope.
+ .Select(IPAddress.Parse)
+ .ToArray();
+
+ CollectionAssert.Contains(ipAddresses, remoteEndPoint.Address);
+
+ var localEndPoint = (IPEndPoint) connection.LocalEndPoint;
+ CollectionAssert.Contains(new[] {IPAddress.Loopback, IPAddress.IPv6Loopback}, localEndPoint.Address);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cluster/ClientClusterDiscoveryTestsBaselineTopology.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cluster/ClientClusterDiscoveryTestsBaselineTopology.cs
new file mode 100644
index 0000000..010ade2
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cluster/ClientClusterDiscoveryTestsBaselineTopology.cs
@@ -0,0 +1,74 @@
+/*
+ * 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.Client.Cluster
+{
+ using System.Linq;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Tests client cluster discovery with baseline topology.
+ /// </summary>
+ [TestFixture]
+ public class ClientClusterDiscoveryTestsBaselineTopology : ClientClusterDiscoveryTests
+ {
+ /** <inheritdoc /> */
+ public override void FixtureSetUp()
+ {
+ base.FixtureSetUp();
+
+ var cluster = Ignition.GetAll().First().GetCluster();
+
+ cluster.SetBaselineAutoAdjustEnabledFlag(false);
+ cluster.SetBaselineTopology(cluster.TopologyVersion);
+ }
+
+ /// <summary>
+ /// Tests client discovery with changing baseline topology.
+ /// </summary>
+ [Test]
+ public void TestClientDiscoveryWithBaselineTopologyChange()
+ {
+ var cache = Client.GetOrCreateCache<int, int>(TestUtils.TestName);
+
+ AssertClientConnectionCount(Client, 3);
+ cache.Put(1, 1);
+
+ // Start new node.
+ var ignite = Ignition.Start(TestUtils.GetTestConfiguration());
+
+ AssertClientConnectionCount(Client, 4);
+ cache.Put(2, 2);
+
+ // Add new node to baseline.
+ var cluster = ignite.GetCluster();
+ cluster.SetBaselineTopology(cluster.TopologyVersion);
+
+ AssertClientConnectionCount(Client, 4);
+ cache.Put(3, 3);
+
+ // Stop node to remove from baseline (live node can't be removed from baseline).
+ ignite.Dispose();
+
+ cluster = Ignition.GetAll().First().GetCluster();
+ cluster.SetBaselineTopology(cluster.TopologyVersion);
+
+ AssertClientConnectionCount(Client, 3);
+ cache.Put(4, 4);
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/MinVersionAttribute.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cluster/ClientClusterDiscoveryTestsNoLocalhost.cs
similarity index 56%
copy from modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/MinVersionAttribute.cs
copy to modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cluster/ClientClusterDiscoveryTestsNoLocalhost.cs
index c218959..db07241 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/MinVersionAttribute.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cluster/ClientClusterDiscoveryTestsNoLocalhost.cs
@@ -1,4 +1,4 @@
-/*
+/*
* 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.
@@ -15,33 +15,22 @@
* limitations under the License.
*/
-namespace Apache.Ignite.Core.Impl.Client
+namespace Apache.Ignite.Core.Tests.Client.Cluster
{
- using System;
+ using NUnit.Framework;
/// <summary>
- /// Version attribute for <see cref="ClientOp"/>.
+ /// Discovery test with no <see cref="IgniteConfiguration.Localhost"/> set.
/// </summary>
- [AttributeUsage(AttributeTargets.Field)]
- internal sealed class MinVersionAttribute : Attribute
+ [TestFixture]
+ public class ClientClusterDiscoveryTestsNoLocalhost : ClientClusterDiscoveryTests
{
- /** */
- private readonly ClientProtocolVersion _version;
-
- /// <summary>
- /// Initializes a new instance of <see cref="MinVersionAttribute"/> class.
- /// </summary>
- public MinVersionAttribute(short major, short minor, short maintenance)
- {
- _version = new ClientProtocolVersion(major, minor, maintenance);
- }
-
/// <summary>
- /// Gets the version.
+ /// Initializes a new instance of <see cref="ClientClusterDiscoveryTestsNoLocalhost"/> class.
/// </summary>
- public ClientProtocolVersion Version
+ public ClientClusterDiscoveryTestsNoLocalhost() : base(true, false)
{
- get { return _version; }
+ // No-op.
}
}
}
\ No newline at end of file
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/MinVersionAttribute.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cluster/ClientClusterDiscoveryTestsSsl.cs
similarity index 56%
copy from modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/MinVersionAttribute.cs
copy to modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cluster/ClientClusterDiscoveryTestsSsl.cs
index c218959..bf6817b 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/MinVersionAttribute.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cluster/ClientClusterDiscoveryTestsSsl.cs
@@ -1,4 +1,4 @@
-/*
+/*
* 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.
@@ -15,33 +15,22 @@
* limitations under the License.
*/
-namespace Apache.Ignite.Core.Impl.Client
+namespace Apache.Ignite.Core.Tests.Client.Cluster
{
- using System;
+ using NUnit.Framework;
/// <summary>
- /// Version attribute for <see cref="ClientOp"/>.
+ /// Tests client discovery with SSL enabled.
/// </summary>
- [AttributeUsage(AttributeTargets.Field)]
- internal sealed class MinVersionAttribute : Attribute
+ [TestFixture]
+ public class ClientClusterDiscoveryTestsSsl : ClientClusterDiscoveryTestsBase
{
- /** */
- private readonly ClientProtocolVersion _version;
-
- /// <summary>
- /// Initializes a new instance of <see cref="MinVersionAttribute"/> class.
- /// </summary>
- public MinVersionAttribute(short major, short minor, short maintenance)
- {
- _version = new ClientProtocolVersion(major, minor, maintenance);
- }
-
/// <summary>
- /// Gets the version.
+ /// Initializes a new instance of <see cref="ClientClusterDiscoveryTestsSsl"/> class.
/// </summary>
- public ClientProtocolVersion Version
+ public ClientClusterDiscoveryTestsSsl() : base(false, true)
{
- get { return _version; }
+ // No-op.
}
}
}
\ No newline at end of file
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
index 46a5965..937c9d1 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
@@ -61,6 +61,7 @@
<Compile Include="Client\IClientCluster.cs" />
<Compile Include="Client\IClientClusterGroup.cs" />
<Compile Include="Client\IClientClusterNode.cs" />
+ <Compile Include="Client\IClientConnection.cs" />
<Compile Include="Client\IgniteClientConfigurationSection.cs" />
<Compile Include="Client\ISslStreamFactory.cs" />
<Compile Include="Client\SslStreamFactory.cs" />
@@ -93,11 +94,13 @@
<Compile Include="Impl\Cache\QueryMetricsImpl.cs" />
<Compile Include="Impl\Cache\Query\PlatformCacheQueryCursor.cs" />
<Compile Include="Impl\Cache\Query\QueryCursorField.cs" />
+ <Compile Include="Impl\Client\ClientBitmaskFeature.cs" />
+ <Compile Include="Impl\Client\ClientConnection.cs" />
<Compile Include="Impl\Client\ClientContextBase.cs" />
- <Compile Include="Impl\Client\ClientOpExtensions.cs" />
+ <Compile Include="Impl\Client\ClientDiscoveryNode.cs" />
+ <Compile Include="Impl\Client\ClientFeatures.cs" />
<Compile Include="Impl\Client\ClientRequestContext.cs" />
<Compile Include="Impl\Client\ClientResponseContext.cs" />
- <Compile Include="Impl\Client\ClientUtils.cs" />
<Compile Include="Impl\Client\Cluster\ClientCluster.cs" />
<Compile Include="Impl\Client\Cache\ClientCachePartitionAwarenessGroup.cs" />
<Compile Include="Impl\Client\Cache\ClientCachePartitionMap.cs" />
@@ -108,7 +111,6 @@
<Compile Include="Impl\Client\Cluster\ClientClusterGroupProjection.cs" />
<Compile Include="Impl\Client\Cluster\ClientClusterNode.cs" />
<Compile Include="Impl\Client\Endpoint.cs" />
- <Compile Include="Impl\Client\MinVersionAttribute.cs" />
<Compile Include="Impl\Client\SocketEndpoint.cs" />
<Compile Include="Impl\Common\PlatformType.cs" />
<Compile Include="Impl\Common\TaskRunner.cs" />
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Client/Cache/CacheClientConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Client/Cache/CacheClientConfiguration.cs
index d0eca45..6c9aa7d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Client/Cache/CacheClientConfiguration.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Client/Cache/CacheClientConfiguration.cs
@@ -118,12 +118,12 @@ namespace Apache.Ignite.Core.Client.Cache
{
using (var stream = IgniteManager.Memory.Allocate().GetStream())
{
- ClientCacheConfigurationSerializer.Write(stream, other, ClientSocket.CurrentProtocolVersion, true);
+ ClientCacheConfigurationSerializer.Write(stream, other, ClientFeatures.CurrentFeatures, true);
stream.SynchronizeOutput();
stream.Seek(0, SeekOrigin.Begin);
- ClientCacheConfigurationSerializer.Read(stream, this, ClientSocket.CurrentProtocolVersion);
+ ClientCacheConfigurationSerializer.Read(stream, this, ClientFeatures.CurrentFeatures);
}
CopyLocalProperties(other);
@@ -159,11 +159,11 @@ namespace Apache.Ignite.Core.Client.Cache
/// <summary>
/// Initializes a new instance of the <see cref="CacheClientConfiguration"/> class.
/// </summary>
- internal CacheClientConfiguration(IBinaryStream stream, ClientProtocolVersion srvVer)
+ internal CacheClientConfiguration(IBinaryStream stream, ClientFeatures features)
{
Debug.Assert(stream != null);
- ClientCacheConfigurationSerializer.Read(stream, this, srvVer);
+ ClientCacheConfigurationSerializer.Read(stream, this, features);
}
/// <summary>
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/MinVersionAttribute.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Client/IClientConnection.cs
similarity index 55%
copy from modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/MinVersionAttribute.cs
copy to modules/platforms/dotnet/Apache.Ignite.Core/Client/IClientConnection.cs
index c218959..4924b7f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/MinVersionAttribute.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Client/IClientConnection.cs
@@ -1,4 +1,4 @@
-/*
+/*
* 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.
@@ -15,33 +15,34 @@
* limitations under the License.
*/
-namespace Apache.Ignite.Core.Impl.Client
+namespace Apache.Ignite.Core.Client
{
using System;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Net;
/// <summary>
- /// Version attribute for <see cref="ClientOp"/>.
+ /// Represents Ignite client connection.
/// </summary>
- [AttributeUsage(AttributeTargets.Field)]
- internal sealed class MinVersionAttribute : Attribute
+ public interface IClientConnection
{
- /** */
- private readonly ClientProtocolVersion _version;
-
/// <summary>
- /// Initializes a new instance of <see cref="MinVersionAttribute"/> class.
+ /// Gets the remote EndPoint.
/// </summary>
- public MinVersionAttribute(short major, short minor, short maintenance)
- {
- _version = new ClientProtocolVersion(major, minor, maintenance);
- }
+ [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly",
+ Justification = "Consistency with EndPoint class name.")]
+ EndPoint RemoteEndPoint { get; }
/// <summary>
- /// Gets the version.
+ /// Gets the local EndPoint.
+ /// </summary>
+ [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly",
+ Justification = "Consistency with EndPoint class name.")]
+ EndPoint LocalEndPoint { get; }
+
+ /// <summary>
+ /// Gets the server node id.
/// </summary>
- public ClientProtocolVersion Version
- {
- get { return _version; }
- }
+ Guid NodeId { get; }
}
}
\ No newline at end of file
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Client/IIgniteClient.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Client/IIgniteClient.cs
index f163fc6..5a94776 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Client/IIgniteClient.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Client/IIgniteClient.cs
@@ -129,5 +129,11 @@ namespace Apache.Ignite.Core.Client
[SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly",
Justification = "Consistency with EndPoint class name.")]
EndPoint LocalEndPoint { get; }
+
+ /// <summary>
+ /// Gets all active connections. Ignite Thin Client maintains connections to multiple server nodes when
+ /// <see cref="IgniteClientConfiguration.EnablePartitionAwareness"/> is true.
+ /// </summary>
+ IEnumerable<IClientConnection> GetConnections();
}
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs
index 4739e5f..67a3059 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs
@@ -560,7 +560,7 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
public CacheClientConfiguration GetConfiguration()
{
return DoOutInOp(ClientOp.CacheGetConfiguration, null,
- ctx => new CacheClientConfiguration(ctx.Stream, ctx.ProtocolVersion));
+ ctx => new CacheClientConfiguration(ctx.Stream, ctx.Features));
}
/** <inheritDoc /> */
@@ -756,11 +756,7 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
if (_expiryPolicy != null)
{
- // Check whether WithExpiryPolicy is supported by the protocol here -
- // ctx.ProtocolVersion refers to exact connection for this request.
- ClientUtils.ValidateOp(
- ClientCacheRequestFlag.WithExpiryPolicy, ctx.ProtocolVersion, ClientSocket.Ver150);
-
+ ctx.Features.ValidateWithExpiryPolicyFlag();
ctx.Stream.WriteByte((byte) ClientCacheRequestFlag.WithExpiryPolicy);
ExpiryPolicySerializer.WritePolicy(ctx.Writer, _expiryPolicy);
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/ClientCacheConfigurationSerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/ClientCacheConfigurationSerializer.cs
index 89443d1..95bcbee 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/ClientCacheConfigurationSerializer.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/ClientCacheConfigurationSerializer.cs
@@ -199,7 +199,7 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
/// <summary>
/// Writes the specified config.
/// </summary>
- public static void Write(IBinaryStream stream, CacheClientConfiguration cfg, ClientProtocolVersion srvVer,
+ public static void Write(IBinaryStream stream, CacheClientConfiguration cfg, ClientFeatures features,
bool skipCodes = false)
{
Debug.Assert(stream != null);
@@ -307,7 +307,7 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
writer.WriteCollectionRaw(cfg.KeyConfiguration);
code(Op.QueryEntities);
- writer.WriteCollectionRaw(cfg.QueryEntities, (w, qe) => WriteQueryEntity(w, qe, srvVer));
+ writer.WriteCollectionRaw(cfg.QueryEntities, (w, qe) => WriteQueryEntity(w, qe, features));
code(Op.ExpiryPolicy);
ExpiryPolicySerializer.WritePolicyFactory(writer, cfg.ExpiryPolicyFactory);
@@ -320,7 +320,7 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
/// <summary>
/// Write query entity of the config.
/// </summary>
- private static void WriteQueryEntity(BinaryWriter writer, QueryEntity entity, ClientProtocolVersion srvVer)
+ private static void WriteQueryEntity(BinaryWriter writer, QueryEntity entity, ClientFeatures features)
{
writer.WriteString(entity.KeyTypeName);
writer.WriteString(entity.ValueTypeName);
@@ -336,7 +336,7 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
foreach (var field in entityFields)
{
- WriteQueryField(writer, field, srvVer);
+ WriteQueryField(writer, field, features);
}
}
else
@@ -378,7 +378,7 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
/// <summary>
/// Writes query field instance to the specified writer.
/// </summary>
- private static void WriteQueryField(BinaryWriter writer, QueryField field, ClientProtocolVersion srvVer)
+ private static void WriteQueryField(BinaryWriter writer, QueryField field, ClientFeatures features)
{
Debug.Assert(writer != null);
@@ -388,7 +388,7 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
writer.WriteBoolean(field.NotNull);
writer.WriteObject(field.DefaultValue);
- if (srvVer.CompareTo(ClientSocket.Ver120) >= 0)
+ if (features.HasQueryFieldPrecisionAndScale())
{
writer.WriteInt(field.Precision);
writer.WriteInt(field.Scale);
@@ -398,7 +398,7 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
/// <summary>
/// Reads the config.
/// </summary>
- public static void Read(IBinaryStream stream, CacheClientConfiguration cfg, ClientProtocolVersion srvVer)
+ public static void Read(IBinaryStream stream, CacheClientConfiguration cfg, ClientFeatures features)
{
Debug.Assert(stream != null);
@@ -437,9 +437,12 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
cfg.SqlSchema = reader.ReadString();
cfg.WriteSynchronizationMode = (CacheWriteSynchronizationMode)reader.ReadInt();
cfg.KeyConfiguration = reader.ReadCollectionRaw(r => new CacheKeyConfiguration(r));
- cfg.QueryEntities = reader.ReadCollectionRaw(r => ReadQueryEntity(r, srvVer));
- if (srvVer.CompareTo(ClientSocket.Ver160) >= 0)
+ cfg.QueryEntities = reader.ReadCollectionRaw(r => ReadQueryEntity(r, features));
+
+ if (features.HasCacheConfigurationExpiryPolicyFactory())
+ {
cfg.ExpiryPolicyFactory = ExpiryPolicySerializer.ReadPolicyFactory(reader);
+ }
Debug.Assert(len == reader.Stream.Position - pos);
}
@@ -447,7 +450,7 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
/// <summary>
/// Reads query entity of the config.
/// </summary>
- private static QueryEntity ReadQueryEntity(BinaryReader reader, ClientProtocolVersion srvVer)
+ private static QueryEntity ReadQueryEntity(BinaryReader reader, ClientFeatures features)
{
Debug.Assert(reader != null);
@@ -463,7 +466,7 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
var count = reader.ReadInt();
value.Fields = count == 0
? null
- : Enumerable.Range(0, count).Select(x => ReadQueryField(reader, srvVer)).ToList();
+ : Enumerable.Range(0, count).Select(x => ReadQueryField(reader, features)).ToList();
count = reader.ReadInt();
value.Aliases = count == 0 ? null : Enumerable.Range(0, count)
@@ -478,7 +481,7 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
/// <summary>
/// Read query field.
/// </summary>
- private static QueryField ReadQueryField(BinaryReader reader, ClientProtocolVersion srvVer)
+ private static QueryField ReadQueryField(BinaryReader reader, ClientFeatures features)
{
Debug.Assert(reader != null);
@@ -491,7 +494,7 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
DefaultValue = reader.ReadObject<object>()
};
- if (srvVer.CompareTo(ClientSocket.Ver120) >= 0)
+ if (features.HasQueryFieldPrecisionAndScale())
{
value.Precision = reader.ReadInt();
value.Scale = reader.ReadInt();
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/MinVersionAttribute.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientBitmaskFeature.cs
similarity index 54%
rename from modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/MinVersionAttribute.cs
rename to modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientBitmaskFeature.cs
index c218959..cd30b88 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/MinVersionAttribute.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientBitmaskFeature.cs
@@ -1,4 +1,4 @@
-/*
+/*
* 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.
@@ -17,31 +17,14 @@
namespace Apache.Ignite.Core.Impl.Client
{
- using System;
-
/// <summary>
- /// Version attribute for <see cref="ClientOp"/>.
+ /// Client feature ids. Values represent the index in the bit array.
/// </summary>
- [AttributeUsage(AttributeTargets.Field)]
- internal sealed class MinVersionAttribute : Attribute
+ internal enum ClientBitmaskFeature
{
- /** */
- private readonly ClientProtocolVersion _version;
-
- /// <summary>
- /// Initializes a new instance of <see cref="MinVersionAttribute"/> class.
- /// </summary>
- public MinVersionAttribute(short major, short minor, short maintenance)
- {
- _version = new ClientProtocolVersion(major, minor, maintenance);
- }
-
- /// <summary>
- /// Gets the version.
- /// </summary>
- public ClientProtocolVersion Version
- {
- get { return _version; }
- }
+ // UserAttributes = 0,
+ // ExecuteTaskByName = 1,
+ // ClusterApi = 2,
+ ClusterGroupGetNodesEndpoints = 3
}
}
\ No newline at end of file
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientConnection.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientConnection.cs
new file mode 100644
index 0000000..46c5148
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientConnection.cs
@@ -0,0 +1,71 @@
+/*
+ * 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.Impl.Client
+{
+ using System;
+ using System.Diagnostics;
+ using System.Net;
+ using Apache.Ignite.Core.Client;
+
+ /// <summary>
+ /// Represents Ignite client connection.
+ /// </summary>
+ internal class ClientConnection : IClientConnection
+ {
+ /** */
+ private readonly EndPoint _localEndPoint;
+
+ /** */
+ private readonly EndPoint _remoteEndPoint;
+
+ /** */
+ private readonly Guid _nodeId;
+
+ /// <summary>
+ /// Initializes a new instance of <see cref="ClientConnection"/>.
+ /// </summary>
+ public ClientConnection(EndPoint localEndPoint, EndPoint remoteEndPoint, Guid nodeId)
+ {
+ Debug.Assert(localEndPoint != null);
+ Debug.Assert(remoteEndPoint != null);
+ Debug.Assert(nodeId != Guid.Empty);
+
+ _localEndPoint = localEndPoint;
+ _remoteEndPoint = remoteEndPoint;
+ _nodeId = nodeId;
+ }
+
+ /** <inheritdoc /> */
+ public EndPoint RemoteEndPoint
+ {
+ get { return _remoteEndPoint; }
+ }
+
+ /** <inheritdoc /> */
+ public EndPoint LocalEndPoint
+ {
+ get { return _localEndPoint; }
+ }
+
+ /** <inheritdoc /> */
+ public Guid NodeId
+ {
+ get { return _nodeId; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientContextBase.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientContextBase.cs
index 9b0b8a0..c5863f2 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientContextBase.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientContextBase.cs
@@ -33,22 +33,22 @@ namespace Apache.Ignite.Core.Impl.Client
private readonly Marshaller _marshaller;
/** */
- private readonly ClientProtocolVersion _protocolVersion;
+ private readonly ClientFeatures _features;
/// <summary>
/// Initializes a new instance of <see cref="ClientContextBase"/> class.
/// </summary>
/// <param name="stream">Stream.</param>
/// <param name="marshaller">Marshaller.</param>
- /// <param name="protocolVersion">Protocol version to be used for this request.</param>
- protected ClientContextBase(IBinaryStream stream, Marshaller marshaller, ClientProtocolVersion protocolVersion)
+ /// <param name="features">Features supported by this request.</param>
+ protected ClientContextBase(IBinaryStream stream, Marshaller marshaller, ClientFeatures features)
{
Debug.Assert(stream != null);
Debug.Assert(marshaller != null);
_stream = stream;
_marshaller = marshaller;
- _protocolVersion = protocolVersion;
+ _features = features;
}
/// <summary>
@@ -68,12 +68,12 @@ namespace Apache.Ignite.Core.Impl.Client
}
/// <summary>
- /// Protocol version to be used for this request.
+ /// Features for this request.
/// (Takes partition awareness, failover and reconnect into account).
/// </summary>
- public ClientProtocolVersion ProtocolVersion
+ public ClientFeatures Features
{
- get { return _protocolVersion; }
+ get { return _features; }
}
}
}
\ No newline at end of file
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientRequestContext.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientDiscoveryNode.cs
similarity index 51%
copy from modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientRequestContext.cs
copy to modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientDiscoveryNode.cs
index d291136..e1b9b98 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientRequestContext.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientDiscoveryNode.cs
@@ -1,4 +1,4 @@
-/*
+/*
* 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.
@@ -17,47 +17,59 @@
namespace Apache.Ignite.Core.Impl.Client
{
- using Apache.Ignite.Core.Impl.Binary;
- using Apache.Ignite.Core.Impl.Binary.IO;
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
/// <summary>
- /// Request context.
+ /// Represents a discovered node.
/// </summary>
- internal sealed class ClientRequestContext : ClientContextBase
+ internal class ClientDiscoveryNode
{
/** */
- private BinaryWriter _writer;
+ private readonly Guid _id;
+
+ /** */
+ private readonly int _port;
+
+ /** */
+ private readonly IList<string> _addresses;
/// <summary>
- /// Initializes a new instance of <see cref="ClientRequestContext"/> class.
+ /// Initializes a new instance of <see cref="ClientDiscoveryNode"/>.
/// </summary>
- /// <param name="stream">Stream.</param>
- /// <param name="marshaller">Marshaller.</param>
- /// <param name="protocolVersion">Protocol version to be used for this request.</param>
- public ClientRequestContext(IBinaryStream stream, Marshaller marshaller, ClientProtocolVersion protocolVersion)
- : base(stream, marshaller, protocolVersion)
+ public ClientDiscoveryNode(Guid id, int port, IList<string> addresses)
+ {
+ Debug.Assert(addresses != null);
+ Debug.Assert(addresses.Count > 0);
+
+ _id = id;
+ _port = port;
+ _addresses = addresses;
+ }
+ /// <summary>
+ /// Gets the id.
+ /// </summary>
+ public Guid Id
{
- // No-op.
+ get { return _id; }
}
/// <summary>
- /// Writer.
+ /// Gets the port.
/// </summary>
- public BinaryWriter Writer
+ public int Port
{
- get { return _writer ?? (_writer = Marshaller.StartMarshal(Stream)); }
+ get { return _port; }
}
/// <summary>
- /// Finishes marshal session for this request (if any).
+ /// Gets the addresses - IPs or host names.
/// </summary>
- public void FinishMarshal()
+ public IList<string> Addresses
{
- if (_writer != null)
- {
- Marshaller.FinishMarshal(_writer);
- }
+ get { return _addresses; }
}
}
}
\ No newline at end of file
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientFailoverSocket.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientFailoverSocket.cs
index d3e97ee..5e35711 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientFailoverSocket.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientFailoverSocket.cs
@@ -39,6 +39,9 @@ namespace Apache.Ignite.Core.Impl.Client
/// </summary>
internal class ClientFailoverSocket : IDisposable
{
+ /** Unknown topology version. */
+ private const long UnknownTopologyVersion = -1;
+
/** Underlying socket. */
private ClientSocket _socket;
@@ -51,24 +54,36 @@ namespace Apache.Ignite.Core.Impl.Client
/** Marshaller. */
private readonly Marshaller _marsh;
- /** Endpoints with corresponding hosts. */
+ /** Endpoints with corresponding hosts - from config. */
private readonly List<SocketEndpoint> _endPoints;
- /** Locker. */
- private readonly object _syncRoot = new object();
+ /** Map from node ID to connected socket. */
+ private volatile Dictionary<Guid, ClientSocket> _nodeSocketMap = new Dictionary<Guid, ClientSocket>();
+
+ /** Discovered nodes map. Represents current topology. */
+ private volatile Dictionary<Guid, ClientDiscoveryNode> _discoveryNodes;
+
+ /** Main socket lock. */
+ private readonly object _socketLock = new object();
+
+ /** Topology change lock. */
+ private readonly object _topologyUpdateLock = new object();
/** Disposed flag. */
- private bool _disposed;
+ private volatile bool _disposed;
/** Current affinity topology version. Store as object to make volatile. */
private volatile object _affinityTopologyVersion;
- /** Map from node ID to connected socket. */
- private volatile Dictionary<Guid, ClientSocket> _nodeSocketMap;
+ /** Topology version that <see cref="_discoveryNodes"/> corresponds to. */
+ private long _discoveryTopologyVersion = UnknownTopologyVersion;
/** Map from cache ID to partition mapping. */
private volatile ClientCacheTopologyPartitionMap _distributionMap;
+ /** Enable discovery flag. */
+ private volatile bool _enableDiscovery = true;
+
/** Distribution map locker. */
private readonly object _distributionMapSyncRoot = new object();
@@ -106,7 +121,7 @@ namespace Apache.Ignite.Core.Impl.Client
_logger = (_config.Logger ?? NoopLogger.Instance).GetLogger(GetType());
Connect();
- }
+ }
/// <summary>
/// Performs a send-receive operation.
@@ -175,7 +190,7 @@ namespace Apache.Ignite.Core.Impl.Client
{
get
{
- var socket = _socket;
+ var socket = GetSocket();
return socket != null ? socket.RemoteEndPoint : null;
}
}
@@ -187,17 +202,52 @@ namespace Apache.Ignite.Core.Impl.Client
{
get
{
- var socket = _socket;
+ var socket = GetSocket();
return socket != null ? socket.LocalEndPoint : null;
}
}
/// <summary>
+ /// Gets active connections.
+ /// </summary>
+ public IEnumerable<IClientConnection> GetConnections()
+ {
+ var map = _nodeSocketMap;
+
+ foreach (var socket in map.Values)
+ {
+ if (!socket.IsDisposed)
+ {
+ yield return new ClientConnection(socket.LocalEndPoint, socket.RemoteEndPoint,
+ socket.ServerNodeId.GetValueOrDefault());
+ }
+ }
+
+ foreach (var socketEndpoint in _endPoints)
+ {
+ var socket = socketEndpoint.Socket;
+
+ if (socket == null || socket.IsDisposed)
+ {
+ continue;
+ }
+
+ if (socket.ServerNodeId != null && map.ContainsKey(socket.ServerNodeId.Value))
+ {
+ continue;
+ }
+
+ yield return new ClientConnection(socket.LocalEndPoint, socket.RemoteEndPoint,
+ socket.ServerNodeId.GetValueOrDefault());
+ }
+ }
+
+ /// <summary>
/// Checks the disposed state.
/// </summary>
private ClientSocket GetSocket()
{
- lock (_syncRoot)
+ lock (_socketLock)
{
ThrowIfDisposed();
@@ -212,6 +262,8 @@ namespace Apache.Ignite.Core.Impl.Client
private ClientSocket GetAffinitySocket<TKey>(int cacheId, TKey key)
{
+ ThrowIfDisposed();
+
if (!_config.EnablePartitionAwareness)
{
return null;
@@ -262,7 +314,8 @@ namespace Apache.Ignite.Core.Impl.Client
Justification = "There is no finalizer.")]
public void Dispose()
{
- lock (_syncRoot)
+ lock (_socketLock)
+ lock (_topologyUpdateLock)
{
_disposed = true;
@@ -281,18 +334,36 @@ namespace Apache.Ignite.Core.Impl.Client
_nodeSocketMap = null;
}
+
+ foreach (var socketEndpoint in _endPoints)
+ {
+ if (socketEndpoint.Socket != null)
+ {
+ socketEndpoint.Socket.Dispose();
+ }
+ }
}
}
/// <summary>
- /// Connects the socket.
+ /// Gets next connected socket, or connects a new one.
/// </summary>
- private void Connect()
+ private ClientSocket GetNextSocket()
{
List<Exception> errors = null;
var startIdx = (int) Interlocked.Increment(ref _endPointIndex);
- _socket = null;
+ // Check socket map first, if available: it includes all cluster nodes.
+ var map = _nodeSocketMap;
+ foreach (var socket in map.Values)
+ {
+ if (!socket.IsDisposed)
+ {
+ return socket;
+ }
+ }
+
+ // Fall back to initially known endpoints.
for (var i = 0; i < _endPoints.Count; i++)
{
var idx = (startIdx + i) % _endPoints.Count;
@@ -300,18 +371,12 @@ namespace Apache.Ignite.Core.Impl.Client
if (endPoint.Socket != null && !endPoint.Socket.IsDisposed)
{
- _socket = endPoint.Socket;
- break;
+ return endPoint.Socket;
}
try
{
- _socket = new ClientSocket(_config, endPoint.EndPoint, endPoint.Host,
- _config.ProtocolVersion, OnAffinityTopologyVersionChange, _marsh);
-
- endPoint.Socket = _socket;
-
- break;
+ return Connect(endPoint);
}
catch (SocketException e)
{
@@ -324,69 +389,125 @@ namespace Apache.Ignite.Core.Impl.Client
}
}
- if (_socket == null && errors != null)
- {
- throw new AggregateException("Failed to establish Ignite thin client connection, " +
- "examine inner exceptions for details.", errors);
- }
+ throw new AggregateException("Failed to establish Ignite thin client connection, " +
+ "examine inner exceptions for details.", errors);
+ }
- if (_socket != null &&
- _config.EnablePartitionAwareness &&
- _socket.ServerVersion < ClientOp.CachePartitions.GetMinVersion())
+ /// <summary>
+ /// Connects the socket.
+ /// </summary>
+ private void Connect()
+ {
+ _socket = GetNextSocket();
+
+ if (_config.EnablePartitionAwareness && !_socket.Features.HasOp(ClientOp.CachePartitions))
{
_config.EnablePartitionAwareness = false;
_logger.Warn("Partition awareness has been disabled: server protocol version {0} " +
"is lower than required {1}",
_socket.ServerVersion,
- ClientOp.CachePartitions.GetMinVersion()
+ ClientFeatures.GetMinVersion(ClientOp.CachePartitions)
);
}
+
+ if (!_socket.Features.HasFeature(ClientBitmaskFeature.ClusterGroupGetNodesEndpoints))
+ {
+ _enableDiscovery = false;
+
+ _logger.Warn("Automatic server node discovery is not supported by the server");
+ }
+ }
+
+ /// <summary>
+ /// Connects to the given endpoint.
+ /// </summary>
+ private ClientSocket Connect(SocketEndpoint endPoint)
+ {
+ var socket = new ClientSocket(_config, endPoint.EndPoint, endPoint.Host,
+ _config.ProtocolVersion, OnAffinityTopologyVersionChange, _marsh);
+
+ endPoint.Socket = socket;
+
+ return socket;
}
/// <summary>
/// Updates current Affinity Topology Version.
/// </summary>
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
+ Justification = "Thread root must catch all exceptions to avoid crashing the process.")]
private void OnAffinityTopologyVersionChange(AffinityTopologyVersion affinityTopologyVersion)
{
_affinityTopologyVersion = affinityTopologyVersion;
- if (_config.EnablePartitionAwareness)
+ if (_discoveryTopologyVersion < affinityTopologyVersion.Version &&_config.EnablePartitionAwareness)
{
- InitSocketMap();
+ ThreadPool.QueueUserWorkItem(_ =>
+ {
+ try
+ {
+ lock (_topologyUpdateLock)
+ {
+ if (!_disposed)
+ {
+ DiscoverEndpoints();
+ InitSocketMap();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ _logger.Log(LogLevel.Error, e, "Failed to update topology information");
+ }
+ });
}
}
/// <summary>
/// Gets the endpoints: all combinations of IP addresses and ports according to configuration.
/// </summary>
- private static IEnumerable<SocketEndpoint> GetIpEndPoints(IgniteClientConfiguration cfg)
+ private IEnumerable<SocketEndpoint> GetIpEndPoints(IgniteClientConfiguration cfg)
{
foreach (var e in Endpoint.GetEndpoints(cfg))
{
var host = e.Host;
Debug.Assert(host != null); // Checked by GetEndpoints.
- // GetHostEntry accepts IPs, but TryParse is a more efficient shortcut.
- IPAddress ip;
-
- if (IPAddress.TryParse(host, out ip))
+ for (var port = e.Port; port <= e.PortRange + e.Port; port++)
{
- for (var i = 0; i <= e.PortRange; i++)
+ foreach (var ip in GetIps(e.Host))
{
- yield return new SocketEndpoint(new IPEndPoint(ip, e.Port + i), host);
+ yield return new SocketEndpoint(new IPEndPoint(ip, port), e.Host);
}
}
- else
+ }
+ }
+
+ /// <summary>
+ /// Gets IP address list from a given host.
+ /// When host is an IP already - parses it. Otherwise, resolves DNS name to IPs.
+ /// </summary>
+ private IEnumerable<IPAddress> GetIps(string host, bool suppressExceptions = false)
+ {
+ try
+ {
+ IPAddress ip;
+
+ // GetHostEntry accepts IPs, but TryParse is a more efficient shortcut.
+ return IPAddress.TryParse(host, out ip) ? new[] {ip} : Dns.GetHostEntry(host).AddressList;
+
+ }
+ catch (SocketException e)
+ {
+ _logger.Debug(e, "Failed to parse host: " + host);
+
+ if (suppressExceptions)
{
- for (var i = 0; i <= e.PortRange; i++)
- {
- foreach (var x in Dns.GetHostEntry(host).AddressList)
- {
- yield return new SocketEndpoint(new IPEndPoint(x, e.Port + i), host);
- }
- }
+ return Enumerable.Empty<IPAddress>();
}
+
+ throw;
}
}
@@ -521,33 +642,187 @@ namespace Apache.Ignite.Core.Impl.Client
private void InitSocketMap()
{
- var map = new Dictionary<Guid, ClientSocket>();
+ var map = new Dictionary<Guid, ClientSocket>(_nodeSocketMap);
- foreach (var endPoint in _endPoints)
+ var defaultSocket = _socket;
+ if (defaultSocket != null && !defaultSocket.IsDisposed && defaultSocket.ServerNodeId != null)
{
- if (endPoint.Socket == null || endPoint.Socket.IsDisposed)
+ map[defaultSocket.ServerNodeId.Value] = defaultSocket;
+ }
+
+ if (_discoveryNodes != null)
+ {
+ // Discovery enabled: make sure we have connection to all nodes in the cluster.
+ foreach (var node in _discoveryNodes.Values)
{
- try
+ ClientSocket socket;
+ if (map.TryGetValue(node.Id, out socket) && !socket.IsDisposed)
{
- var socket = new ClientSocket(_config, endPoint.EndPoint, endPoint.Host,
- _config.ProtocolVersion, OnAffinityTopologyVersionChange, _marsh);
+ continue;
+ }
+
+ socket = TryConnect(node);
- endPoint.Socket = socket;
+ if (socket != null)
+ {
+ map[node.Id] = socket;
}
- catch (SocketException)
+ }
+
+ // Dispose and remove any connections not in current topology.
+ var toRemove = new List<Guid>();
+
+ foreach (var pair in map)
+ {
+ if (!_discoveryNodes.ContainsKey(pair.Key))
{
- continue;
+ pair.Value.Dispose();
+ toRemove.Add(pair.Key);
}
}
- var nodeId = endPoint.Socket.ServerNodeId;
- if (nodeId != null)
+ foreach (var nodeId in toRemove)
{
- map[nodeId.Value] = endPoint.Socket;
+ map.Remove(nodeId);
}
}
+ else
+ {
+ // Discovery disabled: fall back to endpoints from config.
+ foreach (var endPoint in _endPoints)
+ {
+ if (endPoint.Socket == null || endPoint.Socket.IsDisposed)
+ {
+ try
+ {
+ Connect(endPoint);
+ }
+ catch (SocketException)
+ {
+ continue;
+ }
+ }
+ // ReSharper disable once PossibleNullReferenceException (Connect ensures that).
+ var nodeId = endPoint.Socket.ServerNodeId;
+ if (nodeId != null)
+ {
+ map[nodeId.Value] = endPoint.Socket;
+ }
+ }
+ }
+
_nodeSocketMap = map;
}
+
+ private ClientSocket TryConnect(ClientDiscoveryNode node)
+ {
+ foreach (var addr in node.Addresses)
+ {
+ foreach (var ip in GetIps(addr, true))
+ {
+ try
+ {
+ var ipEndpoint = new IPEndPoint(ip, node.Port);
+
+ var socket = new ClientSocket(_config, ipEndpoint, addr,
+ _config.ProtocolVersion, OnAffinityTopologyVersionChange, _marsh);
+
+ if (socket.ServerNodeId == node.Id)
+ {
+ return socket;
+ }
+
+ _logger.Debug(
+ "Autodiscovery connection succeeded, but node id does not match: {0}, {1}. " +
+ "Expected node id: {2}. Actual node id: {3}. Connection dropped.",
+ addr, node.Port, node.Id, socket.ServerNodeId);
+ }
+ catch (SocketException socketEx)
+ {
+ // Ignore: failure to connect is expected.
+ _logger.Debug(socketEx, "Autodiscovery connection failed: {0}, {1}", addr, node.Port);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Updates endpoint info.
+ /// </summary>
+ private void DiscoverEndpoints()
+ {
+ if (!_enableDiscovery)
+ {
+ return;
+ }
+
+ var newVer = GetTopologyVersion();
+
+ if (newVer <= _discoveryTopologyVersion)
+ {
+ return;
+ }
+
+ var discoveryNodes = _discoveryNodes == null
+ ? new Dictionary<Guid, ClientDiscoveryNode>()
+ : new Dictionary<Guid, ClientDiscoveryNode>(_discoveryNodes);
+
+ _discoveryTopologyVersion = GetServerEndpoints(
+ _discoveryTopologyVersion, newVer, discoveryNodes);
+
+ _discoveryNodes = discoveryNodes;
+ }
+
+ /// <summary>
+ /// Gets all server endpoints.
+ /// </summary>
+ private long GetServerEndpoints(long startTopVer, long endTopVer, IDictionary<Guid, ClientDiscoveryNode> dict)
+ {
+ return DoOutInOp(ClientOp.ClusterGroupGetNodesEndpoints,
+ ctx =>
+ {
+ ctx.Writer.WriteLong(startTopVer);
+ ctx.Writer.WriteLong(endTopVer);
+ },
+ ctx =>
+ {
+ var s = ctx.Stream;
+
+ var topVer = s.ReadLong();
+
+ var addedCnt = s.ReadInt();
+
+ for (var i = 0; i < addedCnt; i++)
+ {
+ var id = BinaryUtils.ReadGuid(s);
+ var port = s.ReadInt();
+ var addresses = ctx.Reader.ReadStringCollection();
+
+ dict[id] = new ClientDiscoveryNode(id, port, addresses);
+ }
+
+ var removedCnt = s.ReadInt();
+
+ for (var i = 0; i < removedCnt; i++)
+ {
+ dict.Remove(BinaryUtils.ReadGuid(s));
+ }
+
+ return topVer;
+ });
+ }
+
+ /// <summary>
+ /// Gets current topology version.
+ /// </summary>
+ private long GetTopologyVersion()
+ {
+ var ver = _affinityTopologyVersion;
+
+ return ver == null ? UnknownTopologyVersion : ((AffinityTopologyVersion) ver).Version;
+ }
}
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientFeatures.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientFeatures.cs
new file mode 100644
index 0000000..3e782f1
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientFeatures.cs
@@ -0,0 +1,227 @@
+/*
+ * 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.Impl.Client
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Linq;
+ using Apache.Ignite.Core.Cache.Configuration;
+ using Apache.Ignite.Core.Client;
+
+ /// <summary>
+ /// Handles client features based on protocol version and feature flags.
+ /// </summary>
+ internal class ClientFeatures
+ {
+ /** Bit mask of all features. */
+ public static readonly byte[] AllFeatures = GetAllFeatures();
+
+ /** Current features. */
+ public static readonly ClientFeatures CurrentFeatures =
+ new ClientFeatures(ClientSocket.CurrentProtocolVersion, new BitArray(AllFeatures));
+
+ /** */
+ private static readonly Dictionary<ClientOp, ClientProtocolVersion> OpVersion =
+ new Dictionary<ClientOp, ClientProtocolVersion>
+ {
+ {ClientOp.CachePartitions, new ClientProtocolVersion(1, 4, 0)},
+ {ClientOp.ClusterIsActive, new ClientProtocolVersion(1, 5, 0)},
+ {ClientOp.ClusterChangeState, new ClientProtocolVersion(1, 5, 0)},
+ {ClientOp.ClusterChangeWalState, new ClientProtocolVersion(1, 5, 0)},
+ {ClientOp.ClusterGetWalState, new ClientProtocolVersion(1, 5, 0)},
+ {ClientOp.ClusterGroupGetNodeIds, new ClientProtocolVersion(1, 5, 0)},
+ {ClientOp.ClusterGroupGetNodesInfo, new ClientProtocolVersion(1, 5, 0)},
+ };
+
+ /** */
+ private static readonly Dictionary<ClientOp, ClientBitmaskFeature> OpFeature =
+ new Dictionary<ClientOp, ClientBitmaskFeature>
+ {
+ {ClientOp.ClusterGroupGetNodesEndpoints, ClientBitmaskFeature.ClusterGroupGetNodesEndpoints}
+ };
+
+ /** */
+ private readonly ClientProtocolVersion _protocolVersion;
+
+ /** */
+ private readonly BitArray _features;
+
+ /// <summary>
+ /// Initializes a new instance of <see cref="ClientFeatures"/>.
+ /// </summary>
+ public ClientFeatures(ClientProtocolVersion protocolVersion, BitArray features)
+ {
+ _protocolVersion = protocolVersion;
+ _features = features;
+ }
+
+ /// <summary>
+ /// Returns a value indicating whether specified feature is supported.
+ /// </summary>
+ public bool HasFeature(ClientBitmaskFeature feature)
+ {
+ var index = (int) feature;
+
+ return _features != null && index >= 0 && index < _features.Count && _features.Get(index);
+ }
+
+ /// <summary>
+ /// Returns a value indicating whether specified operation is supported.
+ /// </summary>
+ public bool HasOp(ClientOp op)
+ {
+ return ValidateOp(op, false);
+ }
+
+ /// <summary>
+ /// Checks whether WithExpiryPolicy request flag is supported. Throws an exception when not supported.
+ /// </summary>
+ public void ValidateWithExpiryPolicyFlag()
+ {
+ var requiredVersion = ClientSocket.Ver150;
+
+ if (_protocolVersion < requiredVersion)
+ {
+ ThrowMinimumVersionException("WithExpiryPolicy", requiredVersion);
+ }
+ }
+
+ /// <summary>
+ /// Returns a value indicating whether <see cref="QueryField.Precision"/> and <see cref="QueryField.Scale"/>
+ /// are supported.
+ /// </summary>
+ public bool HasQueryFieldPrecisionAndScale()
+ {
+ return _protocolVersion >= ClientSocket.Ver120;
+ }
+
+ /// <summary>
+ /// Returns a value indicating whether <see cref="CacheConfiguration.ExpiryPolicyFactory"/> is supported.
+ /// </summary>
+ public bool HasCacheConfigurationExpiryPolicyFactory()
+ {
+ return _protocolVersion >= ClientSocket.Ver160;
+ }
+
+ /// <summary>
+ /// Gets minimum protocol version that is required to perform specified operation.
+ /// </summary>
+ /// <param name="op">Operation.</param>
+ /// <returns>Minimum protocol version.</returns>
+ public static ClientProtocolVersion GetMinVersion(ClientOp op)
+ {
+ ClientProtocolVersion minVersion;
+
+ return OpVersion.TryGetValue(op, out minVersion)
+ ? minVersion
+ : ClientSocket.Ver100;
+ }
+
+ /// <summary>
+ /// Validates specified op code against current protocol version and features.
+ /// </summary>
+ /// <param name="operation">Operation.</param>
+ public void ValidateOp(ClientOp operation)
+ {
+ ValidateOp(operation, true);
+ }
+
+ /// <summary>
+ /// Validates specified op code against current protocol version and features.
+ /// </summary>
+ private bool ValidateOp(ClientOp operation, bool shouldThrow)
+ {
+ var requiredProtocolVersion = GetMinVersion(operation);
+
+ if (_protocolVersion < requiredProtocolVersion)
+ {
+ if (shouldThrow)
+ {
+ ThrowMinimumVersionException(operation, requiredProtocolVersion);
+ }
+
+ return false;
+ }
+
+ var requiredFeature = GetFeature(operation);
+
+ if (_features != null && requiredFeature != null && !_features.Get((int) requiredFeature.Value))
+ {
+ if (shouldThrow)
+ {
+ throw new IgniteClientException(string.Format(
+ "Operation {0} is not supported by the server. Feature {1} is missing.",
+ operation, requiredFeature.Value));
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Throws minimum version exception.
+ /// </summary>
+ private void ThrowMinimumVersionException(object operation, ClientProtocolVersion requiredProtocolVersion)
+ {
+ var message = string.Format("Operation {0} is not supported by protocol version {1}. " +
+ "Minimum protocol version required is {2}.",
+ operation, _protocolVersion, requiredProtocolVersion);
+
+ throw new IgniteClientException(message);
+ }
+
+ /// <summary>
+ /// Gets <see cref="ClientBitmaskFeature"/> that is required to perform specified operation.
+ /// </summary>
+ /// <param name="op">Operation.</param>
+ /// <returns>Required feature flag, or null.</returns>
+ private static ClientBitmaskFeature? GetFeature(ClientOp op)
+ {
+ ClientBitmaskFeature feature;
+
+ return OpFeature.TryGetValue(op, out feature)
+ ? feature
+ : (ClientBitmaskFeature?) null;
+ }
+
+ /// <summary>
+ /// Gets a bit array with all supported features.
+ /// </summary>
+ private static byte[] GetAllFeatures()
+ {
+ var values = Enum.GetValues(typeof(ClientBitmaskFeature))
+ .Cast<int>()
+ .ToArray();
+
+ var bits = new BitArray(values.Max() + 1);
+
+ foreach (var feature in values)
+ {
+ bits.Set(feature, true);
+ }
+
+ var bytes = new byte[1 + values.Length / 8];
+ bits.CopyTo(bytes, 0);
+
+ return bytes;
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOp.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOp.cs
index 91ce442..e75fbc9 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOp.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOp.cs
@@ -54,8 +54,6 @@ namespace Apache.Ignite.Core.Impl.Client
CacheGetOrCreateWithConfiguration = 1054,
CacheGetConfiguration = 1055,
CacheDestroy = 1056,
-
- [MinVersion(1, 4, 0)]
CachePartitions = 1101,
// Queries.
@@ -73,20 +71,12 @@ namespace Apache.Ignite.Core.Impl.Client
BinaryTypePut = 3003,
// Cluster.
- [MinVersion(1, 5, 0)]
ClusterIsActive = 5000,
-
- [MinVersion(1, 5, 0)]
ClusterChangeState = 5001,
-
- [MinVersion(1, 5, 0)]
ClusterChangeWalState = 5002,
-
- [MinVersion(1, 5, 0)]
ClusterGetWalState = 5003,
- [MinVersion(1, 5, 0)]
ClusterGroupGetNodeIds = 5100,
- [MinVersion(1, 5, 0)]
- ClusterGroupGetNodesInfo = 5101
+ ClusterGroupGetNodesInfo = 5101,
+ ClusterGroupGetNodesEndpoints = 5102
}
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOpExtensions.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOpExtensions.cs
deleted file mode 100644
index c50ce26f..0000000
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOpExtensions.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-namespace Apache.Ignite.Core.Impl.Client
-{
- using System;
- using System.Collections.Generic;
- using System.Linq;
-
- /// <summary>
- /// Extension methods for <see cref="ClientOp"/>.
- /// </summary>
- internal static class ClientOpExtensions
- {
- /** */
- private static readonly Dictionary<ClientOp, ClientProtocolVersion> VersionMap = GetVersionMap();
-
- /// <summary>
- /// Gets minimum protocol version that is required to perform specified operation.
- /// </summary>
- /// <param name="op">Operation.</param>
- /// <returns>Minimum protocol version.</returns>
- public static ClientProtocolVersion GetMinVersion(this ClientOp op)
- {
- ClientProtocolVersion minVersion;
-
- return VersionMap.TryGetValue(op, out minVersion)
- ? minVersion
- : ClientSocket.Ver100;
- }
-
- /// <summary>
- /// Gets the version map.
- /// </summary>
- private static Dictionary<ClientOp, ClientProtocolVersion> GetVersionMap()
- {
- var res = new Dictionary<ClientOp, ClientProtocolVersion>();
-
- foreach (var memberInfo in typeof(ClientOp).GetMembers())
- {
- var attr = memberInfo.GetCustomAttributes(false)
- .OfType<MinVersionAttribute>()
- .SingleOrDefault();
-
- if (attr == null)
- {
- continue;
- }
-
- var clientOp = (ClientOp) Enum.Parse(typeof(ClientOp), memberInfo.Name);
- res[clientOp] = attr.Version;
- }
-
- return res;
- }
- }
-}
\ No newline at end of file
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientRequestContext.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientRequestContext.cs
index d291136..dbd53e2 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientRequestContext.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientRequestContext.cs
@@ -33,9 +33,9 @@ namespace Apache.Ignite.Core.Impl.Client
/// </summary>
/// <param name="stream">Stream.</param>
/// <param name="marshaller">Marshaller.</param>
- /// <param name="protocolVersion">Protocol version to be used for this request.</param>
- public ClientRequestContext(IBinaryStream stream, Marshaller marshaller, ClientProtocolVersion protocolVersion)
- : base(stream, marshaller, protocolVersion)
+ /// <param name="features">Features supported by this request.</param>
+ public ClientRequestContext(IBinaryStream stream, Marshaller marshaller, ClientFeatures features)
+ : base(stream, marshaller, features)
{
// No-op.
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientResponseContext.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientResponseContext.cs
index 1ef1419..91b09ea 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientResponseContext.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientResponseContext.cs
@@ -33,9 +33,9 @@ namespace Apache.Ignite.Core.Impl.Client
/// </summary>
/// <param name="stream">Stream.</param>
/// <param name="marshaller">Marshaller.</param>
- /// <param name="protocolVersion">Protocol version to be used for this response.</param>
- public ClientResponseContext(IBinaryStream stream, Marshaller marshaller, ClientProtocolVersion protocolVersion)
- : base(stream, marshaller, protocolVersion)
+ /// <param name="features">Features supported by this request.</param>
+ public ClientResponseContext(IBinaryStream stream, Marshaller marshaller, ClientFeatures features)
+ : base(stream, marshaller, features)
{
// No-op.
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientSocket.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientSocket.cs
index 595ade9..09e7095 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientSocket.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientSocket.cs
@@ -18,6 +18,7 @@
namespace Apache.Ignite.Core.Impl.Client
{
using System;
+ using System.Collections;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
@@ -87,9 +88,6 @@ namespace Apache.Ignite.Core.Impl.Client
/** Callback checker guard. */
private volatile bool _checkingTimeouts;
- /** Server protocol version. */
- public ClientProtocolVersion ServerVersion { get; private set; }
-
/** Current async operations, map from request id. */
private readonly ConcurrentDictionary<long, Request> _requests
= new ConcurrentDictionary<long, Request>();
@@ -121,6 +119,9 @@ namespace Apache.Ignite.Core.Impl.Client
/** Marshaller. */
private readonly Marshaller _marsh;
+ /** Features. */
+ private readonly ClientFeatures _features;
+
/// <summary>
/// Initializes a new instance of the <see cref="ClientSocket" /> class.
/// </summary>
@@ -152,7 +153,7 @@ namespace Apache.Ignite.Core.Impl.Client
Validate(clientConfiguration);
- Handshake(clientConfiguration, ServerVersion);
+ _features = Handshake(clientConfiguration, ServerVersion);
// Check periodically if any request has timed out.
if (_timeout > TimeSpan.Zero)
@@ -227,6 +228,14 @@ namespace Apache.Ignite.Core.Impl.Client
}
/// <summary>
+ /// Gets the features.
+ /// </summary>
+ public ClientFeatures Features
+ {
+ get { return _features; }
+ }
+
+ /// <summary>
/// Gets the current remote EndPoint.
/// </summary>
public EndPoint RemoteEndPoint { get { return _socket.RemoteEndPoint; } }
@@ -250,6 +259,11 @@ namespace Apache.Ignite.Core.Impl.Client
}
/// <summary>
+ /// Gets the server protocol version.
+ /// </summary>
+ public ClientProtocolVersion ServerVersion { get; private set; }
+
+ /// <summary>
/// Starts waiting for the new message.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
@@ -347,7 +361,7 @@ namespace Apache.Ignite.Core.Impl.Client
if (statusCode == ClientStatusCode.Success)
{
return readFunc != null
- ? readFunc(new ClientResponseContext(stream, _marsh, ServerVersion))
+ ? readFunc(new ClientResponseContext(stream, _marsh, _features))
: default(T);
}
@@ -364,10 +378,10 @@ namespace Apache.Ignite.Core.Impl.Client
/// <summary>
/// Performs client protocol handshake.
/// </summary>
- private void Handshake(IgniteClientConfiguration clientConfiguration, ClientProtocolVersion version)
+ private ClientFeatures Handshake(IgniteClientConfiguration clientConfiguration, ClientProtocolVersion version)
{
- bool auth = version >= Ver110 && clientConfiguration.UserName != null;
- bool features = version >= Ver170;
+ var hasAuth = version >= Ver110 && clientConfiguration.UserName != null;
+ var hasFeatures = version >= Ver170;
// Send request.
int messageLen;
@@ -385,16 +399,14 @@ namespace Apache.Ignite.Core.Impl.Client
stream.WriteByte(ClientType);
// Writing features.
- if (features)
+ if (hasFeatures)
{
- // TODO: Implement client-side features.
- var featureBytes = new byte[0];
-
- BinaryUtils.Marshaller.Marshal(stream, w => w.WriteByteArray(featureBytes));
+ BinaryUtils.Marshaller.Marshal(stream,
+ w => w.WriteByteArray(ClientFeatures.AllFeatures));
}
// Authentication data.
- if (auth)
+ if (hasAuth)
{
BinaryUtils.Marshaller.Marshal(stream, writer =>
{
@@ -416,10 +428,11 @@ namespace Apache.Ignite.Core.Impl.Client
if (success)
{
- if (version >= Ver170)
+ BitArray featureBits = null;
+
+ if (hasFeatures)
{
- // TODO: Implement features support
- BinaryUtils.Marshaller.Unmarshal<byte[]>(stream);
+ featureBits = new BitArray(BinaryUtils.Marshaller.Unmarshal<byte[]>(stream));
}
if (version >= Ver140)
@@ -432,7 +445,7 @@ namespace Apache.Ignite.Core.Impl.Client
_logger.Debug("Handshake completed on {0}, protocol version = {1}",
_socket.RemoteEndPoint, version);
- return;
+ return new ClientFeatures(version, featureBits);
}
ServerVersion =
@@ -467,14 +480,12 @@ namespace Apache.Ignite.Core.Impl.Client
_logger.Debug("Retrying handshake on {0} with protocol version {1}",
_socket.RemoteEndPoint, ServerVersion);
- Handshake(clientConfiguration, ServerVersion);
- }
- else
- {
- throw new IgniteClientException(string.Format(
- "Client handshake failed: '{0}'. Client version: {1}. Server version: {2}",
- errMsg, version, ServerVersion), null, errCode);
+ return Handshake(clientConfiguration, ServerVersion);
}
+
+ throw new IgniteClientException(string.Format(
+ "Client handshake failed: '{0}'. Client version: {1}. Server version: {2}",
+ errMsg, version, ServerVersion), null, errCode);
}
}
@@ -606,7 +617,7 @@ namespace Apache.Ignite.Core.Impl.Client
/// </summary>
private RequestMessage WriteMessage(Action<ClientRequestContext> writeAction, ClientOp opId)
{
- ClientUtils.ValidateOp(opId, ServerVersion);
+ _features.ValidateOp(opId);
var requestId = Interlocked.Increment(ref _requestId);
@@ -621,7 +632,7 @@ namespace Apache.Ignite.Core.Impl.Client
if (writeAction != null)
{
- var ctx = new ClientRequestContext(stream, _marsh, ServerVersion);
+ var ctx = new ClientRequestContext(stream, _marsh, _features);
writeAction(ctx);
ctx.FinishMarshal();
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientUtils.cs
deleted file mode 100644
index e9bec08..0000000
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientUtils.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-namespace Apache.Ignite.Core.Impl.Client
-{
- using Apache.Ignite.Core.Client;
-
- /// <summary>
- /// Client utils.
- /// </summary>
- internal static class ClientUtils
- {
- /// <summary>
- /// Validates op code against current protocol version.
- /// </summary>
- /// <param name="operation">Operation.</param>
- /// <param name="protocolVersion">Protocol version.</param>
- public static void ValidateOp(ClientOp operation, ClientProtocolVersion protocolVersion)
- {
- ValidateOp(operation, protocolVersion, operation.GetMinVersion());
- }
-
- /// <summary>
- /// Validates op code against current protocol version.
- /// </summary>
- /// <param name="operation">Operation.</param>
- /// <param name="protocolVersion">Protocol version.</param>
- /// <param name="requiredProtocolVersion">Required protocol version.</param>
- public static void ValidateOp<T>(T operation, ClientProtocolVersion protocolVersion,
- ClientProtocolVersion requiredProtocolVersion)
- {
- if (protocolVersion >= requiredProtocolVersion)
- {
- return;
- }
-
- var message = string.Format("Operation {0} is not supported by protocol version {1}. " +
- "Minimum protocol version required is {2}.",
- operation, protocolVersion, requiredProtocolVersion);
-
- throw new IgniteClientException(message);
- }
- }
-}
\ No newline at end of file
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Endpoint.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Endpoint.cs
index a42d6cd..1d56b6d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Endpoint.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Endpoint.cs
@@ -29,7 +29,7 @@ namespace Apache.Ignite.Core.Impl.Client
internal class Endpoint
{
/** */
- private static readonly string[] HostSeparators = {":"};
+ private const char HostSeparator = ':';
/** */
private static readonly string[] PortsSeparators = {".."};
@@ -84,7 +84,7 @@ namespace Apache.Ignite.Core.Impl.Client
/// <summary>
/// Parses the endpoint string.
/// </summary>
- private static Endpoint ParseEndpoint(string endpoint)
+ public static Endpoint ParseEndpoint(string endpoint)
{
if (string.IsNullOrWhiteSpace(endpoint))
{
@@ -92,38 +92,35 @@ namespace Apache.Ignite.Core.Impl.Client
"IgniteClientConfiguration.Endpoints[...] can't be null or whitespace.");
}
- var parts = endpoint.Split(HostSeparators, StringSplitOptions.None);
+ var idx = endpoint.LastIndexOf(HostSeparator);
- if (parts.Length == 1)
+ if (idx == -1)
{
return new Endpoint(endpoint);
}
- if (parts.Length == 2)
+ var host = endpoint.Substring(0, idx);
+ var port = endpoint.Substring(idx + 1);
+
+ var ports = port.Split(PortsSeparators, StringSplitOptions.None);
+
+ if (ports.Length == 1)
{
- var host = parts[0];
- var port = parts[1];
+ return new Endpoint(host, ParsePort(endpoint, port));
+ }
- var ports = port.Split(PortsSeparators, StringSplitOptions.None);
+ if (ports.Length == 2)
+ {
+ var minPort = ParsePort(endpoint, ports[0]);
+ var maxPort = ParsePort(endpoint, ports[1]);
- if (ports.Length == 1)
+ if (maxPort < minPort)
{
- return new Endpoint(host, ParsePort(endpoint, port));
+ throw new IgniteClientException(
+ "Invalid format of IgniteClientConfiguration.Endpoint, port range is empty: " + endpoint);
}
- if (ports.Length == 2)
- {
- var minPort = ParsePort(endpoint, ports[0]);
- var maxPort = ParsePort(endpoint, ports[1]);
-
- if (maxPort < minPort)
- {
- throw new IgniteClientException(
- "Invalid format of IgniteClientConfiguration.Endpoint, port range is empty: " + endpoint);
- }
-
- return new Endpoint(host, minPort, maxPort - minPort);
- }
+ return new Endpoint(host, minPort, maxPort - minPort);
}
throw new IgniteClientException("Unrecognized format of IgniteClientConfiguration.Endpoint: " + endpoint);
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/IgniteClient.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/IgniteClient.cs
index 7d57c0d..4f1100b 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/IgniteClient.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/IgniteClient.cs
@@ -62,6 +62,9 @@ namespace Apache.Ignite.Core.Impl.Client
/** Node info cache. */
private readonly ConcurrentDictionary<Guid, IClientClusterNode> _nodes =
new ConcurrentDictionary<Guid, IClientClusterNode>();
+
+ /** Cluster. */
+ private readonly ClientCluster _cluster;
/// <summary>
/// Initializes a new instance of the <see cref="IgniteClient"/> class.
@@ -83,6 +86,8 @@ namespace Apache.Ignite.Core.Impl.Client
_binProc = _configuration.BinaryProcessor ?? new BinaryProcessorClient(_socket);
_binary = new Binary(_marsh);
+
+ _cluster = new ClientCluster(this, _marsh);
}
/// <summary>
@@ -125,7 +130,7 @@ namespace Apache.Ignite.Core.Impl.Client
IgniteArgumentCheck.NotNull(configuration, "configuration");
DoOutOp(ClientOp.CacheGetOrCreateWithConfiguration,
- ctx => ClientCacheConfigurationSerializer.Write(ctx.Stream, configuration, ctx.ProtocolVersion));
+ ctx => ClientCacheConfigurationSerializer.Write(ctx.Stream, configuration, ctx.Features));
return GetCache<TK, TV>(configuration.Name);
}
@@ -146,7 +151,7 @@ namespace Apache.Ignite.Core.Impl.Client
IgniteArgumentCheck.NotNull(configuration, "configuration");
DoOutOp(ClientOp.CacheCreateWithConfiguration,
- ctx => ClientCacheConfigurationSerializer.Write(ctx.Stream, configuration, ctx.ProtocolVersion));
+ ctx => ClientCacheConfigurationSerializer.Write(ctx.Stream, configuration, ctx.Features));
return GetCache<TK, TV>(configuration.Name);
}
@@ -160,7 +165,7 @@ namespace Apache.Ignite.Core.Impl.Client
/** <inheritDoc /> */
public IClientCluster GetCluster()
{
- return new ClientCluster(this, _marsh);
+ return _cluster;
}
/** <inheritDoc /> */
@@ -221,6 +226,12 @@ namespace Apache.Ignite.Core.Impl.Client
}
/** <inheritDoc /> */
+ public IEnumerable<IClientConnection> GetConnections()
+ {
+ return _socket.GetConnections();
+ }
+
+ /** <inheritDoc /> */
public IBinaryProcessor BinaryProcessor
{
get { return _binProc; }
diff --git a/modules/platforms/dotnet/DEVNOTES.txt b/modules/platforms/dotnet/DEVNOTES.txt
index 3e632fe..dcfaaf7 100644
--- a/modules/platforms/dotnet/DEVNOTES.txt
+++ b/modules/platforms/dotnet/DEVNOTES.txt
@@ -50,9 +50,9 @@ Getting started:
./build.sh
* Run tests:
cd Apache.Ignite.Core.Tests.DotNetCore
- dotnet test --logger "console;verbosity=normal"
+ dotnet test --logger "console;verbosity=detailed"
* Run specific test:
- dotnet test --filter CacheTest --logger "console;verbosity=normal"
+ dotnet test --filter CacheTest --logger "console;verbosity=detailed"
* IDE: Open Apache.Ignite.DotNetCore.sln