package voldemort.server.protocol.admin; import java.io.File; import org.apache.log4j.Logger; import voldemort.VoldemortException; import voldemort.store.metadata.MetadataStore; import voldemort.store.readonly.FileFetcher; import voldemort.store.readonly.ReadOnlyStorageEngine; import voldemort.utils.Utils; public class ReadOnlyStoreFetchOperation extends AsyncOperation { enum State { WAITING, RUNNING, STOPPING, COMPLETED; } private final static Logger logger = Logger.getLogger(ReadOnlyStoreFetchOperation.class); private final FileFetcher fileFetcher; private final String fetchUrl; private final MetadataStore metadataStore; private final String storeName; private final long pushVersion; private final ReadOnlyStorageEngine store; private final long startTime = System.currentTimeMillis(); private final Long diskQuotaSizeInKB; private State currentState; public ReadOnlyStoreFetchOperation(int id, MetadataStore metadataStore, ReadOnlyStorageEngine store, FileFetcher fileFetcher, String storeName, String fetchUrl, long pushVersion, Long diskQuotaSizeInKB) { super(id, "Fetch store '" + storeName + "' v" + pushVersion); this.metadataStore = metadataStore; this.store = store; this.fileFetcher = fileFetcher; this.storeName = storeName; this.fetchUrl = fetchUrl; this.pushVersion = pushVersion; this.currentState = State.WAITING; this.diskQuotaSizeInKB = diskQuotaSizeInKB; updateStatus("Waiting in Queue"); } private String fetchDirPath = null; @Override public void markComplete() { if(fetchDirPath != null) status.setStatus(fetchDirPath); status.setComplete(true); } @Override public void operate() { this.currentState = State.RUNNING; File fetchDir = null; if(fileFetcher == null) { logger.warn("File fetcher class has not instantiated correctly. Assuming local file"); if(!Utils.isReadableDir(fetchUrl)) { throw new VoldemortException("Fetch url " + fetchUrl + " is not readable"); } fetchDir = new File(store.getStoreDirPath(), "version-" + Long.toString(pushVersion)); if(fetchDir.exists()) throw new VoldemortException("Version directory " + fetchDir.getAbsolutePath() + " already exists"); Utils.move(new File(fetchUrl), fetchDir); } else { logger.info("Started executing fetch of " + fetchUrl + " for RO store '" + storeName + "' version " + pushVersion); updateStatus("0 MB copied at 0 MB/sec - 0 % complete"); try { String destinationDir = store.getStoreDirPath() + File.separator + "version-" + Long.toString(pushVersion); fetchDir = fileFetcher.fetch(fetchUrl, destinationDir, status, storeName, pushVersion, metadataStore, diskQuotaSizeInKB); if(fetchDir == null) { String errorMessage = "File fetcher failed for " + fetchUrl + " and store '" + storeName + "' due to incorrect input path/checksum error"; updateStatus(errorMessage); logger.error(errorMessage); throw new VoldemortException(errorMessage); } else { String message = "Successfully executed fetch of " + fetchUrl + " for RO store '" + storeName + "'"; updateStatus(message); logger.info(message); } } catch(VoldemortException ve) { String errorMessage = "File fetcher failed for " + fetchUrl + " and store '" + storeName + "' Reason: \n" + ve.getMessage(); updateStatus(errorMessage); logger.error(errorMessage, ve); throw ve; } catch(Exception e) { throw new VoldemortException("Exception in Fetcher = " + e.getMessage(), e); } } fetchDirPath = fetchDir.getAbsolutePath(); } @Override public void stop() { this.currentState = State.STOPPING; status.setException(new AsyncOperationStoppedException("Fetcher interrupted")); } @Override public long getWaitTimeMs() { if(currentState == State.WAITING) { return System.currentTimeMillis() - startTime; } return 0L; } @Override public boolean isWaiting() { return currentState == State.WAITING; } }