Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d4147bc
IGNITE-26580 Add a preform of a new DC-aware filter and ideas how to …
sergey-chugunov-1985 Oct 17, 2025
d1803fa
IGNITE-24580 Backup Filter implementation
sergey-chugunov-1985 Oct 20, 2025
7d34a24
IGNITE-24580 Implement happy-case and preform of a test
sergey-chugunov-1985 Oct 21, 2025
9ec8010
IGNITE-26580 Test WIP
sergey-chugunov-1985 Oct 22, 2025
5bdf0d8
IGNITE-26580 Finish test, fix bug in an MDC filter
sergey-chugunov-1985 Oct 23, 2025
b0f1bf0
IGNITE-26580 Add documentation for MDC affinity backup filter
sergey-chugunov-1985 Oct 24, 2025
5815442
IGNITE-26580 Include new test to a test suite
sergey-chugunov-1985 Oct 24, 2025
cfcf39a
IGNITE-26580 Improve code after self-review
sergey-chugunov-1985 Oct 24, 2025
2e8c397
IGNITE-26580 Improve code after self-review
sergey-chugunov-1985 Oct 27, 2025
bc0ab84
IGNITE-26580 Address review comments
sergey-chugunov-1985 Oct 28, 2025
c2ad25b
IGNITE-26580 Address review comments
sergey-chugunov-1985 Oct 29, 2025
cd4fb23
IGNITE-26580 Improve tests
sergey-chugunov-1985 Oct 29, 2025
9b34257
IGNITE-26580 Provide proper implementation for hashCode
sergey-chugunov-1985 Oct 29, 2025
a65c860
IGNITE-26580 Add test for stability of partition distribution
sergey-chugunov-1985 Oct 31, 2025
b68f315
IGNITE-26580 Fix checkstyle issues
sergey-chugunov-1985 Oct 31, 2025
988de1a
IGNITE-26580 Add test for baseline
sergey-chugunov-1985 Nov 1, 2025
e425013
IGNITE-26580 Fix tests
sergey-chugunov-1985 Nov 5, 2025
c85be9f
IGNITE-26580 Fix checkstyle
sergey-chugunov-1985 Nov 5, 2025
9c3d0ff
IGNITE-26580 Cleanup system property after test
sergey-chugunov-1985 Nov 6, 2025
67ef506
IGNITE-26580 Remove equals-based validation from AffinityBackupFilter…
sergey-chugunov-1985 Nov 6, 2025
269835d
IGNITE-26580 Adapt test checks to stripped down validation
sergey-chugunov-1985 Nov 6, 2025
09ebf1d
IGNITE-26580 Remove validation for affinity backup filter class as it…
sergey-chugunov-1985 Nov 6, 2025
63232c1
IGNITE-26580 Ignore validation test until proper validation is implem…
sergey-chugunov-1985 Nov 7, 2025
5fd9842
IGNITE-26580 Remove unused methods
sergey-chugunov-1985 Nov 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/*
* 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.cache.affinity.rendezvous;

import java.util.List;
import org.apache.ignite.cluster.ClusterNode;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.lang.IgniteBiPredicate;

/**
* Multi-data center affinity backup filter that ensures each partition's data is distributed across multiple data centers,
* providing high availability and fault tolerance. This implementation guarantees at least one copy of the data in each
* data center and attempts to maintain the configured backup factor without discarding copies.
* <p>
* The filter works by grouping nodes based on their data center identification attribute (@see {@link ClusterNode#dataCenterId()})
* and ensuring that for every partition, at least one node from each data center is included in the primary-backup set.
* <p>
* The filter will discard backup copies only if the number of available nodes in a given data center is less
* than the number of copies assigned to that data center.
* For example, if a partition has 4 copies (1 primary and 3 backups) and the cluster has 2 data centers,
* than 2 copies are assigned to each data center. The only scenario when just a single copy is assigned to a node in a data center is when
* the number of nodes in that data center is one.
* <p>
* This class is constructed with a number of data centers the cluster spans and a number of backups of the cache this filter is applied to.
* Implementation expects that all copies can be spread evenly across all data centers. In other words, (backups + 1) is divisible by
* number of data centers without remainder. Uneven distributions of copies are not supported.
* <p>
* Warning: Ensure that all nodes have a consistent and valid data center identifier attribute. Missing or inconsistent values
* may lead to unexpected placement of data.
* </pre>
* <h2 class="header">Spring Example</h2>
* Create a partitioned cache template where each data center has at least one copy of the data, and the backup count is maintained.
* <pre name="code" class="xml">
* &lt;property name="cacheConfiguration"&gt;
* &lt;list&gt;
* &lt;bean id="cache-template-bean" abstract="true" class="org.apache.ignite.configuration.CacheConfiguration"&gt;
* &lt;property name="name" value="JobcaseDefaultCacheConfig*"/&gt;
* &lt;property name="cacheMode" value="PARTITIONED" /&gt;
* &lt;property name="backups" value="3" /&gt;
* &lt;property name="affinity"&gt;
* &lt;bean class="org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction"&gt;
* &lt;property name="affinityBackupFilter"&gt;
* &lt;bean class="org.apache.ignite.cache.affinity.rendezvous.MdcAffinityBackupFilter"&gt;
* &lt;constructor-arg value="2"/&gt; <!-- dcsNumber -->
* &lt;constructor-arg value="3"/&gt; <!-- backups, the same as in the cache template -->
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;/bean&gt;
* &lt;/list&gt;
* &lt;/property&gt;
* </pre>
* <p>
* With more backups, additional replicas can be distributed across different data centers to further improve redundancy.
*/
public class MdcAffinityBackupFilter implements IgniteBiPredicate<ClusterNode, List<ClusterNode>> {
Comment thread
sergey-chugunov-1985 marked this conversation as resolved.
/** */
private static final long serialVersionUID = 1L;

/** */
private final int partCopiesPerDc;

/**
* @param dcsNum Number of data centers.
* @param backups Number of backups.
*/
public MdcAffinityBackupFilter(int dcsNum, int backups) {
if (dcsNum < 2) {
throw new IllegalArgumentException("MdcAffinityBackupFilter cannot be used in an environment with only one datacenter. " +
"Number of datacenters must be at least 2.");
}

int numCopies = backups + 1;

partCopiesPerDc = numCopies / dcsNum;
int remainder = numCopies % dcsNum;

if (remainder != 0) {
String suggestion = "recommended ";
if (numCopies - remainder <= 0)
suggestion += "value is " + (backups + (dcsNum - remainder));
else
suggestion += "values are " + (backups - remainder) + " and " + (backups + (dcsNum - remainder));

throw new IllegalArgumentException("Number of copies is not completely divisible by number of datacenters, " +
"copies cannot be distributed evenly across DCs. " +
"Please adjust the number of backups, " + suggestion);
}
Comment thread
sergey-chugunov-1985 marked this conversation as resolved.
}

/** {@inheritDoc} */
@Override public boolean apply(ClusterNode candidate, List<ClusterNode> previouslySelected) {
String candidateDcId = candidate.dataCenterId();
int candDcCopiesAssigned = 0;

for (int i = 0; i < previouslySelected.size(); i++) {
String prevDcId = previouslySelected.get(i).dataCenterId();

if (prevDcId == null)
return false;
Comment thread
sergey-chugunov-1985 marked this conversation as resolved.

candDcCopiesAssigned += prevDcId.equals(candidateDcId) ? 1 : 0;
}

return candDcCopiesAssigned < partCopiesPerDc;
}

/** {@inheritDoc} */
@Override public String toString() {
return S.toString(MdcAffinityBackupFilter.class, this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,8 @@ private void checkCache(CacheJoinNodeDiscoveryData.CacheInfo locInfo, CacheData
"Affinity partitions count", locAttr.affinityPartitionsCount(),
rmtAttr.affinityPartitionsCount(), true);

// TODO IGNITE-26967 - implement validation of affinity backup filter.

CU.validateKeyConfigiration(rmtAttr.groupName(), rmtAttr.cacheName(), rmt, rmtAttr.configuration().getKeyConfiguration(),
locAttr.configuration().getKeyConfiguration(), log, true);

Expand Down
Loading
Loading