Search code examples
c++ignitegridgain

How do I provide AffinityFunction.BackupFilter when mainly using C++ bindings


I am using the C++ bindings to have redundancy in my application. Alongside the main C++ node, I am running a vanilla Java node via ignite.sh as a backup on another node. I would like appoint this vanilla Java node to always stay a backup node and never a primary node as long as there is a C++ node running. Also, I need the C++ nodes to always stay as primary nodes. A little data loss is acceptable with the PRIMARY_SYNC synchronization.

My research led me to AffinityFunction.BackupFilter property to filter C++ nodes as primary. It seems that there is also some functions to give attributes to nodes. So I guess I can set a specific attribute on C++ nodes and filter them to always stay as primary nodes.

However, C++ bindings apparently neither provide a way to set backup filter nor allow setting attributes on the launched node. I have noticed some modules get plugged through ignite-dir/libs but there is no tutorial about that approach to add AffinityFunction. How can I achieve what I need? I need to plug a custom affinity function while using C++ as the main and a way to distinguish the C++ nodes.


Solution

  • Ignite adds the files in ignite_dir/libs into classpath. According to the documentation, environment variables can be read via ClusterNode.attribute() method. So I have put the following java code to libs/ folder:

    import java.util.List;
    import org.apache.ignite.cluster.ClusterNode;
    import org.apache.ignite.lang.IgniteBiPredicate;
    import org.apache.ignite.cache.affinity.*;
    
    public class RendezvousAffinityFunction extends org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction {
            @Override
            public List<List<ClusterNode>> assignPartitions(AffinityFunctionContext affCtx) {
                    System.out.println("Assigning partitions...");
    
                    List<List<ClusterNode>> partitions = super.assignPartitions(affCtx);
    
                    for (List<ClusterNode> nodes : partitions) {
                            for (int i = 0; i < nodes.size(); ++i) {
                                    ClusterNode node = nodes.get(i);
                                    boolean is_primary_instance = ((Object)node.attribute("IGNITE_PRIMARY_NODE") != null);
    
                                    if (is_primary_instance && i != 0) {
                                            // move to the top of the node list
                                            nodes.remove(i);
                                            nodes.add(0, node);
    
                                            System.out.println("Putting node " + i + " to the head of the node list.");
                                    }
                            }
                    }
    
                    return partitions;
            }
    }
    

    Apparently, this method is called on topology change. The method override checks the environment variable IGNITE_PRIMARY_NODE, if it exists, it puts the node at the beginning of the ClusterNode list which is then used as the primary node by Ignite. This override will prefer the nodes with IGNITE_PRIMARY_NODE environment variable set as the primary nodes.