/** * This method uses the {@link DatabaseReconciliator} to compare the local database with the * downloaded remote databases, in order to determine a winner. The winner's database versions * will be applied locally. * * <p>For the comparison, the {@link DatabaseVersionHeader}s (mainly the {@link VectorClock}) of each * database version are compared. Using these vector clocks, the underlying algorithms determine * potential conflicts (between database versions, = simultaneous vector clocks), and resolve these * conflicts by comparing local timestamps. * * <p>The detailed algorithm is described in the {@link DatabaseReconciliator}. * * @param localBranch Local database branch (extracted from the local database) * @param allStitchedBranches The newly downloaded remote database version headers (= branches) * @return Returns the branch of the winner * @throws Exception If any kind of error occurs (...) */ private Map.Entry<String, DatabaseBranch> determineWinnerBranch(DatabaseBranches allStitchedBranches) throws Exception { logger.log(Level.INFO, "Determine winner using database reconciliator ..."); Entry<String, DatabaseBranch> winnersBranch = databaseReconciliator.findWinnerBranch(allStitchedBranches); if (winnersBranch != null) { return winnersBranch; } else { return new AbstractMap.SimpleEntry<String, DatabaseBranch>("", new DatabaseBranch()); } }
/** * Implements the core synchronization algorithm as described {@link DatabaseReconciliator in the class description}. * * @param localMachineName Client name of the local machine (required for branch stitching) * @param localBranch Local branch, created from the local database * @param unknownRemoteBranches Newly downloaded unknown remote branches (incomplete branches; will be stitched) * @return Returns the branch of the winning client */ public Map.Entry<String, DatabaseBranch> findWinnerBranch(DatabaseBranches allBranches) throws Exception { Entry<String, DatabaseBranch> winnersNameAndBranch = findWinnersNameAndBranch(allBranches); if (winnersNameAndBranch != null) { String winnersName = winnersNameAndBranch.getKey(); DatabaseBranch winnersBranch = winnersNameAndBranch.getValue(); if (logger.isLoggable(Level.INFO)) { logger.log(Level.INFO, "- Winner is " + winnersName + " with branch: "); for (DatabaseVersionHeader databaseVersionHeader : winnersBranch.getAll()) { logger.log(Level.INFO, " + " + databaseVersionHeader); } } return winnersNameAndBranch; } else { return null; } }
public DownOperation(Config config, DownOperationOptions options) { super(config, ACTION_ID); this.options = options; this.result = new DownOperationResult(); this.localDatabase = new SqlDatabase(config); this.databaseReconciliator = new DatabaseReconciliator(); this.databaseSerializer = new DatabaseXmlSerializer(config.getTransformer()); }
DatabaseBranch localPurgeBranch = databaseReconciliator.findLosersPruneBranch(localBranch, winnersBranch.getValue()); logger.log(Level.INFO, "- Database versions to REMOVE locally: " + localPurgeBranch);
List<PartialFileHistory> preDeleteFileHistoriesWithLastVersion) throws Exception { DatabaseBranch winnersApplyBranch = databaseReconciliator.findWinnersApplyBranch(localBranch, winnersBranch.getValue());
List<DatabaseVersionHeader> databaseVersionHeaders = sortBranches(allBranches);