IGNITE-1302: Moving some common .Net classes to Ignite.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/8df6b935 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/8df6b935 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/8df6b935 Branch: refs/heads/ignite-884 Commit: 8df6b935c32d8b801ead4deb0470f84df435ff5a Parents: 824cfa4 Author: Pavel Tupitsyn <ptupit...@gridgain.com> Authored: Wed Aug 26 15:55:24 2015 +0300 Committer: vozerov-gridgain <voze...@gridgain.com> Committed: Wed Aug 26 15:55:24 2015 +0300 ---------------------------------------------------------------------- .../Apache.Ignite.Core.csproj | 22 ++ .../Common/AsyncSupportedAttribute.cs | 33 +++ .../Apache.Ignite.Core/Common/IAsyncSupport.cs | 52 ++++ .../dotnet/Apache.Ignite.Core/Common/IFuture.cs | 115 ++++++++ .../Common/IgniteException.cs | 66 +++++ .../Impl/Collections/CollectionExtensions.cs | 45 +++ .../Impl/Collections/MultiValueDictionary.cs | 143 ++++++++++ .../Impl/Collections/ReadOnlyCollection.cs | 102 +++++++ .../Impl/Collections/ReadOnlyDictionary.cs | 149 ++++++++++ .../Impl/Common/AsyncResult.cs | 71 +++++ .../Impl/Common/CompletedAsyncResult.cs | 70 +++++ .../Common/CopyOnWriteConcurrentDictionary.cs | 70 +++++ .../Impl/Common/DelegateConverter.cs | 253 ++++++++++++++++ .../Apache.Ignite.Core/Impl/Common/Future.cs | 286 +++++++++++++++++++ .../Impl/Common/FutureType.cs | 52 ++++ .../Impl/Common/GridArgumentCheck.cs | 76 +++++ .../Impl/Common/IFutureConverter.cs | 32 +++ .../Impl/Common/IFutureInternal.cs | 45 +++ .../Impl/Common/LoadedAssembliesResolver.cs | 96 +++++++ .../Impl/Common/TypeCaster.cs | 72 +++++ 20 files changed, 1850 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj index 658e5fb..12e335a 100644 --- a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj @@ -16,6 +16,7 @@ <PlatformTarget>x64</PlatformTarget> <OutputPath>bin\x64\Debug\</OutputPath> <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <DefineConstants>DEBUG</DefineConstants> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> <PlatformTarget>x64</PlatformTarget> @@ -26,6 +27,7 @@ <PlatformTarget>x86</PlatformTarget> <OutputPath>bin\x86\Debug\</OutputPath> <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <DefineConstants>DEBUG</DefineConstants> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'"> <PlatformTarget>x86</PlatformTarget> @@ -47,7 +49,26 @@ <Reference Include="System.Core" /> </ItemGroup> <ItemGroup> + <Compile Include="Common\IgniteException.cs" /> + <Compile Include="Common\IAsyncSupport.cs" /> + <Compile Include="Common\IFuture.cs" /> <Compile Include="Ignition.cs" /> + <Compile Include="Common\AsyncSupportedAttribute.cs" /> + <Compile Include="Impl\Collections\CollectionExtensions.cs" /> + <Compile Include="Impl\Collections\MultiValueDictionary.cs" /> + <Compile Include="Impl\Collections\ReadOnlyCollection.cs" /> + <Compile Include="Impl\Collections\ReadOnlyDictionary.cs" /> + <Compile Include="Impl\Common\AsyncResult.cs" /> + <Compile Include="Impl\Common\CompletedAsyncResult.cs" /> + <Compile Include="Impl\Common\CopyOnWriteConcurrentDictionary.cs" /> + <Compile Include="Impl\Common\DelegateConverter.cs" /> + <Compile Include="Impl\Common\Future.cs" /> + <Compile Include="Impl\Common\FutureType.cs" /> + <Compile Include="Impl\Common\GridArgumentCheck.cs" /> + <Compile Include="Impl\Common\IFutureConverter.cs" /> + <Compile Include="Impl\Common\IFutureInternal.cs" /> + <Compile Include="Impl\Common\LoadedAssembliesResolver.cs" /> + <Compile Include="Impl\Common\TypeCaster.cs" /> <Compile Include="Impl\Handle\Handle.cs" /> <Compile Include="Impl\Handle\HandleRegistry.cs" /> <Compile Include="Impl\Handle\IHandle.cs" /> @@ -64,6 +85,7 @@ <Compile Include="Impl\Portable\IO\IPortableStream.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> </ItemGroup> + <ItemGroup /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/AsyncSupportedAttribute.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/AsyncSupportedAttribute.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/AsyncSupportedAttribute.cs new file mode 100644 index 0000000..094a93c --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/AsyncSupportedAttribute.cs @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace Apache.Ignite.Core.Common +{ + using System; + + /// <summary> + /// Attribute to indicate that method can be executed asynchronously if async mode is enabled. + /// To enable async mode, invoke <see cref="IAsyncSupport{TWithAsync}.WithAsync"/> method on the API. + /// The future for the async method can be retrieved via + /// <see cref="IFuture{T}"/> right after the execution of an asynchronous method. + /// </summary> + [AttributeUsage(AttributeTargets.Method)] + public sealed class AsyncSupportedAttribute : Attribute + { + // No-op. + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IAsyncSupport.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IAsyncSupport.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IAsyncSupport.cs new file mode 100644 index 0000000..f6b6551 --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IAsyncSupport.cs @@ -0,0 +1,52 @@ +/* + * 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.Common +{ + /// <summary> + /// Allows to enable asynchronous mode on Grid APIs. + /// </summary> + /// <typeparam name="TWithAsync">Type of WithAsync method result.</typeparam> + public interface IAsyncSupport<out TWithAsync> where TWithAsync : IAsyncSupport<TWithAsync> + { + /// <summary> + /// Gets component with asynchronous mode enabled. + /// </summary> + /// <returns>Component with asynchronous mode enabled.</returns> + TWithAsync WithAsync(); + + /// <summary> + /// Gets a value indicating whether this instance is in asynchronous mode. + /// </summary> + /// <value> + /// <c>true</c> if asynchronous mode is enabled. + /// </value> + bool IsAsync { get; } + + /// <summary> + /// Gets and resets future for previous asynchronous operation. + /// </summary> + /// <returns>Future for previous asynchronous operation.</returns> + IFuture GetFuture(); + + /// <summary> + /// Gets and resets future for previous asynchronous operation. + /// </summary> + /// <returns>Future for previous asynchronous operation.</returns> + IFuture<TResult> GetFuture<TResult>(); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IFuture.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IFuture.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IFuture.cs new file mode 100644 index 0000000..2e94cd4 --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IFuture.cs @@ -0,0 +1,115 @@ +/* + * 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.Common +{ + using System; + using System.Threading.Tasks; + + /// <summary> + /// Non-generic Future. Represents an asynchronous operation that can return a value. + /// <para/> + /// All members are thread-safe and may be used concurrently from multiple threads. + /// </summary> + public interface IFuture + { + /// <summary> + /// Gets a value indicating whether this instance is done. + /// </summary> + bool IsDone + { + get; + } + + /// <summary> + /// Gets the future result. + /// </summary> + /// <returns>Future result.</returns> + object Get(); + + /// <summary> + /// Gets the future result with a timeout. + /// </summary> + /// <param name="timeout">The timeout.</param> + /// <returns> + /// Future result, if it is obtained within specified timeout; otherwise, throws <see cref="TimeoutException"/> + /// </returns> + /// <exception cref="TimeoutException">Thrown if Get operation exceeded specified timeout.</exception> + object Get(TimeSpan timeout); + + /// <summary> + /// Listens this instance and invokes callback upon future completion. + /// </summary> + /// <param name="callback">The callback to execute upon future completion.</param> + void Listen(Action callback); + + /// <summary> + /// Listens this instance and invokes callback upon future completion. + /// </summary> + /// <param name="callback">The callback to execute upon future completion.</param> + void Listen(Action<IFuture> callback); + + /// <summary> + /// Gets an IAsyncResult indicating the state of this Future. + /// </summary> + /// <returns>Future state representation in form of IAsyncResult.</returns> + IAsyncResult ToAsyncResult(); + + /// <summary> + /// Gets a Task that returns the result of this Future. + /// </summary> + /// <returns>Task that completes when this future gets done and returns the result.</returns> + Task<object> ToTask(); + } + + /// <summary> + /// Generic Future. Represents an asynchronous operation that can return a value. + /// <para/> + /// All members are thread-safe and may be used concurrently from multiple threads. + /// </summary> + /// <typeparam name="T">Future result type.</typeparam> + public interface IFuture<T> : IFuture + { + /// <summary> + /// Gets the future result. + /// </summary> + /// <returns>Future result.</returns> + new T Get(); + + /// <summary> + /// Gets the future result with a timeout. + /// </summary> + /// <param name="timeout">The timeout.</param> + /// <returns> + /// Future result, if it is obtained within specified timeout; otherwise, throws <see cref="TimeoutException"/> + /// </returns> + /// <exception cref="TimeoutException">Thrown if Get operation exceeded specified timeout.</exception> + new T Get(TimeSpan timeout); + + /// <summary> + /// Gets a Task that returns the result of this Future. + /// </summary> + /// <returns>Task that completes when this future gets done and returns the result.</returns> + new Task<T> ToTask(); + + /// <summary> + /// Listens this instance and invokes callback upon future completion. + /// </summary> + /// <param name="callback">The callback to execute upon future completion.</param> + void Listen(Action<IFuture<T>> callback); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IgniteException.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IgniteException.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IgniteException.cs new file mode 100644 index 0000000..4626407 --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IgniteException.cs @@ -0,0 +1,66 @@ +/* + * 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.Common +{ + using System; + using System.Runtime.Serialization; + + /// <summary> + /// General grid exception. Indicates any error condition within Grid. + /// </summary> + [Serializable] + public class IgniteException : Exception + { + /// <summary> + /// Initializes a new instance of the <see cref="IgniteException"/> class. + /// </summary> + public IgniteException() + { + // No-op. + } + + /// <summary> + /// Initializes a new instance of the <see cref="IgniteException" /> class. + /// </summary> + /// <param name="message">The message that describes the error.</param> + public IgniteException(string message) : base(message) + { + // No-op. + } + + /// <summary> + /// Initializes a new instance of the <see cref="IgniteException" /> class. + /// </summary> + /// <param name="message">The message.</param> + /// <param name="cause">The cause.</param> + public IgniteException(string message, Exception cause) : base(message, cause) + { + // No-op. + } + + /// <summary> + /// Initializes a new instance of the <see cref="IgniteException"/> class. + /// </summary> + /// <param name="info">Serialization information.</param> + /// <param name="ctx">Streaming context.</param> + protected IgniteException(SerializationInfo info, StreamingContext ctx) : base(info, ctx) + { + // No-op. + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/CollectionExtensions.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/CollectionExtensions.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/CollectionExtensions.cs new file mode 100644 index 0000000..57295cb --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/CollectionExtensions.cs @@ -0,0 +1,45 @@ +/* + * 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.Collections +{ + using System.Collections.Generic; + + /// <summary> + /// Collection extension methods. + /// </summary> + public static class CollectionExtensions + { + /// <summary> + /// Returns a read-only System.Collections.Generic.IDictionary{K, V} wrapper for the current collection. + /// </summary> + public static IDictionary<TKey, TValue> AsReadOnly<TKey, TValue>(this IDictionary<TKey, TValue> dict) + { + return new ReadOnlyDictionary<TKey, TValue>(dict); + } + + /// <summary> + /// Returns a read-only System.Collections.Generic.ICollection{K, V} wrapper for the current collection. + /// </summary> + public static ICollection<T> AsReadOnly<T>(this ICollection<T> col) + { + var list = col as List<T>; + + return list != null ? (ICollection<T>) list.AsReadOnly() : new ReadOnlyCollection<T>(col); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/MultiValueDictionary.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/MultiValueDictionary.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/MultiValueDictionary.cs new file mode 100644 index 0000000..bd7e895 --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/MultiValueDictionary.cs @@ -0,0 +1,143 @@ +/* + * 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.Collections +{ + using System.Collections.Generic; + + /// <summary> + /// Multiple-values-per-key dictionary. + /// </summary> + public class MultiValueDictionary<TKey, TValue> + { + /** Inner dictionary */ + private readonly Dictionary<TKey, object> _dict = new Dictionary<TKey, object>(); + + /// <summary> + /// Adds a value. + /// </summary> + /// <param name="key">The key.</param> + /// <param name="val">The value.</param> + public void Add(TKey key, TValue val) + { + object val0; + + if (_dict.TryGetValue(key, out val0)) + { + var list = val0 as List<TValue>; + + if (list != null) + list.Add(val); + else + _dict[key] = new List<TValue> {(TValue) val0, val}; + } + else + _dict[key] = val; + } + + /// <summary> + /// Tries the get a value. In case of multiple values for a key, returns the last one. + /// </summary> + /// <param name="key">The key.</param> + /// <param name="val">The value.</param> + /// <returns>True if value has been found for specified key; otherwise false.</returns> + public bool TryGetValue(TKey key, out TValue val) + { + object val0; + + if (!_dict.TryGetValue(key, out val0)) + { + val = default(TValue); + return false; + } + + var list = val0 as List<TValue>; + + if (list != null) + val = list[list.Count - 1]; + else + val = (TValue) val0; + + return true; + } + + /// <summary> + /// Removes the specified value for the specified key. + /// </summary> + /// <param name="key">The key.</param> + /// <param name="val">The value.</param> + public void Remove(TKey key, TValue val) + { + object val0; + + if (!_dict.TryGetValue(key, out val0)) + return; + + var list = val0 as List<TValue>; + + if (list != null) + { + list.Remove(val); + + if (list.Count == 0) + _dict.Remove(key); + } + else if (Equals(val0, val)) + _dict.Remove(key); + } + + /// <summary> + /// Removes the last value for the specified key and returns it. + /// </summary> + /// <param name="key">The key.</param> + /// <param name="val">The value.</param> + /// <returns>True if value has been found for specified key; otherwise false.</returns> + public bool TryRemove(TKey key, out TValue val) + { + object val0; + + if (!_dict.TryGetValue(key, out val0)) + { + val = default(TValue); + + return false; + } + + var list = val0 as List<TValue>; + + if (list != null) + { + var index = list.Count - 1; + + val = list[index]; + + list.RemoveAt(index); + + if (list.Count == 0) + _dict.Remove(key); + + return true; + } + + val = (TValue) val0; + + _dict.Remove(key); + + return true; + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/ReadOnlyCollection.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/ReadOnlyCollection.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/ReadOnlyCollection.cs new file mode 100644 index 0000000..23cae6b --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/ReadOnlyCollection.cs @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace Apache.Ignite.Core.Impl.Collections +{ + using System; + using System.Collections; + using System.Collections.Generic; + + /// <summary> + /// Read-only wrapper over ICollection{T}. + /// </summary> + internal struct ReadOnlyCollection<T> : ICollection<T> + { + /** Wrapped collection. */ + private readonly ICollection<T> _col; + + /// <summary> + /// Initializes a new instance of the <see cref="ReadOnlyCollection{T}"/> class. + /// </summary> + public ReadOnlyCollection(ICollection<T> col) + { + _col = col; + } + + /** <inheritdoc /> */ + public IEnumerator<T> GetEnumerator() + { + return _col.GetEnumerator(); + } + + /** <inheritdoc /> */ + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable) _col).GetEnumerator(); + } + + /** <inheritdoc /> */ + public void Add(T item) + { + throw GetReadOnlyException(); + } + + /** <inheritdoc /> */ + public void Clear() + { + throw GetReadOnlyException(); + } + + /** <inheritdoc /> */ + public bool Contains(T item) + { + return _col.Contains(item); + } + + /** <inheritdoc /> */ + public void CopyTo(T[] array, int arrayIndex) + { + _col.CopyTo(array, arrayIndex); + } + + /** <inheritdoc /> */ + public bool Remove(T item) + { + throw GetReadOnlyException(); + } + + /** <inheritdoc /> */ + public int Count + { + get { return _col.Count; } + } + + /** <inheritdoc /> */ + public bool IsReadOnly + { + get { return true; } + } + + /// <summary> + /// Gets the readonly exception. + /// </summary> + private static Exception GetReadOnlyException() + { + return new NotSupportedException("Collection is read-only."); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/ReadOnlyDictionary.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/ReadOnlyDictionary.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/ReadOnlyDictionary.cs new file mode 100644 index 0000000..60ec9d0 --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/ReadOnlyDictionary.cs @@ -0,0 +1,149 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace Apache.Ignite.Core.Impl.Collections +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + + /// <summary> + /// Read-only wrapper over IDictionary{K, V}. + /// </summary> + internal struct ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue> + { + /** Inner dict. */ + private readonly IDictionary<TKey, TValue> _dict; + + /// <summary> + /// Initializes a new instance of the <see cref="ReadOnlyDictionary{K, V}"/> class. + /// </summary> + /// <param name="dict">The dictionary to wrap.</param> + public ReadOnlyDictionary(IDictionary<TKey, TValue> dict) + { + Debug.Assert(dict != null); + + _dict = dict; + } + + /** <inheritdoc /> */ + public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() + { + return _dict.GetEnumerator(); + } + + /** <inheritdoc /> */ + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable) _dict).GetEnumerator(); + } + + /** <inheritdoc /> */ + public void Add(KeyValuePair<TKey, TValue> item) + { + throw GetReadonlyException(); + } + + /** <inheritdoc /> */ + public void Clear() + { + throw GetReadonlyException(); + } + + /** <inheritdoc /> */ + public bool Contains(KeyValuePair<TKey, TValue> item) + { + return _dict.Contains(item); + } + + /** <inheritdoc /> */ + public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) + { + _dict.CopyTo(array, arrayIndex); + } + + /** <inheritdoc /> */ + public bool Remove(KeyValuePair<TKey, TValue> item) + { + throw GetReadonlyException(); + } + + /** <inheritdoc /> */ + public int Count + { + get { return _dict.Count; } + } + + /** <inheritdoc /> */ + public bool IsReadOnly + { + get { return true; } + } + + /** <inheritdoc /> */ + public bool ContainsKey(TKey key) + { + return _dict.ContainsKey(key); + } + + /** <inheritdoc /> */ + public void Add(TKey key, TValue value) + { + throw GetReadonlyException(); + } + + /** <inheritdoc /> */ + public bool Remove(TKey key) + { + return _dict.Remove(key); + } + + /** <inheritdoc /> */ + public bool TryGetValue(TKey key, out TValue value) + { + return _dict.TryGetValue(key, out value); + } + + /** <inheritdoc /> */ + public TValue this[TKey key] + { + get { return _dict[key]; } + set { throw GetReadonlyException(); } + } + + /** <inheritdoc /> */ + public ICollection<TKey> Keys + { + get { return _dict.Keys; } + } + + /** <inheritdoc /> */ + public ICollection<TValue> Values + { + get { return _dict.Values; } + } + + /// <summary> + /// Gets the readonly exception. + /// </summary> + private static Exception GetReadonlyException() + { + return new NotSupportedException("Dictionary is read-only."); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/AsyncResult.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/AsyncResult.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/AsyncResult.cs new file mode 100644 index 0000000..4e5c396 --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/AsyncResult.cs @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace Apache.Ignite.Core.Impl.Common +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.Threading; + using Apache.Ignite.Core.Common; + + /// <summary> + /// Adapts IGridFuture to the IAsyncResult. + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable", + Justification = "Implementing IDisposable has no point since we return this class as IAsyncResult " + + "to the client, and IAsyncResult is not IDisposable.")] + public class AsyncResult : IAsyncResult + { + /** */ + private readonly ManualResetEvent _waitHandle; + + /// <summary> + /// Initializes a new instance of the <see cref="AsyncResult"/> class. + /// </summary> + /// <param name="fut">The future to wrap.</param> + public AsyncResult(IFuture fut) + { + _waitHandle = new ManualResetEvent(false); + + fut.Listen(() => _waitHandle.Set()); + } + + /** <inheritdoc /> */ + public bool IsCompleted + { + get { return _waitHandle.WaitOne(0); } + } + + /** <inheritdoc /> */ + public WaitHandle AsyncWaitHandle + { + get { return _waitHandle; } + } + + /** <inheritdoc /> */ + public object AsyncState + { + get { return null; } + } + + /** <inheritdoc /> */ + public bool CompletedSynchronously + { + get { return false; } + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/CompletedAsyncResult.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/CompletedAsyncResult.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/CompletedAsyncResult.cs new file mode 100644 index 0000000..14195fd --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/CompletedAsyncResult.cs @@ -0,0 +1,70 @@ +/* + * 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.Common +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.Threading; + + /// <summary> + /// Represents an IAsyncResult that is completed. + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable", + Justification = "Implementing IDisposable has no point since we return this class as IAsyncResult " + + "to the client, and IAsyncResult is not IDisposable.")] + public class CompletedAsyncResult : IAsyncResult + { + /** Singleton instance. */ + public static readonly IAsyncResult Instance = new CompletedAsyncResult(); + + /** */ + private readonly WaitHandle _asyncWaitHandle = new ManualResetEvent(true); + + /// <summary> + /// Prevents a default instance of the <see cref="CompletedAsyncResult"/> class from being created. + /// </summary> + private CompletedAsyncResult() + { + // No-op. + } + + /** <inheritdoc /> */ + public bool IsCompleted + { + get { return true; } + } + + /** <inheritdoc /> */ + public WaitHandle AsyncWaitHandle + { + get { return _asyncWaitHandle; } + } + + /** <inheritdoc /> */ + public object AsyncState + { + get { return null; } + } + + /** <inheritdoc /> */ + public bool CompletedSynchronously + { + get { return false; } + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/CopyOnWriteConcurrentDictionary.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/CopyOnWriteConcurrentDictionary.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/CopyOnWriteConcurrentDictionary.cs new file mode 100644 index 0000000..fa785b2 --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/CopyOnWriteConcurrentDictionary.cs @@ -0,0 +1,70 @@ +/* + * 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.Common +{ + using System; + using System.Collections.Generic; + + /// <summary> + /// Concurrent dictionary with CopyOnWrite mechanism inside. + /// Good for frequent reads / infrequent writes scenarios. + /// </summary> + public class CopyOnWriteConcurrentDictionary<TKey, TValue> + { + /** */ + private volatile Dictionary<TKey, TValue> _dict = new Dictionary<TKey, TValue>(); + + /// <summary> + /// Gets the value associated with the specified key. + /// </summary> + /// <param name="key">The key.</param> + /// <param name="val">The value.</param> + /// <returns>true if the dictionary contains an element with the specified key; otherwise, false.</returns> + public bool TryGetValue(TKey key, out TValue val) + { + return _dict.TryGetValue(key, out val); + } + + /// <summary> + /// Adds a key/value pair if the key does not already exist. + /// </summary> + /// <param name="key">The key.</param> + /// <param name="valueFactory">The function used to generate a value for the key.</param> + /// <returns>The value for the key.</returns> + public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory) + { + lock (this) + { + TValue res; + + if (_dict.TryGetValue(key, out res)) + return res; + + var dict0 = new Dictionary<TKey, TValue>(_dict); + + res = valueFactory(key); + + dict0[key] = res; + + _dict = dict0; + + return res; + } + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/DelegateConverter.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/DelegateConverter.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/DelegateConverter.cs new file mode 100644 index 0000000..7f83588 --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/DelegateConverter.cs @@ -0,0 +1,253 @@ +/* + * 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.Common +{ + using System; + using System.Diagnostics; + using System.Linq.Expressions; + using System.Reflection; + using System.Reflection.Emit; + + /// <summary> + /// Converts generic and non-generic delegates. + /// </summary> + public static class DelegateConverter + { + /** */ + private const string DefaultMethodName = "Invoke"; + + /// <summary> + /// Compiles a function without arguments. + /// </summary> + /// <param name="targetType">Type of the target.</param> + /// <returns>Compiled function that calls specified method on specified target.</returns> + public static Func<object, object> CompileFunc(Type targetType) + { + var method = targetType.GetMethod(DefaultMethodName); + + var targetParam = Expression.Parameter(typeof(object)); + var targetParamConverted = Expression.Convert(targetParam, targetType); + + var callExpr = Expression.Call(targetParamConverted, method); + var convertResultExpr = Expression.Convert(callExpr, typeof(object)); + + return Expression.Lambda<Func<object, object>>(convertResultExpr, targetParam).Compile(); + } + + /// <summary> + /// Compiles a function with arbitrary number of arguments. + /// </summary> + /// <typeparam name="T">Resulting delegate type.</typeparam> + /// <param name="targetType">Type of the target.</param> + /// <param name="argTypes">Argument types.</param> + /// <param name="convertToObject"> + /// Flags that indicate whether func params and/or return value should be converted from/to object. + /// </param> + /// <param name="methodName">Name of the method.</param> + /// <returns> + /// Compiled function that calls specified method on specified target. + /// </returns> + public static T CompileFunc<T>(Type targetType, Type[] argTypes, bool[] convertToObject = null, + string methodName = null) + where T : class + { + var method = targetType.GetMethod(methodName ?? DefaultMethodName, argTypes); + + return CompileFunc<T>(targetType, method, argTypes, convertToObject); + } + + /// <summary> + /// Compiles a function with arbitrary number of arguments. + /// </summary> + /// <typeparam name="T">Resulting delegate type.</typeparam> + /// <param name="method">Method.</param> + /// <param name="targetType">Type of the target.</param> + /// <param name="argTypes">Argument types.</param> + /// <param name="convertToObject"> + /// Flags that indicate whether func params and/or return value should be converted from/to object. + /// </param> + /// <returns> + /// Compiled function that calls specified method on specified target. + /// </returns> + public static T CompileFunc<T>(Type targetType, MethodInfo method, Type[] argTypes, + bool[] convertToObject = null) + where T : class + { + if (argTypes == null) + { + var args = method.GetParameters(); + argTypes = new Type[args.Length]; + + for (int i = 0; i < args.Length; i++) + argTypes[i] = args[i].ParameterType; + } + + Debug.Assert(convertToObject == null || (convertToObject.Length == argTypes.Length + 1)); + Debug.Assert(method != null); + + targetType = method.IsStatic ? null : (targetType ?? method.DeclaringType); + + var targetParam = Expression.Parameter(typeof(object)); + + Expression targetParamConverted = null; + ParameterExpression[] argParams; + int argParamsOffset = 0; + + if (targetType != null) + { + targetParamConverted = Expression.Convert(targetParam, targetType); + argParams = new ParameterExpression[argTypes.Length + 1]; + argParams[0] = targetParam; + argParamsOffset = 1; + } + else + argParams = new ParameterExpression[argTypes.Length]; // static method + + var argParamsConverted = new Expression[argTypes.Length]; + + for (var i = 0; i < argTypes.Length; i++) + { + if (convertToObject == null || convertToObject[i]) + { + var argParam = Expression.Parameter(typeof (object)); + argParams[i + argParamsOffset] = argParam; + argParamsConverted[i] = Expression.Convert(argParam, argTypes[i]); + } + else + { + var argParam = Expression.Parameter(argTypes[i]); + argParams[i + argParamsOffset] = argParam; + argParamsConverted[i] = argParam; + } + } + + Expression callExpr = Expression.Call(targetParamConverted, method, argParamsConverted); + + if (convertToObject == null || convertToObject[argTypes.Length]) + callExpr = Expression.Convert(callExpr, typeof(object)); + + return Expression.Lambda<T>(callExpr, argParams).Compile(); + } + + /// <summary> + /// Compiles a generic ctor with arbitrary number of arguments. + /// </summary> + /// <typeparam name="T">Result func type.</typeparam> + /// <param name="type">Type to be created by ctor.</param> + /// <param name="argTypes">Argument types.</param> + /// <param name="convertResultToObject">if set to <c>true</c> [convert result to object]. + /// Flag that indicates whether ctor return value should be converted to object. + /// </param> + /// <returns> + /// Compiled generic constructor. + /// </returns> + public static T CompileCtor<T>(Type type, Type[] argTypes, bool convertResultToObject = true) + { + var ctor = type.GetConstructor(argTypes); + + Debug.Assert(ctor != null); + + var args = new ParameterExpression[argTypes.Length]; + var argsConverted = new Expression[argTypes.Length]; + + for (var i = 0; i < argTypes.Length; i++) + { + var arg = Expression.Parameter(typeof(object)); + args[i] = arg; + argsConverted[i] = Expression.Convert(arg, argTypes[i]); + } + + Expression ctorExpr = Expression.New(ctor, argsConverted); // ctor takes args of specific types + + if (convertResultToObject) + ctorExpr = Expression.Convert(ctorExpr, typeof (object)); // convert ctor result to object + + return Expression.Lambda<T>(ctorExpr, args).Compile(); // lambda takes args as objects + } + + /// <summary> + /// Compiles the field setter. + /// </summary> + /// <param name="field">The field.</param> + /// <returns>Compiled field setter.</returns> + public static Action<object, object> CompileFieldSetter(FieldInfo field) + { + Debug.Assert(field != null); + Debug.Assert(field.DeclaringType != null); // non-static + + var targetParam = Expression.Parameter(typeof(object)); + var targetParamConverted = Expression.Convert(targetParam, field.DeclaringType); + + var valParam = Expression.Parameter(typeof(object)); + var valParamConverted = Expression.Convert(valParam, field.FieldType); + + var assignExpr = Expression.Call(GetWriteFieldMethod(field), targetParamConverted, valParamConverted); + + return Expression.Lambda<Action<object, object>>(assignExpr, targetParam, valParam).Compile(); + } + + /// <summary> + /// Compiles the property setter. + /// </summary> + /// <param name="prop">The property.</param> + /// <returns>Compiled property setter.</returns> + public static Action<object, object> CompilePropertySetter(PropertyInfo prop) + { + Debug.Assert(prop != null); + Debug.Assert(prop.DeclaringType != null); // non-static + + var targetParam = Expression.Parameter(typeof(object)); + var targetParamConverted = Expression.Convert(targetParam, prop.DeclaringType); + + var valParam = Expression.Parameter(typeof(object)); + var valParamConverted = Expression.Convert(valParam, prop.PropertyType); + + var fld = Expression.Property(targetParamConverted, prop); + + var assignExpr = Expression.Assign(fld, valParamConverted); + + return Expression.Lambda<Action<object, object>>(assignExpr, targetParam, valParam).Compile(); + } + + /// <summary> + /// Gets a method to write a field (including private and readonly). + /// NOTE: Expression Trees can't write readonly fields. + /// </summary> + /// <param name="field">The field.</param> + /// <returns>Resulting MethodInfo.</returns> + public static DynamicMethod GetWriteFieldMethod(FieldInfo field) + { + Debug.Assert(field != null); + + var module = Assembly.GetExecutingAssembly().GetModules()[0]; + + var method = new DynamicMethod(string.Empty, null, new[] { field.DeclaringType, field.FieldType }, module, + true); + + var il = method.GetILGenerator(); + + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Stfld, field); + il.Emit(OpCodes.Ret); + + return method; + } + + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/Future.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/Future.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/Future.cs new file mode 100644 index 0000000..c62cfd2 --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/Future.cs @@ -0,0 +1,286 @@ +/* + * 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.Common +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.Threading; + using System.Threading.Tasks; + + using Apache.Ignite.Core.Common; + using Apache.Ignite.Core.Impl.Portable.IO; + + /// <summary> + /// Grid future implementation. + /// </summary> + [SuppressMessage("ReSharper", "ParameterHidesMember")] + public sealed class Future<T> : IFutureInternal, IFuture<T> + { + /** Converter. */ + private readonly IFutureConverter<T> _converter; + + /** Result. */ + private T _res; + + /** Caught cxception. */ + private Exception _err; + + /** Done flag. */ + private volatile bool _done; + + /** Listener(s). Either Action or List{Action}. */ + private object _callbacks; + + /// <summary> + /// Constructor. + /// </summary> + /// <param name="converter">Future result marshaller and converter.</param> + public Future(IFutureConverter<T> converter = null) + { + _converter = converter; + } + + /** <inheritdoc/> */ + public bool IsDone + { + get { return _done; } + } + + /** <inheritdoc/> */ + public T Get() + { + if (!_done) + { + lock (this) + { + while (!_done) + Monitor.Wait(this); + } + } + + return Get0(); + } + + /** <inheritdoc/> */ + public T Get(TimeSpan timeout) + { + long ticks = timeout.Ticks; + + if (ticks < 0) + throw new ArgumentException("Timeout cannot be negative."); + + if (ticks == 0) + return Get(); + + if (!_done) + { + // Fallback to locked mode. + lock (this) + { + long endTime = DateTime.Now.Ticks + ticks; + + if (!_done) + { + while (true) + { + Monitor.Wait(this, timeout); + + if (_done) + break; + + ticks = endTime - DateTime.Now.Ticks; + + if (ticks <= 0) + throw new TimeoutException("Timeout waiting for future completion."); + + timeout = TimeSpan.FromTicks(ticks); + } + } + } + } + + return Get0(); + } + + /** <inheritdoc/> */ + public void Listen(Action callback) + { + Listen((Action<IFuture<T>>) (fut => callback())); + } + + /** <inheritdoc/> */ + public void Listen(Action<IFuture> callback) + { + Listen((Action<IFuture<T>>)callback); + } + + /** <inheritdoc/> */ + public void Listen(Action<IFuture<T>> callback) + { + GridArgumentCheck.NotNull(callback, "callback"); + + if (!_done) + { + lock (this) + { + if (!_done) + { + AddCallback(callback); + + return; + } + } + } + + callback(this); + } + + /// <summary> + /// Get result or throw an error. + /// </summary> + private T Get0() + { + if (_err != null) + throw _err; + + return _res; + } + + /** <inheritdoc/> */ + public IAsyncResult ToAsyncResult() + { + return _done ? CompletedAsyncResult.Instance : new AsyncResult(this); + } + + /** <inheritdoc/> */ + Task<object> IFuture.ToTask() + { + return Task.Factory.FromAsync(ToAsyncResult(), x => (object) Get()); + } + + /** <inheritdoc/> */ + public Task<T> ToTask() + { + return Task.Factory.FromAsync(ToAsyncResult(), x => Get()); + } + + /** <inheritdoc/> */ + object IFuture.Get(TimeSpan timeout) + { + return Get(timeout); + } + + /** <inheritdoc/> */ + object IFuture.Get() + { + return Get(); + } + + /** <inheritdoc /> */ + public void OnResult(IPortableStream stream) + { + try + { + OnResult(_converter.Convert(stream)); + } + catch (Exception ex) + { + OnError(ex); + } + } + + /** <inheritdoc /> */ + public void OnError(Exception err) + { + OnDone(default(T), err); + } + + /** <inheritdoc /> */ + public void OnNullResult() + { + OnResult(default(T)); + } + + /// <summary> + /// Set result. + /// </summary> + /// <param name="res">Result.</param> + internal void OnResult(T res) + { + OnDone(res, null); + } + + /// <summary> + /// Set future to Done state. + /// </summary> + /// <param name="res">Result.</param> + /// <param name="err">Error.</param> + public void OnDone(T res, Exception err) + { + object callbacks0 = null; + + lock (this) + { + if (!_done) + { + _res = res; + _err = err; + + _done = true; + + Monitor.PulseAll(this); + + // Notify listeners outside the lock + callbacks0 = _callbacks; + _callbacks = null; + } + } + + if (callbacks0 != null) + { + var list = callbacks0 as List<Action<IFuture<T>>>; + + if (list != null) + list.ForEach(x => x(this)); + else + ((Action<IFuture<T>>) callbacks0)(this); + } + } + + /// <summary> + /// Adds a callback. + /// </summary> + private void AddCallback(Action<IFuture<T>> callback) + { + if (_callbacks == null) + { + _callbacks = callback; + + return; + } + + var list = _callbacks as List<Action<IFuture<T>>> ?? + new List<Action<IFuture<T>>> {(Action<IFuture<T>>) _callbacks}; + + list.Add(callback); + + _callbacks = list; + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/FutureType.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/FutureType.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/FutureType.cs new file mode 100644 index 0000000..0beff04 --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/FutureType.cs @@ -0,0 +1,52 @@ +/* + * 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.Common +{ + /// <summary> + /// Future types. + /// </summary> + public enum FutureType + { + /** Future type: byte. */ + Byte = 1, + + /** Future type: boolean. */ + Bool = 2, + + /** Future type: short. */ + Short = 3, + + /** Future type: char. */ + Char = 4, + + /** Future type: int. */ + Int = 5, + + /** Future type: float. */ + Float = 6, + + /** Future type: long. */ + Long = 7, + + /** Future type: double. */ + Double = 8, + + /** Future type: object. */ + Object = 9 + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/GridArgumentCheck.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/GridArgumentCheck.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/GridArgumentCheck.cs new file mode 100644 index 0000000..a1fadfe --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/GridArgumentCheck.cs @@ -0,0 +1,76 @@ +/* + * 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.Common +{ + using System; + using System.Collections.Generic; + + /// <summary> + /// Arguments check helpers. + /// </summary> + public static class GridArgumentCheck + { + /// <summary> + /// Throws an ArgumentNullException if specified arg is null. + /// </summary> + /// <param name="arg">The argument.</param> + /// <param name="argName">Name of the argument.</param> + public static void NotNull(object arg, string argName) + { + if (arg == null) + throw new ArgumentNullException(argName); + } + + /// <summary> + /// Throws an ArgumentException if specified arg is null or empty string. + /// </summary> + /// <param name="arg">The argument.</param> + /// <param name="argName">Name of the argument.</param> + public static void NotNullOrEmpty(string arg, string argName) + { + if (string.IsNullOrEmpty(arg)) + throw new ArgumentException(string.Format("'{0}' argument should not be null or empty.", argName), + argName); + } + + /// <summary> + /// Throws an ArgumentException if specified arg is null or empty string. + /// </summary> + /// <param name="collection">The collection.</param> + /// <param name="argName">Name of the argument.</param> + public static void NotNullOrEmpty<T>(ICollection<T> collection, string argName) + { + if (collection == null || collection.Count == 0) + throw new ArgumentException(string.Format("'{0}' argument should not be null or empty.", argName), + argName); + } + + /// <summary> + /// Throws an ArgumentException if specified condition is false. + /// </summary> + /// <param name="condition">Condition.</param> + /// <param name="argName">Name of the argument.</param> + /// <param name="message">Message.</param> + public static void Ensure(bool condition, string argName, string message) + { + if (!condition) + throw new ArgumentException(string.Format("'{0}' argument is invalid: {1}", argName, message), + argName); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/IFutureConverter.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/IFutureConverter.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/IFutureConverter.cs new file mode 100644 index 0000000..4169c61 --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/IFutureConverter.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.Common +{ + using Apache.Ignite.Core.Impl.Portable.IO; + + /// <summary> + /// Marshals and converts future value. + /// </summary> + public interface IFutureConverter<out T> + { + /// <summary> + /// Reads and converts a value. + /// </summary> + T Convert(IPortableStream stream); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/IFutureInternal.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/IFutureInternal.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/IFutureInternal.cs new file mode 100644 index 0000000..8547545 --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/IFutureInternal.cs @@ -0,0 +1,45 @@ +/* + * 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.Common +{ + using System; + using Apache.Ignite.Core.Impl.Portable.IO; + + /// <summary> + /// Internal future interface. + /// </summary> + public interface IFutureInternal + { + /// <summary> + /// Set result from stream. + /// </summary> + /// <param name="stream">Stream.</param> + void OnResult(IPortableStream stream); + + /// <summary> + /// Set null result. + /// </summary> + void OnNullResult(); + + /// <summary> + /// Set error result. + /// </summary> + /// <param name="err">Exception.</param> + void OnError(Exception err); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/LoadedAssembliesResolver.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/LoadedAssembliesResolver.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/LoadedAssembliesResolver.cs new file mode 100644 index 0000000..c158d5c --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/LoadedAssembliesResolver.cs @@ -0,0 +1,96 @@ +/* + * 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.Common +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.Reflection; + + /// <summary> + /// Resolves loaded assemblies by name. + /// </summary> + public class LoadedAssembliesResolver + { + // The lazy singleton instance. + private static readonly Lazy<LoadedAssembliesResolver> LazyInstance = new Lazy<LoadedAssembliesResolver>(); + + // Assemblies map. + private volatile Dictionary<string, Assembly> _map; + + /// <summary> + /// Initializes a new instance of the <see cref="LoadedAssembliesResolver"/> class. + /// </summary> + public LoadedAssembliesResolver() + { + lock (this) + { + AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad; + + UpdateMap(); + } + } + + /// <summary> + /// Handles the AssemblyLoad event of the AppDomain. + /// </summary> + /// <param name="sender">The source of the event.</param> + /// <param name="args">The <see cref="AssemblyLoadEventArgs"/> instance containing the event data.</param> + private void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args) + { + lock (this) + { + UpdateMap(); + } + } + + /// <summary> + /// Updates the assembly map according to the current list of loaded assemblies. + /// </summary> + private void UpdateMap() + { + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + + _map = new Dictionary<string, Assembly>(assemblies.Length); + + foreach (var assembly in assemblies) + _map[assembly.FullName] = assembly; + } + + /// <summary> + /// Gets the singleton instance. + /// </summary> + public static LoadedAssembliesResolver Instance + { + get { return LazyInstance.Value; } + } + + /// <summary> + /// Gets the assembly by name. + /// </summary> + /// <param name="assemblyName">Name of the assembly.</param> + /// <returns>Assembly with specified name, or null.</returns> + [SuppressMessage("ReSharper", "InconsistentlySynchronizedField")] + public Assembly GetAssembly(string assemblyName) + { + Assembly asm; + + return _map.TryGetValue(assemblyName, out asm) ? asm : null; + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/TypeCaster.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/TypeCaster.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/TypeCaster.cs new file mode 100644 index 0000000..d0dd2a9 --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/TypeCaster.cs @@ -0,0 +1,72 @@ +/* + * 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.Common +{ + using System; + using System.Linq.Expressions; + + /// <summary> + /// Does type casts without extra boxing. + /// Should be used when casting compile-time incompatible value types instead of "(T)(object)x". + /// </summary> + /// <typeparam name="T">Target type</typeparam> + public static class TypeCaster<T> + { + /// <summary> + /// Efficiently casts an object from TFrom to T. + /// Does not cause boxing for value types. + /// </summary> + /// <typeparam name="TFrom">Source type to cast from.</typeparam> + /// <param name="obj">The object to cast.</param> + /// <returns>Casted object.</returns> + public static T Cast<TFrom>(TFrom obj) + { + return Casters<TFrom>.Caster(obj); + } + + /// <summary> + /// Inner class serving as a cache. + /// </summary> + private static class Casters<TFrom> + { + /// <summary> + /// Compiled caster delegate. + /// </summary> + internal static readonly Func<TFrom, T> Caster = Compile(); + + /// <summary> + /// Compiles caster delegate. + /// </summary> + private static Func<TFrom, T> Compile() + { + if (typeof (T) == typeof (TFrom)) + { + // Just return what we have + var pExpr = Expression.Parameter(typeof(TFrom)); + + return Expression.Lambda<Func<TFrom, T>>(pExpr, pExpr).Compile(); + } + + var paramExpr = Expression.Parameter(typeof(TFrom)); + var convertExpr = Expression.Convert(paramExpr, typeof(T)); + + return Expression.Lambda<Func<TFrom, T>>(convertExpr, paramExpr).Compile(); + } + } + } +} \ No newline at end of file