package org.ovirt.engine.core.utils.archivers.tar; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import org.ovirt.engine.core.common.config.Config; import org.ovirt.engine.core.common.config.ConfigValues; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Handles cache tar file based on directory. * * Cache tar based on directory structure. If files are changed * recreate tar file. Test file change once per interval. */ public class CachedTar { private static final Logger log = LoggerFactory.getLogger(CachedTar.class); private long refreshInterval = 10000; private long nextCheckTime = 0; private File archive; private File dir; private void create() throws IOException { // must create within same directory // so rename be atomic File temp = File.createTempFile( this.archive.getName(), "tmp", this.archive.getParentFile() ); try { try (OutputStream os = new FileOutputStream(temp)) { Tar.doTar(os, this.dir); } catch(IOException e) { throw new IOException(String.format("Cannot create tarball '%1$s'", this.archive), e); } if (!temp.renameTo(this.archive)) { throw new IOException( String.format( "Cannot rename '%1$s' to '%2$s'", temp.getCanonicalPath(), archive.getCanonicalPath() ) ); } temp = null; } catch(IOException e) { log.error("Exception", e); throw e; } finally { if (temp != null && !temp.delete()) { log.error("Cannot delete '{}'", temp.getAbsolutePath()); } } } private void ensure() throws IOException { if (!this.archive.exists() || this.nextCheckTime <= System.currentTimeMillis()) { log.info( "Tarball '{}' refresh", this.archive.getAbsolutePath() ); this.nextCheckTime = System.currentTimeMillis() + this.refreshInterval; create(); } } /** * Constructor. * @param archive name of tar to cache. * @param dir base directory. */ public CachedTar(File archive, File dir) { this.archive = archive; this.dir = dir; this.refreshInterval = Config.<Integer>getValue( ConfigValues.BootstrapCacheRefreshInterval ); } /** * Get file of archive, without enforcing cache. * This should be used only if file is not to be accessed (messages). * @return File name. */ public File getFileNoUse() { return this.archive; } /** * Get file of archive. * @return File name. */ public File getFile() throws IOException { ensure(); return this.archive; } }