public static CueballFilePath getCueballFilePathForVersion(
     DomainVersion version,
     DomainVersion currentVersion,
     String localPartitionRoot,
     String localPartitionRootCache,
     boolean isBase) {
   if (currentVersion != null && currentVersion.equals(version)) {
     // If version is current version, data is in root
     return new CueballFilePath(
         localPartitionRoot + "/" + Cueball.getName(version.getVersionNumber(), isBase));
   } else {
     // Otherwise, version must be in cache
     return new CueballFilePath(
         localPartitionRootCache + "/" + Cueball.getName(version.getVersionNumber(), isBase));
   }
 }
 @Override
 protected void fetchVersion(DomainVersion domainVersion, String fetchRoot) throws IOException {
   String fileToFetch = Cueball.getName(domainVersion);
   LOG.info(
       "Fetching from " + partitionRemoteFileOps + " file " + fileToFetch + " to " + fetchRoot);
   partitionRemoteFileOps.copyToLocalRoot(fileToFetch, fetchRoot);
 }
 @Override
 protected Integer detectCurrentVersionNumber() throws IOException {
   SortedSet<CueballFilePath> localBases = Cueball.getBases(localPartitionRoot);
   if (localBases.size() > 0) {
     return localBases.last().getVersion();
   } else {
     return null;
   }
 }
 @Override
 protected Set<DomainVersion> detectCachedDeltasCore() throws IOException {
   return detectCachedVersions(Cueball.getDeltas(localPartitionRootCache));
 }
 public static boolean isEmptyVersion(
     PartitionRemoteFileOps partitionRemoteFileOps, DomainVersion domainVersion)
     throws IOException {
   return !partitionRemoteFileOps.exists(Cueball.getName(domainVersion.getVersionNumber(), true))
       && !partitionRemoteFileOps.exists(Cueball.getName(domainVersion.getVersionNumber(), false));
 }
  public static void runUpdateCore(
      DomainVersion currentVersion,
      DomainVersion updatingToVersion,
      IncrementalUpdatePlan updatePlan,
      String updateWorkRoot,
      String localPartitionRoot,
      String localPartitionRootCache,
      ICueballMerger cueballMerger,
      int keyHashSize,
      int valueSize,
      int hashIndexBits,
      CueballCompressionCodec compressionCodec,
      ValueTransformer valueTransformer,
      PartitionUpdateTaskStatistics statistics)
      throws IOException {

    // Determine new base path
    String newBasePath =
        updateWorkRoot + "/" + Cueball.getName(updatingToVersion.getVersionNumber(), true);

    // Determine files from versions
    CueballFilePath base =
        getCueballFilePathForVersion(
            updatePlan.getBase(),
            currentVersion,
            localPartitionRoot,
            localPartitionRootCache,
            true);
    List<CueballFilePath> deltas = new ArrayList<CueballFilePath>();
    for (DomainVersion delta : updatePlan.getDeltasOrdered()) {
      deltas.add(
          getCueballFilePathForVersion(
              delta, currentVersion, localPartitionRoot, localPartitionRootCache, false));
    }

    // Check that all required files are available
    checkRequiredFileExists(base.getPath());
    for (CueballFilePath delta : deltas) {
      checkRequiredFileExists(delta.getPath());
    }

    HankTimer timer = new HankTimer();
    // If there are no deltas, simply move the required base to the target version.
    // Otherwise, perform merging.
    if (deltas.size() == 0) {
      if (!new File(base.getPath()).renameTo(new File(newBasePath))) {
        throw new IOException(
            "Failed to rename Cueball base: " + base.getPath() + " to: " + newBasePath);
      }
    } else {
      cueballMerger.merge(
          base,
          deltas,
          newBasePath,
          keyHashSize,
          valueSize,
          valueTransformer,
          hashIndexBits,
          compressionCodec);
    }
    statistics.getDurationsMs().put("Cueball merge", timer.getDurationMs());
  }