http://git-wip-us.apache.org/repos/asf/ignite/blob/5cec202c/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Ignite.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Ignite.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Ignite.cs new file mode 100644 index 0000000..7e33416 --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Ignite.cs @@ -0,0 +1,547 @@ +/* + * 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 +{ + using System; + using System.Collections.Concurrent; + using System.Collections.Generic; + using System.Diagnostics; + using Apache.Ignite.Core.Cache; + using Apache.Ignite.Core.Cluster; + using Apache.Ignite.Core.Compute; + using Apache.Ignite.Core.Datastream; + using Apache.Ignite.Core.Events; + using Apache.Ignite.Core.Impl.Cache; + using Apache.Ignite.Core.Impl.Cluster; + using Apache.Ignite.Core.Impl.Common; + using Apache.Ignite.Core.Impl.Datastream; + using Apache.Ignite.Core.Impl.Handle; + using Apache.Ignite.Core.Impl.Portable; + using Apache.Ignite.Core.Impl.Transactions; + using Apache.Ignite.Core.Impl.Unmanaged; + using Apache.Ignite.Core.Lifecycle; + using Apache.Ignite.Core.Messaging; + using Apache.Ignite.Core.Portable; + using Apache.Ignite.Core.Services; + using Apache.Ignite.Core.Transactions; + using UU = Apache.Ignite.Core.Impl.Unmanaged.UnmanagedUtils; + + /// <summary> + /// Native Ignite wrapper. + /// </summary> + internal class Ignite : IIgnite, IClusterGroupEx, ICluster + { + /** */ + private readonly IgniteConfiguration _cfg; + + /** Grid name. */ + private readonly string _name; + + /** Unmanaged node. */ + private readonly IUnmanagedTarget _proc; + + /** Marshaller. */ + private readonly PortableMarshaller _marsh; + + /** Initial projection. */ + private readonly ClusterGroupImpl _prj; + + /** Portables. */ + private readonly PortablesImpl _portables; + + /** Cached proxy. */ + private readonly IgniteProxy _proxy; + + /** Lifecycle beans. */ + private readonly IList<LifecycleBeanHolder> _lifecycleBeans; + + /** Local node. */ + private IClusterNode _locNode; + + /** Transactions facade. */ + private readonly TransactionsImpl _transactions; + + /** Callbacks */ + private readonly UnmanagedCallbacks _cbs; + + /** Node info cache. */ + + private readonly ConcurrentDictionary<Guid, ClusterNodeImpl> _nodes = + new ConcurrentDictionary<Guid, ClusterNodeImpl>(); + + /// <summary> + /// Constructor. + /// </summary> + /// <param name="cfg">Configuration.</param> + /// <param name="name">Grid name.</param> + /// <param name="proc">Interop processor.</param> + /// <param name="marsh">Marshaller.</param> + /// <param name="lifecycleBeans">Lifecycle beans.</param> + /// <param name="cbs">Callbacks.</param> + public Ignite(IgniteConfiguration cfg, string name, IUnmanagedTarget proc, PortableMarshaller marsh, + IList<LifecycleBeanHolder> lifecycleBeans, UnmanagedCallbacks cbs) + { + Debug.Assert(cfg != null); + Debug.Assert(proc != null); + Debug.Assert(marsh != null); + Debug.Assert(lifecycleBeans != null); + Debug.Assert(cbs != null); + + _cfg = cfg; + _name = name; + _proc = proc; + _marsh = marsh; + _lifecycleBeans = lifecycleBeans; + _cbs = cbs; + + marsh.Ignite = this; + + _prj = new ClusterGroupImpl(proc, UU.ProcessorProjection(proc), marsh, this, null); + + _portables = new PortablesImpl(marsh); + + _proxy = new IgniteProxy(this); + + cbs.Initialize(this); + + _transactions = new TransactionsImpl(UU.ProcessorTransactions(proc), marsh, LocalNode.Id); + } + + /// <summary> + /// On-start routine. + /// </summary> + internal void OnStart() + { + foreach (var lifecycleBean in _lifecycleBeans) + lifecycleBean.OnStart(this); + } + + /// <summary> + /// Gets Ignite proxy. + /// </summary> + /// <returns>Proxy.</returns> + public IgniteProxy Proxy + { + get { return _proxy; } + } + + /** <inheritdoc /> */ + public string Name + { + get { return _name; } + } + + /** <inheritdoc /> */ + public ICluster Cluster + { + get { return this; } + } + + /** <inheritdoc /> */ + IIgnite IClusterGroup.Ignite + { + get { return this; } + } + + /** <inheritdoc /> */ + public IClusterGroup ForLocal() + { + return _prj.ForNodes(LocalNode); + } + + /** <inheritdoc /> */ + public ICompute Compute() + { + return _prj.Compute(); + } + + /** <inheritdoc /> */ + public ICompute Compute(IClusterGroup clusterGroup) + { + IgniteArgumentCheck.NotNull(clusterGroup, "clusterGroup"); + + return clusterGroup.Compute(); + } + + /** <inheritdoc /> */ + public IClusterGroup ForNodes(IEnumerable<IClusterNode> nodes) + { + return ((IClusterGroup) _prj).ForNodes(nodes); + } + + /** <inheritdoc /> */ + public IClusterGroup ForNodes(params IClusterNode[] nodes) + { + return _prj.ForNodes(nodes); + } + + /** <inheritdoc /> */ + public IClusterGroup ForNodeIds(IEnumerable<Guid> ids) + { + return ((IClusterGroup) _prj).ForNodeIds(ids); + } + + /** <inheritdoc /> */ + public IClusterGroup ForNodeIds(ICollection<Guid> ids) + { + return _prj.ForNodeIds(ids); + } + + /** <inheritdoc /> */ + public IClusterGroup ForNodeIds(params Guid[] ids) + { + return _prj.ForNodeIds(ids); + } + + /** <inheritdoc /> */ + public IClusterGroup ForPredicate(Func<IClusterNode, bool> p) + { + IgniteArgumentCheck.NotNull(p, "p"); + + return _prj.ForPredicate(p); + } + + /** <inheritdoc /> */ + public IClusterGroup ForAttribute(string name, string val) + { + return _prj.ForAttribute(name, val); + } + + /** <inheritdoc /> */ + public IClusterGroup ForCacheNodes(string name) + { + return _prj.ForCacheNodes(name); + } + + /** <inheritdoc /> */ + public IClusterGroup ForDataNodes(string name) + { + return _prj.ForDataNodes(name); + } + + /** <inheritdoc /> */ + public IClusterGroup ForClientNodes(string name) + { + return _prj.ForClientNodes(name); + } + + /** <inheritdoc /> */ + public IClusterGroup ForRemotes() + { + return _prj.ForRemotes(); + } + + /** <inheritdoc /> */ + public IClusterGroup ForHost(IClusterNode node) + { + IgniteArgumentCheck.NotNull(node, "node"); + + return _prj.ForHost(node); + } + + /** <inheritdoc /> */ + public IClusterGroup ForRandom() + { + return _prj.ForRandom(); + } + + /** <inheritdoc /> */ + public IClusterGroup ForOldest() + { + return _prj.ForOldest(); + } + + /** <inheritdoc /> */ + public IClusterGroup ForYoungest() + { + return _prj.ForYoungest(); + } + + /** <inheritdoc /> */ + public IClusterGroup ForDotNet() + { + return _prj.ForDotNet(); + } + + /** <inheritdoc /> */ + public ICollection<IClusterNode> Nodes() + { + return _prj.Nodes(); + } + + /** <inheritdoc /> */ + public IClusterNode Node(Guid id) + { + return _prj.Node(id); + } + + /** <inheritdoc /> */ + public IClusterNode Node() + { + return _prj.Node(); + } + + /** <inheritdoc /> */ + public IClusterMetrics Metrics() + { + return _prj.Metrics(); + } + + /** <inheritdoc /> */ + public void Dispose() + { + Ignition.Stop(Name, true); + } + + /// <summary> + /// Internal stop routine. + /// </summary> + /// <param name="cancel">Cancel flag.</param> + internal unsafe void Stop(bool cancel) + { + UU.IgnitionStop(_proc.Context, Name, cancel); + + _cbs.Cleanup(); + + foreach (var bean in _lifecycleBeans) + bean.OnLifecycleEvent(LifecycleEventType.AfterNodeStop); + } + + /** <inheritdoc /> */ + public ICache<TK, TV> Cache<TK, TV>(string name) + { + return Cache<TK, TV>(UU.ProcessorCache(_proc, name)); + } + + /** <inheritdoc /> */ + public ICache<TK, TV> GetOrCreateCache<TK, TV>(string name) + { + return Cache<TK, TV>(UU.ProcessorGetOrCreateCache(_proc, name)); + } + + /** <inheritdoc /> */ + public ICache<TK, TV> CreateCache<TK, TV>(string name) + { + return Cache<TK, TV>(UU.ProcessorCreateCache(_proc, name)); + } + + /// <summary> + /// Gets cache from specified native cache object. + /// </summary> + /// <param name="nativeCache">Native cache.</param> + /// <param name="keepPortable">Portable flag.</param> + /// <returns> + /// New instance of cache wrapping specified native cache. + /// </returns> + public ICache<TK, TV> Cache<TK, TV>(IUnmanagedTarget nativeCache, bool keepPortable = false) + { + var cacheImpl = new CacheImpl<TK, TV>(this, nativeCache, _marsh, false, keepPortable, false, false); + + return new CacheProxyImpl<TK, TV>(cacheImpl); + } + + /** <inheritdoc /> */ + public IClusterNode LocalNode + { + get + { + if (_locNode == null) + { + foreach (IClusterNode node in Nodes()) + { + if (node.IsLocal) + { + _locNode = node; + + break; + } + } + } + + return _locNode; + } + } + + /** <inheritdoc /> */ + public bool PingNode(Guid nodeId) + { + return _prj.PingNode(nodeId); + } + + /** <inheritdoc /> */ + public long TopologyVersion + { + get { return _prj.TopologyVersion; } + } + + /** <inheritdoc /> */ + public ICollection<IClusterNode> Topology(long ver) + { + return _prj.Topology(ver); + } + + /** <inheritdoc /> */ + public void ResetMetrics() + { + UU.ProjectionResetMetrics(_prj.Target); + } + + /** <inheritdoc /> */ + public IDataStreamer<TK, TV> DataStreamer<TK, TV>(string cacheName) + { + return new DataStreamerImpl<TK, TV>(UU.ProcessorDataStreamer(_proc, cacheName, false), + _marsh, cacheName, false); + } + + /** <inheritdoc /> */ + public IPortables Portables() + { + return _portables; + } + + /** <inheritdoc /> */ + public ICacheAffinity Affinity(string cacheName) + { + return new CacheAffinityImpl(UU.ProcessorAffinity(_proc, cacheName), _marsh, false, this); + } + + /** <inheritdoc /> */ + public ITransactions Transactions + { + get { return _transactions; } + } + + /** <inheritdoc /> */ + public IMessaging Message() + { + return _prj.Message(); + } + + /** <inheritdoc /> */ + public IMessaging Message(IClusterGroup clusterGroup) + { + IgniteArgumentCheck.NotNull(clusterGroup, "clusterGroup"); + + return clusterGroup.Message(); + } + + /** <inheritdoc /> */ + public IEvents Events() + { + return _prj.Events(); + } + + /** <inheritdoc /> */ + public IEvents Events(IClusterGroup clusterGroup) + { + if (clusterGroup == null) + throw new ArgumentNullException("clusterGroup"); + + return clusterGroup.Events(); + } + + /** <inheritdoc /> */ + public IServices Services() + { + return _prj.Services(); + } + + /// <summary> + /// Gets internal projection. + /// </summary> + /// <returns>Projection.</returns> + internal ClusterGroupImpl ClusterGroup + { + get { return _prj; } + } + + /// <summary> + /// Marshaller. + /// </summary> + internal PortableMarshaller Marshaller + { + get { return _marsh; } + } + + /// <summary> + /// Configuration. + /// </summary> + internal IgniteConfiguration Configuration + { + get { return _cfg; } + } + + /// <summary> + /// Put metadata to Grid. + /// </summary> + /// <param name="metas">Metadata.</param> + internal void PutMetadata(IDictionary<int, IPortableMetadata> metas) + { + _prj.PutMetadata(metas); + } + + /** <inheritDoc /> */ + public IPortableMetadata Metadata(int typeId) + { + return _prj.Metadata(typeId); + } + + /// <summary> + /// Handle registry. + /// </summary> + public HandleRegistry HandleRegistry + { + get { return _cbs.HandleRegistry; } + } + + /// <summary> + /// Updates the node information from stream. + /// </summary> + /// <param name="memPtr">Stream ptr.</param> + public void UpdateNodeInfo(long memPtr) + { + var stream = IgniteManager.Memory.Get(memPtr).Stream(); + + IPortableRawReader reader = Marshaller.StartUnmarshal(stream, false); + + var node = new ClusterNodeImpl(reader); + + node.Init(this); + + _nodes[node.Id] = node; + } + + /// <summary> + /// Gets the node from cache. + /// </summary> + /// <param name="id">Node id.</param> + /// <returns>Cached node.</returns> + public ClusterNodeImpl GetNode(Guid? id) + { + return id == null ? null : _nodes[id.Value]; + } + + /// <summary> + /// Gets the interop processor. + /// </summary> + internal IUnmanagedTarget InteropProcessor + { + get { return _proc; } + } + } +}
http://git-wip-us.apache.org/repos/asf/ignite/blob/5cec202c/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/IgniteConfigurationEx.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/IgniteConfigurationEx.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/IgniteConfigurationEx.cs new file mode 100644 index 0000000..358e805 --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/IgniteConfigurationEx.cs @@ -0,0 +1,57 @@ +/* + * 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 +{ + /// <summary> + /// Internal extensions for IgniteConfiguration. + /// </summary> + internal class IgniteConfigurationEx : IgniteConfiguration + { + /// <summary> + /// Default constructor. + /// </summary> + public IgniteConfigurationEx() + { + // No-op. + } + + /// <summary> + /// Copying constructor. + /// </summary> + /// <param name="cfg">Configuration.</param> + public IgniteConfigurationEx(IgniteConfiguration cfg) : base(cfg) + { + // No-op. + } + + /// <summary> + /// Copying constructor. + /// </summary> + /// <param name="cfg">Configuration.</param> + public IgniteConfigurationEx(IgniteConfigurationEx cfg) + : this((IgniteConfiguration) cfg) + { + GridName = cfg.GridName; + } + + /// <summary> + /// Grid name which is used if not provided in configuration file. + /// </summary> + public string GridName { get; set; } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5cec202c/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/IgniteManager.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/IgniteManager.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/IgniteManager.cs new file mode 100644 index 0000000..6203b3c --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/IgniteManager.cs @@ -0,0 +1,492 @@ +/* + * 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 +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.IO; + using System.Linq; + using System.Reflection; + using System.Runtime.InteropServices; + using System.Text; + using Apache.Ignite.Core.Common; + using Apache.Ignite.Core.Impl.Memory; + using Apache.Ignite.Core.Impl.Unmanaged; + using UU = Apache.Ignite.Core.Impl.Unmanaged.UnmanagedUtils; + + /// <summary> + /// Native interface manager. + /// </summary> + internal static unsafe class IgniteManager + { + /** Environment variable: IGNITE_HOME. */ + internal const string EnvIgniteHome = "IGNITE_HOME"; + + /** Environment variable: whether to set test classpath or not. */ + private const string EnvIgniteNativeTestClasspath = "IGNITE_NATIVE_TEST_CLASSPATH"; + + /** Classpath prefix. */ + private const string ClasspathPrefix = "-Djava.class.path="; + + /** Java Command line argument: Xms. Case sensitive. */ + private const string CmdJvmMinMemJava = "-Xms"; + + /** Java Command line argument: Xmx. Case sensitive. */ + private const string CmdJvmMaxMemJava = "-Xmx"; + + /** Monitor for DLL load synchronization. */ + private static readonly object SyncRoot = new object(); + + /** First created context. */ + private static void* _ctx; + + /** Configuration used on JVM start. */ + private static JvmConfiguration _jvmCfg; + + /** Memory manager. */ + private static PlatformMemoryManager _mem; + + /// <summary> + /// Static initializer. + /// </summary> + static IgniteManager() + { + // No-op. + } + + /// <summary> + /// Create JVM. + /// </summary> + /// <param name="cfg">Configuration.</param> + /// <param name="cbs">Callbacks.</param> + /// <returns>Context.</returns> + internal static void* GetContext(IgniteConfiguration cfg, UnmanagedCallbacks cbs) + { + lock (SyncRoot) + { + // 1. Warn about possible configuration inconsistency. + JvmConfiguration jvmCfg = JvmConfig(cfg); + + if (!cfg.SuppressWarnings && _jvmCfg != null) + { + if (!_jvmCfg.Equals(jvmCfg)) + { + Console.WriteLine("Attempting to start Ignite node with different Java " + + "configuration; current Java configuration will be ignored (consider " + + "starting node in separate process) [oldConfig=" + _jvmCfg + + ", newConfig=" + jvmCfg + ']'); + } + } + + // 2. Create unmanaged pointer. + void* ctx = CreateJvm(cfg, cbs); + + cbs.SetContext(ctx); + + // 3. If this is the first JVM created, preserve it. + if (_ctx == null) + { + _ctx = ctx; + _jvmCfg = jvmCfg; + _mem = new PlatformMemoryManager(1024); + } + + return ctx; + } + } + + /// <summary> + /// Memory manager attached to currently running JVM. + /// </summary> + internal static PlatformMemoryManager Memory + { + get { return _mem; } + } + + /// <summary> + /// Destroy JVM. + /// </summary> + public static void DestroyJvm() + { + lock (SyncRoot) + { + if (_ctx != null) + { + UU.DestroyJvm(_ctx); + + _ctx = null; + } + } + } + + /// <summary> + /// Create JVM. + /// </summary> + /// <returns>JVM.</returns> + private static void* CreateJvm(IgniteConfiguration cfg, UnmanagedCallbacks cbs) + { + var ggHome = GetIgniteHome(cfg); + + var cp = CreateClasspath(ggHome, cfg, false); + + var jvmOpts = GetMergedJvmOptions(cfg); + + var hasGgHome = !string.IsNullOrWhiteSpace(ggHome); + + var opts = new sbyte*[1 + jvmOpts.Count + (hasGgHome ? 1 : 0)]; + + int idx = 0; + + opts[idx++] = IgniteUtils.StringToUtf8Unmanaged(cp); + + if (hasGgHome) + opts[idx++] = IgniteUtils.StringToUtf8Unmanaged("-DIGNITE_HOME=" + ggHome); + + foreach (string cfgOpt in jvmOpts) + opts[idx++] = IgniteUtils.StringToUtf8Unmanaged(cfgOpt); + + try + { + IntPtr mem = Marshal.AllocHGlobal(opts.Length * 8); + + fixed (sbyte** opts0 = opts) + { + PlatformMemoryUtils.CopyMemory(opts0, mem.ToPointer(), opts.Length * 8); + } + + try + { + return UU.CreateContext(mem.ToPointer(), opts.Length, cbs.CallbacksPointer); + } + finally + { + Marshal.FreeHGlobal(mem); + } + } + finally + { + foreach (sbyte* opt in opts) + Marshal.FreeHGlobal((IntPtr)opt); + } + } + + /// <summary> + /// Gets JvmOptions collection merged with individual properties (Min/Max mem, etc) according to priority. + /// </summary> + private static IList<string> GetMergedJvmOptions(IgniteConfiguration cfg) + { + var jvmOpts = cfg.JvmOptions == null ? new List<string>() : cfg.JvmOptions.ToList(); + + // JvmInitialMemoryMB / JvmMaxMemoryMB have lower priority than CMD_JVM_OPT + if (!jvmOpts.Any(opt => opt.StartsWith(CmdJvmMinMemJava, StringComparison.OrdinalIgnoreCase))) + jvmOpts.Add(string.Format("{0}{1}m", CmdJvmMinMemJava, cfg.JvmInitialMemoryMb)); + + if (!jvmOpts.Any(opt => opt.StartsWith(CmdJvmMaxMemJava, StringComparison.OrdinalIgnoreCase))) + jvmOpts.Add(string.Format("{0}{1}m", CmdJvmMaxMemJava, cfg.JvmMaxMemoryMb)); + + return jvmOpts; + } + + /// <summary> + /// Create JVM configuration value object. + /// </summary> + /// <param name="cfg">Configuration.</param> + /// <returns>JVM configuration.</returns> + private static JvmConfiguration JvmConfig(IgniteConfiguration cfg) + { + return new JvmConfiguration + { + Home = cfg.IgniteHome, + Dll = cfg.JvmDllPath, + Classpath = cfg.JvmClasspath, + Options = cfg.JvmOptions + }; + } + + /// <summary> + /// Append jars from the given path. + /// </summary> + /// <param name="path">Path.</param> + /// <param name="cpStr">Classpath string builder.</param> + private static void AppendJars(string path, StringBuilder cpStr) + { + if (Directory.Exists(path)) + { + foreach (string jar in Directory.EnumerateFiles(path, "*.jar")) + { + cpStr.Append(jar); + cpStr.Append(';'); + } + } + } + + /// <summary> + /// Calculate Ignite home. + /// </summary> + /// <param name="cfg">Configuration.</param> + /// <returns></returns> + internal static string GetIgniteHome(IgniteConfiguration cfg) + { + var home = cfg == null ? null : cfg.IgniteHome; + + if (string.IsNullOrWhiteSpace(home)) + home = Environment.GetEnvironmentVariable(EnvIgniteHome); + else if (!IsIgniteHome(new DirectoryInfo(home))) + throw new IgniteException(string.Format("IgniteConfiguration.IgniteHome is not valid: '{0}'", home)); + + if (string.IsNullOrWhiteSpace(home)) + home = ResolveIgniteHome(); + else if (!IsIgniteHome(new DirectoryInfo(home))) + throw new IgniteException(string.Format("{0} is not valid: '{1}'", EnvIgniteHome, home)); + + return home; + } + + /// <summary> + /// Automatically resolve Ignite home directory. + /// </summary> + /// <returns>Ignite home directory.</returns> + private static string ResolveIgniteHome() + { + var probeDirs = new[] + { + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + Directory.GetCurrentDirectory() + }; + + foreach (var probeDir in probeDirs.Where(x => !string.IsNullOrEmpty(x))) + { + var dir = new DirectoryInfo(probeDir); + + while (dir != null) + { + if (IsIgniteHome(dir)) + return dir.FullName; + + dir = dir.Parent; + } + } + + return null; + } + + /// <summary> + /// Determines whether specified dir looks like a Ignite home. + /// </summary> + /// <param name="dir">Directory.</param> + /// <returns>Value indicating whether specified dir looks like a Ignite home.</returns> + private static bool IsIgniteHome(DirectoryInfo dir) + { + return dir.Exists && dir.EnumerateDirectories().Count(x => x.Name == "examples" || x.Name == "bin") == 2; + } + + /// <summary> + /// Creates classpath from the given configuration, or default classpath if given config is null. + /// </summary> + /// <param name="cfg">The configuration.</param> + /// <param name="forceTestClasspath">Append test directories even if <see cref="EnvIgniteNativeTestClasspath" /> is not set.</param> + /// <returns> + /// Classpath string. + /// </returns> + internal static string CreateClasspath(IgniteConfiguration cfg = null, bool forceTestClasspath = false) + { + return CreateClasspath(GetIgniteHome(cfg), cfg, forceTestClasspath); + } + + /// <summary> + /// Creates classpath from the given configuration, or default classpath if given config is null. + /// </summary> + /// <param name="ggHome">The home dir.</param> + /// <param name="cfg">The configuration.</param> + /// <param name="forceTestClasspath">Append test directories even if + /// <see cref="EnvIgniteNativeTestClasspath" /> is not set.</param> + /// <returns> + /// Classpath string. + /// </returns> + private static string CreateClasspath(string ggHome, IgniteConfiguration cfg, bool forceTestClasspath) + { + var cpStr = new StringBuilder(); + + if (cfg != null && cfg.JvmClasspath != null) + { + cpStr.Append(cfg.JvmClasspath); + + if (!cfg.JvmClasspath.EndsWith(";")) + cpStr.Append(';'); + } + + if (!string.IsNullOrWhiteSpace(ggHome)) + AppendHomeClasspath(ggHome, forceTestClasspath, cpStr); + + return ClasspathPrefix + cpStr; + } + + /// <summary> + /// Appends classpath from home directory, if it is defined. + /// </summary> + /// <param name="ggHome">The home dir.</param> + /// <param name="forceTestClasspath">Append test directories even if + /// <see cref="EnvIgniteNativeTestClasspath"/> is not set.</param> + /// <param name="cpStr">The classpath string.</param> + private static void AppendHomeClasspath(string ggHome, bool forceTestClasspath, StringBuilder cpStr) + { + // Append test directories (if needed) first, because otherwise build *.jar will be picked first. + if (forceTestClasspath || "true".Equals(Environment.GetEnvironmentVariable(EnvIgniteNativeTestClasspath))) + { + AppendTestClasses(ggHome + "\\examples", cpStr); + AppendTestClasses(ggHome + "\\modules", cpStr); + AppendTestClasses(ggHome + "\\..\\incubator-ignite\\examples", cpStr); + AppendTestClasses(ggHome + "\\..\\incubator-ignite\\modules", cpStr); + } + + string ggLibs = ggHome + "\\libs"; + + AppendJars(ggLibs, cpStr); + + if (Directory.Exists(ggLibs)) + { + foreach (string dir in Directory.EnumerateDirectories(ggLibs)) + { + if (!dir.EndsWith("optional")) + AppendJars(dir, cpStr); + } + } + } + + /// <summary> + /// Append target (compile) directories to classpath (for testing purposes only). + /// </summary> + /// <param name="path">Path</param> + /// <param name="cp">Classpath builder.</param> + private static void AppendTestClasses(string path, StringBuilder cp) + { + if (Directory.Exists(path)) + { + AppendTestClasses0(path, cp); + + foreach (string moduleDir in Directory.EnumerateDirectories(path)) + AppendTestClasses0(moduleDir, cp); + } + } + + /// <summary> + /// Internal routine to append classes and jars from eploded directory. + /// </summary> + /// <param name="path">Path.</param> + /// <param name="cp">Classpath builder.</param> + private static void AppendTestClasses0(string path, StringBuilder cp) + { + if (path.EndsWith("rest-http", StringComparison.OrdinalIgnoreCase)) + return; + + if (Directory.Exists(path + "\\target\\classes")) + cp.Append(path + "\\target\\classes;"); + + if (Directory.Exists(path + "\\target\\test-classes")) + cp.Append(path + "\\target\\test-classes;"); + + if (Directory.Exists(path + "\\target\\libs")) + AppendJars(path + "\\target\\libs", cp); + } + + /// <summary> + /// JVM configuration. + /// </summary> + private class JvmConfiguration + { + /// <summary> + /// Gets or sets the home. + /// </summary> + public string Home { get; set; } + + /// <summary> + /// Gets or sets the DLL. + /// </summary> + public string Dll { get; set; } + + /// <summary> + /// Gets or sets the cp. + /// </summary> + public string Classpath { get; set; } + + /// <summary> + /// Gets or sets the options. + /// </summary> + public ICollection<string> Options { get; set; } + + /** <inheritDoc /> */ + public override int GetHashCode() + { + return 0; + } + + /** <inheritDoc /> */ + [SuppressMessage("ReSharper", "FunctionComplexityOverflow")] + public override bool Equals(object obj) + { + JvmConfiguration other = obj as JvmConfiguration; + + if (other == null) + return false; + + if (!string.Equals(Home, other.Home, StringComparison.OrdinalIgnoreCase)) + return false; + + if (!string.Equals(Classpath, other.Classpath, StringComparison.OrdinalIgnoreCase)) + return false; + + if (!string.Equals(Dll, other.Dll, StringComparison.OrdinalIgnoreCase)) + return false; + + return (Options == null && other.Options == null) || + (Options != null && other.Options != null && Options.Count == other.Options.Count + && !Options.Except(other.Options).Any()); + } + + /** <inheritDoc /> */ + public override string ToString() + { + var sb = new StringBuilder("[IgniteHome=" + Home + ", JvmDllPath=" + Dll); + + if (Options != null && Options.Count > 0) + { + sb.Append(", JvmOptions=["); + + bool first = true; + + foreach (string opt in Options) + { + if (first) + first = false; + else + sb.Append(", "); + + sb.Append(opt); + } + + sb.Append(']'); + } + + sb.Append(", Classpath=" + Classpath + ']'); + + return sb.ToString(); + } + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5cec202c/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs new file mode 100644 index 0000000..f180830 --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs @@ -0,0 +1,351 @@ +/* + * 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 +{ + using System; + using System.Collections.Generic; + using Apache.Ignite.Core.Cache; + using Apache.Ignite.Core.Cluster; + using Apache.Ignite.Core.Compute; + using Apache.Ignite.Core.Datastream; + using Apache.Ignite.Core.Events; + using Apache.Ignite.Core.Impl.Cluster; + using Apache.Ignite.Core.Impl.Portable; + using Apache.Ignite.Core.Messaging; + using Apache.Ignite.Core.Portable; + using Apache.Ignite.Core.Services; + using Apache.Ignite.Core.Transactions; + + /// <summary> + /// Grid proxy with fake serialization. + /// </summary> + [Serializable] + internal class IgniteProxy : IIgnite, IClusterGroupEx, IPortableWriteAware, ICluster + { + /** */ + [NonSerialized] + private readonly IIgnite _ignite; + + /// <summary> + /// Default ctor for marshalling. + /// </summary> + public IgniteProxy() + { + // No-op. + } + + /// <summary> + /// Constructor. + /// </summary> + /// <param name="ignite">Grid.</param> + public IgniteProxy(IIgnite ignite) + { + _ignite = ignite; + } + + /** <inheritdoc /> */ + public string Name + { + get { return _ignite.Name; } + } + + /** <inheritdoc /> */ + public ICluster Cluster + { + get { return this; } + } + + /** <inheritdoc /> */ + public IIgnite Ignite + { + get { return this; } + } + + /** <inheritdoc /> */ + public IClusterGroup ForLocal() + { + return _ignite.Cluster.ForLocal(); + } + + /** <inheritdoc /> */ + public ICompute Compute() + { + return _ignite.Compute(); + } + + /** <inheritdoc /> */ + public ICompute Compute(IClusterGroup clusterGroup) + { + return clusterGroup.Compute(); + } + + /** <inheritdoc /> */ + public IClusterGroup ForNodes(IEnumerable<IClusterNode> nodes) + { + return _ignite.Cluster.ForNodes(nodes); + } + + /** <inheritdoc /> */ + public IClusterGroup ForNodes(params IClusterNode[] nodes) + { + return _ignite.Cluster.ForNodes(nodes); + } + + /** <inheritdoc /> */ + public IClusterGroup ForNodeIds(IEnumerable<Guid> ids) + { + return _ignite.Cluster.ForNodeIds(ids); + } + + /** <inheritdoc /> */ + public IClusterGroup ForNodeIds(ICollection<Guid> ids) + { + return _ignite.Cluster.ForNodeIds(ids); + } + + /** <inheritdoc /> */ + public IClusterGroup ForNodeIds(params Guid[] ids) + { + return _ignite.Cluster.ForNodeIds(ids); + } + + /** <inheritdoc /> */ + public IClusterGroup ForPredicate(Func<IClusterNode, bool> p) + { + return _ignite.Cluster.ForPredicate(p); + } + + /** <inheritdoc /> */ + public IClusterGroup ForAttribute(string name, string val) + { + return _ignite.Cluster.ForAttribute(name, val); + } + + /** <inheritdoc /> */ + public IClusterGroup ForCacheNodes(string name) + { + return _ignite.Cluster.ForCacheNodes(name); + } + + /** <inheritdoc /> */ + public IClusterGroup ForDataNodes(string name) + { + return _ignite.Cluster.ForDataNodes(name); + } + + /** <inheritdoc /> */ + public IClusterGroup ForClientNodes(string name) + { + return _ignite.Cluster.ForClientNodes(name); + } + + /** <inheritdoc /> */ + public IClusterGroup ForRemotes() + { + return _ignite.Cluster.ForRemotes(); + } + + /** <inheritdoc /> */ + public IClusterGroup ForHost(IClusterNode node) + { + return _ignite.Cluster.ForHost(node); + } + + /** <inheritdoc /> */ + public IClusterGroup ForRandom() + { + return _ignite.Cluster.ForRandom(); + } + + /** <inheritdoc /> */ + public IClusterGroup ForOldest() + { + return _ignite.Cluster.ForOldest(); + } + + /** <inheritdoc /> */ + public IClusterGroup ForYoungest() + { + return _ignite.Cluster.ForYoungest(); + } + + /** <inheritdoc /> */ + public IClusterGroup ForDotNet() + { + return _ignite.Cluster.ForDotNet(); + } + + /** <inheritdoc /> */ + public ICollection<IClusterNode> Nodes() + { + return _ignite.Cluster.Nodes(); + } + + /** <inheritdoc /> */ + public IClusterNode Node(Guid id) + { + return _ignite.Cluster.Node(id); + } + + /** <inheritdoc /> */ + public IClusterNode Node() + { + return _ignite.Cluster.Node(); + } + + /** <inheritdoc /> */ + public IClusterMetrics Metrics() + { + return _ignite.Cluster.Metrics(); + } + + /** <inheritdoc /> */ + public void Dispose() + { + _ignite.Dispose(); + } + + /** <inheritdoc /> */ + public ICache<TK, TV> Cache<TK, TV>(string name) + { + return _ignite.Cache<TK, TV>(name); + } + + /** <inheritdoc /> */ + public ICache<TK, TV> GetOrCreateCache<TK, TV>(string name) + { + return _ignite.GetOrCreateCache<TK, TV>(name); + } + + /** <inheritdoc /> */ + public ICache<TK, TV> CreateCache<TK, TV>(string name) + { + return _ignite.CreateCache<TK, TV>(name); + } + + /** <inheritdoc /> */ + public IClusterNode LocalNode + { + get + { + return _ignite.Cluster.LocalNode; + } + } + + /** <inheritdoc /> */ + public bool PingNode(Guid nodeId) + { + return _ignite.Cluster.PingNode(nodeId); + } + + /** <inheritdoc /> */ + public long TopologyVersion + { + get { return _ignite.Cluster.TopologyVersion; } + } + + /** <inheritdoc /> */ + public ICollection<IClusterNode> Topology(long ver) + { + return _ignite.Cluster.Topology(ver); + } + + /** <inheritdoc /> */ + public void ResetMetrics() + { + _ignite.Cluster.ResetMetrics(); + } + + /** <inheritdoc /> */ + public IDataStreamer<TK, TV> DataStreamer<TK, TV>(string cacheName) + { + return _ignite.DataStreamer<TK, TV>(cacheName); + } + + /** <inheritdoc /> */ + public IPortables Portables() + { + return _ignite.Portables(); + } + + /** <inheritdoc /> */ + public ICacheAffinity Affinity(string name) + { + return _ignite.Affinity(name); + } + + /** <inheritdoc /> */ + public ITransactions Transactions + { + get { return _ignite.Transactions; } + } + + /** <inheritdoc /> */ + public IMessaging Message() + { + return _ignite.Message(); + } + + /** <inheritdoc /> */ + public IMessaging Message(IClusterGroup clusterGroup) + { + return _ignite.Message(clusterGroup); + } + + /** <inheritdoc /> */ + public IEvents Events() + { + return _ignite.Events(); + } + + /** <inheritdoc /> */ + public IEvents Events(IClusterGroup clusterGroup) + { + return _ignite.Events(clusterGroup); + } + + /** <inheritdoc /> */ + public IServices Services() + { + return _ignite.Services(); + } + + /** <inheritdoc /> */ + public void WritePortable(IPortableWriter writer) + { + // No-op. + } + + /// <summary> + /// Target grid. + /// </summary> + internal IIgnite Target + { + get + { + return _ignite; + } + } + + /** <inheritdoc /> */ + public IPortableMetadata Metadata(int typeId) + { + return ((IClusterGroupEx)_ignite).Metadata(typeId); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5cec202c/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/IgniteUtils.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/IgniteUtils.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/IgniteUtils.cs new file mode 100644 index 0000000..265fd0d --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/IgniteUtils.cs @@ -0,0 +1,438 @@ +/* + * 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 +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Reflection; + using System.Runtime.InteropServices; + using System.Text; + using Apache.Ignite.Core.Cluster; + using Apache.Ignite.Core.Common; + using Apache.Ignite.Core.Impl.Cluster; + using Apache.Ignite.Core.Impl.Common; + using Apache.Ignite.Core.Impl.Portable; + using Apache.Ignite.Core.Impl.Unmanaged; + using Apache.Ignite.Core.Portable; + + /// <summary> + /// Native utility methods. + /// </summary> + internal static class IgniteUtils + { + /** Environment variable: JAVA_HOME. */ + private const string EnvJavaHome = "JAVA_HOME"; + + /** Directory: jre. */ + private const string DirJre = "jre"; + + /** Directory: bin. */ + private const string DirBin = "bin"; + + /** Directory: server. */ + private const string DirServer = "server"; + + /** File: jvm.dll. */ + private const string FileJvmDll = "jvm.dll"; + + /** File: Ignite.Common.dll. */ + internal const string FileIgniteJniDll = "ignite.common.dll"; + + /** Prefix for temp directory names. */ + private const string DirIgniteTmp = "Ignite_"; + + /** Loaded. */ + private static bool _loaded; + + /** Thread-local random. */ + [ThreadStatic] + private static Random _rnd; + + /// <summary> + /// Initializes the <see cref="IgniteUtils"/> class. + /// </summary> + static IgniteUtils() + { + TryCleanTempDirectories(); + } + + /// <summary> + /// Gets thread local random. + /// </summary> + /// <returns>Thread local random.</returns> + public static Random ThreadLocalRandom() + { + if (_rnd == null) + _rnd = new Random(); + + return _rnd; + } + + /// <summary> + /// Returns shuffled list copy. + /// </summary> + /// <returns>Shuffled list copy.</returns> + public static IList<T> Shuffle<T>(IList<T> list) + { + int cnt = list.Count; + + if (cnt > 1) { + List<T> res = new List<T>(list); + + Random rnd = ThreadLocalRandom(); + + while (cnt > 1) + { + cnt--; + + int idx = rnd.Next(cnt + 1); + + T val = res[idx]; + res[idx] = res[cnt]; + res[cnt] = val; + } + + return res; + } + return list; + } + + /// <summary> + /// Load JVM DLL if needed. + /// </summary> + /// <param name="configJvmDllPath">JVM DLL path from config.</param> + public static void LoadDlls(string configJvmDllPath) + { + if (_loaded) return; + + // 1. Load JNI dll. + LoadJvmDll(configJvmDllPath); + + // 2. Load GG JNI dll. + UnmanagedUtils.Initialize(); + + _loaded = true; + } + + /// <summary> + /// Create new instance of specified class. + /// </summary> + /// <param name="assemblyName">Assembly name.</param> + /// <param name="clsName">Class name</param> + /// <returns>New Instance.</returns> + public static object CreateInstance(string assemblyName, string clsName) + { + IgniteArgumentCheck.NotNullOrEmpty(clsName, "clsName"); + + var type = new TypeResolver().ResolveType(clsName, assemblyName); + + if (type == null) + throw new IgniteException("Failed to create class instance [assemblyName=" + assemblyName + + ", className=" + clsName + ']'); + + return Activator.CreateInstance(type); + } + + /// <summary> + /// Set properties on the object. + /// </summary> + /// <param name="target">Target object.</param> + /// <param name="props">Properties.</param> + public static void SetProperties(object target, IEnumerable<KeyValuePair<string, object>> props) + { + if (props == null) + return; + + IgniteArgumentCheck.NotNull(target, "target"); + + Type typ = target.GetType(); + + foreach (KeyValuePair<string, object> prop in props) + { + PropertyInfo prop0 = typ.GetProperty(prop.Key, + BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + + if (prop0 == null) + throw new IgniteException("Property is not found [type=" + typ.Name + + ", property=" + prop.Key + ']'); + + prop0.SetValue(target, prop.Value, null); + } + } + + /// <summary> + /// Loads the JVM DLL. + /// </summary> + private static void LoadJvmDll(string configJvmDllPath) + { + var messages = new List<string>(); + foreach (var dllPath in GetJvmDllPaths(configJvmDllPath)) + { + var errCode = LoadDll(dllPath.Value, FileJvmDll); + if (errCode == 0) + return; + + messages.Add(string.Format("[option={0}, path={1}, errorCode={2}]", + dllPath.Key, dllPath.Value, errCode)); + + if (dllPath.Value == configJvmDllPath) + break; // if configJvmDllPath is specified and is invalid - do not try other options + } + + if (!messages.Any()) // not loaded and no messages - everything was null + messages.Add(string.Format("Please specify IgniteConfiguration.JvmDllPath or {0}.", EnvJavaHome)); + + if (messages.Count == 1) + throw new IgniteException(string.Format("Failed to load {0} ({1})", FileJvmDll, messages[0])); + + var combinedMessage = messages.Aggregate((x, y) => string.Format("{0}\n{1}", x, y)); + throw new IgniteException(string.Format("Failed to load {0}:\n{1}", FileJvmDll, combinedMessage)); + } + + /// <summary> + /// Try loading DLLs first using file path, then using it's simple name. + /// </summary> + /// <param name="filePath"></param> + /// <param name="simpleName"></param> + /// <returns>Zero in case of success, error code in case of failure.</returns> + private static int LoadDll(string filePath, string simpleName) + { + int res = 0; + + IntPtr ptr; + + if (filePath != null) + { + ptr = NativeMethods.LoadLibrary(filePath); + + if (ptr == IntPtr.Zero) + res = Marshal.GetLastWin32Error(); + else + return res; + } + + // Failed to load using file path, fallback to simple name. + ptr = NativeMethods.LoadLibrary(simpleName); + + if (ptr == IntPtr.Zero) + { + // Preserve the first error code, if any. + if (res == 0) + res = Marshal.GetLastWin32Error(); + } + else + res = 0; + + return res; + } + + /// <summary> + /// Gets the JVM DLL paths in order of lookup priority. + /// </summary> + private static IEnumerable<KeyValuePair<string, string>> GetJvmDllPaths(string configJvmDllPath) + { + if (!string.IsNullOrEmpty(configJvmDllPath)) + yield return new KeyValuePair<string, string>("IgniteConfiguration.JvmDllPath", configJvmDllPath); + + var javaHomeDir = Environment.GetEnvironmentVariable(EnvJavaHome); + + if (!string.IsNullOrEmpty(javaHomeDir)) + yield return + new KeyValuePair<string, string>(EnvJavaHome, GetJvmDllPath(Path.Combine(javaHomeDir, DirJre))); + } + + /// <summary> + /// Gets the JVM DLL path from JRE dir. + /// </summary> + private static string GetJvmDllPath(string jreDir) + { + return Path.Combine(jreDir, DirBin, DirServer, FileJvmDll); + } + + /// <summary> + /// Unpacks an embedded resource into a temporary folder and returns the full path of resulting file. + /// </summary> + /// <param name="resourceName">Resource name.</param> + /// <returns>Path to a temp file with an unpacked resource.</returns> + public static string UnpackEmbeddedResource(string resourceName) + { + var dllRes = Assembly.GetExecutingAssembly().GetManifestResourceNames() + .Single(x => x.EndsWith(resourceName, StringComparison.OrdinalIgnoreCase)); + + return WriteResourceToTempFile(dllRes, resourceName); + } + + /// <summary> + /// Writes the resource to temporary file. + /// </summary> + /// <param name="resource">The resource.</param> + /// <param name="name">File name prefix</param> + /// <returns>Path to the resulting temp file.</returns> + private static string WriteResourceToTempFile(string resource, string name) + { + // Dll file name should not be changed, so we create a temp folder with random name instead. + var file = Path.Combine(GetTempDirectoryName(), name); + + using (var src = Assembly.GetExecutingAssembly().GetManifestResourceStream(resource)) + using (var dest = File.OpenWrite(file)) + { + // ReSharper disable once PossibleNullReferenceException + src.CopyTo(dest); + + return file; + } + } + + /// <summary> + /// Tries to clean temporary directories created with <see cref="GetTempDirectoryName"/>. + /// </summary> + private static void TryCleanTempDirectories() + { + foreach (var dir in Directory.GetDirectories(Path.GetTempPath(), DirIgniteTmp + "*")) + { + try + { + Directory.Delete(dir, true); + } + catch (IOException) + { + // Expected + } + catch (UnauthorizedAccessException) + { + // Expected + } + } + } + + /// <summary> + /// Creates a uniquely named, empty temporary directory on disk and returns the full path of that directory. + /// </summary> + /// <returns>The full path of the temporary directory.</returns> + private static string GetTempDirectoryName() + { + while (true) + { + var dir = Path.Combine(Path.GetTempPath(), DirIgniteTmp + Path.GetRandomFileName()); + + try + { + return Directory.CreateDirectory(dir).FullName; + } + catch (IOException) + { + // Expected + } + catch (UnauthorizedAccessException) + { + // Expected + } + } + } + + /// <summary> + /// Convert unmanaged char array to string. + /// </summary> + /// <param name="chars">Char array.</param> + /// <param name="charsLen">Char array length.</param> + /// <returns></returns> + public static unsafe string Utf8UnmanagedToString(sbyte* chars, int charsLen) + { + IntPtr ptr = new IntPtr(chars); + + if (ptr == IntPtr.Zero) + return null; + + byte[] arr = new byte[charsLen]; + + Marshal.Copy(ptr, arr, 0, arr.Length); + + return Encoding.UTF8.GetString(arr); + } + + /// <summary> + /// Convert string to unmanaged byte array. + /// </summary> + /// <param name="str">String.</param> + /// <returns>Unmanaged byte array.</returns> + public static unsafe sbyte* StringToUtf8Unmanaged(string str) + { + var ptr = IntPtr.Zero; + + if (str != null) + { + byte[] strBytes = Encoding.UTF8.GetBytes(str); + + ptr = Marshal.AllocHGlobal(strBytes.Length + 1); + + Marshal.Copy(strBytes, 0, ptr, strBytes.Length); + + *((byte*)ptr.ToPointer() + strBytes.Length) = 0; // NULL-terminator. + } + + return (sbyte*)ptr.ToPointer(); + } + + /// <summary> + /// Reads node collection from stream. + /// </summary> + /// <param name="reader">Reader.</param> + /// <param name="pred">The predicate.</param> + /// <returns> Nodes list or null. </returns> + public static List<IClusterNode> ReadNodes(IPortableRawReader reader, Func<ClusterNodeImpl, bool> pred = null) + { + var cnt = reader.ReadInt(); + + if (cnt < 0) + return null; + + var res = new List<IClusterNode>(cnt); + + var ignite = ((PortableReaderImpl)reader).Marshaller.Ignite; + + if (pred == null) + { + for (var i = 0; i < cnt; i++) + res.Add(ignite.GetNode(reader.ReadGuid())); + } + else + { + for (var i = 0; i < cnt; i++) + { + var node = ignite.GetNode(reader.ReadGuid()); + + if (pred(node)) + res.Add(node); + } + } + + return res; + } + + /// <summary> + /// Gets the asynchronous mode disabled exception. + /// </summary> + /// <returns>Asynchronous mode disabled exception.</returns> + public static InvalidOperationException GetAsyncModeDisabledException() + { + return new InvalidOperationException("Asynchronous mode is disabled"); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5cec202c/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Interop/InteropDotNetConfiguration.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Interop/InteropDotNetConfiguration.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Interop/InteropDotNetConfiguration.cs new file mode 100644 index 0000000..2dffd28 --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Interop/InteropDotNetConfiguration.cs @@ -0,0 +1,62 @@ +/* + * 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.Interop +{ + using System.Collections.Generic; + using Apache.Ignite.Core.Impl.Portable; + using Apache.Ignite.Core.Portable; + + /// <summary> + /// .Net configuration as defined in Java configuration file. + /// </summary> + internal class InteropDotNetConfiguration : IPortableWriteAware + { + /// <summary> + /// Portable configuration. + /// </summary> + public InteropDotNetPortableConfiguration PortableCfg { get; set; } + + /// <summary> + /// Assemblies to load. + /// </summary> + public IList<string> Assemblies { get; set; } + + /** {@inheritDoc} */ + public void WritePortable(IPortableWriter writer) + { + IPortableRawWriter rawWriter = writer.RawWriter(); + + rawWriter.WriteObject(PortableCfg); + + rawWriter.WriteGenericCollection(Assemblies); + } + + /// <summary> + /// Initializes a new instance of the <see cref="InteropDotNetConfiguration"/> class. + /// </summary> + /// <param name="reader">The reader.</param> + public InteropDotNetConfiguration(IPortableReader reader) + { + IPortableRawReader rawReader = reader.RawReader(); + + PortableCfg = rawReader.ReadObject<InteropDotNetPortableConfiguration>(); + + Assemblies = (List<string>) rawReader.ReadGenericCollection<string>(); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5cec202c/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Interop/InteropDotNetPortableConfiguration.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Interop/InteropDotNetPortableConfiguration.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Interop/InteropDotNetPortableConfiguration.cs new file mode 100644 index 0000000..4f36e84 --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Interop/InteropDotNetPortableConfiguration.cs @@ -0,0 +1,127 @@ +/* + * 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.Interop +{ + using System.Collections.Generic; + using Apache.Ignite.Core.Impl.Portable; + using Apache.Ignite.Core.Portable; + + /// <summary> + /// .Net portable configuration as defined in Java configuration. + /// </summary> + internal class InteropDotNetPortableConfiguration : IPortableWriteAware + { + /// <summary> + /// Type configurations. + /// </summary> + public ICollection<InteropDotNetPortableTypeConfiguration> TypeConfigurations { get; set; } + + /// <summary> + /// Portable types. Shorthand for creating PortableTypeConfiguration. + /// </summary> + public ICollection<string> Types { get; set; } + + /// <summary> + /// Default name mapper. + /// </summary> + public string DefaultNameMapper { get; set; } + + /// <summary> + /// Default ID mapper. + /// </summary> + public string DefaultIdMapper { get; set; } + + /// <summary> + /// Default serializer. + /// </summary> + public string DefaultSerializer { get; set; } + + /// <summary> + /// Default metadata enabled flag. Defaults to true. + /// </summary> + public bool DefaultMetadataEnabled { get; set; } + + /// <summary> + /// Keep deserialized flag. If set to non-null value, overrides default value set in + /// PortableConfiguration. + /// </summary> + public bool DefaultKeepDeserialized { get; set; } + + /// <summary> + /// Creates PortableConfiguration. + /// </summary> + /// <returns>PortableConfiguration</returns> + public PortableConfiguration ToPortableConfiguration() + { + PortableConfiguration res = new PortableConfiguration(); + + if (TypeConfigurations != null) + { + List<PortableTypeConfiguration> typeCfgs = new List<PortableTypeConfiguration>(); + + foreach (InteropDotNetPortableTypeConfiguration dotNetTypeCfg in TypeConfigurations) + typeCfgs.Add(dotNetTypeCfg.ToPortableTypeConfiguration()); + + res.TypeConfigurations = typeCfgs; + } + + res.Types = Types; + res.DefaultNameMapper = + (IPortableNameMapper) InteropDotNetPortableTypeConfiguration.CreateInstance(DefaultNameMapper); + res.DefaultIdMapper = + (IPortableIdMapper) InteropDotNetPortableTypeConfiguration.CreateInstance(DefaultIdMapper); + res.DefaultSerializer = + (IPortableSerializer) InteropDotNetPortableTypeConfiguration.CreateInstance(DefaultSerializer); + res.DefaultMetadataEnabled = DefaultMetadataEnabled; + res.DefaultKeepDeserialized = DefaultKeepDeserialized; + + return res; + } + + /** {@inheritDoc} */ + public void WritePortable(IPortableWriter writer) + { + IPortableRawWriter rawWriter = writer.RawWriter(); + + rawWriter.WriteGenericCollection(TypeConfigurations); + rawWriter.WriteGenericCollection(Types); + rawWriter.WriteString(DefaultNameMapper); + rawWriter.WriteString(DefaultIdMapper); + rawWriter.WriteString(DefaultSerializer); + rawWriter.WriteBoolean(DefaultMetadataEnabled); + rawWriter.WriteBoolean(DefaultKeepDeserialized); + } + + /// <summary> + /// Initializes a new instance of the <see cref="InteropDotNetPortableConfiguration"/> class. + /// </summary> + /// <param name="reader">The reader.</param> + public InteropDotNetPortableConfiguration(IPortableReader reader) + { + IPortableRawReader rawReader = reader.RawReader(); + + TypeConfigurations = rawReader.ReadGenericCollection<InteropDotNetPortableTypeConfiguration>(); + Types = rawReader.ReadGenericCollection<string>(); + DefaultNameMapper = rawReader.ReadString(); + DefaultIdMapper = rawReader.ReadString(); + DefaultSerializer = rawReader.ReadString(); + DefaultMetadataEnabled = rawReader.ReadBoolean(); + DefaultKeepDeserialized = rawReader.ReadBoolean(); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5cec202c/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Interop/InteropDotNetPortableTypeConfiguration.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Interop/InteropDotNetPortableTypeConfiguration.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Interop/InteropDotNetPortableTypeConfiguration.cs new file mode 100644 index 0000000..0c3b433 --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Interop/InteropDotNetPortableTypeConfiguration.cs @@ -0,0 +1,151 @@ +/* + * 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.Interop +{ + using System; + using System.Reflection; + using Apache.Ignite.Core.Impl.Portable; + using Apache.Ignite.Core.Portable; + + /// <summary> + /// .Net portable configuration type as defined in Java configuration. + /// </summary> + internal class InteropDotNetPortableTypeConfiguration : IPortableWriteAware + { + /// <summary> + /// Assembly name. + /// </summary> + public string AssemblyName { get; set; } + + /// <summary> + /// Fully qualified type name. + /// </summary> + public string TypeName { get; set; } + + /// <summary> + /// Name mapper for the given type. + /// </summary> + public string NameMapper { get; set; } + + /// <summary> + /// ID mapper for the given type. When it is necessary to resolve class (field) ID, then + /// this property will be checked first. If not set, then PortableClassIdAttribute + /// (PortableFieldIdAttribute) will be checked in class through reflection. If required + /// attribute is not set, then ID will be hash code of the class (field) simple name in lower case. + /// </summary> + public string IdMapper { get; set; } + + /// <summary> + /// Serializer for the given type. If not provided and class implements IPortable + /// then its custom logic will be used. If not provided and class doesn't implement IPortable + /// then all fields of the class except of those with [NotSerialized] attribute will be serialized + ///with help of reflection. + /// </summary> + public string Serializer { get; set; } + + /// <summary> + /// Affinity key field name. + /// </summary> + public string AffinityKeyFieldName { get; set; } + + /// <summary> + /// Metadata enabled flag. If set to non-null value, overrides default value set in + /// PortableConfiguration. + /// </summary> + public bool? MetadataEnabled { get; set; } + + /// <summary> + /// Keep deserialized flag. If set to non-null value, overrides default value set in + /// PortableConfiguration. + /// </summary> + public bool? KeepDeserialized { get; set; } + + /// <summary> + /// Creates new instance of PortableTypeConfiguration. + /// </summary> + /// <returns>PortableTypeConfiguration</returns> + public PortableTypeConfiguration ToPortableTypeConfiguration() + { + return new PortableTypeConfiguration + { + AssemblyName = AssemblyName, + AffinityKeyFieldName = AffinityKeyFieldName, + TypeName = TypeName, + NameMapper = (IPortableNameMapper) CreateInstance(NameMapper), + IdMapper = (IPortableIdMapper) CreateInstance(IdMapper), + Serializer = (IPortableSerializer) CreateInstance(Serializer), + MetadataEnabled = MetadataEnabled, + KeepDeserialized = KeepDeserialized + }; + } + + /** {@inheritDoc} */ + public void WritePortable(IPortableWriter writer) + { + IPortableRawWriter rawWriter = writer.RawWriter(); + + rawWriter.WriteString(AssemblyName); + rawWriter.WriteString(TypeName); + rawWriter.WriteString(NameMapper); + rawWriter.WriteString(IdMapper); + rawWriter.WriteString(Serializer); + rawWriter.WriteString(AffinityKeyFieldName); + rawWriter.WriteObject(MetadataEnabled); + rawWriter.WriteObject(KeepDeserialized); + } + + /// <summary> + /// Initializes a new instance of the <see cref="InteropDotNetPortableTypeConfiguration"/> class. + /// </summary> + /// <param name="reader">The reader.</param> + public InteropDotNetPortableTypeConfiguration(IPortableReader reader) + { + IPortableRawReader rawReader = reader.RawReader(); + + AssemblyName = rawReader.ReadString(); + TypeName = rawReader.ReadString(); + NameMapper = rawReader.ReadString(); + IdMapper = rawReader.ReadString(); + Serializer = rawReader.ReadString(); + AffinityKeyFieldName = rawReader.ReadString(); + MetadataEnabled = rawReader.ReadObject<bool?>(); + KeepDeserialized = rawReader.ReadObject<bool?>(); + } + + /// <summary> + /// Create new instance of specified class. + /// </summary> + /// <param name="typeName">Name of the type.</param> + /// <returns>New Instance.</returns> + public static object CreateInstance(string typeName) + { + if (typeName == null) + return null; + + foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) + { + object instance = assembly.CreateInstance(typeName); + + if (instance != null) + return instance; + } + + throw new PortableException("Failed to find class: " + typeName); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5cec202c/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/InteropExceptionHolder.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/InteropExceptionHolder.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/InteropExceptionHolder.cs new file mode 100644 index 0000000..98d57da --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/InteropExceptionHolder.cs @@ -0,0 +1,85 @@ +/* + * 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 +{ + using System; + using System.Runtime.Serialization.Formatters.Binary; + using Apache.Ignite.Core.Impl.Portable; + using Apache.Ignite.Core.Impl.Portable.IO; + using Apache.Ignite.Core.Portable; + + /// <summary> + /// Holder of exception which must be serialized to Java and then backwards to the native platform. + /// </summary> + internal class InteropExceptionHolder : IPortableMarshalAware + { + /** Initial exception. */ + private Exception _err; + + /// <summary> + /// Constructor. + /// </summary> + public InteropExceptionHolder() + { + // No-op. + } + + /// <summary> + /// Constructor. + /// </summary> + /// <param name="err">Error.</param> + public InteropExceptionHolder(Exception err) + { + _err = err; + } + + /// <summary> + /// Underlying exception. + /// </summary> + public Exception Error + { + get { return _err; } + } + + /** <inheritDoc /> */ + public void WritePortable(IPortableWriter writer) + { + var writer0 = (PortableWriterImpl) writer.RawWriter(); + + if (writer0.IsPortable(_err)) + { + writer0.WriteBoolean(true); + writer0.WriteObject(_err); + } + else + { + writer0.WriteBoolean(false); + + BinaryFormatter bf = new BinaryFormatter(); + + bf.Serialize(new PortableStreamAdapter(writer0.Stream), _err); + } + } + + /** <inheritDoc /> */ + public void ReadPortable(IPortableReader reader) + { + throw new NotImplementedException(); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5cec202c/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/LifecycleBeanHolder.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/LifecycleBeanHolder.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/LifecycleBeanHolder.cs new file mode 100644 index 0000000..cce4ec5 --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/LifecycleBeanHolder.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.Impl +{ + using Apache.Ignite.Core.Impl.Resource; + using Apache.Ignite.Core.Lifecycle; + + /// <summary> + /// Lifecycle bean holder. + /// </summary> + internal class LifecycleBeanHolder : ILifecycleBean + { + /** Target bean. */ + private readonly ILifecycleBean _target; + + /** Whether start event was invoked. */ + private volatile bool _startEvt; + + /// <summary> + /// Constructor. + /// </summary> + /// <param name="target">Target bean.</param> + public LifecycleBeanHolder(ILifecycleBean target) + { + _target = target; + } + + /** <inheritDoc /> */ + public void OnLifecycleEvent(LifecycleEventType evt) + { + if (evt == LifecycleEventType.AfterNodeStart) + // This event cannot be propagated right away because at this point we + // do not have Ignite instance yet. So just schedule it. + _startEvt = true; + else + _target.OnLifecycleEvent(evt); + } + + /// <summary> + /// Grid start callback. + /// </summary> + /// <param name="grid">Ignite instance.</param> + internal void OnStart(Ignite grid) + { + ResourceProcessor.Inject(_target, grid); + + if (_startEvt) + _target.OnLifecycleEvent(LifecycleEventType.AfterNodeStart); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5cec202c/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Memory/InteropExternalMemory.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Memory/InteropExternalMemory.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Memory/InteropExternalMemory.cs new file mode 100644 index 0000000..d356b5e --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Memory/InteropExternalMemory.cs @@ -0,0 +1,46 @@ +/* + * 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.Memory +{ + /// <summary> + /// Interop external memory chunk. + /// </summary> + internal class InteropExternalMemory : PlatformMemory + { + /// <summary> + /// Constructor. + /// </summary> + /// <param name="memPtr">Memory pointer.</param> + public InteropExternalMemory(long memPtr) : base(memPtr) + { + // No-op. + } + + /** <inheritdoc /> */ + public override void Reallocate(int cap) + { + InteropMemoryUtils.ReallocateExternal(Pointer, cap); + } + + /** <inheritdoc /> */ + public override void Release() + { + // Memory can only be released by native platform. + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5cec202c/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Memory/InteropMemoryUtils.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Memory/InteropMemoryUtils.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Memory/InteropMemoryUtils.cs new file mode 100644 index 0000000..485d3db --- /dev/null +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Memory/InteropMemoryUtils.cs @@ -0,0 +1,38 @@ +/* + * 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.Memory +{ + using Apache.Ignite.Core.Impl.Unmanaged; + + /// <summary> + /// Utility methods for interop memory management. + /// </summary> + internal static class InteropMemoryUtils + { + /// <summary> + /// Re-allocate external memory chunk. + /// </summary> + /// <param name="memPtr">Memory pointer.</param> + /// <param name="cap">CalculateCapacity.</param> + /// <returns>New memory pointer.</returns> + public static void ReallocateExternal(long memPtr, int cap) + { + UnmanagedUtils.Reallocate(memPtr, cap); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5cec202c/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryManager.cs ---------------------------------------------------------------------- diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryManager.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryManager.cs index 2d52dd6..3dc3953 100644 --- a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryManager.cs +++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryManager.cs @@ -17,10 +17,9 @@ namespace Apache.Ignite.Core.Impl.Memory { - using System; using System.Diagnostics.CodeAnalysis; using System.Threading; - + /// <summary> /// Memory manager implementation. /// </summary> @@ -100,7 +99,7 @@ namespace Apache.Ignite.Core.Impl.Memory /// <returns>Memory.</returns> protected virtual IPlatformMemory GetExternalMemory(long memPtr) { - throw new NotSupportedException("Not supported in Ignite yet"); + return new InteropExternalMemory(memPtr); } } }
