private Database readWinnersDatabase(Branch winnersApplyBranch, List<File> remoteDatabases) throws IOException { // Make map 'short filename' -> 'full filename' Map<String, File> shortFilenameToFileMap = new HashMap<String, File>(); for (File remoteDatabase : remoteDatabases) { shortFilenameToFileMap.put(remoteDatabase.getName(), remoteDatabase); } // Load individual databases for branch ranges DatabaseDAO databaseDAO = new XmlDatabaseDAO(config.getTransformer()); Database winnerBranchDatabase = new Database(); // Database cannot be reused, since these might be different clients String clientName = null; VectorClock clientVersionFrom = null; VectorClock clientVersionTo = null; for (DatabaseVersionHeader databaseVersionHeader : winnersApplyBranch.getAll()) { // First of range for this client if (clientName == null || !clientName.equals(databaseVersionHeader.getClient())) { clientName = databaseVersionHeader.getClient(); clientVersionFrom = databaseVersionHeader.getVectorClock(); clientVersionTo = databaseVersionHeader.getVectorClock(); } // Still in range for this client else if (clientName.equals(databaseVersionHeader.getClient())) { clientVersionTo = databaseVersionHeader.getVectorClock(); } String potentialDatabaseShortFileNameForRange = "db-" + clientName + "-" + clientVersionTo.get(clientName); // TODO [medium] Naming stuff File databaseFileForRange = shortFilenameToFileMap.get(potentialDatabaseShortFileNameForRange); if (databaseFileForRange != null) { // Load database logger.log( Level.INFO, "- Loading " + databaseFileForRange + " (from " + clientVersionFrom + ", to " + clientVersionTo + ") ..."); databaseDAO.load( winnerBranchDatabase, databaseFileForRange, clientVersionFrom, clientVersionTo); // Reset range clientName = null; clientVersionFrom = null; clientVersionTo = null; } } return winnerBranchDatabase; }
private void applyWinnersBranch(Branch winnersBranch, List<File> unknownRemoteDatabasesInCache) throws Exception { Branch winnersApplyBranch = databaseReconciliator.findWinnersApplyBranch(localBranch, winnersBranch); logger.log(Level.INFO, "- Database versions to APPLY locally: " + winnersApplyBranch); if (winnersApplyBranch.size() == 0) { logger.log(Level.WARNING, " + Nothing to update. Nice!"); result.setResultCode(DownResultCode.OK_NO_REMOTE_CHANGES); } else { logger.log(Level.INFO, "- Loading winners database ..."); Database winnersDatabase = readWinnersDatabase(winnersApplyBranch, unknownRemoteDatabasesInCache); FileSystemActionReconciliator actionReconciliator = new FileSystemActionReconciliator(config, localDatabase, result); List<FileSystemAction> actions = actionReconciliator.determineFileSystemActions(winnersDatabase); Set<MultiChunkEntry> unknownMultiChunks = determineRequiredMultiChunks(actions, winnersDatabase); downloadAndDecryptMultiChunks(unknownMultiChunks); applyFileSystemActions(actions); // Add winners database to local database // Note: This must happen AFTER the file system stuff, because we compare the winners database // with the local database! for (DatabaseVersionHeader applyDatabaseVersionHeader : winnersApplyBranch.getAll()) { logger.log( Level.INFO, " + Applying database version " + applyDatabaseVersionHeader.getVectorClock()); DatabaseVersion applyDatabaseVersion = winnersDatabase.getDatabaseVersion(applyDatabaseVersionHeader.getVectorClock()); localDatabase.addDatabaseVersion(applyDatabaseVersion); } logger.log(Level.INFO, "- Saving local database to " + config.getDatabaseFile() + " ..."); saveLocalDatabase(localDatabase, config.getDatabaseFile()); result.setResultCode(DownResultCode.OK_WITH_REMOTE_CHANGES); } }
public static DatabaseVersionHeader createFromString(String databaseVersionHeaderString) throws Exception { Matcher databaseVersionHeaderMatcher = databaseVersionHeaderPattern.matcher(databaseVersionHeaderString); if (!databaseVersionHeaderMatcher.matches()) { throw new Exception("Invalid database version header string: " + databaseVersionHeaderString); } String client = databaseVersionHeaderMatcher.group(1); String vectorClockString = databaseVersionHeaderMatcher.group(2); long databaseVersionHeaderTime = Long.parseLong(databaseVersionHeaderMatcher.group(3)); VectorClock vectorClock = createVectorClock(vectorClockString); DatabaseVersionHeader newDatabaseVersionHeader = new DatabaseVersionHeader(); newDatabaseVersionHeader.setDate(new Date(databaseVersionHeaderTime)); newDatabaseVersionHeader.setVectorClock(vectorClock); newDatabaseVersionHeader.setClient(client); return newDatabaseVersionHeader; }
private void pruneConflictingLocalBranch(Branch winnersBranch) throws Exception { Branch localPruneBranch = databaseReconciliator.findLosersPruneBranch(localBranch, winnersBranch); logger.log(Level.INFO, "- Database versions to REMOVE locally: " + localPruneBranch); if (localPruneBranch.size() == 0) { logger.log(Level.INFO, " + Nothing to prune locally. No conflicts. Only updates. Nice!"); } else { // Load dirty database (if existent) logger.log(Level.INFO, " + Pruning databases locally ..."); Database dirtyDatabase = new Database(); for (DatabaseVersionHeader databaseVersionHeader : localPruneBranch.getAll()) { // Database version DatabaseVersion databaseVersion = localDatabase.getDatabaseVersion(databaseVersionHeader.getVectorClock()); dirtyDatabase.addDatabaseVersion(databaseVersion); // Remove database version locally logger.log(Level.INFO, " * Removing " + databaseVersionHeader + " ..."); localDatabase.removeDatabaseVersion(databaseVersion); DatabaseRemoteFile remoteFileToPrune = new DatabaseRemoteFile( "db-" + config.getMachineName() + "-" + databaseVersionHeader.getVectorClock().get(config.getMachineName())); logger.log(Level.INFO, " * Deleting remote database file " + remoteFileToPrune + " ..."); transferManager.delete(remoteFileToPrune); } logger.log( Level.INFO, " * Saving dirty database to " + config.getDirtyDatabaseFile() + " ..."); saveLocalDatabase(dirtyDatabase, config.getDirtyDatabaseFile()); } }
public static DatabaseVersion createDatabaseVersion( DatabaseVersionHeader basedOnDatabaseVersionHeader, Date date) { VectorClock vectorClock = (basedOnDatabaseVersionHeader != null) ? basedOnDatabaseVersionHeader.getVectorClock().clone() : new VectorClock(); vectorClock.incrementClock("someclient"); DatabaseVersion databaseVersion = new DatabaseVersion(); databaseVersion.setClient("someclient"); databaseVersion.setTimestamp(date); databaseVersion.setVectorClock(vectorClock); return databaseVersion; }