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 <[email protected]> Authored: Fri Sep 15 14:05:53 2017 +0300 Committer: devozerov <[email protected]> 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 ); }
