You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2015/08/28 14:49:35 UTC

[17/41] ignite git commit: IGNITE-1292: Moved handle registry to Ignite. Contributed by Pavel Tupitsyn.

IGNITE-1292: Moved handle registry to Ignite.
Contributed by Pavel Tupitsyn.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/7c351bf3
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/7c351bf3
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/7c351bf3

Branch: refs/heads/ignite-1093
Commit: 7c351bf3e0ef5fd28b88d9a279a32f4796a60c91
Parents: 08be80f
Author: vozerov-gridgain <vo...@gridgain.com>
Authored: Wed Aug 26 12:10:32 2015 +0300
Committer: vozerov-gridgain <vo...@gridgain.com>
Committed: Wed Aug 26 12:10:32 2015 +0300

----------------------------------------------------------------------
 .../Apache.Ignite.Core.csproj                   |   3 +
 .../Apache.Ignite.Core/Impl/Handle/Handle.cs    |  69 ++++
 .../Impl/Handle/HandleRegistry.cs               | 340 +++++++++++++++++++
 .../Apache.Ignite.Core/Impl/Handle/IHandle.cs   |  35 ++
 4 files changed, 447 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/7c351bf3/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 c6c8324..658e5fb 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
@@ -48,6 +48,9 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Ignition.cs" />
+    <Compile Include="Impl\Handle\Handle.cs" />
+    <Compile Include="Impl\Handle\HandleRegistry.cs" />
+    <Compile Include="Impl\Handle\IHandle.cs" />
     <Compile Include="Impl\Memory\IPlatformMemory.cs" />
     <Compile Include="Impl\Memory\PlatformBigEndianMemoryStream.cs" />
     <Compile Include="Impl\Memory\PlatformMemory.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c351bf3/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Handle/Handle.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Handle/Handle.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Handle/Handle.cs
new file mode 100644
index 0000000..0168963
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Handle/Handle.cs
@@ -0,0 +1,69 @@
+/*
+ * 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.Handle
+{
+    using System;
+    using System.Threading;
+
+    /// <summary>
+    /// Wrapper over some resource ensuring it's release.
+    /// </summary>
+    public class Handle<T> : IHandle
+    {
+        /** Target.*/
+        private readonly T _target;
+
+        /** Release action. */
+        private readonly Action<T> _releaseAction; 
+
+        /** Release flag. */
+        private int _released;
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="target">Target.</param>
+        /// <param name="releaseAction">Release action.</param>
+        public Handle(T target, Action<T> releaseAction)
+        {
+            _target = target;
+            _releaseAction = releaseAction;
+        }
+
+        /// <summary>
+        /// Target.
+        /// </summary>
+        public T Target
+        {
+            get { return _target; }
+        }
+
+        /** <inheritdoc /> */
+        public void Release()
+        {
+            if (Interlocked.CompareExchange(ref _released, 1, 0) == 0)
+                _releaseAction(_target);
+        }
+
+        /** <inheritdoc /> */
+        public bool Released
+        {
+            get { return Thread.VolatileRead(ref _released) == 1; }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c351bf3/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Handle/HandleRegistry.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Handle/HandleRegistry.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Handle/HandleRegistry.cs
new file mode 100644
index 0000000..2a67c41
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Handle/HandleRegistry.cs
@@ -0,0 +1,340 @@
+/*
+ * 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.Handle
+{
+    using System;
+    using System.Collections.Concurrent;
+    using System.Collections.Generic;
+    using System.Linq;
+    using System.Threading;
+
+    /// <summary>
+    /// Resource registry.
+    /// </summary>
+    public class HandleRegistry
+    {
+        /** Default critical resources capacity. */
+        internal const int DfltFastCap = 1024;
+
+        /** Array for fast-path. */
+        private readonly object[] _fast;
+
+        /** Dictionery for slow-path. */
+        private readonly ConcurrentDictionary<long, object> _slow;
+
+        /** Capacity of fast array. */
+        private readonly int _fastCap;
+
+        /** Counter for fast-path. */
+        private int _fastCtr;
+
+        /** Counter for slow-path. */
+        private long _slowCtr;
+
+        /** Close flag. */
+        private int _closed;
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        public HandleRegistry() : this(DfltFastCap)
+        {
+            // No-op.
+        }
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="fastCap">Amount of critical resources this registry can allocate in "fast" mode.</param>
+        public HandleRegistry(int fastCap)
+        {
+            _fastCap = fastCap;
+            _fast = new object[fastCap];
+
+            _slow = new ConcurrentDictionary<long, object>();
+            _slowCtr = fastCap;
+        }
+
+        /// <summary>
+        /// Allocate a handle for resource.
+        /// </summary>
+        /// <param name="target">Target.</param>
+        /// <returns>Pointer.</returns>
+        public long Allocate(object target)
+        {
+            return Allocate0(target, false, false);
+        }
+
+        /// <summary>
+        /// Allocate a handle in safe mode.
+        /// </summary>
+        /// <param name="target">Target.</param>
+        /// <returns>Pointer.</returns>
+        public long AllocateSafe(object target)
+        {
+            return Allocate0(target, false, true);
+        }
+
+        /// <summary>
+        /// Allocate a handle for critical resource.
+        /// </summary>
+        /// <param name="target">Target.</param>
+        /// <returns>Pointer.</returns>
+        public long AllocateCritical(object target)
+        {
+            return Allocate0(target, true, false);
+        }
+
+        /// <summary>
+        /// Allocate a handle for critical resource in safe mode.
+        /// </summary>
+        /// <param name="target">Target.</param>
+        /// <returns>Pointer.</returns>
+        public long AllocateCriticalSafe(object target)
+        {
+            return Allocate0(target, true, true);
+        }
+
+        /// <summary>
+        /// Internal allocation routine.
+        /// </summary>
+        /// <param name="target">Target.</param>
+        /// <param name="critical">Critical flag.</param>
+        /// <param name="safe">Safe flag.</param>
+        /// <returns>Pointer.</returns>
+        private long Allocate0(object target, bool critical, bool safe)
+        {
+            if (Closed)
+                throw ClosedException();
+
+            // Try allocating on critical path.
+            if (critical)
+            {
+                if (_fastCtr < _fastCap) // Non-volatile read could yield in old value, but increment resolves this.
+                {
+                    int fastIdx = Interlocked.Increment(ref _fastCtr);
+
+                    if (fastIdx < _fastCap)
+                    {
+                        Thread.VolatileWrite(ref _fast[fastIdx], target);
+
+                        if (safe && Closed)
+                        {
+                            Thread.VolatileWrite(ref _fast[fastIdx], null);
+
+                            Release0(target, true);
+
+                            throw ClosedException();
+                        }
+
+                        return fastIdx;
+                    }
+                }
+            }
+            
+            // Critical allocation failed, fallback to slow mode.
+            long slowIdx = Interlocked.Increment(ref _slowCtr);
+
+            _slow[slowIdx] = target;
+
+            if (safe && Closed)
+            {
+                _slow[slowIdx] = null;
+
+                Release0(target, true);
+
+                throw ClosedException();
+            }
+
+            return slowIdx;
+        }
+
+
+        /// <summary>
+        /// Release handle.
+        /// </summary>
+        /// <param name="id">Identifier.</param>
+        /// <param name="quiet">Whether release must be quiet or not.</param>
+        public void Release(long id, bool quiet = false)
+        {
+            if (id < _fastCap)
+            {
+                object target = Thread.VolatileRead(ref _fast[id]);
+
+                if (target != null)
+                {
+                    Thread.VolatileWrite(ref _fast[id], null);
+
+                    Release0(target, quiet);
+                }
+            }
+            else
+            {
+                object target;
+
+                if (_slow.TryRemove(id, out target))
+                    Release0(target, quiet);
+            }
+        }
+        
+        /// <summary>
+        /// Internal release routine.
+        /// </summary>
+        /// <param name="target">Target.</param>
+        /// <param name="quiet">Whether release must be quiet or not.</param>
+        private static void Release0(object target, bool quiet)
+        {
+            IHandle target0 = target as IHandle;
+
+            if (target0 != null)
+            {
+                if (quiet)
+                {
+                    try
+                    {
+                        target0.Release();
+                    }
+                    catch (Exception)
+                    {
+                        // No-op.
+                    }
+                }
+                else
+                    target0.Release();
+            }
+        }
+
+        /// <summary>
+        /// Gets handle target.
+        /// </summary>
+        /// <param name="id">Identifier.</param>
+        /// <returns>Target.</returns>
+        public T Get<T>(long id)
+        {
+            return Get<T>(id, false);
+        }
+
+        /// <summary>
+        /// Gets handle target.
+        /// </summary>
+        /// <param name="id">Identifier.</param>
+        /// <param name="throwOnAbsent">Whether to throw an exception if resource is not found.</param>
+        /// <returns>Target.</returns>
+        public T Get<T>(long id, bool throwOnAbsent)
+        {
+            object target;
+
+            if (id < _fastCap)
+            {
+                target = Thread.VolatileRead(ref _fast[id]);
+
+                if (target != null)
+                    return (T)target;
+            }
+            else
+            {
+                if (_slow.TryGetValue(id, out target))
+                    return (T) target;
+            }
+
+            if (throwOnAbsent)
+                throw new InvalidOperationException("Resource handle has been released (is grid stopping?).");
+
+            return default(T);
+        }
+
+        /// <summary>
+        /// Close the registry. All resources allocated at the moment of close are
+        /// guaranteed to be released.
+        /// </summary>
+        public void Close()
+        {
+            if (Interlocked.CompareExchange(ref _closed, 1, 0) == 0)
+            {
+                // Cleanup on fast-path.
+                for (int i = 0; i < _fastCap; i++)
+                {
+                    object target = Thread.VolatileRead(ref _fast[i]);
+
+                    if (target != null)
+                    {
+                        Thread.VolatileWrite(ref _fast[i], null);
+
+                        Release0(target, true);
+                    }
+                }
+
+                // Cleanup on slow-path.
+                foreach (var item in _slow)
+                {
+                    object target = item.Value;
+
+                    if (target != null)
+                        Release0(target, true);
+                }
+
+                _slow.Clear();
+            }
+        }
+
+        /// <summary>
+        /// Closed flag.
+        /// </summary>
+        public bool Closed
+        {
+            get { return Thread.VolatileRead(ref _closed) == 1; }
+        }
+
+        /// <summary>
+        /// Gets the current handle count.
+        /// </summary>
+        public int Count
+        {
+            get
+            {
+                Thread.MemoryBarrier();
+
+                return _fast.Count(x => x != null) + _slow.Count;
+            }
+        }
+
+        /// <summary>
+        /// Gets a snapshot of currently referenced objects list.
+        /// </summary>
+        public List<KeyValuePair<long, object>> GetItems()
+        {
+            Thread.MemoryBarrier();
+
+            return
+                _fast.Select((x, i) => new KeyValuePair<long, object>(i, x))
+                    .Where(x => x.Value != null)
+                    .Concat(_slow)
+                    .ToList();
+        }
+
+        /// <summary>
+        /// Create new exception for closed state.
+        /// </summary>
+        /// <returns>Exception.</returns>
+        private static Exception ClosedException()
+        {
+            return new InvalidOperationException("Cannot allocate a resource handle because grid is stopping.");
+        }
+    }
+}
+ 
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c351bf3/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Handle/IHandle.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Handle/IHandle.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Handle/IHandle.cs
new file mode 100644
index 0000000..d147f8b
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Handle/IHandle.cs
@@ -0,0 +1,35 @@
+/*
+ * 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.Handle
+{
+    /// <summary>
+    /// Wrapper over some resource ensuring it's release.
+    /// </summary>
+    public interface IHandle
+    {
+        /// <summary>
+        /// Release the resource.
+        /// </summary>
+        void Release();
+
+        /// <summary>
+        /// Resource released flag.
+        /// </summary>
+        bool Released { get; }
+    }
+}
\ No newline at end of file