You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2017/09/18 08:43:08 UTC
[08/26] ignite git commit: IGNITE-6368: Initial .NET part of thin
client. This closes #2670.
IGNITE-6368: Initial .NET part of thin client. This closes #2670.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/a00052e9
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/a00052e9
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/a00052e9
Branch: refs/heads/ignite-6149
Commit: a00052e94531528c5df0dc4485d8882514b40af4
Parents: 8741acc
Author: Pavel Tupitsyn <pt...@apache.org>
Authored: Fri Sep 15 14:05:53 2017 +0300
Committer: devozerov <vo...@gridgain.com>
Committed: Fri Sep 15 14:05:53 2017 +0300
----------------------------------------------------------------------
.../Apache.Ignite.Core.Tests.csproj | 6 +
.../Binary/BinaryFooterTest.cs | 2 +-
.../Client/CacheTest.cs | 201 ++++++++++++++
.../Client/CacheTestNoMeta.cs | 159 +++++++++++
.../Client/ClientConnectionTest.cs | 146 ++++++++++
.../Client/IgniteClientConfigurationTest.cs | 42 +++
.../Apache.Ignite.Core.Tests/Client/Person.cs | 48 ++++
.../Client/RawSocketTest.cs | 164 ++++++++++++
.../IgniteConfigurationTest.cs | 2 +
.../Apache.Ignite.Core.csproj | 9 +
.../dotnet/Apache.Ignite.Core/Cache/ICache.cs | 9 +-
.../Client/Cache/ICacheClient.cs | 59 +++++
.../Apache.Ignite.Core/Client/IIgniteClient.cs | 44 ++++
.../Client/IgniteClientConfiguration.cs | 104 ++++++++
.../dotnet/Apache.Ignite.Core/IIgnite.cs | 4 +-
.../dotnet/Apache.Ignite.Core/Ignition.cs | 17 ++
.../Impl/Binary/BinaryProcessorClient.cs | 113 ++++++++
.../Impl/Binary/BinaryUtils.cs | 16 +-
.../Apache.Ignite.Core/Impl/Cache/CacheImpl.cs | 4 +-
.../Impl/Client/Cache/CacheClient.cs | 160 +++++++++++
.../Apache.Ignite.Core/Impl/Client/ClientOp.cs | 32 +++
.../Impl/Client/ClientProtocolVersion.cs | 119 +++++++++
.../Impl/Client/ClientSocket.cs | 263 +++++++++++++++++++
.../Impl/Client/IgniteClient.cs | 152 +++++++++++
.../Impl/Cluster/ClusterGroupImpl.cs | 2 +-
.../Impl/Compute/ComputeJobHolder.cs | 2 +-
.../Impl/Deployment/PeerAssemblyResolver.cs | 4 +-
.../Impl/Deployment/PeerLoadingObjectHolder.cs | 2 +-
.../Apache.Ignite.Core/Impl/ExceptionUtils.cs | 7 +-
.../Apache.Ignite.Core/Impl/IIgniteInternal.cs | 13 +-
.../dotnet/Apache.Ignite.Core/Impl/Ignite.cs | 10 +-
31 files changed, 1891 insertions(+), 24 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
----------------------------------------------------------------------
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 3f5f9b3..31e95fb 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
@@ -92,6 +92,12 @@
<Compile Include="Cache\Query\Linq\CacheLinqTest.Contains.cs" />
<Compile Include="Cache\Store\CacheStoreSessionTestCodeConfig.cs" />
<Compile Include="Cache\Store\CacheStoreSessionTestSharedFactory.cs" />
+ <Compile Include="Client\CacheTestNoMeta.cs" />
+ <Compile Include="Client\Person.cs" />
+ <Compile Include="Client\RawSocketTest.cs" />
+ <Compile Include="Client\CacheTest.cs" />
+ <Compile Include="Client\ClientConnectionTest.cs" />
+ <Compile Include="Client\IgniteClientConfigurationTest.cs" />
<Compile Include="Deployment\CacheGetFunc.cs" />
<Compile Include="Deployment\GetAddressFunc.cs" />
<Compile Include="Deployment\PeerAssemblyLoadingAllApisTest.cs" />
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryFooterTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryFooterTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryFooterTest.cs
index 5088e5a..9fa4538 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryFooterTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryFooterTest.cs
@@ -137,7 +137,7 @@ namespace Apache.Ignite.Core.Tests.Binary
return;
}
- var cache = ignite.GetOrCreateCache<int, OffsetTest>(
+ var cache = ignite.GetIgnite().GetOrCreateCache<int, OffsetTest>(
new CacheConfiguration("offs", new QueryEntity(typeof(int), typeof(OffsetTest))));
// Cache operation.
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/CacheTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/CacheTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/CacheTest.cs
new file mode 100644
index 0000000..2831e57
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/CacheTest.cs
@@ -0,0 +1,201 @@
+/*
+ * 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.Collections.Concurrent;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Net;
+ using System.Threading;
+ using Apache.Ignite.Core.Binary;
+ using Apache.Ignite.Core.Cache;
+ using Apache.Ignite.Core.Client;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Thin client cache test.
+ /// </summary>
+ public sealed class CacheTest
+ {
+ /** Cache name. */
+ private const string CacheName = "cache";
+
+ /// <summary>
+ /// Fixture tear down.
+ /// </summary>
+ [TestFixtureSetUp]
+ public void FixtureSetUp()
+ {
+ Ignition.Start(TestUtils.GetTestConfiguration());
+ }
+
+ /// <summary>
+ /// Fixture tear down.
+ /// </summary>
+ [TestFixtureTearDown]
+ public void FixtureTearDown()
+ {
+ Ignition.StopAll(true);
+ }
+
+ /// <summary>
+ /// Tests the cache put / get with primitive data types.
+ /// </summary>
+ [Test]
+ public void TestPutGetPrimitives()
+ {
+ using (var client = GetClient())
+ {
+ GetCache<string>().Put(1, "foo");
+
+ var clientCache = client.GetCache<int?, string>(CacheName);
+
+ clientCache.Put(2, "bar");
+ clientCache[3] = "baz";
+
+ // Existing key.
+ Assert.AreEqual("foo", clientCache.Get(1));
+ Assert.AreEqual("foo", clientCache[1]);
+ Assert.AreEqual("bar", clientCache[2]);
+ Assert.AreEqual("baz", clientCache[3]);
+
+ // Missing key.
+ Assert.Throws<KeyNotFoundException>(() => clientCache.Get(-1));
+
+ // Null key.
+ Assert.Throws<ArgumentNullException>(() => clientCache.Get(null));
+ }
+ }
+
+ /// <summary>
+ /// Tests the cache put / get with user data types.
+ /// </summary>
+ [Test]
+ public void TestPutGetUserObjects([Values(true, false)] bool compactFooter)
+ {
+ var cfg = GetClientConfiguration();
+
+ cfg.BinaryConfiguration = new BinaryConfiguration
+ {
+ CompactFooter = compactFooter
+ };
+
+ using (var client = Ignition.StartClient(cfg))
+ {
+ var person = new Person {Id = 100, Name = "foo"};
+ var person2 = new Person2 {Id = 200, Name = "bar"};
+
+ var serverCache = GetCache<Person>();
+ var clientCache = client.GetCache<int?, Person>(CacheName);
+
+ Assert.AreEqual(CacheName, clientCache.Name);
+
+ // Put through server cache.
+ serverCache.Put(1, person);
+
+ // Put through client cache.
+ clientCache.Put(2, person2);
+ clientCache[3] = person2;
+
+ // Read from client cache.
+ Assert.AreEqual("foo", clientCache.Get(1).Name);
+ Assert.AreEqual(100, clientCache[1].Id);
+ Assert.AreEqual(200, clientCache[2].Id);
+ Assert.AreEqual(200, clientCache[3].Id);
+
+ // Read from server cache.
+ Assert.AreEqual("foo", serverCache.Get(1).Name);
+ Assert.AreEqual(100, serverCache[1].Id);
+ Assert.AreEqual(200, serverCache[2].Id);
+ Assert.AreEqual(200, serverCache[3].Id);
+
+ // Null key or value.
+ Assert.Throws<ArgumentNullException>(() => clientCache.Put(10, null));
+ Assert.Throws<ArgumentNullException>(() => clientCache.Put(null, person));
+ }
+ }
+
+ /// <summary>
+ /// Tests client get in multiple threads with a single client.
+ /// </summary>
+ [Test]
+ [Category(TestUtils.CategoryIntensive)]
+ public void TestGetMultithreadedSingleClient()
+ {
+ GetCache<string>().Put(1, "foo");
+
+ using (var client = GetClient())
+ {
+ var clientCache = client.GetCache<int, string>(CacheName);
+
+ TestUtils.RunMultiThreaded(() => Assert.AreEqual("foo", clientCache.Get(1)),
+ Environment.ProcessorCount, 5);
+ }
+ }
+
+ /// <summary>
+ /// Tests client get in multiple threads with multiple clients.
+ /// </summary>
+ [Test]
+ [Category(TestUtils.CategoryIntensive)]
+ public void TestGetMultithreadedMultiClient()
+ {
+ GetCache<string>().Put(1, "foo");
+
+ // One client per thread.
+ var clients = new ConcurrentDictionary<int, IIgniteClient>();
+
+ TestUtils.RunMultiThreaded(() =>
+ {
+ var client = clients.GetOrAdd(Thread.CurrentThread.ManagedThreadId, _ => GetClient());
+
+ var clientCache = client.GetCache<int, string>(CacheName);
+
+ Assert.AreEqual("foo", clientCache.Get(1));
+ },
+ Environment.ProcessorCount, 5);
+
+ clients.ToList().ForEach(x => x.Value.Dispose());
+ }
+
+ /// <summary>
+ /// Gets the cache.
+ /// </summary>
+ private static ICache<int, T> GetCache<T>()
+ {
+ return Ignition.GetIgnite().GetOrCreateCache<int, T>(CacheName);
+ }
+
+ /// <summary>
+ /// Gets the client.
+ /// </summary>
+ private static IIgniteClient GetClient()
+ {
+ return Ignition.StartClient(GetClientConfiguration());
+ }
+
+ /// <summary>
+ /// Gets the client configuration.
+ /// </summary>
+ private static IgniteClientConfiguration GetClientConfiguration()
+ {
+ return new IgniteClientConfiguration {Host = "127.0.0.1"};
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/CacheTestNoMeta.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/CacheTestNoMeta.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/CacheTestNoMeta.cs
new file mode 100644
index 0000000..a011583
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/CacheTestNoMeta.cs
@@ -0,0 +1,159 @@
+/*
+ * 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.Collections.Generic;
+ using System.Linq;
+ using System.Net;
+ using Apache.Ignite.Core.Binary;
+ using Apache.Ignite.Core.Cache.Configuration;
+ using Apache.Ignite.Core.Cache.Query;
+ using Apache.Ignite.Core.Client;
+ using Apache.Ignite.Core.Impl.Binary;
+ using Apache.Ignite.Core.Impl.Binary.Metadata;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Client cache test without metadata (no-op binary processor).
+ /// </summary>
+ public class CacheTestNoMeta
+ {
+ /** Cache name. */
+ private const string CacheName = "cache";
+
+ /// <summary>
+ /// Fixture tear down.
+ /// </summary>
+ [TestFixtureSetUp]
+ public void FixtureSetUp()
+ {
+ Ignition.Start(TestUtils.GetTestConfiguration());
+ }
+
+ /// <summary>
+ /// Fixture tear down.
+ /// </summary>
+ [TestFixtureTearDown]
+ public void FixtureTearDown()
+ {
+ Ignition.StopAll(true);
+ }
+
+ /// <summary>
+ /// Tests the cache put / get with user data types.
+ /// </summary>
+ [Test]
+ public void TestPutGetUserObjects()
+ {
+ var cfg = new IgniteClientConfiguration
+ {
+ BinaryProcessor = new NoopBinaryProcessor(),
+ BinaryConfiguration = new BinaryConfiguration
+ {
+ CompactFooter = false
+ },
+ Host = IPAddress.Loopback.ToString()
+ };
+
+ using (var client = Ignition.StartClient(cfg))
+ {
+ var serverCache = Ignition.GetIgnite().GetOrCreateCache<int?, Person>(
+ new CacheConfiguration(CacheName, new QueryEntity
+ {
+ KeyType = typeof(int),
+ ValueType = typeof(Person),
+ Fields = new[]
+ {
+ new QueryField("id", typeof(int)),
+ new QueryField("name", typeof(string))
+ }
+ }));
+
+ var clientCache = client.GetCache<int?, Person>(CacheName);
+
+ // Put through client cache.
+ clientCache.Put(1, new Person { Id = 100, Name = "foo" });
+ clientCache[2] = new Person { Id = 200, Name = "bar" };
+
+ // Read from client cache.
+ Assert.AreEqual("foo", clientCache.Get(1).Name);
+ Assert.AreEqual(100, clientCache[1].Id);
+ Assert.AreEqual(200, clientCache[2].Id);
+
+ // Read from server cache.
+ Assert.AreEqual("foo", serverCache.Get(1).Name);
+ Assert.AreEqual(100, serverCache[1].Id);
+ Assert.AreEqual(200, serverCache[2].Id);
+
+ // SQL from server cache.
+ var sqlRes = serverCache.Query(new SqlQuery(typeof(Person), "where id = 100")).GetAll().Single();
+ Assert.AreEqual(1, sqlRes.Key);
+ Assert.AreEqual(100, sqlRes.Value.Id);
+ Assert.AreEqual("foo", sqlRes.Value.Name);
+ }
+ }
+
+ /// <summary>
+ /// No-op binary processor (does not send meta to cluster).
+ /// </summary>
+ private class NoopBinaryProcessor : IBinaryProcessor
+ {
+ /** <inheritdoc /> */
+ public BinaryType GetBinaryType(int typeId)
+ {
+ return null;
+ }
+
+ /** <inheritdoc /> */
+ public List<IBinaryType> GetBinaryTypes()
+ {
+ return null;
+ }
+
+ /** <inheritdoc /> */
+ public int[] GetSchema(int typeId, int schemaId)
+ {
+ return null;
+ }
+
+ /** <inheritdoc /> */
+ public void PutBinaryTypes(ICollection<BinaryType> types)
+ {
+ // No-op.
+ }
+
+ /** <inheritdoc /> */
+ public bool RegisterType(int id, string typeName)
+ {
+ return false;
+ }
+
+ /** <inheritdoc /> */
+ public BinaryType RegisterEnum(string typeName, IEnumerable<KeyValuePair<string, int>> values)
+ {
+ return null;
+ }
+
+ /** <inheritdoc /> */
+ public string GetTypeName(int id)
+ {
+ return null;
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
new file mode 100644
index 0000000..8874bb5
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Tests.Client
+{
+ using System;
+ using System.Linq;
+ using System.Net;
+ using System.Net.Sockets;
+ using Apache.Ignite.Core.Client;
+ using Apache.Ignite.Core.Common;
+ using Apache.Ignite.Core.Configuration;
+ using Apache.Ignite.Core.Impl.Client;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Tests client connection: port ranges, version checks, etc.
+ /// </summary>
+ public class ClientConnectionTest
+ {
+ /// <summary>
+ /// Fixture tear down.
+ /// </summary>
+ [TestFixtureTearDown]
+ public void FixtureTearDown()
+ {
+ Ignition.StopAll(true);
+ }
+
+ /// <summary>
+ /// Tests that missing server yields connection refused error.
+ /// </summary>
+ [Test]
+ public void TestNoServerConnectionRefused()
+ {
+ var ex = Assert.Throws<AggregateException>(() => StartClient());
+ var socketEx = ex.InnerExceptions.OfType<SocketException>().First();
+ Assert.AreEqual(SocketError.ConnectionRefused, socketEx.SocketErrorCode);
+ }
+
+ /// <summary>
+ /// Tests that multiple clients can connect to one server.
+ /// </summary>
+ [Test]
+ public void TestMultipleClients()
+ {
+ using (Ignition.Start(TestUtils.GetTestConfiguration()))
+ {
+ var client1 = StartClient();
+ var client2 = StartClient();
+ var client3 = StartClient();
+
+ client1.Dispose();
+ client2.Dispose();
+ client3.Dispose();
+ }
+ }
+
+ /// <summary>
+ /// Tests custom connector and client configuration.
+ /// </summary>
+ [Test]
+ [Category(TestUtils.CategoryIntensive)]
+ public void TestCustomConfig()
+ {
+ var servCfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
+ {
+ SqlConnectorConfiguration = new SqlConnectorConfiguration
+ {
+ Host = "localhost",
+ Port = 2000,
+ PortRange = 1
+ }
+ };
+
+ var clientCfg = new IgniteClientConfiguration
+ {
+ Host = "localhost",
+ Port = 2000
+ };
+
+ using (Ignition.Start(servCfg))
+ using (Ignition.StartClient(clientCfg))
+ {
+ // No-op.
+ }
+ }
+
+ /// <summary>
+ /// Tests that default configuration throws.
+ /// </summary>
+ [Test]
+ public void TestDefaultConfigThrows()
+ {
+ Assert.Throws<ArgumentNullException>(() => Ignition.StartClient(new IgniteClientConfiguration()));
+ }
+
+ /// <summary>
+ /// Tests the incorrect protocol version error.
+ /// </summary>
+ [Test]
+ [Category(TestUtils.CategoryIntensive)]
+ public void TestIncorrectProtocolVersionError()
+ {
+ using (Ignition.Start(TestUtils.GetTestConfiguration()))
+ {
+ // ReSharper disable once ObjectCreationAsStatement
+ var ex = Assert.Throws<IgniteException>(() => new ClientSocket(GetClientConfiguration(),
+ new ClientProtocolVersion(-1, -1, -1)));
+
+ Assert.AreEqual("Client handhsake failed: 'Unsupported version.'. " +
+ "Client version: -1.-1.-1. Server version: 1.0.0", ex.Message);
+ }
+ }
+
+ /// <summary>
+ /// Starts the client.
+ /// </summary>
+ private static IIgniteClient StartClient()
+ {
+ return Ignition.StartClient(GetClientConfiguration());
+ }
+
+ /// <summary>
+ /// Gets the client configuration.
+ /// </summary>
+ private static IgniteClientConfiguration GetClientConfiguration()
+ {
+ return new IgniteClientConfiguration { Host = IPAddress.Loopback.ToString() };
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/IgniteClientConfigurationTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/IgniteClientConfigurationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/IgniteClientConfigurationTest.cs
new file mode 100644
index 0000000..0734f42
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/IgniteClientConfigurationTest.cs
@@ -0,0 +1,42 @@
+/*
+ * 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 Apache.Ignite.Core.Client;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Tests for <see cref="IgniteClientConfiguration"/>.
+ /// </summary>
+ public class IgniteClientConfigurationTest
+ {
+ /// <summary>
+ /// Tests the defaults.
+ /// </summary>
+ [Test]
+ public void TestDefaults()
+ {
+ var cfg = new IgniteClientConfiguration();
+
+ Assert.AreEqual(IgniteClientConfiguration.DefaultPort, cfg.Port);
+ Assert.AreEqual(IgniteClientConfiguration.DefaultSocketBufferSize, cfg.SocketReceiveBufferSize);
+ Assert.AreEqual(IgniteClientConfiguration.DefaultSocketBufferSize, cfg.SocketSendBufferSize);
+ Assert.AreEqual(IgniteClientConfiguration.DefaultTcpNoDelay, cfg.TcpNoDelay);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Person.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Person.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Person.cs
new file mode 100644
index 0000000..7f0309f
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Person.cs
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Tests.Client
+{
+ /// <summary>
+ /// Test person.
+ /// </summary>
+ public class Person
+ {
+ /// <summary>
+ /// Gets or sets the identifier.
+ /// </summary>
+ public int Id { get; set; }
+
+ /// <summary>
+ /// Gets or sets the name.
+ /// </summary>
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the parent.
+ /// </summary>
+ public Person Parent { get;set; }
+ }
+
+ /// <summary>
+ /// Test person 2.
+ /// </summary>
+ public class Person2 : Person
+ {
+ // No-op.
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSocketTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSocketTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSocketTest.cs
new file mode 100644
index 0000000..9e2200f
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSocketTest.cs
@@ -0,0 +1,164 @@
+/*
+ * 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.Net;
+ using System.Net.Sockets;
+ using Apache.Ignite.Core.Cache.Configuration;
+ using Apache.Ignite.Core.Configuration;
+ using Apache.Ignite.Core.Impl;
+ using Apache.Ignite.Core.Impl.Binary;
+ using Apache.Ignite.Core.Impl.Binary.IO;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Tests the thin client mode with a raw socket.
+ /// </summary>
+ public class RawSocketTest
+ {
+ /// <summary>
+ /// Tests the socket handshake connection.
+ /// </summary>
+ [Test]
+ public void TestCacheGet()
+ {
+ var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
+ {
+ SqlConnectorConfiguration = new SqlConnectorConfiguration()
+ };
+
+ using (var ignite = Ignition.Start(cfg))
+ {
+ var marsh = ((Ignite) ignite).Marshaller;
+
+ // Create cache.
+ var cacheCfg = new CacheConfiguration("foo", new QueryEntity(typeof(int), typeof(string)));
+ var cache = ignite.CreateCache<int, string>(cacheCfg);
+ cache[1] = "bar";
+
+ // Connect socket.
+ var sock = GetSocket(SqlConnectorConfiguration.DefaultPort);
+ Assert.IsTrue(sock.Connected);
+
+ DoHandshake(sock);
+
+ // Cache get.
+ SendRequest(sock, stream =>
+ {
+ stream.WriteShort(1); // OP_GET
+ stream.WriteLong(1); // Request id.
+ var cacheId = BinaryUtils.GetStringHashCode(cache.Name);
+ stream.WriteInt(cacheId);
+ stream.WriteByte(0); // Flags (withSkipStore, etc)
+
+ var writer = marsh.StartMarshal(stream);
+
+ writer.WriteObject(1); // Key
+ });
+
+ var msg = ReceiveMessage(sock);
+
+ using (var stream = new BinaryHeapStream(msg))
+ {
+ var reader = marsh.StartUnmarshal(stream);
+
+ var requestId = reader.ReadLong();
+ Assert.AreEqual(1, requestId);
+
+ var res = reader.ReadObject<string>();
+ Assert.AreEqual(cache[1], res);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Does the handshake.
+ /// </summary>
+ /// <param name="sock">The sock.</param>
+ private static void DoHandshake(Socket sock)
+ {
+ var sentBytes = SendRequest(sock, stream =>
+ {
+ // Handshake.
+ stream.WriteByte(1);
+
+ // Protocol version.
+ stream.WriteShort(1);
+ stream.WriteShort(0);
+ stream.WriteShort(0);
+
+ // Client type: platform.
+ stream.WriteByte(2);
+ });
+
+ Assert.AreEqual(12, sentBytes);
+
+ // ACK.
+ var ack = ReceiveMessage(sock);
+
+ Assert.AreEqual(1, ack.Length);
+ Assert.AreEqual(1, ack[0]);
+ }
+
+ /// <summary>
+ /// Receives the message.
+ /// </summary>
+ private static byte[] ReceiveMessage(Socket sock)
+ {
+ var buf = new byte[4];
+ sock.Receive(buf);
+
+ using (var stream = new BinaryHeapStream(buf))
+ {
+ var size = stream.ReadInt();
+ buf = new byte[size];
+ sock.Receive(buf);
+ return buf;
+ }
+ }
+
+ /// <summary>
+ /// Sends the request.
+ /// </summary>
+ private static int SendRequest(Socket sock, Action<BinaryHeapStream> writeAction)
+ {
+ using (var stream = new BinaryHeapStream(128))
+ {
+ stream.WriteInt(0); // Reserve message size.
+
+ writeAction(stream);
+
+ stream.WriteInt(0, stream.Position - 4); // Write message size.
+
+ return sock.Send(stream.GetArray(), stream.Position, SocketFlags.None);
+ }
+ }
+
+ /// <summary>
+ /// Gets the socket.
+ /// </summary>
+ private static Socket GetSocket(int port)
+ {
+ var endPoint = new IPEndPoint(IPAddress.Loopback, port);
+ var sock = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
+ sock.Connect(endPoint);
+ return sock;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
index 93d6af3..950f36d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
@@ -26,6 +26,7 @@ namespace Apache.Ignite.Core.Tests
using Apache.Ignite.Core.Cache.Affinity.Rendezvous;
using Apache.Ignite.Core.Cache.Configuration;
using Apache.Ignite.Core.Cache.Eviction;
+ using Apache.Ignite.Core.Client;
using Apache.Ignite.Core.Common;
using Apache.Ignite.Core.Communication.Tcp;
using Apache.Ignite.Core.Configuration;
@@ -87,6 +88,7 @@ namespace Apache.Ignite.Core.Tests
CheckDefaultValueAttributes(new MemoryPolicyConfiguration());
CheckDefaultValueAttributes(new SqlConnectorConfiguration());
CheckDefaultValueAttributes(new PersistentStoreConfiguration());
+ CheckDefaultValueAttributes(new IgniteClientConfiguration());
}
/// <summary>
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
----------------------------------------------------------------------
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 65b8372..615ce90 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
@@ -97,12 +97,21 @@
<Compile Include="Cache\Configuration\MemoryPolicyConfiguration.cs" />
<Compile Include="Cache\Configuration\PartitionLossPolicy.cs" />
<Compile Include="Cache\IMemoryMetrics.cs" />
+ <Compile Include="Client\Cache\ICacheClient.cs" />
+ <Compile Include="Client\IgniteClientConfiguration.cs" />
+ <Compile Include="Client\IIgniteClient.cs" />
<Compile Include="Common\ExceptionFactory.cs" />
<Compile Include="Configuration\Package-Info.cs" />
<Compile Include="Impl\Binary\BinaryTypeId.cs" />
<Compile Include="Impl\Cache\Query\PlatformQueryQursorBase.cs" />
+ <Compile Include="Impl\Binary\BinaryProcessorClient.cs" />
<Compile Include="Impl\Binary\IBinaryProcessor.cs" />
<Compile Include="Impl\IIgniteInternal.cs" />
+ <Compile Include="Impl\Client\Cache\CacheClient.cs" />
+ <Compile Include="Impl\Client\ClientOp.cs" />
+ <Compile Include="Impl\Client\ClientProtocolVersion.cs" />
+ <Compile Include="Impl\Client\ClientSocket.cs" />
+ <Compile Include="Impl\Client\IgniteClient.cs" />
<Compile Include="Impl\IPlatformTargetInternal.cs" />
<Compile Include="Impl\PersistentStore\PersistentStoreMetrics.cs" />
<Compile Include="Impl\PlatformDisposableTargetAdapter.cs" />
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Cache/ICache.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/ICache.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/ICache.cs
index 8c7fcf9..f83f279 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/ICache.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/ICache.cs
@@ -251,32 +251,33 @@ namespace Apache.Ignite.Core.Cache
/// </summary>
/// <param name="key">Key.</param>
/// <returns>Cache value with the specified key.</returns>
+ /// <exception cref="KeyNotFoundException">If the key is not present in the cache.</exception>
TV this[TK key] { get; set; }
/// <summary>
- /// Retrieves value mapped to the specified key from cache. Throws an exception if t
+ /// Retrieves value mapped to the specified key from cache.
///
/// If the value is not present in cache, then it will be looked up from swap storage. If
/// it's not present in swap, or if swap is disable, and if read-through is allowed, value
/// will be loaded from persistent store.
/// This method is transactional and will enlist the entry into ongoing transaction if there is one.
- /// If key is not present in cache, KeyNotFoundException will be thrown.
/// </summary>
/// <param name="key">Key.</param>
/// <returns>Value.</returns>
+ /// <exception cref="KeyNotFoundException">If the key is not present in the cache.</exception>
TV Get(TK key);
/// <summary>
- /// Retrieves value mapped to the specified key from cache. Throws an exception if t
+ /// Retrieves value mapped to the specified key from cache.
///
/// If the value is not present in cache, then it will be looked up from swap storage. If
/// it's not present in swap, or if swap is disable, and if read-through is allowed, value
/// will be loaded from persistent store.
/// This method is transactional and will enlist the entry into ongoing transaction if there is one.
- /// If key is not present in cache, KeyNotFoundException will be thrown.
/// </summary>
/// <param name="key">Key.</param>
/// <returns>Value.</returns>
+ /// <exception cref="KeyNotFoundException">If the key is not present in the cache.</exception>
Task<TV> GetAsync(TK key);
/// <summary>
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Client/Cache/ICacheClient.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Client/Cache/ICacheClient.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Client/Cache/ICacheClient.cs
new file mode 100644
index 0000000..b4cd3c5
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Client/Cache/ICacheClient.cs
@@ -0,0 +1,59 @@
+/*
+ * 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.Client.Cache
+{
+ using System.Collections.Generic;
+
+ /// <summary>
+ /// Client cache API. See <see cref="IIgniteClient.GetCache{K, V}"/>.
+ /// </summary>
+ public interface ICacheClient<TK, TV>
+ {
+ /// <summary>
+ /// Name of this cache (<c>null</c> for default cache).
+ /// </summary>
+ string Name { get; }
+
+ /// <summary>
+ /// Associates the specified value with the specified key in the cache.
+ /// <para />
+ /// If the cache previously contained a mapping for the key,
+ /// the old value is replaced by the specified value.
+ /// </summary>
+ /// <param name="key">Key with which the specified value is to be associated.</param>
+ /// <param name="val">Value to be associated with the specified key.</param>
+ void Put(TK key, TV val);
+
+ /// <summary>
+ /// Retrieves value mapped to the specified key from cache.
+ /// </summary>
+ /// <param name="key">Key.</param>
+ /// <returns>Value.</returns>
+ /// <exception cref="KeyNotFoundException">If the key is not present in the cache.</exception>
+ TV Get(TK key);
+
+ /// <summary>
+ /// Gets or sets a cache value with the specified key.
+ /// Shortcut to <see cref="Get"/> and <see cref="Put"/>
+ /// </summary>
+ /// <param name="key">Key.</param>
+ /// <returns>Cache value with the specified key.</returns>
+ /// <exception cref="KeyNotFoundException">If the key is not present in the cache.</exception>
+ TV this[TK key] { get; set; }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Client/IIgniteClient.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Client/IIgniteClient.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Client/IIgniteClient.cs
new file mode 100644
index 0000000..ceb8f26
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Client/IIgniteClient.cs
@@ -0,0 +1,44 @@
+/*
+ * 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.Client
+{
+ using System;
+ using Apache.Ignite.Core.Client.Cache;
+
+ /// <summary>
+ /// Main entry point for Ignite Thin Client APIs.
+ /// You can obtain an instance of <see cref="IIgniteClient"/> through <see cref="Ignition.StartClient"/>.
+ /// </summary>
+ public interface IIgniteClient : IDisposable
+ {
+ /// <summary>
+ /// Gets the cache instance for the given name to work with keys and values of specified types.
+ /// <para/>
+ /// You can get instances of <see cref="ICacheClient{TK,TV}"/> of the same name,
+ /// but with different key/value types.
+ /// These will use the same named cache, but only allow working with entries of specified types.
+ /// Attempt to retrieve an entry of incompatible type will result in <see cref="InvalidCastException"/>.
+ /// Use <see cref="GetCache{TK,TV}"/> in order to work with entries of arbitrary types.
+ /// </summary>
+ /// <param name="name">Cache name.</param>
+ /// <returns>Cache instance for given name.</returns>
+ /// <typeparam name="TK">Cache key type.</typeparam>
+ /// <typeparam name="TV">Cache value type.</typeparam>
+ ICacheClient<TK, TV> GetCache<TK, TV>(string name);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Client/IgniteClientConfiguration.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Client/IgniteClientConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Client/IgniteClientConfiguration.cs
new file mode 100644
index 0000000..3339c65
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Client/IgniteClientConfiguration.cs
@@ -0,0 +1,104 @@
+/*
+ * 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.Client
+{
+ using System.ComponentModel;
+ using Apache.Ignite.Core.Binary;
+ using Apache.Ignite.Core.Impl.Binary;
+
+ /// <summary>
+ /// Ignite thin client configuration.
+ /// <para />
+ /// Ignite thin client connects to a specific Ignite node with a socket and does not start JVM in process.
+ /// This configuration should correspond to <see cref="IgniteConfiguration.SqlConnectorConfiguration"/>
+ /// on a target node.
+ /// </summary>
+ public class IgniteClientConfiguration
+ {
+ /// <summary>
+ /// Default port.
+ /// </summary>
+ public const int DefaultPort = 10800;
+
+ /// <summary>
+ /// Default socket buffer size.
+ /// </summary>
+ public const int DefaultSocketBufferSize = 0;
+
+ /// <summary>
+ /// Default value of <see cref="TcpNoDelay" /> property.
+ /// </summary>
+ public const bool DefaultTcpNoDelay = true;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="IgniteClientConfiguration"/> class.
+ /// </summary>
+ public IgniteClientConfiguration()
+ {
+ Port = DefaultPort;
+ SocketSendBufferSize = DefaultSocketBufferSize;
+ SocketReceiveBufferSize = DefaultSocketBufferSize;
+ TcpNoDelay = DefaultTcpNoDelay;
+ }
+
+ /// <summary>
+ /// Gets or sets the host. Should not be null.
+ /// </summary>
+ public string Host { get; set; }
+
+ /// <summary>
+ /// Gets or sets the port.
+ /// </summary>
+ [DefaultValue(DefaultPort)]
+ public int Port { get; set; }
+
+ /// <summary>
+ /// Gets or sets the size of the socket send buffer. When set to 0, operating system default is used.
+ /// </summary>
+ [DefaultValue(DefaultSocketBufferSize)]
+ public int SocketSendBufferSize { get; set; }
+
+ /// <summary>
+ /// Gets or sets the size of the socket receive buffer. When set to 0, operating system default is used.
+ /// </summary>
+ [DefaultValue(DefaultSocketBufferSize)]
+ public int SocketReceiveBufferSize { get; set; }
+
+ /// <summary>
+ /// Gets or sets the value for <c>TCP_NODELAY</c> socket option. Each
+ /// socket will be opened using provided value.
+ /// <para />
+ /// Setting this option to <c>true</c> disables Nagle's algorithm
+ /// for socket decreasing latency and delivery time for small messages.
+ /// <para />
+ /// For systems that work under heavy network load it is advisable to set this value to <c>false</c>.
+ /// </summary>
+ [DefaultValue(DefaultTcpNoDelay)]
+ public bool TcpNoDelay { get; set; }
+
+ /// <summary>
+ /// Gets or sets the binary configuration.
+ /// </summary>
+ public BinaryConfiguration BinaryConfiguration { get; set; }
+
+ /// <summary>
+ /// Gets or sets custom binary processor. Internal property for tests.
+ /// </summary>
+ internal IBinaryProcessor BinaryProcessor { get; set; }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs b/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
index bf061db..9548aca 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
@@ -39,9 +39,9 @@ namespace Apache.Ignite.Core
/// <summary>
/// Main entry point for all Ignite APIs.
- /// You can obtain an instance of <c>IGrid</c> through <see cref="Ignition.GetIgnite()"/>,
+ /// You can obtain an instance of <see cref="IIgnite"/> through <see cref="Ignition.GetIgnite()"/>,
/// or for named grids you can use <see cref="Ignition.GetIgnite(string)"/>. Note that you
- /// can have multiple instances of <c>IGrid</c> running in the same process by giving
+ /// can have multiple instances of <see cref="IIgnite"/> running in the same process by giving
/// each instance a different name.
/// <para/>
/// All members are thread-safe and may be used concurrently from multiple threads.
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs
index 568eea7..1bb6b3d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs
@@ -28,11 +28,13 @@ namespace Apache.Ignite.Core
using System.Threading;
using Apache.Ignite.Core.Binary;
using Apache.Ignite.Core.Cache.Affinity;
+ using Apache.Ignite.Core.Client;
using Apache.Ignite.Core.Common;
using Apache.Ignite.Core.Impl;
using Apache.Ignite.Core.Impl.Binary;
using Apache.Ignite.Core.Impl.Binary.IO;
using Apache.Ignite.Core.Impl.Cache.Affinity;
+ using Apache.Ignite.Core.Impl.Client;
using Apache.Ignite.Core.Impl.Common;
using Apache.Ignite.Core.Impl.Handle;
using Apache.Ignite.Core.Impl.Log;
@@ -730,6 +732,21 @@ namespace Apache.Ignite.Core
}
/// <summary>
+ /// Connects Ignite lightweight (thin) client to an Ignite node.
+ /// <para />
+ /// Thin client connects to an existing Ignite node with a socket and does not start JVM in process.
+ /// </summary>
+ /// <param name="clientConfiguration">The client configuration.</param>
+ /// <returns>Ignite instance.</returns>
+ public static IIgniteClient StartClient(IgniteClientConfiguration clientConfiguration)
+ {
+ IgniteArgumentCheck.NotNull(clientConfiguration, "clientConfiguration");
+ IgniteArgumentCheck.NotNull(clientConfiguration.Host, "clientConfiguration.Host");
+
+ return new IgniteClient(clientConfiguration);
+ }
+
+ /// <summary>
/// Handles the DomainUnload event of the CurrentDomain control.
/// </summary>
/// <param name="sender">The source of the event.</param>
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessorClient.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessorClient.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessorClient.cs
new file mode 100644
index 0000000..26a8e9b
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessorClient.cs
@@ -0,0 +1,113 @@
+/*
+ * 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.Binary
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using Apache.Ignite.Core.Binary;
+ using Apache.Ignite.Core.Impl.Binary.Metadata;
+ using Apache.Ignite.Core.Impl.Client;
+
+ /// <summary>
+ /// Thin client binary processor.
+ /// </summary>
+ internal class BinaryProcessorClient : IBinaryProcessor
+ {
+ /** Type registry platform id. See org.apache.ignite.internal.MarshallerPlatformIds in Java. */
+ private const byte DotNetPlatformId = 1;
+
+ /** Socket. */
+ private readonly ClientSocket _socket;
+
+ /** Marshaller. */
+ private readonly Marshaller _marsh = BinaryUtils.Marshaller;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="BinaryProcessorClient"/> class.
+ /// </summary>
+ /// <param name="socket">The socket.</param>
+ public BinaryProcessorClient(ClientSocket socket)
+ {
+ Debug.Assert(socket != null);
+
+ _socket = socket;
+ }
+
+ /** <inheritdoc /> */
+ public BinaryType GetBinaryType(int typeId)
+ {
+ return _socket.DoOutInOp(ClientOp.BinaryTypeGet, s => s.WriteInt(typeId),
+ s => new BinaryType(_marsh.StartUnmarshal(s), true));
+ }
+
+ /** <inheritdoc /> */
+ public List<IBinaryType> GetBinaryTypes()
+ {
+ throw new NotImplementedException();
+ }
+
+ /** <inheritdoc /> */
+ public int[] GetSchema(int typeId, int schemaId)
+ {
+ return GetBinaryType(typeId).Schema.Get(schemaId);
+ }
+
+ /** <inheritdoc /> */
+ public void PutBinaryTypes(ICollection<BinaryType> types)
+ {
+ Debug.Assert(types != null);
+
+ foreach (var binaryType in types)
+ {
+ var type = binaryType; // Access to modified closure.
+
+ _socket.DoOutInOp<object>(ClientOp.BinaryTypePut,
+ s => BinaryProcessor.WriteBinaryType(_marsh.StartMarshal(s), type), null);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public bool RegisterType(int id, string typeName)
+ {
+ return _socket.DoOutInOp(ClientOp.BinaryTypeNamePut, s =>
+ {
+ s.WriteByte(DotNetPlatformId);
+ s.WriteInt(id);
+ _marsh.StartMarshal(s).WriteString(typeName);
+ }, s => s.ReadBool());
+ }
+
+ /** <inheritdoc /> */
+ public BinaryType RegisterEnum(string typeName, IEnumerable<KeyValuePair<string, int>> values)
+ {
+ throw new NotImplementedException();
+ }
+
+ /** <inheritdoc /> */
+ public string GetTypeName(int id)
+ {
+ return _socket.DoOutInOp(ClientOp.BinaryTypeNameGet, s =>
+ {
+ s.WriteByte(DotNetPlatformId);
+ s.WriteInt(id);
+ },
+ s => _marsh.StartUnmarshal(s).ReadString());
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
index 1146f35..46e6752 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
@@ -1330,11 +1330,9 @@ namespace Apache.Ignite.Core.Impl.Binary
return res;
}
- /**
- * <summary>Get string hash code.</summary>
- * <param name="val">Value.</param>
- * <returns>Hash code.</returns>
- */
+ /// <summary>
+ /// Gets the string hash code using Java algorithm.
+ /// </summary>
public static int GetStringHashCode(string val)
{
if (val == null)
@@ -1353,6 +1351,14 @@ namespace Apache.Ignite.Core.Impl.Binary
}
/// <summary>
+ /// Gets the cache identifier.
+ /// </summary>
+ public static int GetCacheId(string cacheName)
+ {
+ return string.IsNullOrEmpty(cacheName) ? 1 : GetStringHashCode(cacheName);
+ }
+
+ /// <summary>
/// Cleans the name of the field.
/// </summary>
public static string CleanFieldName(string fieldName)
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs
index 921b5e0..9d45f50 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs
@@ -84,7 +84,7 @@ namespace Apache.Ignite.Core.Impl.Cache
_flagPartitionRecover = flagPartitionRecover;
_txManager = GetConfiguration().AtomicityMode == CacheAtomicityMode.Transactional
- ? new CacheTransactionManager(_ignite.GetTransactions())
+ ? new CacheTransactionManager(_ignite.GetIgnite().GetTransactions())
: null;
_readException = stream => ReadException(Marshaller.StartUnmarshal(stream));
@@ -93,7 +93,7 @@ namespace Apache.Ignite.Core.Impl.Cache
/** <inheritDoc /> */
public IIgnite Ignite
{
- get { return _ignite; }
+ get { return _ignite.GetIgnite(); }
}
/// <summary>
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..affa815
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs
@@ -0,0 +1,160 @@
+/*
+ * 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.Cache
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.IO;
+ using Apache.Ignite.Core.Client;
+ using Apache.Ignite.Core.Client.Cache;
+ using Apache.Ignite.Core.Impl.Binary;
+ using Apache.Ignite.Core.Impl.Binary.IO;
+ using Apache.Ignite.Core.Impl.Client;
+ using Apache.Ignite.Core.Impl.Common;
+ using BinaryWriter = Apache.Ignite.Core.Impl.Binary.BinaryWriter;
+
+ /// <summary>
+ /// Client cache implementation.
+ /// </summary>
+ internal class CacheClient<TK, TV> : ICacheClient<TK, TV>
+ {
+ /** Cache name. */
+ private readonly string _name;
+
+ /** Cache id. */
+ private readonly int _id;
+
+ /** Ignite. */
+ private readonly IgniteClient _ignite;
+
+ /** Marshaller. */
+ private readonly Marshaller _marsh;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="CacheClient{TK, TV}" /> class.
+ /// </summary>
+ /// <param name="ignite">Ignite.</param>
+ /// <param name="name">Cache name.</param>
+ public CacheClient(IgniteClient ignite, string name)
+ {
+ Debug.Assert(ignite != null);
+ Debug.Assert(name != null);
+
+ _name = name;
+ _ignite = ignite;
+ _marsh = _ignite.Marshaller;
+ _id = BinaryUtils.GetCacheId(name);
+ }
+
+ /** <inheritDoc /> */
+ public string Name
+ {
+ get { return _name; }
+ }
+
+ /** <inheritDoc /> */
+ public IIgniteClient Ignite
+ {
+ get { return _ignite; }
+ }
+
+ /** <inheritDoc /> */
+ public TV this[TK key]
+ {
+ get { return Get(key); }
+ set { Put(key, value); }
+ }
+
+ /** <inheritDoc /> */
+ public TV Get(TK key)
+ {
+ IgniteArgumentCheck.NotNull(key, "key");
+
+ return DoOutInOp(ClientOp.CacheGet, w => w.WriteObject(key), UnmarshalNotNull<TV>);
+ }
+
+ /** <inheritDoc /> */
+ public void Put(TK key, TV val)
+ {
+ IgniteArgumentCheck.NotNull(key, "key");
+ IgniteArgumentCheck.NotNull(val, "val");
+
+ DoOutOp(ClientOp.CachePut, w =>
+ {
+ w.WriteObjectDetached(key);
+ w.WriteObjectDetached(val);
+ });
+ }
+
+ /// <summary>
+ /// Does the out in op.
+ /// </summary>
+ private T DoOutInOp<T>(ClientOp opId, Action<BinaryWriter> writeAction,
+ Func<IBinaryStream, T> readFunc)
+ {
+ return _ignite.Socket.DoOutInOp(opId, stream =>
+ {
+ stream.WriteInt(_id);
+ stream.WriteByte(0); // Flags (skipStore, etc).
+
+ if (writeAction != null)
+ {
+ var writer = _marsh.StartMarshal(stream);
+
+ writeAction(writer);
+
+ _marsh.FinishMarshal(writer);
+ }
+ }, readFunc);
+ }
+
+ /// <summary>
+ /// Does the out op.
+ /// </summary>
+ private void DoOutOp(ClientOp opId, Action<BinaryWriter> writeAction)
+ {
+ DoOutInOp<object>(opId, writeAction, null);
+ }
+
+ /// <summary>
+ /// Unmarshals the value, throwing an exception for nulls.
+ /// </summary>
+ private T UnmarshalNotNull<T>(IBinaryStream stream)
+ {
+ var hdr = stream.ReadByte();
+
+ if (hdr == BinaryUtils.HdrNull)
+ {
+ throw GetKeyNotFoundException();
+ }
+
+ stream.Seek(-1, SeekOrigin.Current);
+
+ return _marsh.Unmarshal<T>(stream);
+ }
+
+ /// <summary>
+ /// Gets the key not found exception.
+ /// </summary>
+ private static KeyNotFoundException GetKeyNotFoundException()
+ {
+ return new KeyNotFoundException("The given key was not present in the cache.");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOp.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOp.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOp.cs
new file mode 100644
index 0000000..79d7c9e
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOp.cs
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Client
+{
+ /// <summary>
+ /// Client op code.
+ /// </summary>
+ internal enum ClientOp : short
+ {
+ CacheGet = 1,
+ BinaryTypeNameGet = 2,
+ BinaryTypeGet = 3,
+ CachePut = 4,
+ BinaryTypeNamePut = 5,
+ BinaryTypePut = 6
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientProtocolVersion.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientProtocolVersion.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientProtocolVersion.cs
new file mode 100644
index 0000000..bfdf5a3
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientProtocolVersion.cs
@@ -0,0 +1,119 @@
+/*
+ * 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;
+
+ /// <summary>
+ /// Client protocol version.
+ /// </summary>
+ internal struct ClientProtocolVersion : IEquatable<ClientProtocolVersion>
+ {
+ /** */
+ private readonly short _major;
+
+ /** */
+ private readonly short _minor;
+
+ /** */
+ private readonly short _maintenance;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ClientProtocolVersion"/> struct.
+ /// </summary>
+ public ClientProtocolVersion(short major, short minor, short maintenance)
+ {
+ _major = major;
+ _minor = minor;
+ _maintenance = maintenance;
+ }
+
+ /// <summary>
+ /// Gets the major part.
+ /// </summary>
+ public short Major
+ {
+ get { return _major; }
+ }
+
+ /// <summary>
+ /// Gets the minor part.
+ /// </summary>
+ public short Minor
+ {
+ get { return _minor; }
+ }
+
+ /// <summary>
+ /// Gets the maintenance part.
+ /// </summary>
+ public short Maintenance
+ {
+ get { return _maintenance; }
+ }
+
+ /// <summary>
+ /// Returns a value indicating whether specified instance equals to current.
+ /// </summary>
+ public bool Equals(ClientProtocolVersion other)
+ {
+ return _major == other._major && _minor == other._minor && _maintenance == other._maintenance;
+ }
+
+ /** <inheritdoc /> */
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj))
+ {
+ return false;
+ }
+
+ return obj is ClientProtocolVersion && Equals((ClientProtocolVersion) obj);
+ }
+
+ /** <inheritdoc /> */
+ public static bool operator ==(ClientProtocolVersion left, ClientProtocolVersion right)
+ {
+ return left.Equals(right);
+ }
+
+ /** <inheritdoc /> */
+ public static bool operator !=(ClientProtocolVersion left, ClientProtocolVersion right)
+ {
+ return !left.Equals(right);
+ }
+
+ /** <inheritdoc /> */
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ var hashCode = _major.GetHashCode();
+ hashCode = (hashCode * 397) ^ _minor.GetHashCode();
+ hashCode = (hashCode * 397) ^ _maintenance.GetHashCode();
+ return hashCode;
+ }
+ }
+
+ /** <inheritdoc /> */
+ public override string ToString()
+ {
+ return string.Format("{0}.{1}.{2}", Major, Minor, Maintenance);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientSocket.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientSocket.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientSocket.cs
new file mode 100644
index 0000000..0204ef8
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientSocket.cs
@@ -0,0 +1,263 @@
+/*
+ * 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.Diagnostics;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Linq;
+ using System.Net;
+ using System.Net.Sockets;
+ using System.Threading;
+ using Apache.Ignite.Core.Client;
+ using Apache.Ignite.Core.Common;
+ using Apache.Ignite.Core.Impl.Binary;
+ using Apache.Ignite.Core.Impl.Binary.IO;
+
+ /// <summary>
+ /// Wrapper over framework socket for Ignite thin client operations.
+ /// </summary>
+ internal class ClientSocket : IDisposable
+ {
+ /** Current version. */
+ private static readonly ClientProtocolVersion CurrentProtocolVersion = new ClientProtocolVersion(1, 0, 0);
+
+ /** Handshake opcode. */
+ private const byte OpHandshake = 1;
+
+ /** Client type code. */
+ private const byte ClientType = 2;
+
+ /** Unerlying socket. */
+ private readonly Socket _socket;
+
+ /** */
+ private long _requestId;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ClientSocket" /> class.
+ /// </summary>
+ /// <param name="clientConfiguration">The client configuration.</param>
+ /// <param name="version">Protocol version.</param>
+ public ClientSocket(IgniteClientConfiguration clientConfiguration, ClientProtocolVersion? version = null)
+ {
+ Debug.Assert(clientConfiguration != null);
+
+ _socket = Connect(clientConfiguration);
+
+ Handshake(_socket, version ?? CurrentProtocolVersion);
+ }
+
+ /// <summary>
+ /// Performs a send-receive operation.
+ /// </summary>
+ public T DoOutInOp<T>(ClientOp opId, Action<IBinaryStream> writeAction,
+ Func<IBinaryStream, T> readFunc)
+ {
+ var requestId = Interlocked.Increment(ref _requestId);
+
+ var resBytes = SendReceive(_socket, stream =>
+ {
+ stream.WriteShort((short) opId);
+ stream.WriteLong(requestId);
+
+ if (writeAction != null)
+ {
+ writeAction(stream);
+ }
+ });
+
+ using (var stream = new BinaryHeapStream(resBytes))
+ {
+ var resRequestId = stream.ReadLong();
+ Debug.Assert(requestId == resRequestId);
+
+ if (readFunc != null)
+ {
+ return readFunc(stream);
+ }
+ }
+
+ return default(T);
+ }
+
+ /// <summary>
+ /// Performs client protocol handshake.
+ /// </summary>
+ private static void Handshake(Socket sock, ClientProtocolVersion version)
+ {
+ var res = SendReceive(sock, stream =>
+ {
+ // Handshake.
+ stream.WriteByte(OpHandshake);
+
+ // Protocol version.
+ stream.WriteShort(version.Major);
+ stream.WriteShort(version.Minor);
+ stream.WriteShort(version.Maintenance);
+
+ // Client type: platform.
+ stream.WriteByte(ClientType);
+ }, 20);
+
+ using (var stream = new BinaryHeapStream(res))
+ {
+ var success = stream.ReadBool();
+
+ if (success)
+ {
+ return;
+ }
+
+ var serverVersion =
+ new ClientProtocolVersion(stream.ReadShort(), stream.ReadShort(), stream.ReadShort());
+
+ var errMsg = BinaryUtils.Marshaller.Unmarshal<string>(stream);
+
+ throw new IgniteException(string.Format(
+ "Client handhsake failed: '{0}'. Client version: {1}. Server version: {2}",
+ errMsg, version, serverVersion));
+ }
+ }
+
+ /// <summary>
+ /// Sends the request and receives a response.
+ /// </summary>
+ private static byte[] SendReceive(Socket sock, Action<IBinaryStream> writeAction, int bufSize = 128)
+ {
+ int messageLen;
+ var buf = WriteMessage(writeAction, bufSize, out messageLen);
+
+ lock (sock)
+ {
+ var sent = sock.Send(buf, messageLen, SocketFlags.None);
+ Debug.Assert(sent == messageLen);
+
+ buf = new byte[4];
+ var received = sock.Receive(buf);
+ Debug.Assert(received == buf.Length);
+
+ using (var stream = new BinaryHeapStream(buf))
+ {
+ var size = stream.ReadInt();
+
+ buf = new byte[size];
+ received = sock.Receive(buf);
+ Debug.Assert(received == buf.Length);
+
+ return buf;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Writes the message to a byte array.
+ /// </summary>
+ private static byte[] WriteMessage(Action<IBinaryStream> writeAction, int bufSize, out int messageLen)
+ {
+ using (var stream = new BinaryHeapStream(bufSize))
+ {
+ stream.WriteInt(0); // Reserve message size.
+
+ writeAction(stream);
+
+ stream.WriteInt(0, stream.Position - 4); // Write message size.
+
+ messageLen = stream.Position;
+
+ return stream.GetArray();
+ }
+ }
+
+ /// <summary>
+ /// Connects the socket.
+ /// </summary>
+ private static Socket Connect(IgniteClientConfiguration cfg)
+ {
+ List<Exception> errors = null;
+
+ foreach (var ipEndPoint in GetEndPoints(cfg))
+ {
+ try
+ {
+ var socket = new Socket(ipEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
+ {
+ SendBufferSize = cfg.SocketSendBufferSize,
+ ReceiveBufferSize = cfg.SocketReceiveBufferSize,
+ NoDelay = cfg.TcpNoDelay
+ };
+
+ socket.Connect(ipEndPoint);
+
+ return socket;
+ }
+ catch (SocketException e)
+ {
+ if (errors == null)
+ {
+ errors = new List<Exception>();
+ }
+
+ errors.Add(e);
+ }
+ }
+
+ if (errors == null)
+ {
+ throw new IgniteException("Failed to resolve client host: " + cfg.Host);
+ }
+
+ throw new AggregateException("Failed to establish Ignite thin client connection, " +
+ "examine inner exceptions for details.", errors);
+ }
+
+ /// <summary>
+ /// Gets the endpoints: all combinations of IP addresses and ports according to configuration.
+ /// </summary>
+ private static IEnumerable<IPEndPoint> GetEndPoints(IgniteClientConfiguration cfg)
+ {
+ var host = cfg.Host;
+
+ if (host == null)
+ {
+ throw new IgniteException("IgniteClientConfiguration.Host cannot be null.");
+ }
+
+ // GetHostEntry accepts IPs, but TryParse is a more efficient shortcut.
+ IPAddress ip;
+
+ if (IPAddress.TryParse(host, out ip))
+ {
+ return new[] {new IPEndPoint(ip, cfg.Port)};
+ }
+
+ return Dns.GetHostEntry(host).AddressList.Select(x => new IPEndPoint(x, cfg.Port));
+ }
+
+ /// <summary>
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ /// </summary>
+ [SuppressMessage("Microsoft.Usage", "CA1816:CallGCSuppressFinalizeCorrectly",
+ Justification = "There is no finalizer.")]
+ public void Dispose()
+ {
+ _socket.Dispose();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/IgniteClient.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/IgniteClient.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/IgniteClient.cs
new file mode 100644
index 0000000..29b8a2c
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/IgniteClient.cs
@@ -0,0 +1,152 @@
+/*
+ * 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.Diagnostics.CodeAnalysis;
+ using Apache.Ignite.Core.Binary;
+ using Apache.Ignite.Core.Client;
+ using Apache.Ignite.Core.Client.Cache;
+ using Apache.Ignite.Core.Datastream;
+ using Apache.Ignite.Core.Impl.Binary;
+ using Apache.Ignite.Core.Impl.Client.Cache;
+ using Apache.Ignite.Core.Impl.Cluster;
+ using Apache.Ignite.Core.Impl.Common;
+ using Apache.Ignite.Core.Impl.Handle;
+ using Apache.Ignite.Core.Impl.Plugin;
+
+ /// <summary>
+ /// Thin client implementation
+ /// </summary>
+ internal class IgniteClient : IIgniteInternal, IIgniteClient
+ {
+ /** Socket. */
+ private readonly ClientSocket _socket;
+
+ /** Marshaller. */
+ private readonly Marshaller _marsh;
+
+ /** Binary processor. */
+ private readonly IBinaryProcessor _binProc;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="IgniteClient"/> class.
+ /// </summary>
+ /// <param name="clientConfiguration">The client configuration.</param>
+ public IgniteClient(IgniteClientConfiguration clientConfiguration)
+ {
+ Debug.Assert(clientConfiguration != null);
+
+ _socket = new ClientSocket(clientConfiguration);
+
+ _marsh = new Marshaller(clientConfiguration.BinaryConfiguration)
+ {
+ Ignite = this
+ };
+
+ _binProc = clientConfiguration.BinaryProcessor ?? new BinaryProcessorClient(_socket);
+ }
+
+ /// <summary>
+ /// Gets the socket.
+ /// </summary>
+ public ClientSocket Socket
+ {
+ get { return _socket; }
+ }
+
+ /** <inheritDoc /> */
+ [SuppressMessage("Microsoft.Usage", "CA1816:CallGCSuppressFinalizeCorrectly",
+ Justification = "There is no finalizer.")]
+ public void Dispose()
+ {
+ _socket.Dispose();
+ }
+
+ /** <inheritDoc /> */
+ public ICacheClient<TK, TV> GetCache<TK, TV>(string name)
+ {
+ IgniteArgumentCheck.NotNull(name, "name");
+
+ return new CacheClient<TK, TV>(this, name);
+ }
+
+ /** <inheritDoc /> */
+ public IIgnite GetIgnite()
+ {
+ throw GetClientNotSupportedException();
+ }
+
+ /** <inheritDoc /> */
+ public IBinary GetBinary()
+ {
+ throw GetClientNotSupportedException();
+ }
+
+ /** <inheritDoc /> */
+ public IBinaryProcessor BinaryProcessor
+ {
+ get { return _binProc; }
+ }
+
+ /** <inheritDoc /> */
+ public IgniteConfiguration Configuration
+ {
+ get { throw GetClientNotSupportedException(); }
+ }
+
+ /** <inheritDoc /> */
+ public HandleRegistry HandleRegistry
+ {
+ get { throw GetClientNotSupportedException(); }
+ }
+
+ /** <inheritDoc /> */
+ public ClusterNodeImpl GetNode(Guid? id)
+ {
+ throw GetClientNotSupportedException();
+ }
+
+ /** <inheritDoc /> */
+ public Marshaller Marshaller
+ {
+ get { return _marsh; }
+ }
+
+ /** <inheritDoc /> */
+ public PluginProcessor PluginProcessor
+ {
+ get { throw GetClientNotSupportedException(); }
+ }
+
+ /** <inheritDoc /> */
+ public IDataStreamer<TK, TV> GetDataStreamer<TK, TV>(string cacheName, bool keepBinary)
+ {
+ throw GetClientNotSupportedException();
+ }
+
+ /// <summary>
+ /// Gets the client not supported exception.
+ /// </summary>
+ private static NotSupportedException GetClientNotSupportedException()
+ {
+ return new NotSupportedException("Operation is not supported in thin client mode.");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cluster/ClusterGroupImpl.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cluster/ClusterGroupImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cluster/ClusterGroupImpl.cs
index 6d6756f..b32d331 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cluster/ClusterGroupImpl.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cluster/ClusterGroupImpl.cs
@@ -190,7 +190,7 @@ namespace Apache.Ignite.Core.Impl.Cluster
/** <inheritDoc /> */
public IIgnite Ignite
{
- get { return _ignite; }
+ get { return _ignite.GetIgnite(); }
}
/** <inheritDoc /> */
http://git-wip-us.apache.org/repos/asf/ignite/blob/a00052e9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeJobHolder.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeJobHolder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeJobHolder.cs
index 945f2ab..1489f59 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeJobHolder.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeJobHolder.cs
@@ -86,7 +86,7 @@ namespace Apache.Ignite.Core.Impl.Compute
success ? null : new IgniteException("Compute job has failed on local node, " +
"examine InnerException for details.", (Exception) res),
_job,
- _ignite.GetCluster().GetLocalNode().Id,
+ _ignite.GetIgnite().GetCluster().GetLocalNode().Id,
cancel
);
}