Repository: ignite Updated Branches: refs/heads/master 140fe1933 -> 444d549ab
IGNITE-3371 .NET: Configure PlatformAffinityFunction in Spring This closes #832 Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/444d549a Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/444d549a Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/444d549a Branch: refs/heads/master Commit: 444d549ab51753f558120b718b093328e25ce85e Parents: 140fe19 Author: Pavel Tupitsyn <[email protected]> Authored: Thu Jun 30 12:10:45 2016 +0300 Committer: Pavel Tupitsyn <[email protected]> Committed: Thu Jun 30 12:10:45 2016 +0300 ---------------------------------------------------------------------- .../affinity/PlatformAffinityFunction.java | 24 ++- .../PlatformDotNetConfigurationClosure.java | 41 ++++ .../dotnet/PlatformDotNetAffinityFunction.java | 211 +++++++++++++++++++ .../Apache.Ignite.Core.Tests.csproj | 4 + .../Affinity/AffinityFunctionSpringTest.cs | 132 ++++++++++++ .../Cache/Affinity/AffinityFunctionTest.cs | 26 +++ .../Config/Cache/Affinity/affinity-function.xml | 87 ++++++++ .../Apache.Ignite.Core.Tests/TestRunner.cs | 2 +- .../Cache/Affinity/AffinityFunctionBase.cs | 13 ++ .../dotnet/Apache.Ignite.Core/Ignition.cs | 41 ++-- .../Impl/Cache/Store/CacheStore.cs | 4 +- .../Apache.Ignite.Core/Impl/IgniteUtils.cs | 12 +- .../Impl/Unmanaged/UnmanagedCallbacks.cs | 8 +- 13 files changed, 579 insertions(+), 26 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/444d549a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/cache/affinity/PlatformAffinityFunction.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/cache/affinity/PlatformAffinityFunction.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/cache/affinity/PlatformAffinityFunction.java index 4da5e24..fc2496c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/cache/affinity/PlatformAffinityFunction.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/cache/affinity/PlatformAffinityFunction.java @@ -52,7 +52,13 @@ public class PlatformAffinityFunction implements AffinityFunction, Externalizabl /** */ private Object userFunc; - /** */ + /** + * Partition count. + * + * 1) Java calls partitions() method very early (before LifecycleAware.start) during CacheConfiguration validation. + * 2) Partition count never changes. + * Therefore, we get the value on .NET side once, and pass it along with PlatformAffinity. + */ private int partitions; /** */ @@ -76,13 +82,27 @@ public class PlatformAffinityFunction implements AffinityFunction, Externalizabl * Ctor. * * @param func User fun object. - * @param partitions Initial number of partitions. + * @param partitions Number of partitions. */ public PlatformAffinityFunction(Object func, int partitions) { userFunc = func; this.partitions = partitions; } + /** + * Ctor. + * + * @param ptr User func ptr. + * @param partitions Number of partitions. + */ + public PlatformAffinityFunction(PlatformContext ctx, long ptr, int partitions) { + this.ctx = ctx; + this.ptr = ptr; + this.partitions = partitions; + + ignite = ctx.kernalContext().grid(); + } + /** {@inheritDoc} */ public Object getUserFunc() { return userFunc; http://git-wip-us.apache.org/repos/asf/ignite/blob/444d549a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/dotnet/PlatformDotNetConfigurationClosure.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/dotnet/PlatformDotNetConfigurationClosure.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/dotnet/PlatformDotNetConfigurationClosure.java index db2fa4d..0a267fb 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/dotnet/PlatformDotNetConfigurationClosure.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/dotnet/PlatformDotNetConfigurationClosure.java @@ -24,6 +24,7 @@ import org.apache.ignite.binary.BinaryBasicNameMapper; import org.apache.ignite.binary.BinaryIdMapper; import org.apache.ignite.binary.BinaryNameMapper; import org.apache.ignite.configuration.BinaryConfiguration; +import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.configuration.PlatformConfiguration; import org.apache.ignite.internal.binary.BinaryMarshaller; @@ -40,6 +41,7 @@ import org.apache.ignite.internal.processors.platform.utils.PlatformUtils; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lifecycle.LifecycleBean; import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.platform.dotnet.PlatformDotNetAffinityFunction; import org.apache.ignite.platform.dotnet.PlatformDotNetConfiguration; import org.apache.ignite.platform.dotnet.PlatformDotNetLifecycleBean; @@ -180,6 +182,7 @@ public class PlatformDotNetConfigurationClosure extends PlatformAbstractConfigur PlatformConfigurationUtils.writeDotNetConfiguration(writer, interopCfg.unwrap()); + // Write .NET beans List<PlatformDotNetLifecycleBean> beans = beans(igniteCfg); writer.writeInt(beans.size()); @@ -189,6 +192,14 @@ public class PlatformDotNetConfigurationClosure extends PlatformAbstractConfigur writer.writeMap(bean.getProperties()); } + // Write .NET affinity funcs + List<PlatformDotNetAffinityFunction> affFuncs = affinityFunctions(igniteCfg); + + writer.writeInt(affFuncs.size()); + + for (PlatformDotNetAffinityFunction func : affFuncs) + func.write(writer); + out.synchronize(); gate.extensionCallbackInLongLongOutLong( @@ -209,6 +220,7 @@ public class PlatformDotNetConfigurationClosure extends PlatformAbstractConfigur PlatformConfigurationUtils.readIgniteConfiguration(in, cfg); + // Process beans List<PlatformDotNetLifecycleBean> beans = beans(cfg); List<PlatformLifecycleBean> newBeans = new ArrayList<>(); @@ -240,6 +252,14 @@ public class PlatformDotNetConfigurationClosure extends PlatformAbstractConfigur cfg.setLifecycleBeans(mergedBeans); } } + + // Process affinity functions + List<PlatformDotNetAffinityFunction> affFuncs = affinityFunctions(cfg); + + if (!affFuncs.isEmpty()) { + for (PlatformDotNetAffinityFunction aff : affFuncs) + aff.initPartitions(in.readInt()); + } } /** @@ -260,4 +280,25 @@ public class PlatformDotNetConfigurationClosure extends PlatformAbstractConfigur return res; } + + /** + * Find .NET affinity functions in configuration. + * + * @param cfg Configuration. + * @return affinity functions. + */ + private static List<PlatformDotNetAffinityFunction> affinityFunctions(IgniteConfiguration cfg) { + List<PlatformDotNetAffinityFunction> res = new ArrayList<>(); + + CacheConfiguration[] cacheCfg = cfg.getCacheConfiguration(); + + if (cacheCfg != null) { + for (CacheConfiguration ccfg : cacheCfg) { + if (ccfg.getAffinity() instanceof PlatformDotNetAffinityFunction) + res.add((PlatformDotNetAffinityFunction)ccfg.getAffinity()); + } + } + + return res; + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/444d549a/modules/core/src/main/java/org/apache/ignite/platform/dotnet/PlatformDotNetAffinityFunction.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/platform/dotnet/PlatformDotNetAffinityFunction.java b/modules/core/src/main/java/org/apache/ignite/platform/dotnet/PlatformDotNetAffinityFunction.java new file mode 100644 index 0000000..6642693 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/platform/dotnet/PlatformDotNetAffinityFunction.java @@ -0,0 +1,211 @@ +/* + * 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. + */ + +package org.apache.ignite.platform.dotnet; + +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteException; +import org.apache.ignite.binary.BinaryRawWriter; +import org.apache.ignite.cache.affinity.AffinityFunction; +import org.apache.ignite.cache.affinity.AffinityFunctionContext; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.internal.binary.BinaryRawWriterEx; +import org.apache.ignite.internal.processors.platform.PlatformContext; +import org.apache.ignite.internal.processors.platform.cache.affinity.PlatformAffinityFunction; +import org.apache.ignite.internal.processors.platform.memory.PlatformMemory; +import org.apache.ignite.internal.processors.platform.memory.PlatformOutputStream; +import org.apache.ignite.internal.processors.platform.utils.PlatformUtils; +import org.apache.ignite.lifecycle.LifecycleAware; +import org.apache.ignite.resources.IgniteInstanceResource; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** + * AffinityFunction implementation which can be used to configure .NET affinity function in Java Spring configuration. + */ +public class PlatformDotNetAffinityFunction implements AffinityFunction, Externalizable, LifecycleAware { + /** */ + private static final long serialVersionUID = 0L; + + /** .NET type name. */ + private String typName; + + /** Properties. */ + private Map<String, ?> props; + + /** + * Partition count. + * + * 1) Java calls partitions() method very early (before LifecycleAware.start) during CacheConfiguration validation. + * 2) Partition count never changes. + * Therefore, we get the value on .NET side once, and pass it along with PlatformAffinity. + */ + private int partitions; + + /** Inner function. */ + private transient PlatformAffinityFunction func; + + /** Ignite. */ + private transient Ignite ignite; + + /** + * Gets .NET type name. + * + * @return .NET type name. + */ + public String getTypeName() { + return typName; + } + + /** + * Sets .NET type name. + * + * @param typName .NET type name. + */ + public void setTypeName(String typName) { + this.typName = typName; + } + + /** + * Get properties. + * + * @return Properties. + */ + public Map<String, ?> getProperties() { + return props; + } + + /** + * Set properties. + * + * @param props Properties. + */ + public void setProperties(Map<String, ?> props) { + this.props = props; + } + + /** {@inheritDoc} */ + @Override public void reset() { + assert func != null; + + func.reset(); + } + + /** {@inheritDoc} */ + @Override public int partitions() { + return partitions; + } + + /** {@inheritDoc} */ + @Override public int partition(Object key) { + assert func != null; + + return func.partition(key); + } + + /** {@inheritDoc} */ + @Override public List<List<ClusterNode>> assignPartitions(AffinityFunctionContext affCtx) { + assert func != null; + + return func.assignPartitions(affCtx); + } + + /** {@inheritDoc} */ + @Override public void removeNode(UUID nodeId) { + assert func != null; + + func.removeNode(nodeId); + } + + /** + * Writes this func to the writer. + * + * @param writer Writer. + */ + public void write(BinaryRawWriter writer) { + assert writer != null; + + writer.writeObject(typName); + writer.writeMap(props); + } + + /** {@inheritDoc} */ + @Override public void writeExternal(ObjectOutput out) throws IOException { + out.writeObject(typName); + out.writeObject(props); + out.writeInt(partitions); + } + + /** {@inheritDoc} */ + @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + typName = (String)in.readObject(); + props = (Map<String, ?>)in.readObject(); + partitions = in.readInt(); + } + + /** + * Initializes the partitions count. + * + * @param partitions Number of partitions. + */ + public void initPartitions(int partitions) { + this.partitions = partitions; + } + + /** {@inheritDoc} */ + @Override public void start() throws IgniteException { + assert ignite != null; + + PlatformContext ctx = PlatformUtils.platformContext(ignite); + assert ctx != null; + + try (PlatformMemory mem = ctx.memory().allocate()) { + PlatformOutputStream out = mem.output(); + BinaryRawWriterEx writer = ctx.writer(out); + + write(writer); + + out.synchronize(); + + long ptr = ctx.gateway().affinityFunctionInit(mem.pointer()); + + func = new PlatformAffinityFunction(ctx, ptr, partitions); + } + } + + /** {@inheritDoc} */ + @Override public void stop() throws IgniteException { + if (func != null) + func.stop(); + } + + /** + * Injects the Ignite. + * + * @param ignite Ignite. + */ + @IgniteInstanceResource + private void setIgnite(Ignite ignite) { + this.ignite = ignite; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/444d549a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj index 15e46ae..a601dbd 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj @@ -60,6 +60,7 @@ <Compile Include="Binary\BinarySelfTestFullFooter.cs" /> <Compile Include="Binary\BinaryStringTest.cs" /> <Compile Include="Cache\Affinity\AffinityFieldTest.cs" /> + <Compile Include="Cache\Affinity\AffinityFunctionSpringTest.cs" /> <Compile Include="Cache\Affinity\AffinityFunctionTest.cs" /> <Compile Include="Cache\CacheConfigurationTest.cs" /> <Compile Include="Cache\CacheDynamicStartTest.cs" /> @@ -208,6 +209,9 @@ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <SubType>Designer</SubType> </Content> + <Content Include="Config\Cache\Affinity\affinity-function.xml"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> <Content Include="Config\Cache\Store\cache-store-session.xml"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> http://git-wip-us.apache.org/repos/asf/ignite/blob/444d549a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFunctionSpringTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFunctionSpringTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFunctionSpringTest.cs new file mode 100644 index 0000000..33c0ce1 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFunctionSpringTest.cs @@ -0,0 +1,132 @@ +/* + * 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. + */ + +// ReSharper disable UnusedAutoPropertyAccessor.Local +// ReSharper disable UnusedMember.Local +namespace Apache.Ignite.Core.Tests.Cache.Affinity +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Apache.Ignite.Core.Cache; + using Apache.Ignite.Core.Cache.Affinity; + using Apache.Ignite.Core.Cluster; + using Apache.Ignite.Core.Resource; + using NUnit.Framework; + + /// <summary> + /// Tests AffinityFunction defined in Spring XML. + /// </summary> + public class AffinityFunctionSpringTest : IgniteTestBase + { + /** */ + private IIgnite _ignite; + + /// <summary> + /// Initializes a new instance of the <see cref="AffinityFunctionSpringTest"/> class. + /// </summary> + public AffinityFunctionSpringTest() : base(3, "config\\cache\\affinity\\affinity-function.xml") + { + // No-op. + } + + /** <inheritdoc /> */ + public override void TestSetUp() + { + base.TestSetUp(); + + // Start another node without spring config + if (Ignition.TryGetIgnite("grid2") == null) + { + var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration()) {GridName = "grid2"}; + _ignite = Ignition.Start(cfg); + } + } + + /// <summary> + /// Tests the static cache. + /// </summary> + [Test] + public void TestStaticCache() + { + ValidateAffinityFunction(Grid.GetCache<int, int>("cache1")); + ValidateAffinityFunction(_ignite.GetCache<int, int>("cache1")); + } + + /// <summary> + /// Tests the dynamic cache. + /// </summary> + [Test] + public void TestDynamicCache() + { + ValidateAffinityFunction(Grid.CreateCache<int, int>("dyn-cache-1")); + ValidateAffinityFunction(_ignite.GetCache<int, int>("dyn-cache-1")); + + ValidateAffinityFunction(_ignite.CreateCache<int, int>("dyn-cache-2")); + ValidateAffinityFunction(Grid.GetCache<int, int>("dyn-cache-2")); + } + + /// <summary> + /// Validates the affinity function. + /// </summary> + /// <param name="cache">The cache.</param> + private static void ValidateAffinityFunction(ICache<int, int> cache) + { + Assert.IsNull(cache.GetConfiguration().AffinityFunction); + + var aff = cache.Ignite.GetAffinity(cache.Name); + Assert.AreEqual(5, aff.Partitions); + Assert.AreEqual(4, aff.GetPartition(2)); + Assert.AreEqual(3, aff.GetPartition(4)); + } + + [Serializable] + private class TestFunc : IAffinityFunction + { + [InstanceResource] + private readonly IIgnite _ignite = null; + + private int Property1 { get; set; } + + private string Property2 { get; set; } + + public int Partitions + { + get { return 5; } + } + + public int GetPartition(object key) + { + Assert.IsNotNull(_ignite); + Assert.AreEqual(1, Property1); + Assert.AreEqual("1", Property2); + + return (int) key * 2 % 5; + } + + public void RemoveNode(Guid nodeId) + { + // No-op. + } + + public IEnumerable<IEnumerable<IClusterNode>> AssignPartitions(AffinityFunctionContext context) + { + return Enumerable.Range(0, Partitions).Select(x => context.CurrentTopologySnapshot); + } + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/444d549a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFunctionTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFunctionTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFunctionTest.cs index 70e0d78..ed0a95b 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFunctionTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFunctionTest.cs @@ -23,6 +23,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Affinity using System.Linq; using Apache.Ignite.Core.Cache; using Apache.Ignite.Core.Cache.Affinity; + using Apache.Ignite.Core.Cache.Affinity.Fair; using Apache.Ignite.Core.Cache.Configuration; using Apache.Ignite.Core.Cluster; using Apache.Ignite.Core.Common; @@ -216,6 +217,25 @@ namespace Apache.Ignite.Core.Tests.Cache.Affinity Assert.AreEqual("User error", ex.InnerException.Message); } + /// <summary> + /// Tests user-defined function that inherits predefined function. + /// </summary> + [Test] + public void TestInheritPredefinedFunction() + { + var ex = Assert.Throws<IgniteException>(() => + _ignite.CreateCache<int, int>( + new CacheConfiguration("failCache3") + { + AffinityFunction = new FairAffinityFunctionInheritor() + })); + + Assert.AreEqual("User-defined AffinityFunction can not inherit from " + + "Apache.Ignite.Core.Cache.Affinity.AffinityFunctionBase: " + + "Apache.Ignite.Core.Tests.Cache.Affinity.AffinityFunctionTest" + + "+FairAffinityFunctionInheritor", ex.Message); + } + [Serializable] private class SimpleAffinityFunction : IAffinityFunction { @@ -278,5 +298,11 @@ namespace Apache.Ignite.Core.Tests.Cache.Affinity return Enumerable.Range(0, Partitions).Select(x => context.CurrentTopologySnapshot); } } + + [Serializable] + private class FairAffinityFunctionInheritor : FairAffinityFunction + { + // No-op. + } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/444d549a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Cache/Affinity/affinity-function.xml ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Cache/Affinity/affinity-function.xml b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Cache/Affinity/affinity-function.xml new file mode 100644 index 0000000..e7fc516 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Cache/Affinity/affinity-function.xml @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + 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. +--> + +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:util="http://www.springframework.org/schema/util" + xsi:schemaLocation=" + http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/util + http://www.springframework.org/schema/util/spring-util.xsd"> + <bean id="grid.cfg" class="org.apache.ignite.configuration.IgniteConfiguration"> + <property name="localHost" value="127.0.0.1"/> + <property name="connectorConfiguration"><null/></property> + + <property name="cacheConfiguration"> + <list> + <bean class="org.apache.ignite.configuration.CacheConfiguration"> + <property name="name" value="cache1"/> + + <property name="affinity"> + <bean class="org.apache.ignite.platform.dotnet.PlatformDotNetAffinityFunction"> + <property name="typeName" value="Apache.Ignite.Core.Tests.Cache.Affinity.AffinityFunctionSpringTest+TestFunc, Apache.Ignite.Core.Tests"/> + <property name="properties"> + <map> + <entry key="Property1"> + <value type="java.lang.Integer">1</value> + </entry> + <entry key="Property2" value="1"/> + </map> + </property> + </bean> + </property> + </bean> + <bean class="org.apache.ignite.configuration.CacheConfiguration"> + <property name="name" value="dyn-cache-*"/> + + <property name="affinity"> + <bean class="org.apache.ignite.platform.dotnet.PlatformDotNetAffinityFunction"> + <property name="typeName" value="Apache.Ignite.Core.Tests.Cache.Affinity.AffinityFunctionSpringTest+TestFunc, Apache.Ignite.Core.Tests"/> + <property name="properties"> + <map> + <entry key="Property1"> + <value type="java.lang.Integer">1</value> + </entry> + <entry key="Property2" value="1"/> + </map> + </property> + </bean> + </property> + </bean> + </list> + </property> + + <property name="discoverySpi"> + <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi"> + <property name="ipFinder"> + <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder"> + <property name="addresses"> + <list> + <!-- In distributed environment, replace with actual host IP address. --> + <value>127.0.0.1:47500</value> + </list> + </property> + </bean> + </property> + <property name="socketTimeout" value="300" /> + </bean> + </property> + </bean> +</beans> http://git-wip-us.apache.org/repos/asf/ignite/blob/444d549a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestRunner.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestRunner.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestRunner.cs index 726fa3b..8f11122 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestRunner.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestRunner.cs @@ -50,7 +50,7 @@ namespace Apache.Ignite.Core.Tests //TestOne(typeof(BinaryStringTest), "Test"); - TestAll(typeof (AffinityFunctionTest)); + TestAll(typeof (AffinityFunctionSpringTest)); //TestAllInAssembly(); } http://git-wip-us.apache.org/repos/asf/ignite/blob/444d549a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Affinity/AffinityFunctionBase.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Affinity/AffinityFunctionBase.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Affinity/AffinityFunctionBase.cs index 9b89780..3434384 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Affinity/AffinityFunctionBase.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Affinity/AffinityFunctionBase.cs @@ -163,6 +163,7 @@ namespace Apache.Ignite.Core.Cache.Affinity if (p != null) { + ValidateAffinityFunctionType(p.GetType()); writer.WriteByte(p is FairAffinityFunction ? TypeCodeFair : TypeCodeRendezvous); writer.WriteInt(p.Partitions); writer.WriteBoolean(p.ExcludeNeighbors); @@ -180,6 +181,18 @@ namespace Apache.Ignite.Core.Cache.Affinity } /// <summary> + /// Validates the type of the affinity function. + /// </summary> + private static void ValidateAffinityFunctionType(Type funcType) + { + if (funcType == typeof(FairAffinityFunction) || funcType == typeof(RendezvousAffinityFunction)) + return; + + throw new IgniteException(string.Format("User-defined AffinityFunction can not inherit from {0}: {1}", + typeof(AffinityFunctionBase), funcType)); + } + + /// <summary> /// Gets the direct usage error. /// </summary> private Exception GetDirectUsageError() http://git-wip-us.apache.org/repos/asf/ignite/blob/444d549a/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs index a22c9d0..48eeec2 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs @@ -27,6 +27,7 @@ namespace Apache.Ignite.Core using System.Runtime; using System.Threading; using Apache.Ignite.Core.Binary; + using Apache.Ignite.Core.Cache.Affinity; using Apache.Ignite.Core.Common; using Apache.Ignite.Core.Impl; using Apache.Ignite.Core.Impl.Binary; @@ -249,7 +250,7 @@ namespace Apache.Ignite.Core /// <summary> /// Prepare callback invoked from Java. /// </summary> - /// <param name="inStream">Intput stream with data.</param> + /// <param name="inStream">Input stream with data.</param> /// <param name="outStream">Output stream.</param> /// <param name="handleRegistry">Handle registry.</param> internal static void OnPrepare(PlatformMemoryStream inStream, PlatformMemoryStream outStream, @@ -262,6 +263,10 @@ namespace Apache.Ignite.Core PrepareConfiguration(reader, outStream); PrepareLifecycleBeans(reader, outStream, handleRegistry); + + PrepareAffinityFunctions(reader, outStream); + + outStream.SynchronizeOutput(); } catch (Exception e) { @@ -306,7 +311,7 @@ namespace Apache.Ignite.Core /// <param name="reader">Reader.</param> /// <param name="outStream">Output stream.</param> /// <param name="handleRegistry">Handle registry.</param> - private static void PrepareLifecycleBeans(BinaryReader reader, PlatformMemoryStream outStream, + private static void PrepareLifecycleBeans(IBinaryRawReader reader, IBinaryStream outStream, HandleRegistry handleRegistry) { IList<LifecycleBeanHolder> beans = new List<LifecycleBeanHolder> @@ -318,9 +323,9 @@ namespace Apache.Ignite.Core int cnt = reader.ReadInt(); for (int i = 0; i < cnt; i++) - beans.Add(new LifecycleBeanHolder(CreateLifecycleBean(reader))); + beans.Add(new LifecycleBeanHolder(CreateObject<ILifecycleBean>(reader))); - // 2. Append beans definied in local configuration. + // 2. Append beans defined in local configuration. ICollection<ILifecycleBean> nativeBeans = _startup.Configuration.LifecycleBeans; if (nativeBeans != null) @@ -335,28 +340,32 @@ namespace Apache.Ignite.Core foreach (LifecycleBeanHolder bean in beans) outStream.WriteLong(handleRegistry.AllocateCritical(bean)); - outStream.SynchronizeOutput(); - // 4. Set beans to STARTUP object. _startup.LifecycleBeans = beans; } /// <summary> - /// Create lifecycle bean. + /// Prepares the affinity functions. /// </summary> - /// <param name="reader">Reader.</param> - /// <returns>Lifecycle bean.</returns> - private static ILifecycleBean CreateLifecycleBean(BinaryReader reader) + private static void PrepareAffinityFunctions(BinaryReader reader, PlatformMemoryStream outStream) { - // 1. Instantiate. - var bean = IgniteUtils.CreateInstance<ILifecycleBean>(reader.ReadString()); + var cnt = reader.ReadInt(); - // 2. Set properties. - var props = reader.ReadDictionaryAsGeneric<string, object>(); + var writer = reader.Marshaller.StartMarshal(outStream); - IgniteUtils.SetProperties(bean, props); + for (var i = 0; i < cnt; i++) + writer.WriteInt(CreateObject<IAffinityFunction>(reader).Partitions); + } - return bean; + /// <summary> + /// Creates an object and sets the properties. + /// </summary> + /// <param name="reader">Reader.</param> + /// <returns>Resulting object.</returns> + private static T CreateObject<T>(IBinaryRawReader reader) + { + return IgniteUtils.CreateInstance<T>(reader.ReadString(), + reader.ReadDictionaryAsGeneric<string, object>()); } /// <summary> http://git-wip-us.apache.org/repos/asf/ignite/blob/444d549a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Store/CacheStore.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Store/CacheStore.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Store/CacheStore.cs index 7785280..a297075 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Store/CacheStore.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Store/CacheStore.cs @@ -115,9 +115,7 @@ namespace Apache.Ignite.Core.Impl.Cache.Store var className = reader.ReadString(); var propertyMap = reader.ReadDictionaryAsGeneric<string, object>(); - store = IgniteUtils.CreateInstance<ICacheStore>(className); - - IgniteUtils.SetProperties(store, propertyMap); + store = IgniteUtils.CreateInstance<ICacheStore>(className, propertyMap); } http://git-wip-us.apache.org/repos/asf/ignite/blob/444d549a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteUtils.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteUtils.cs index e992e81..94f6166 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteUtils.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteUtils.cs @@ -140,8 +140,9 @@ namespace Apache.Ignite.Core.Impl /// Create new instance of specified class. /// </summary> /// <param name="typeName">Class name</param> + /// <param name="props">Properties to set.</param> /// <returns>New Instance.</returns> - public static T CreateInstance<T>(string typeName) + public static T CreateInstance<T>(string typeName, IEnumerable<KeyValuePair<string, object>> props = null) { IgniteArgumentCheck.NotNullOrEmpty(typeName, "typeName"); @@ -150,7 +151,12 @@ namespace Apache.Ignite.Core.Impl if (type == null) throw new IgniteException("Failed to create class instance [className=" + typeName + ']'); - return (T) Activator.CreateInstance(type); + var res = (T) Activator.CreateInstance(type); + + if (props != null) + SetProperties(res, props); + + return res; } /// <summary> @@ -158,7 +164,7 @@ namespace Apache.Ignite.Core.Impl /// </summary> /// <param name="target">Target object.</param> /// <param name="props">Properties.</param> - public static void SetProperties(object target, IEnumerable<KeyValuePair<string, object>> props) + private static void SetProperties(object target, IEnumerable<KeyValuePair<string, object>> props) { if (props == null) return; http://git-wip-us.apache.org/repos/asf/ignite/blob/444d549a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs index 408b48f..176d3b4 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs @@ -1115,7 +1115,13 @@ namespace Apache.Ignite.Core.Impl.Unmanaged { using (var stream = IgniteManager.Memory.Get(memPtr).GetStream()) { - var func = _ignite.Marshaller.Unmarshal<IAffinityFunction>(stream); + var reader = _ignite.Marshaller.StartUnmarshal(stream); + + var funcOrTypeName = reader.ReadObject<object>(); + + var func = funcOrTypeName as IAffinityFunction + ?? IgniteUtils.CreateInstance<IAffinityFunction>((string) funcOrTypeName, + reader.ReadDictionaryAsGeneric<string, object>()); ResourceProcessor.Inject(func, _ignite);
