/** * Copyright 2011 LiveRamp * * 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. */ package com.liveramp.hank.storage.curly; import com.liveramp.hank.coordinator.Domain; import com.liveramp.hank.coordinator.DomainVersion; import com.liveramp.hank.partition_server.PartitionUpdateTaskStatistics; import com.liveramp.hank.storage.Compactor; import com.liveramp.hank.storage.PartitionRemoteFileOps; import com.liveramp.hank.storage.Writer; import com.liveramp.hank.storage.cueball.CueballFilePath; import com.liveramp.hank.storage.cueball.CueballPartitionUpdater; import com.liveramp.hank.storage.cueball.ICueballStreamBufferMergeSortFactory; import com.liveramp.hank.storage.cueball.IKeyFileStreamBufferMergeSort; import com.liveramp.hank.storage.incremental.IncrementalUpdatePlan; import com.liveramp.hank.util.HankTimer; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class CurlyCompactor extends AbstractCurlyPartitionUpdater implements Compactor { private final ICurlyCompactingMerger merger; private final ICueballStreamBufferMergeSortFactory cueballStreamBufferMergeSortFactory; private final ICurlyReaderFactory curlyReaderFactory; private Writer writer; public CurlyCompactor(Domain domain, PartitionRemoteFileOps partitionRemoteFileOps, String localPartitionRoot, ICurlyCompactingMerger merger, ICueballStreamBufferMergeSortFactory cueballStreamBufferMergeSortFactory, ICurlyReaderFactory curlyReaderFactory) throws IOException { super(domain, partitionRemoteFileOps, localPartitionRoot); this.merger = merger; this.cueballStreamBufferMergeSortFactory = cueballStreamBufferMergeSortFactory; this.curlyReaderFactory = curlyReaderFactory; } @Override public void compact(DomainVersion versionToCompact, Writer writer) throws IOException { this.writer = writer; this.updateTo(versionToCompact, new PartitionUpdateTaskStatistics()); } @Override protected boolean shouldFetchCurlyVersion(DomainVersion version) throws IOException { // The CurlyCompactor needs all versions of curly return true; } @Override protected void runUpdateCore(DomainVersion currentVersion, DomainVersion updatingToVersion, IncrementalUpdatePlan updatePlan, String updateWorkRoot, PartitionUpdateTaskStatistics statistics) throws IOException { // Prepare Curly // Determine files from versions CurlyFilePath curlyBasePath = getCurlyFilePathForVersion(updatePlan.getBase(), currentVersion, true); List<CurlyFilePath> curlyDeltas = new ArrayList<CurlyFilePath>(); for (DomainVersion curlyDeltaVersion : updatePlan.getDeltasOrdered()) { curlyDeltas.add(getCurlyFilePathForVersion(curlyDeltaVersion, currentVersion, false)); } // Check that all required files are available CueballPartitionUpdater.checkRequiredFileExists(curlyBasePath.getPath()); for (CurlyFilePath curlyDelta : curlyDeltas) { CueballPartitionUpdater.checkRequiredFileExists(curlyDelta.getPath()); } // Prepare Cueball // Determine files from versions CueballFilePath cueballBasePath = CueballPartitionUpdater.getCueballFilePathForVersion(updatePlan.getBase(), currentVersion, localPartitionRoot, localPartitionRootCache, true); List<CueballFilePath> cueballDeltas = new ArrayList<CueballFilePath>(); for (DomainVersion cueballDelta : updatePlan.getDeltasOrdered()) { // Only add to the delta list if the version is not empty if (!CueballPartitionUpdater.isEmptyVersion(partitionRemoteFileOps, cueballDelta)) { cueballDeltas.add(CueballPartitionUpdater.getCueballFilePathForVersion(cueballDelta, currentVersion, localPartitionRoot, localPartitionRootCache, false)); } } // Check that all required files are available CueballPartitionUpdater.checkRequiredFileExists(cueballBasePath.getPath()); for (CueballFilePath cueballDelta : cueballDeltas) { CueballPartitionUpdater.checkRequiredFileExists(cueballDelta.getPath()); } // Note: the writer used to perform the compaction must not hash the passed-in key because // it will directly receive key hashes. This is because the actual key is unknown when compacting. IKeyFileStreamBufferMergeSort cueballStreamBufferMergeSort = cueballStreamBufferMergeSortFactory.getInstance(cueballBasePath, cueballDeltas); HankTimer timer = new HankTimer(); merger.merge(curlyBasePath, curlyDeltas, cueballStreamBufferMergeSort, curlyReaderFactory, writer); statistics.getDurationsMs().put("Curly compaction", timer.getDurationMs()); } }