IGNITE-1645: Throw exception on null flag in PortableReader when reading non-nullable value types.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/2ed4794f Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/2ed4794f Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/2ed4794f Branch: refs/heads/ignite-1655 Commit: 2ed4794f7aeae28bdd51662a810309f1156090d9 Parents: 2730097 Author: thatcoach <[email protected]> Authored: Tue Oct 20 16:56:44 2015 +0300 Committer: thatcoach <[email protected]> Committed: Tue Oct 20 16:56:44 2015 +0300 ---------------------------------------------------------------------- .../Cache/CacheAbstractTest.cs | 159 +++++++++------ .../Cache/CacheTestAsyncWrapper.cs | 35 +++- .../Dataload/DataStreamerTest.cs | 6 +- .../Apache.Ignite.Core.csproj | 1 + .../Apache.Ignite.Core/Cache/CacheResult.cs | 98 +++++++++ .../dotnet/Apache.Ignite.Core/Cache/ICache.cs | 62 +++++- .../Apache.Ignite.Core/Impl/Cache/CacheImpl.cs | 204 ++++++++++++++++--- .../Apache.Ignite.Core/Impl/Cache/CacheOp.cs | 1 + .../Impl/Cache/CacheProxyImpl.cs | 33 ++- .../Apache.Ignite.Core/Impl/Common/Future.cs | 16 +- .../Impl/Common/FutureConverter.cs | 4 +- .../Impl/Common/IFutureConverter.cs | 1 + .../Apache.Ignite.Core/Impl/PlatformTarget.cs | 1 + .../Impl/Portable/PortableReaderImpl.cs | 4 + 14 files changed, 503 insertions(+), 122 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/2ed4794f/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs index 964f4e8..94ec2d6 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs @@ -487,11 +487,15 @@ namespace Apache.Ignite.Core.Tests.Cache cache.Put(key1, 1); + int val; + Assert.AreEqual(1, cache.LocalPeek(key1)); - Assert.AreEqual(0, cache.LocalPeek(-1)); + Assert.Throws<KeyNotFoundException>(() => cache.LocalPeek(-1)); + Assert.IsFalse(cache.TryLocalPeek(-1, out val)); Assert.AreEqual(1, cache.LocalPeek(key1, CachePeekMode.All)); - Assert.AreEqual(0, cache.LocalPeek(-1, CachePeekMode.All)); + Assert.Throws<KeyNotFoundException>(() => cache.LocalPeek(-1, CachePeekMode.All)); + Assert.AreEqual(false, cache.TryLocalPeek(-1, out val, CachePeekMode.All)); } [Test] @@ -504,7 +508,19 @@ namespace Apache.Ignite.Core.Tests.Cache Assert.AreEqual(1, cache.Get(1)); Assert.AreEqual(2, cache.Get(2)); - Assert.AreEqual(0, cache.Get(3)); + + Assert.Throws<KeyNotFoundException>(() => cache.Get(3)); + + int value; + + Assert.IsTrue(cache.TryGet(1, out value)); + Assert.AreEqual(1, value); + + Assert.IsTrue(cache.TryGet(2, out value)); + Assert.AreEqual(2, value); + + Assert.IsFalse(cache.TryGet(3, out value)); + Assert.AreEqual(0, value); } [Test] @@ -517,7 +533,8 @@ namespace Apache.Ignite.Core.Tests.Cache Assert.AreEqual(1, cache.Get(1)); Assert.AreEqual(2, cache.Get(2)); - Assert.AreEqual(0, cache.Get(3)); + Assert.IsFalse(cache.ContainsKey(3)); + Assert.Throws<KeyNotFoundException>(() => cache.Get(3)); } [Test] @@ -561,17 +578,17 @@ namespace Apache.Ignite.Core.Tests.Cache { var cache = Cache(); - Assert.AreEqual(0, cache.Get(1)); + Assert.AreEqual(false, cache.ContainsKey(1)); - int old = cache.GetAndPut(1, 1); + var old = cache.GetAndPut(1, 1); - Assert.AreEqual(0, old); + Assert.IsFalse(old.Success); Assert.AreEqual(1, cache.Get(1)); old = cache.GetAndPut(1, 2); - Assert.AreEqual(1, old); + Assert.AreEqual(1, old.Value); Assert.AreEqual(2, cache.Get(1)); } @@ -583,11 +600,11 @@ namespace Apache.Ignite.Core.Tests.Cache cache.Put(1, 10); - Assert.AreEqual(10, cache.GetAndReplace(1, 100)); + Assert.AreEqual(10, cache.GetAndReplace(1, 100).Value); - Assert.AreEqual(0, cache.GetAndReplace(2, 2)); + Assert.AreEqual(false, cache.GetAndReplace(2, 2).Success); - Assert.AreEqual(0, cache.Get(2)); + Assert.AreEqual(false, cache.ContainsKey(2)); Assert.AreEqual(100, cache.Get(1)); @@ -603,13 +620,13 @@ namespace Apache.Ignite.Core.Tests.Cache Assert.AreEqual(1, cache.Get(1)); - Assert.AreEqual(0, cache.GetAndRemove(0)); - - Assert.AreEqual(1, cache.GetAndRemove(1)); + Assert.IsFalse(cache.GetAndRemove(0).Success); - Assert.AreEqual(0, cache.GetAndRemove(1)); + Assert.AreEqual(1, cache.GetAndRemove(1).Value); + + Assert.IsFalse(cache.GetAndRemove(1).Success); - Assert.AreEqual(0, cache.Get(1)); + Assert.IsFalse(cache.ContainsKey(1)); } [Test] @@ -617,17 +634,17 @@ namespace Apache.Ignite.Core.Tests.Cache { var cache = Cache().WithAsync().WrapAsync(); - Assert.AreEqual(0, cache.Get(1)); + Assert.AreEqual(false, cache.ContainsKey(1)); - int old = cache.GetAndPut(1, 1); + var old = cache.GetAndPut(1, 1); - Assert.AreEqual(0, old); + Assert.IsFalse(old.Success); Assert.AreEqual(1, cache.Get(1)); old = cache.GetAndPut(1, 2); - Assert.AreEqual(1, old); + Assert.AreEqual(1, old.Value); Assert.AreEqual(2, cache.Get(1)); } @@ -657,7 +674,7 @@ namespace Apache.Ignite.Core.Tests.Cache { var cache = Cache(); - Assert.AreEqual(0, cache.Get(1)); + Assert.IsFalse(cache.ContainsKey(1)); Assert.AreEqual(true, cache.PutIfAbsent(1, 1)); @@ -673,13 +690,13 @@ namespace Apache.Ignite.Core.Tests.Cache { var cache = Cache(); - Assert.AreEqual(0, cache.Get(1)); + Assert.IsFalse(cache.ContainsKey(1)); - Assert.AreEqual(0, cache.GetAndPutIfAbsent(1, 1)); + Assert.IsFalse(cache.GetAndPutIfAbsent(1, 1).Success); Assert.AreEqual(1, cache.Get(1)); - Assert.AreEqual(1, cache.GetAndPutIfAbsent(1, 2)); + Assert.AreEqual(1, cache.GetAndPutIfAbsent(1, 2).Value); Assert.AreEqual(1, cache.Get(1)); } @@ -689,17 +706,17 @@ namespace Apache.Ignite.Core.Tests.Cache { var cache = Cache().WithAsync().WrapAsync(); - Assert.AreEqual(0, cache.Get(1)); + Assert.IsFalse(cache.ContainsKey(1)); - int old = cache.GetAndPutIfAbsent(1, 1); + var old = cache.GetAndPutIfAbsent(1, 1); - Assert.AreEqual(0, old); + Assert.IsFalse(old.Success); Assert.AreEqual(1, cache.Get(1)); old = cache.GetAndPutIfAbsent(1, 2); - Assert.AreEqual(1, old); + Assert.AreEqual(1, old.Value); Assert.AreEqual(1, cache.Get(1)); } @@ -709,7 +726,8 @@ namespace Apache.Ignite.Core.Tests.Cache { var cache = Cache().WithAsync().WrapAsync(); - Assert.AreEqual(0, cache.Get(1)); + Assert.Throws<KeyNotFoundException>(() => cache.Get(1)); + Assert.IsFalse(cache.ContainsKey(1)); Assert.IsTrue(cache.PutIfAbsent(1, 1)); @@ -725,13 +743,13 @@ namespace Apache.Ignite.Core.Tests.Cache { var cache = Cache(); - Assert.AreEqual(0, cache.Get(1)); + Assert.IsFalse(cache.ContainsKey(1)); bool success = cache.Replace(1, 1); Assert.AreEqual(false, success); - Assert.AreEqual(0, cache.Get(1)); + Assert.IsFalse(cache.ContainsKey(1)); cache.Put(1, 1); @@ -757,13 +775,13 @@ namespace Apache.Ignite.Core.Tests.Cache { var cache = Cache().WithAsync().WrapAsync(); - Assert.AreEqual(0, cache.Get(1)); + Assert.IsFalse(cache.ContainsKey(1)); - int old = cache.GetAndReplace(1, 1); + var old = cache.GetAndReplace(1, 1); - Assert.AreEqual(0, old); + Assert.IsFalse(old.Success); - Assert.AreEqual(0, cache.Get(1)); + Assert.IsFalse(cache.ContainsKey(1)); cache.Put(1, 1); @@ -771,7 +789,7 @@ namespace Apache.Ignite.Core.Tests.Cache old = cache.GetAndReplace(1, 2); - Assert.AreEqual(1, old); + Assert.AreEqual(1, old.Value); Assert.AreEqual(2, cache.Get(1)); @@ -789,11 +807,11 @@ namespace Apache.Ignite.Core.Tests.Cache { var cache = Cache(); - Assert.AreEqual(0, cache.Get(1)); + Assert.IsFalse(cache.ContainsKey(1)); Assert.IsFalse(cache.Replace(1, 1)); - Assert.AreEqual(0, cache.Get(1)); + Assert.IsFalse(cache.ContainsKey(1)); cache.Put(1, 1); @@ -809,11 +827,11 @@ namespace Apache.Ignite.Core.Tests.Cache { var cache = Cache().WithAsync().WrapAsync(); - Assert.AreEqual(0, cache.Get(1)); + Assert.IsFalse(cache.ContainsKey(1)); Assert.IsFalse(cache.Replace(1, 1)); - Assert.AreEqual(0, cache.Get(1)); + Assert.IsFalse(cache.ContainsKey(1)); cache.Put(1, 1); @@ -1092,7 +1110,8 @@ namespace Apache.Ignite.Core.Tests.Cache { cache.Clear(key); - Assert.AreEqual(0, cache.Get(key)); + Assert.IsFalse(cache.ContainsKey(key)); + Assert.Throws<KeyNotFoundException>(() => cache.Get(key)); Assert.Less(cache.GetSize(), i); @@ -1111,8 +1130,7 @@ namespace Apache.Ignite.Core.Tests.Cache cache.ClearAll(keys); - foreach (var key in keys) - Assert.AreEqual(0, cache.Get(key)); + Assert.IsFalse(cache.ContainsKeys(keys)); } [Test] @@ -1130,7 +1148,8 @@ namespace Apache.Ignite.Core.Tests.Cache { cache.LocalClear(key); - Assert.AreEqual(0, cache.LocalPeek(key)); + int val; + Assert.IsFalse(cache.TryLocalPeek(key, out val)); Assert.Less(cache.GetSize(), i); @@ -1151,8 +1170,10 @@ namespace Apache.Ignite.Core.Tests.Cache cache.LocalClearAll(keys); + int val; + foreach (var key in keys) - Assert.AreEqual(0, cache.LocalPeek(key)); + Assert.IsFalse(cache.TryLocalPeek(key, out val)); cache.Clear(); } @@ -1170,7 +1191,7 @@ namespace Apache.Ignite.Core.Tests.Cache Assert.AreEqual(0, cache.GetSize()); - Assert.AreEqual(0, cache.Get(1)); + Assert.IsFalse(cache.ContainsKey(1)); cache.Put(1, 1); @@ -1181,7 +1202,7 @@ namespace Apache.Ignite.Core.Tests.Cache Assert.AreEqual(0, cache.GetSize()); - Assert.AreEqual(0, cache.Get(1)); + Assert.IsFalse(cache.ContainsKey(1)); } [Test] @@ -1193,11 +1214,11 @@ namespace Apache.Ignite.Core.Tests.Cache Assert.AreEqual(1, cache.Get(1)); - Assert.AreEqual(1, cache.GetAndRemove(1)); + Assert.AreEqual(1, cache.GetAndRemove(1).Value); Assert.AreEqual(0, cache.GetSize()); - Assert.AreEqual(0, cache.Get(1)); + Assert.IsFalse(cache.ContainsKey(1)); cache.Put(1, 1); @@ -1208,7 +1229,7 @@ namespace Apache.Ignite.Core.Tests.Cache Assert.AreEqual(0, cache.GetSize()); - Assert.AreEqual(0, cache.Get(1)); + Assert.IsFalse(cache.ContainsKey(1)); } [Test] @@ -1225,7 +1246,7 @@ namespace Apache.Ignite.Core.Tests.Cache Assert.AreEqual(0, cache.GetSize()); - Assert.AreEqual(0, cache.Get(1)); + Assert.IsFalse(cache.ContainsKey(1)); } [Test] @@ -1242,7 +1263,7 @@ namespace Apache.Ignite.Core.Tests.Cache Assert.AreEqual(0, cache.GetSize()); - Assert.AreEqual(0, cache.Get(1)); + Assert.IsFalse(cache.ContainsKey(1)); } [Test] @@ -1250,7 +1271,7 @@ namespace Apache.Ignite.Core.Tests.Cache { var cache = Cache(); - List<int> keys = PrimaryKeysForCache(cache, 2); + var keys = PrimaryKeysForCache(cache, 2); cache.Put(keys[0], 1); cache.Put(keys[1], 2); @@ -1262,8 +1283,7 @@ namespace Apache.Ignite.Core.Tests.Cache Assert.AreEqual(0, cache.GetSize()); - Assert.AreEqual(0, cache.Get(keys[0])); - Assert.AreEqual(0, cache.Get(keys[1])); + Assert.IsFalse(cache.ContainsKeys(keys)); } [Test] @@ -1283,8 +1303,7 @@ namespace Apache.Ignite.Core.Tests.Cache Assert.AreEqual(0, cache.GetSize()); - Assert.AreEqual(0, cache.Get(keys[0])); - Assert.AreEqual(0, cache.Get(keys[1])); + Assert.IsFalse(cache.ContainsKeys(keys)); } [Test] @@ -1306,8 +1325,7 @@ namespace Apache.Ignite.Core.Tests.Cache Assert.AreEqual(1, cache.GetSize(CachePeekMode.Primary)); - Assert.AreEqual(0, cache.Get(1)); - Assert.AreEqual(0, cache.Get(2)); + Assert.IsFalse(cache.ContainsKeys(new[] {1, 2})); Assert.AreEqual(3, cache.Get(3)); } @@ -1330,8 +1348,7 @@ namespace Apache.Ignite.Core.Tests.Cache Assert.AreEqual(1, cache.GetSize(CachePeekMode.Primary)); - Assert.AreEqual(0, cache.Get(1)); - Assert.AreEqual(0, cache.Get(2)); + Assert.IsFalse(cache.ContainsKeys(new[] {1, 2})); Assert.AreEqual(3, cache.Get(3)); } @@ -2860,7 +2877,7 @@ namespace Apache.Ignite.Core.Tests.Cache // Remove entry Assert.AreEqual(0, cache.Invoke(key, new T {Remove = true}, arg)); - Assert.AreEqual(0, cache.Get(key)); + Assert.AreEqual(false, cache.ContainsKey(key)); // Test exceptions AssertThrowsCacheEntryProcessorException(() => cache.Invoke(key, new T {ThrowErr = true}, arg)); @@ -3079,6 +3096,18 @@ namespace Apache.Ignite.Core.Tests.Cache Assert.AreEqual(10, cache1.Get(1)); } + [Test] + public void TestIndexer() + { + var cache = Cache(); + + Assert.Throws<KeyNotFoundException>(() => Console.WriteLine(cache[0])); // missing key throws + + cache[1] = 5; + + Assert.AreEqual(5, cache[1]); + } + private void TestKeepPortableFlag(bool async) { var cache0 = async ? Cache().WithAsync().WrapAsync() : Cache(); @@ -3246,7 +3275,11 @@ namespace Apache.Ignite.Core.Tests.Cache private static int PeekInt(ICache<int, int> cache, int key) { - return cache.LocalPeek(key, CachePeekMode.Onheap); + int val; + + cache.TryLocalPeek(key, out val, CachePeekMode.Onheap); + + return val; } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/2ed4794f/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheTestAsyncWrapper.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheTestAsyncWrapper.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheTestAsyncWrapper.cs index c4e8d7e..1b5321c 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheTestAsyncWrapper.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheTestAsyncWrapper.cs @@ -149,6 +149,19 @@ namespace Apache.Ignite.Core.Tests.Cache } /** <inheritDoc /> */ + public bool TryLocalPeek(TK key, out TV value, params CachePeekMode[] modes) + { + return _cache.TryLocalPeek(key, out value, modes); + } + + /** <inheritDoc /> */ + public TV this[TK key] + { + get { return _cache[key]; } + set { _cache[key] = value; } + } + + /** <inheritDoc /> */ public TV Get(TK key) { _cache.Get(key); @@ -156,6 +169,12 @@ namespace Apache.Ignite.Core.Tests.Cache } /** <inheritDoc /> */ + public bool TryGet(TK key, out TV value) + { + return _cache.TryGet(key, out value); + } + + /** <inheritDoc /> */ public IDictionary<TK, TV> GetAll(IEnumerable<TK> keys) { _cache.GetAll(keys); @@ -170,24 +189,24 @@ namespace Apache.Ignite.Core.Tests.Cache } /** <inheritDoc /> */ - public TV GetAndPut(TK key, TV val) + public CacheResult<TV> GetAndPut(TK key, TV val) { _cache.GetAndPut(key, val); - return GetResult<TV>(); + return GetResult<CacheResult<TV>>(); } /** <inheritDoc /> */ - public TV GetAndReplace(TK key, TV val) + public CacheResult<TV> GetAndReplace(TK key, TV val) { _cache.GetAndReplace(key, val); - return GetResult<TV>(); + return GetResult<CacheResult<TV>>(); } /** <inheritDoc /> */ - public TV GetAndRemove(TK key) + public CacheResult<TV> GetAndRemove(TK key) { _cache.GetAndRemove(key); - return GetResult<TV>(); + return GetResult<CacheResult<TV>>(); } /** <inheritDoc /> */ @@ -198,10 +217,10 @@ namespace Apache.Ignite.Core.Tests.Cache } /** <inheritDoc /> */ - public TV GetAndPutIfAbsent(TK key, TV val) + public CacheResult<TV> GetAndPutIfAbsent(TK key, TV val) { _cache.GetAndPutIfAbsent(key, val); - return GetResult<TV>(); + return GetResult<CacheResult<TV>>(); } /** <inheritDoc /> */ http://git-wip-us.apache.org/repos/asf/ignite/blob/2ed4794f/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Dataload/DataStreamerTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Dataload/DataStreamerTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Dataload/DataStreamerTest.cs index 0195f19..bad2cf7 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Dataload/DataStreamerTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Dataload/DataStreamerTest.cs @@ -143,7 +143,7 @@ namespace Apache.Ignite.Core.Tests.Dataload // Removal. ldr.RemoveData(1); ldr.Flush(); - Assert.IsNull(_cache.Get(1)); + Assert.IsFalse(_cache.ContainsKey(1)); // Mixed. ldr.AddData(5, 5); @@ -159,7 +159,7 @@ namespace Apache.Ignite.Core.Tests.Dataload ldr.Flush(); for (int i = 2; i < 5; i++) - Assert.IsNull(_cache.Get(i)); + Assert.IsFalse(_cache.ContainsKey(i)); for (int i = 5; i < 13; i++) Assert.AreEqual(i, _cache.Get(i)); @@ -257,7 +257,7 @@ namespace Apache.Ignite.Core.Tests.Dataload fut.Get(); - Assert.IsNull(_cache.Get(1)); + Assert.IsFalse(_cache.ContainsKey(1)); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/2ed4794f/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 401b46c..9bcb41a 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj @@ -68,6 +68,7 @@ <Compile Include="Cache\ICacheEntryProcessorResult.cs" /> <Compile Include="Cache\ICacheLock.cs" /> <Compile Include="Cache\ICacheMetrics.cs" /> + <Compile Include="Cache\CacheResult.cs" /> <Compile Include="Cache\IMutableCacheEntry.cs" /> <Compile Include="Cache\Query\Continuous\ContinuousQuery.cs" /> <Compile Include="Cache\Query\Continuous\IContinuousQueryHandle.cs" /> http://git-wip-us.apache.org/repos/asf/ignite/blob/2ed4794f/modules/platforms/dotnet/Apache.Ignite.Core/Cache/CacheResult.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/CacheResult.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/CacheResult.cs new file mode 100644 index 0000000..75208cd --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/CacheResult.cs @@ -0,0 +1,98 @@ +/* + * 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.Cache +{ + using System; + using System.Collections.Generic; + + /// <summary> + /// Represents a cache operation result with a success flag. + /// </summary> + /// <typeparam name="T">Operation result value type.</typeparam> + public struct CacheResult<T> : IEquatable<CacheResult<T>> + { + /** Value. */ + private readonly T _value; + + /** Success flag. */ + private readonly bool _success; + + /// <summary> + /// Initializes a new instance of the <see cref="CacheResult{T}"/> struct with a specified value + /// and sets success flag to true. + /// </summary> + /// <param name="value">The value.</param> + public CacheResult(T value) + { + _value = value; + _success = true; + } + + /// <summary> + /// Gets the cache value. + /// </summary> + public T Value + { + get { return _value; } + } + + /// <summary> + /// Gets a value indicating whether the operation completed successfully. + /// </summary> + public bool Success + { + get { return _success; } + } + + /** <inehritdoc /> */ + public bool Equals(CacheResult<T> other) + { + return EqualityComparer<T>.Default.Equals(_value, other._value) && _success == other._success; + } + + /** <inehritdoc /> */ + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) + return false; + + return obj is CacheResult<T> && Equals((CacheResult<T>) obj); + } + + /** <inehritdoc /> */ + public override int GetHashCode() + { + unchecked + { + return (EqualityComparer<T>.Default.GetHashCode(_value) * 397) ^ _success.GetHashCode(); + } + } + + /** <inehritdoc /> */ + public static bool operator ==(CacheResult<T> left, CacheResult<T> right) + { + return left.Equals(right); + } + + /** <inehritdoc /> */ + public static bool operator !=(CacheResult<T> left, CacheResult<T> right) + { + return !left.Equals(right); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/2ed4794f/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 98ac254..204c56c 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/ICache.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/ICache.cs @@ -153,6 +153,7 @@ namespace Apache.Ignite.Core.Cache /// non-null value is found, it will be immediately returned. /// This method does not participate in any transactions, however, it may peek at transactional /// value depending on the peek modes used. + /// If key is not present in cache, KeyNotFoundException will be thrown. /// </summary> /// <param name="key">Key.</param> /// <param name="modes">Peek modes.</param> @@ -160,11 +161,38 @@ namespace Apache.Ignite.Core.Cache TV LocalPeek(TK key, params CachePeekMode[] modes); /// <summary> - /// Retrieves value mapped to the specified key from cache. + /// Peeks at cached value using optional set of peek modes. This method will sequentially + /// iterate over given peek modes, and try to peek at value using each peek mode. Once a + /// non-null value is found, it will be immediately returned. + /// This method does not participate in any transactions, however, it may peek at transactional + /// value depending on the peek modes used. + /// </summary> + /// <param name="key">Key.</param> + /// <param name="value">When this method returns, the value associated with the specified key, + /// if the key is found; otherwise, the default value for the type of the value parameter. + /// This parameter is passed uninitialized.</param> + /// <param name="modes">Peek modes.</param> + /// <returns> + /// true if the cache contains an element with the specified key; otherwise, false. + /// </returns> + bool TryLocalPeek(TK key, out TV value, params CachePeekMode[] modes); + + /// <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> + TV this[TK key] { get; set; } + + /// <summary> + /// Retrieves value mapped to the specified key from cache. Throws an exception if t + /// /// 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> @@ -172,6 +200,22 @@ namespace Apache.Ignite.Core.Cache TV Get(TK key); /// <summary> + /// 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. + /// </summary> + /// <param name="key">Key.</param> + /// <param name="value">When this method returns, the value associated with the specified key, + /// if the key is found; otherwise, the default value for the type of the value parameter. + /// This parameter is passed uninitialized.</param> + /// <returns> + /// true if the cache contains an element with the specified key; otherwise, false. + /// </returns> + bool TryGet(TK key, out TV value); + + /// <summary> /// Retrieves values mapped to the specified keys from cache. /// If some 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 disabled, and if read-through is allowed, value @@ -201,10 +245,10 @@ namespace Apache.Ignite.Core.Cache /// <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> /// <returns> - /// The value associated with the key at the start of the operation or null if none was associated. + /// The value associated with the key at the start of the operation. /// </returns> [AsyncSupported] - TV GetAndPut(TK key, TV val); + CacheResult<TV> GetAndPut(TK key, TV val); /// <summary> /// Atomically replaces the value for a given key if and only if there is a value currently mapped by the key. @@ -212,18 +256,18 @@ namespace Apache.Ignite.Core.Cache /// <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> /// <returns> - /// The previous value associated with the specified key, or null if there was no mapping for the key. + /// The previous value associated with the specified key. /// </returns> [AsyncSupported] - TV GetAndReplace(TK key, TV val); + CacheResult<TV> GetAndReplace(TK key, TV val); /// <summary> /// Atomically removes the entry for a key only if currently mapped to some value. /// </summary> /// <param name="key">Key with which the specified value is associated.</param> - /// <returns>The value if one existed or null if no mapping existed for this key.</returns> + /// <returns>The value if one existed.</returns> [AsyncSupported] - TV GetAndRemove(TK key); + CacheResult<TV> GetAndRemove(TK key); /// <summary> /// Atomically associates the specified key with the given value if it is not already associated with a value. @@ -248,10 +292,10 @@ namespace Apache.Ignite.Core.Cache /// <param name="key">Key to store in cache.</param> /// <param name="val">Value to be associated with the given key.</param> /// <returns> - /// Previously contained value regardless of whether put happened or not (null if there was no previous value). + /// Previously contained value regardless of whether put happened or not. /// </returns> [AsyncSupported] - TV GetAndPutIfAbsent(TK key, TV val); + CacheResult<TV> GetAndPutIfAbsent(TK key, TV val); /// <summary> /// Stores given key-value pair in cache only if there is a previous mapping for it. http://git-wip-us.apache.org/repos/asf/ignite/blob/2ed4794f/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 dcecc52..5a01006 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs @@ -20,6 +20,7 @@ namespace Apache.Ignite.Core.Impl.Cache using System; using System.Collections; using System.Collections.Generic; + using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Threading; using Apache.Ignite.Core.Cache; @@ -124,22 +125,22 @@ namespace Apache.Ignite.Core.Impl.Cache /// <summary> /// Gets and resets future for previous asynchronous operation. /// </summary> - /// <param name="lastAsyncOpId">The last async op id.</param> + /// <param name="lastAsyncOp">The last async op id.</param> /// <returns> /// Future for previous asynchronous operation. /// </returns> /// <exception cref="System.InvalidOperationException">Asynchronous mode is disabled</exception> - internal IFuture<TResult> GetFuture<TResult>(int lastAsyncOpId) + internal IFuture<TResult> GetFuture<TResult>(CacheOp lastAsyncOp) { if (!_flagAsync) throw IgniteUtils.GetAsyncModeDisabledException(); - var converter = GetFutureResultConverter<TResult>(lastAsyncOpId); + var converter = GetFutureResultConverter<TResult>(lastAsyncOp); _invokeAllConverter.Value = null; - return GetFuture((futId, futTypeId) => UU.TargetListenFutureForOperation(Target, futId, futTypeId, lastAsyncOpId), - _flagKeepPortable, converter); + return GetFuture((futId, futTypeId) => UU.TargetListenFutureForOperation(Target, futId, futTypeId, + (int) lastAsyncOp), _flagKeepPortable, converter); } /** <inheritDoc /> */ @@ -290,11 +291,47 @@ namespace Apache.Ignite.Core.Impl.Cache { IgniteArgumentCheck.NotNull(key, "key"); - return DoOutInOp<TV>((int)CacheOp.Peek, writer => + TV res; + + if (TryLocalPeek(key, out res)) + return res; + + throw GetKeyNotFoundException(); + } + + /** <inheritDoc /> */ + public bool TryLocalPeek(TK key, out TV value, params CachePeekMode[] modes) + { + IgniteArgumentCheck.NotNull(key, "key"); + + var res = DoOutInOpNullable<TV>((int)CacheOp.Peek, writer => { writer.Write(key); writer.WriteInt(EncodePeekModes(modes)); }); + + value = res.Success ? res.Value : default(TV); + + return res.Success; + } + + /** <inheritDoc /> */ + public TV this[TK key] + { + get + { + if (IsAsync) + throw new InvalidOperationException("Indexer can't be used in async mode."); + + return Get(key); + } + set + { + if (IsAsync) + throw new InvalidOperationException("Indexer can't be used in async mode."); + + Put(key, value); + } } /** <inheritDoc /> */ @@ -302,7 +339,34 @@ namespace Apache.Ignite.Core.Impl.Cache { IgniteArgumentCheck.NotNull(key, "key"); - return DoOutInOp<TK, TV>((int)CacheOp.Get, key); + var result = DoOutInOpNullable<TK, TV>((int) CacheOp.Get, key); + + if (!IsAsync) + { + if (!result.Success) + throw GetKeyNotFoundException(); + + return result.Value; + } + + Debug.Assert(!result.Success); + + return default(TV); + } + + /** <inheritDoc /> */ + public bool TryGet(TK key, out TV value) + { + IgniteArgumentCheck.NotNull(key, "key"); + + if (IsAsync) + throw new InvalidOperationException("TryGet can't be used in async mode."); + + var res = DoOutInOpNullable<TK, TV>((int) CacheOp.Get, key); + + value = res.Value; + + return res.Success; } /** <inheritDoc /> */ @@ -331,31 +395,31 @@ namespace Apache.Ignite.Core.Impl.Cache } /** <inheritDoc /> */ - public TV GetAndPut(TK key, TV val) + public CacheResult<TV> GetAndPut(TK key, TV val) { IgniteArgumentCheck.NotNull(key, "key"); IgniteArgumentCheck.NotNull(val, "val"); - return DoOutInOp<TK, TV, TV>((int)CacheOp.GetAndPut, key, val); + return DoOutInOpNullable<TK, TV, TV>((int)CacheOp.GetAndPut, key, val); } /** <inheritDoc /> */ - public TV GetAndReplace(TK key, TV val) + public CacheResult<TV> GetAndReplace(TK key, TV val) { IgniteArgumentCheck.NotNull(key, "key"); IgniteArgumentCheck.NotNull(val, "val"); - return DoOutInOp<TK, TV, TV>((int)CacheOp.GetAndReplace, key, val); + return DoOutInOpNullable<TK, TV, TV>((int)CacheOp.GetAndReplace, key, val); } /** <inheritDoc /> */ - public TV GetAndRemove(TK key) + public CacheResult<TV> GetAndRemove(TK key) { IgniteArgumentCheck.NotNull(key, "key"); - return DoOutInOp<TK, TV>((int)CacheOp.GetAndRemove, key); + return DoOutInOpNullable<TK, TV>((int)CacheOp.GetAndRemove, key); } /** <inheritdoc /> */ @@ -369,13 +433,13 @@ namespace Apache.Ignite.Core.Impl.Cache } /** <inheritdoc /> */ - public TV GetAndPutIfAbsent(TK key, TV val) + public CacheResult<TV> GetAndPutIfAbsent(TK key, TV val) { IgniteArgumentCheck.NotNull(key, "key"); IgniteArgumentCheck.NotNull(val, "val"); - return DoOutInOp<TK, TV, TV>((int)CacheOp.GetAndPutIfAbsent, key, val); + return DoOutInOpNullable<TK, TV, TV>((int)CacheOp.GetAndPutIfAbsent, key, val); } /** <inheritdoc /> */ @@ -916,26 +980,108 @@ namespace Apache.Ignite.Core.Impl.Cache /// <typeparam name="TResult">The type of the future result.</typeparam> /// <param name="lastAsyncOpId">The last op id.</param> /// <returns>Future result converter.</returns> - private Func<PortableReaderImpl, TResult> GetFutureResultConverter<TResult>(int lastAsyncOpId) + private Func<PortableReaderImpl, TResult> GetFutureResultConverter<TResult>(CacheOp lastAsyncOpId) { - if (lastAsyncOpId == (int) CacheOp.GetAll) - return reader => (TResult)ReadGetAllDictionary(reader); - - if (lastAsyncOpId == (int)CacheOp.Invoke) - return reader => - { - var hasError = reader.ReadBoolean(); + switch (lastAsyncOpId) + { + case CacheOp.Get: + return reader => + { + if (reader != null) + return reader.ReadObject<TResult>(); + + throw GetKeyNotFoundException(); + }; + + case CacheOp.GetAll: + return reader => reader == null ? default(TResult) : (TResult) ReadGetAllDictionary(reader); + + case CacheOp.Invoke: + return reader => + { + if (reader == null) + return default(TResult); + + var hasError = reader.ReadBoolean(); + + if (hasError) + throw ReadException(reader.Stream); - if (hasError) - throw ReadException(reader.Stream); + return reader.ReadObject<TResult>(); + }; - return reader.ReadObject<TResult>(); - }; + case CacheOp.InvokeAll: + return _invokeAllConverter.Value as Func<PortableReaderImpl, TResult>; - if (lastAsyncOpId == (int) CacheOp.InvokeAll) - return _invokeAllConverter.Value as Func<PortableReaderImpl, TResult>; + case CacheOp.GetAndPut: + case CacheOp.GetAndPutIfAbsent: + case CacheOp.GetAndRemove: + case CacheOp.GetAndReplace: + return reader => + { + var res = reader == null + ? new CacheResult<TV>() + : new CacheResult<TV>(reader.ReadObject<TV>()); + + return TypeCaster<TResult>.Cast(res); + }; + } return null; } + + /// <summary> + /// Throws the key not found exception. + /// </summary> + private static KeyNotFoundException GetKeyNotFoundException() + { + return new KeyNotFoundException("The given key was not present in the cache."); + } + + /// <summary> + /// Perform simple out-in operation accepting single argument. + /// </summary> + /// <param name="type">Operation type.</param> + /// <param name="val">Value.</param> + /// <returns>Result.</returns> + private CacheResult<TR> DoOutInOpNullable<T1, TR>(int type, T1 val) + { + var res = DoOutInOp<T1, object>(type, val); + + return res == null + ? new CacheResult<TR>() + : new CacheResult<TR>((TR)res); + } + + /// <summary> + /// Perform out-in operation. + /// </summary> + /// <param name="type">Operation type.</param> + /// <param name="outAction">Out action.</param> + /// <returns>Result.</returns> + private CacheResult<TR> DoOutInOpNullable<TR>(int type, Action<PortableWriterImpl> outAction) + { + var res = DoOutInOp<object>(type, outAction); + + return res == null + ? new CacheResult<TR>() + : new CacheResult<TR>((TR)res); + } + + /// <summary> + /// Perform simple out-in operation accepting single argument. + /// </summary> + /// <param name="type">Operation type.</param> + /// <param name="val1">Value.</param> + /// <param name="val2">Value.</param> + /// <returns>Result.</returns> + private CacheResult<TR> DoOutInOpNullable<T1, T2, TR>(int type, T1 val1, T2 val2) + { + var res = DoOutInOp<T1, T2, object>(type, val1, val2); + + return res == null + ? new CacheResult<TR>() + : new CacheResult<TR>((TR)res); + } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/2ed4794f/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheOp.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheOp.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheOp.cs index 3eb63ca..1709dc5 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheOp.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheOp.cs @@ -22,6 +22,7 @@ namespace Apache.Ignite.Core.Impl.Cache /// </summary> internal enum CacheOp { + None = 0, Clear = 1, ClearAll = 2, ContainsKey = 3, http://git-wip-us.apache.org/repos/asf/ignite/blob/2ed4794f/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheProxyImpl.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheProxyImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheProxyImpl.cs index 0f868d8..aaaf8c3 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheProxyImpl.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheProxyImpl.cs @@ -38,7 +38,7 @@ namespace Apache.Ignite.Core.Impl.Cache private readonly CacheImpl<TK, TV> _cache; /** */ - private readonly ThreadLocal<int> _lastAsyncOp = new ThreadLocal<int>(() => PlatformTarget.OpNone); + private readonly ThreadLocal<CacheOp> _lastAsyncOp = new ThreadLocal<CacheOp>(() => CacheOp.None); /// <summary> /// Initializes a new instance of the <see cref="CacheProxyImpl{K, V}"/> class. @@ -185,6 +185,19 @@ namespace Apache.Ignite.Core.Impl.Cache } /** <inheritDoc /> */ + public bool TryLocalPeek(TK key, out TV value, params CachePeekMode[] modes) + { + return _cache.TryLocalPeek(key, out value, modes); + } + + /** <inheritDoc /> */ + public TV this[TK key] + { + get { return _cache[key]; } + set { _cache[key] = value; } + } + + /** <inheritDoc /> */ public TV Get(TK key) { var result = _cache.Get(key); @@ -195,6 +208,12 @@ namespace Apache.Ignite.Core.Impl.Cache } /** <inheritDoc /> */ + public bool TryGet(TK key, out TV value) + { + return _cache.TryGet(key, out value); + } + + /** <inheritDoc /> */ public IDictionary<TK, TV> GetAll(IEnumerable<TK> keys) { var result = _cache.GetAll(keys); @@ -213,7 +232,7 @@ namespace Apache.Ignite.Core.Impl.Cache } /** <inheritDoc /> */ - public TV GetAndPut(TK key, TV val) + public CacheResult<TV> GetAndPut(TK key, TV val) { var result = _cache.GetAndPut(key, val); @@ -223,7 +242,7 @@ namespace Apache.Ignite.Core.Impl.Cache } /** <inheritDoc /> */ - public TV GetAndReplace(TK key, TV val) + public CacheResult<TV> GetAndReplace(TK key, TV val) { var result = _cache.GetAndReplace(key, val); @@ -233,7 +252,7 @@ namespace Apache.Ignite.Core.Impl.Cache } /** <inheritDoc /> */ - public TV GetAndRemove(TK key) + public CacheResult<TV> GetAndRemove(TK key) { var result = _cache.GetAndRemove(key); @@ -253,7 +272,7 @@ namespace Apache.Ignite.Core.Impl.Cache } /** <inheritDoc /> */ - public TV GetAndPutIfAbsent(TK key, TV val) + public CacheResult<TV> GetAndPutIfAbsent(TK key, TV val) { var result = _cache.GetAndPutIfAbsent(key, val); @@ -484,7 +503,7 @@ namespace Apache.Ignite.Core.Impl.Cache private void SetLastAsyncOp(CacheOp opId) { if (IsAsync) - _lastAsyncOp.Value = (int) opId; + _lastAsyncOp.Value = opId; } /// <summary> @@ -494,7 +513,7 @@ namespace Apache.Ignite.Core.Impl.Cache private void ClearLastAsyncOp() { if (IsAsync) - _lastAsyncOp.Value = PlatformTarget.OpNone; + _lastAsyncOp.Value = CacheOp.None; } } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/2ed4794f/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/Future.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/Future.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/Future.cs index a25bada..70bebc4 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/Future.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/Future.cs @@ -215,7 +215,21 @@ namespace Apache.Ignite.Core.Impl.Common /** <inheritdoc /> */ public void OnNullResult() { - OnResult(default(T)); + if (_converter == null) + { + OnResult(default(T)); + + return; + } + + try + { + OnResult(_converter.Convert(null)); + } + catch (Exception ex) + { + OnError(ex); + } } /// <summary> http://git-wip-us.apache.org/repos/asf/ignite/blob/2ed4794f/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/FutureConverter.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/FutureConverter.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/FutureConverter.cs index a07d954..5d158ec 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/FutureConverter.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/FutureConverter.cs @@ -46,7 +46,7 @@ namespace Apache.Ignite.Core.Impl.Common { _marsh = marsh; _keepPortable = keepPortable; - _func = func ?? (reader => reader.ReadObject<T>()); + _func = func ?? (reader => reader == null ? default(T) : reader.ReadObject<T>()); } /// <summary> @@ -54,7 +54,7 @@ namespace Apache.Ignite.Core.Impl.Common /// </summary> public T Convert(IPortableStream stream) { - var reader = _marsh.StartUnmarshal(stream, _keepPortable); + var reader = stream == null ? null : _marsh.StartUnmarshal(stream, _keepPortable); return _func(reader); } http://git-wip-us.apache.org/repos/asf/ignite/blob/2ed4794f/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IFutureConverter.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IFutureConverter.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IFutureConverter.cs index e07597d..d97adeb 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IFutureConverter.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IFutureConverter.cs @@ -28,6 +28,7 @@ namespace Apache.Ignite.Core.Impl.Common { /// <summary> /// Reads and converts a value. + /// Null stream means null value. /// </summary> T Convert(IPortableStream stream); } http://git-wip-us.apache.org/repos/asf/ignite/blob/2ed4794f/modules/platforms/dotnet/Apache.Ignite.Core/Impl/PlatformTarget.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/PlatformTarget.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/PlatformTarget.cs index 03ccf8b..6d0a324 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/PlatformTarget.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/PlatformTarget.cs @@ -22,6 +22,7 @@ namespace Apache.Ignite.Core.Impl using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; + using Apache.Ignite.Core.Cache; using Apache.Ignite.Core.Common; using Apache.Ignite.Core.Impl.Common; using Apache.Ignite.Core.Impl.Memory; http://git-wip-us.apache.org/repos/asf/ignite/blob/2ed4794f/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs index dfc7c74..fe5f5c9 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs @@ -600,6 +600,10 @@ namespace Apache.Ignite.Core.Impl.Portable switch (hdr) { case PortableUtils.HdrNull: + if (default(T) != null) + throw new PortableException(string.Format("Invalid data on deserialization. " + + "Expected: '{0}' But was: null", typeof (T))); + return default(T); case PortableUtils.HdrHnd:
