/* * Copyright (c) 2013. Bump Technologies Inc. All Rights Reserved. */ package com.bumptech.glide.load.engine.cache; import android.util.Log; import com.bumptech.glide.disklrucache.DiskLruCache; import com.bumptech.glide.disklrucache.DiskLruCache.Value; import com.bumptech.glide.load.Key; import java.io.File; import java.io.IOException; /** * The default DiskCache implementation. There must be no more than one active instance for a given * directory at a time. * * @see #get(java.io.File, int) */ public class DiskLruCacheWrapper implements DiskCache { private static final String TAG = "DiskLruCacheWrapper"; private static final int APP_VERSION = 1; private static final int VALUE_COUNT = 1; private static DiskLruCacheWrapper wrapper = null; private final SafeKeyGenerator safeKeyGenerator; private final File directory; private final int maxSize; private final DiskCacheWriteLocker writeLocker = new DiskCacheWriteLocker(); private DiskLruCache diskLruCache; /** * Get a DiskCache in the given directory and size. If a disk cache has already been created with * a different directory and/or size, it will be returned instead and the new arguments will be * ignored. * * @param directory The directory for the disk cache * @param maxSize The max size for the disk cache * @return The new disk cache with the given arguments, or the current cache if one already exists */ public static synchronized DiskCache get(File directory, int maxSize) { // TODO calling twice with different arguments makes it return the cache for the same // directory, it's public! if (wrapper == null) { wrapper = new DiskLruCacheWrapper(directory, maxSize); } return wrapper; } protected DiskLruCacheWrapper(File directory, int maxSize) { this.directory = directory; this.maxSize = maxSize; this.safeKeyGenerator = new SafeKeyGenerator(); } private synchronized DiskLruCache getDiskCache() throws IOException { if (diskLruCache == null) { diskLruCache = DiskLruCache.open(directory, APP_VERSION, VALUE_COUNT, maxSize); } return diskLruCache; } @Override public File get(Key key) { String safeKey = safeKeyGenerator.getSafeKey(key); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Get: Obtained: " + safeKey + " for for Key: " + key); } File result = null; try { // It is possible that the there will be a put in between these two gets. If so that shouldn't // be a problem because we will always put the same value at the same key so our input streams // will still represent the same data. final DiskLruCache.Value value = getDiskCache().get(safeKey); if (value != null) { result = value.getFile(0); } } catch (IOException e) { if (Log.isLoggable(TAG, Log.WARN)) { Log.w(TAG, "Unable to get from disk cache", e); } } return result; } @Override public void put(Key key, Writer writer) { // We want to make sure that puts block so that data is available when put completes. We may // actually not write any data if we find that data is written by the time we acquire the lock. writeLocker.acquire(key); try { String safeKey = safeKeyGenerator.getSafeKey(key); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Put: Obtained: " + safeKey + " for for Key: " + key); } try { // We assume we only need to put once, so if data was written while we were trying to get // the lock, we can simply abort. DiskLruCache diskCache = getDiskCache(); Value current = diskCache.get(safeKey); if (current != null) { return; } DiskLruCache.Editor editor = diskCache.edit(safeKey); if (editor == null) { throw new IllegalStateException("Had two simultaneous puts for: " + safeKey); } try { File file = editor.getFile(0); if (writer.write(file)) { editor.commit(); } } finally { editor.abortUnlessCommitted(); } } catch (IOException e) { if (Log.isLoggable(TAG, Log.WARN)) { Log.w(TAG, "Unable to put to disk cache", e); } } } finally { writeLocker.release(key); } } @Override public void delete(Key key) { String safeKey = safeKeyGenerator.getSafeKey(key); try { getDiskCache().remove(safeKey); } catch (IOException e) { if (Log.isLoggable(TAG, Log.WARN)) { Log.w(TAG, "Unable to delete from disk cache", e); } } } @Override public synchronized void clear() { try { getDiskCache().delete(); resetDiskCache(); } catch (IOException e) { if (Log.isLoggable(TAG, Log.WARN)) { Log.w(TAG, "Unable to clear disk cache", e); } } } private synchronized void resetDiskCache() { diskLruCache = null; } }