/*
*
* * Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com)
* *
* * Licensed 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.
* *
* * For more information: http://www.orientechnologies.com
*
*/
package com.orientechnologies.orient.server.distributed.conflict;
import com.orientechnologies.common.log.OLogManager;
import com.orientechnologies.orient.core.id.ORecordId;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.server.distributed.ODistributedConfiguration;
import com.orientechnologies.orient.server.distributed.ODistributedServerManager;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Conflict resolver implementation based on the majority of results. If there is no majority, no operation is executed.
*
* @author Luca Garulli
*/
public class OMajorityDistributedConflictResolver extends OAbstractDistributedConflictResolver {
public static final String NAME = "majority";
public OConflictResult onConflict(final String databaseName, final String clusterName, final ORecordId rid,
final ODistributedServerManager dManager, final Map<Object, List<String>> candidates, final ODocument config) {
final OConflictResult result = new OConflictResult();
final Object bestResult = getBestResult(candidates, null);
if (bestResult == null)
return result;
final ODistributedConfiguration dCfg = dManager.getDatabaseConfiguration(databaseName);
final int writeQuorum = dCfg.getWriteQuorum(clusterName, dManager.getAvailableNodes(databaseName), dManager.getLocalNodeName());
final int bestResultServerCount = candidates.get(bestResult).size();
if (bestResultServerCount >= writeQuorum) {
// BEST RESULT RESPECT THE QUORUM, IT'S DEFINITELY THE WINNER
OLogManager.instance().debug(this,
"Majority Conflict Resolver decided the value '%s' is the winner for record %s, because is major than the configured writeQuorum (%d). Servers ok=%s",
bestResult, rid, writeQuorum, candidates.get(result.winner));
result.winner = bestResult;
} else {
// FOUND IF THERE IS AT LEAST A MAJORITY
final List<Object> exclude = new ArrayList<Object>();
exclude.add(bestResult);
final Object secondBestResult = getBestResult(candidates, exclude);
if (bestResultServerCount > candidates.get(secondBestResult).size()) {
OLogManager.instance().debug(this,
"Majority Conflict Resolver decided the value '%s' is the winner for the record %s because it is the majority even if under the configured writeQuorum (%d). Servers ok=%s",
bestResult, rid, writeQuorum, candidates.get(result.winner));
result.winner = bestResult;
} else {
// NO MAJORITY: DON'T TAKE ANY ACTION
OLogManager.instance().debug(this, "Majority Conflict Resolver could not find a winner for the record %s (candidates=%s)", rid,
candidates);
// COLLECT ALL THE RESULT == BEST RESULT
result.candidates.put(bestResult, candidates.get(bestResult));
result.candidates.put(secondBestResult, candidates.get(secondBestResult));
exclude.add(secondBestResult);
Object lastBestResult = getBestResult(candidates, exclude);
int resultCount = candidates.get(secondBestResult).size();
while (lastBestResult != null && resultCount == bestResultServerCount && exclude.size() < candidates.size()) {
result.candidates.put(lastBestResult, candidates.get(lastBestResult));
exclude.add(lastBestResult);
lastBestResult = getBestResult(candidates, exclude);
if (lastBestResult == null)
break;
resultCount = candidates.get(lastBestResult).size();
}
}
}
return result;
}
public String getName() {
return NAME;
}
}