Example #1
0
  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;
  }
Example #2
0
  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);
    }
  }
Example #3
0
  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());
    }
  }
Example #4
0
  private Branches readUnknownDatabaseVersionHeaders(List<File> remoteDatabases)
      throws IOException {
    logger.log(Level.INFO, "Loading database headers, creating branches ...");
    // Sort files (db-a-1 must be before db-a-2 !)
    Collections.sort(
        remoteDatabases); // TODO [medium] natural sort is a workaround, database file names should
    // be centrally managed, db-name-0000000009 avoids natural sort

    // Read database files
    Branches unknownRemoteBranches = new Branches();
    DatabaseDAO dbDAO = new XmlDatabaseDAO(config.getTransformer());

    for (File remoteDatabaseFileInCache : remoteDatabases) {
      Database remoteDatabase =
          new Database(); // Database cannot be reused, since these might be different clients

      RemoteDatabaseFile remoteDatabaseFile = new RemoteDatabaseFile(remoteDatabaseFileInCache);
      dbDAO.load(
          remoteDatabase,
          remoteDatabaseFile
              .getFile()); // TODO [medium] Performance: This is very, very, very inefficient, DB is
      // loaded and then discarded
      List<DatabaseVersion> remoteDatabaseVersions = remoteDatabase.getDatabaseVersions();

      // Populate branches
      Branch remoteClientBranch =
          unknownRemoteBranches.getBranch(remoteDatabaseFile.getClientName(), true);

      for (DatabaseVersion remoteDatabaseVersion : remoteDatabaseVersions) {
        DatabaseVersionHeader header = remoteDatabaseVersion.getHeader();
        remoteClientBranch.add(header);
      }
    }

    return unknownRemoteBranches;
  }