package com.emc.ecs.sync; import com.emc.ecs.sync.config.SyncOptions; import com.emc.ecs.sync.model.SyncObject; import com.emc.ecs.sync.util.EnhancedThreadPoolExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingDeque; public class Md5Verifier implements SyncVerifier { private static final Logger log = LoggerFactory.getLogger(Md5Verifier.class); private ExecutorService executor; public Md5Verifier(SyncOptions syncOptions) { executor = new EnhancedThreadPoolExecutor(syncOptions.getThreadCount() * 2, new LinkedBlockingDeque<Runnable>(), "verify-pool"); } @Override public void verify(final SyncObject sourceObject, final SyncObject targetObject) { // this implementation only verifies data objects if (sourceObject.getMetadata().isDirectory()) { if (!targetObject.getMetadata().isDirectory()) throw new RuntimeException("source is directory; target is not"); } else { if (targetObject.getMetadata().isDirectory()) throw new RuntimeException("source is data object; target is directory"); // thread the streams for efficiency (in case of verify-only) Future<String> futureSourceMd5 = executor.submit(new Callable<String>() { @Override public String call() throws Exception { return sourceObject.getMd5Hex(true); } }); Future<String> futureTargetMd5 = executor.submit(new Callable<String>() { @Override public String call() throws Exception { return targetObject.getMd5Hex(true); } }); try { String sourceMd5 = futureSourceMd5.get(), targetMd5 = futureTargetMd5.get(); if (!sourceMd5.equals(targetMd5)) throw new RuntimeException(String.format("MD5 sum mismatch (%s != %s)", sourceMd5, targetMd5)); else log.debug("MD5 sum verified ({} == {})", sourceMd5, targetMd5); } catch (Exception e) { if (e instanceof RuntimeException) throw (RuntimeException) e; throw new RuntimeException(e); } } } @Override public void close() throws Exception { List<Runnable> tasks = executor.shutdownNow(); if (!tasks.isEmpty()) log.warn(tasks.size() + " verification tasks still running when closed"); } }