1a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas/* 2a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Copyright (C) 2011 The Android Open Source Project 3a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * 4a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Licensed under the Apache License, Version 2.0 (the "License"); 5a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * you may not use this file except in compliance with the License. 6a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * You may obtain a copy of the License at 7a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * 8a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * http://www.apache.org/licenses/LICENSE-2.0 9a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * 10a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Unless required by applicable law or agreed to in writing, software 11a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * distributed under the License is distributed on an "AS IS" BASIS, 12a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * See the License for the specific language governing permissions and 14a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * limitations under the License. 15a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 16a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 17a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucaspackage com.example.android.displayingbitmaps.util; 18a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 19a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.io.BufferedInputStream; 20a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.io.BufferedWriter; 21a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.io.Closeable; 22a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.io.EOFException; 23a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.io.File; 24a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.io.FileInputStream; 25a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.io.FileNotFoundException; 26a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.io.FileOutputStream; 27a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.io.FileWriter; 28a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.io.FilterOutputStream; 29a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.io.IOException; 30a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.io.InputStream; 31a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.io.InputStreamReader; 32a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.io.OutputStream; 33a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.io.OutputStreamWriter; 34a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.io.Reader; 35a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.io.StringWriter; 36a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.io.Writer; 37a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.lang.reflect.Array; 38a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.nio.charset.Charset; 39a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.util.ArrayList; 40a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.util.Arrays; 41a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.util.Iterator; 42a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.util.LinkedHashMap; 43a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.util.Map; 44a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.util.concurrent.Callable; 45a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.util.concurrent.ExecutorService; 46a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.util.concurrent.LinkedBlockingQueue; 47a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.util.concurrent.ThreadPoolExecutor; 48a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucasimport java.util.concurrent.TimeUnit; 49a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 50a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas/** 51a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas ****************************************************************************** 52a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Taken from the JB source code, can be found in: 53a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * libcore/luni/src/main/java/libcore/io/DiskLruCache.java 54a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * or direct link: 55a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * https://android.googlesource.com/platform/libcore/+/android-4.1.1_r1/luni/src/main/java/libcore/io/DiskLruCache.java 56a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas ****************************************************************************** 57a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * 58a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * A cache that uses a bounded amount of space on a filesystem. Each cache 59a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * entry has a string key and a fixed number of values. Values are byte 60a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * sequences, accessible as streams or files. Each value must be between {@code 61a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * 0} and {@code Integer.MAX_VALUE} bytes in length. 62a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * 63a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * <p>The cache stores its data in a directory on the filesystem. This 64a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * directory must be exclusive to the cache; the cache may delete or overwrite 65a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * files from its directory. It is an error for multiple processes to use the 66a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * same cache directory at the same time. 67a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * 68a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * <p>This cache limits the number of bytes that it will store on the 69a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * filesystem. When the number of stored bytes exceeds the limit, the cache will 70a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * remove entries in the background until the limit is satisfied. The limit is 71a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * not strict: the cache may temporarily exceed it while waiting for files to be 72a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * deleted. The limit does not include filesystem overhead or the cache 73a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * journal so space-sensitive applications should set a conservative limit. 74a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * 75a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * <p>Clients call {@link #edit} to create or update the values of an entry. An 76a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * entry may have only one editor at one time; if a value is not available to be 77a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * edited then {@link #edit} will return null. 78a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * <ul> 79a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * <li>When an entry is being <strong>created</strong> it is necessary to 80a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * supply a full set of values; the empty value should be used as a 81a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * placeholder if necessary. 82a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * <li>When an entry is being <strong>edited</strong>, it is not necessary 83a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * to supply data for every value; values default to their previous 84a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * value. 85a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * </ul> 86a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Every {@link #edit} call must be matched by a call to {@link Editor#commit} 87a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * or {@link Editor#abort}. Committing is atomic: a read observes the full set 88a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * of values as they were before or after the commit, but never a mix of values. 89a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * 90a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * <p>Clients call {@link #get} to read a snapshot of an entry. The read will 91a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * observe the value at the time that {@link #get} was called. Updates and 92a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * removals after the call do not impact ongoing reads. 93a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * 94a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * <p>This class is tolerant of some I/O errors. If files are missing from the 95a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * filesystem, the corresponding entries will be dropped from the cache. If 96a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * an error occurs while writing a cache value, the edit will fail silently. 97a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Callers should handle other problems by catching {@code IOException} and 98a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * responding appropriately. 99a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 100a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucaspublic final class DiskLruCache implements Closeable { 101a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas static final String JOURNAL_FILE = "journal"; 102a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas static final String JOURNAL_FILE_TMP = "journal.tmp"; 103a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas static final String MAGIC = "libcore.io.DiskLruCache"; 104a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas static final String VERSION_1 = "1"; 105a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas static final long ANY_SEQUENCE_NUMBER = -1; 106a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private static final String CLEAN = "CLEAN"; 107a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private static final String DIRTY = "DIRTY"; 108a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private static final String REMOVE = "REMOVE"; 109a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private static final String READ = "READ"; 110a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 111a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private static final Charset UTF_8 = Charset.forName("UTF-8"); 112a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private static final int IO_BUFFER_SIZE = 8 * 1024; 113a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 114a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /* 115a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * This cache uses a journal file named "journal". A typical journal file 116a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * looks like this: 117a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * libcore.io.DiskLruCache 118a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * 1 119a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * 100 120a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * 2 121a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * 122a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054 123a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * DIRTY 335c4c6028171cfddfbaae1a9c313c52 124a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342 125a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * REMOVE 335c4c6028171cfddfbaae1a9c313c52 126a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * DIRTY 1ab96a171faeeee38496d8b330771a7a 127a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234 128a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * READ 335c4c6028171cfddfbaae1a9c313c52 129a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * READ 3400330d1dfc7f3f7f4b8d4d803dfcf6 130a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * 131a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * The first five lines of the journal form its header. They are the 132a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * constant string "libcore.io.DiskLruCache", the disk cache's version, 133a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * the application's version, the value count, and a blank line. 134a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * 135a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Each of the subsequent lines in the file is a record of the state of a 136a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * cache entry. Each line contains space-separated values: a state, a key, 137a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * and optional state-specific values. 138a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * o DIRTY lines track that an entry is actively being created or updated. 139a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Every successful DIRTY action should be followed by a CLEAN or REMOVE 140a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * action. DIRTY lines without a matching CLEAN or REMOVE indicate that 141a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * temporary files may need to be deleted. 142a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * o CLEAN lines track a cache entry that has been successfully published 143a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * and may be read. A publish line is followed by the lengths of each of 144a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * its values. 145a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * o READ lines track accesses for LRU. 146a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * o REMOVE lines track entries that have been deleted. 147a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * 148a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * The journal file is appended to as cache operations occur. The journal may 149a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * occasionally be compacted by dropping redundant lines. A temporary file named 150a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * "journal.tmp" will be used during compaction; that file should be deleted if 151a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * it exists when the cache is opened. 152a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 153a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 154a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private final File directory; 155a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private final File journalFile; 156a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private final File journalFileTmp; 157a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private final int appVersion; 158a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private final long maxSize; 159a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private final int valueCount; 160a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private long size = 0; 161a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private Writer journalWriter; 162a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private final LinkedHashMap<String, Entry> lruEntries 163a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas = new LinkedHashMap<String, Entry>(0, 0.75f, true); 164a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private int redundantOpCount; 165a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 166a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 167a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * To differentiate between old and current snapshots, each entry is given 168a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * a sequence number each time an edit is committed. A snapshot is stale if 169a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * its sequence number is not equal to its entry's sequence number. 170a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 171a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private long nextSequenceNumber = 0; 172a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 173a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /* From java.util.Arrays */ 174a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas @SuppressWarnings("unchecked") 175a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private static <T> T[] copyOfRange(T[] original, int start, int end) { 176a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas final int originalLength = original.length; // For exception priority compatibility. 177a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (start > end) { 178a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw new IllegalArgumentException(); 179a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 180a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (start < 0 || start > originalLength) { 181a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw new ArrayIndexOutOfBoundsException(); 182a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 183a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas final int resultLength = end - start; 184a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas final int copyLength = Math.min(resultLength, originalLength - start); 185a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas final T[] result = (T[]) Array 186a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas .newInstance(original.getClass().getComponentType(), resultLength); 187a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas System.arraycopy(original, start, result, 0, copyLength); 188a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return result; 189a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 190a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 191a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 192a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Returns the remainder of 'reader' as a string, closing it when done. 193a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 194a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public static String readFully(Reader reader) throws IOException { 195a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas try { 196a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas StringWriter writer = new StringWriter(); 197a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas char[] buffer = new char[1024]; 198a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas int count; 199a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas while ((count = reader.read(buffer)) != -1) { 200a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas writer.write(buffer, 0, count); 201a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 202a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return writer.toString(); 203a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } finally { 204a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas reader.close(); 205a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 206a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 207a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 208a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 209a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Returns the ASCII characters up to but not including the next "\r\n", or 210a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * "\n". 211a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * 212a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * @throws java.io.EOFException if the stream is exhausted before the next newline 213a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * character. 214a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 215a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public static String readAsciiLine(InputStream in) throws IOException { 216a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas // TODO: support UTF-8 here instead 217a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 218a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas StringBuilder result = new StringBuilder(80); 219a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas while (true) { 220a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas int c = in.read(); 221a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (c == -1) { 222a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw new EOFException(); 223a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } else if (c == '\n') { 224a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas break; 225a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 226a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 227a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas result.append((char) c); 228a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 229a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas int length = result.length(); 230a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (length > 0 && result.charAt(length - 1) == '\r') { 231a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas result.setLength(length - 1); 232a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 233a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return result.toString(); 234a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 235a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 236a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 237a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null. 238a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 239a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public static void closeQuietly(Closeable closeable) { 240a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (closeable != null) { 241a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas try { 242a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas closeable.close(); 243a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } catch (RuntimeException rethrown) { 244a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw rethrown; 245a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } catch (Exception ignored) { 246a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 247a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 248a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 249a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 250a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 251a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Recursively delete everything in {@code dir}. 252a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 253a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas // TODO: this should specify paths as Strings rather than as Files 254a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public static void deleteContents(File dir) throws IOException { 255a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas File[] files = dir.listFiles(); 256a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (files == null) { 257a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw new IllegalArgumentException("not a directory: " + dir); 258a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 259a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas for (File file : files) { 260a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (file.isDirectory()) { 261a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas deleteContents(file); 262a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 263a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (!file.delete()) { 264a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw new IOException("failed to delete file: " + file); 265a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 266a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 267a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 268a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 269a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** This cache uses a single background thread to evict entries. */ 270a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private final ExecutorService executorService = new ThreadPoolExecutor(0, 1, 271a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); 272a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private final Callable<Void> cleanupCallable = new Callable<Void>() { 273a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas @Override public Void call() throws Exception { 274a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas synchronized (DiskLruCache.this) { 275a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (journalWriter == null) { 276a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return null; // closed 277a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 278a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas trimToSize(); 279a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (journalRebuildRequired()) { 280a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas rebuildJournal(); 281a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas redundantOpCount = 0; 282a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 283a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 284a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return null; 285a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 286a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas }; 287a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 288a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) { 289a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas this.directory = directory; 290a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas this.appVersion = appVersion; 291a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas this.journalFile = new File(directory, JOURNAL_FILE); 292a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas this.journalFileTmp = new File(directory, JOURNAL_FILE_TMP); 293a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas this.valueCount = valueCount; 294a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas this.maxSize = maxSize; 295a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 296a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 297a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 298a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Opens the cache in {@code directory}, creating a cache if none exists 299a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * there. 300a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * 301a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * @param directory a writable directory 302a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * @param appVersion 303a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * @param valueCount the number of values per cache entry. Must be positive. 304a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * @param maxSize the maximum number of bytes this cache should use to store 305a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * @throws java.io.IOException if reading or writing the cache directory fails 306a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 307a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize) 308a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throws IOException { 309a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (maxSize <= 0) { 310a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw new IllegalArgumentException("maxSize <= 0"); 311a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 312a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (valueCount <= 0) { 313a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw new IllegalArgumentException("valueCount <= 0"); 314a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 315a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 316a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas // prefer to pick up where we left off 317a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); 318a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (cache.journalFile.exists()) { 319a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas try { 320a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas cache.readJournal(); 321a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas cache.processJournal(); 322a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas cache.journalWriter = new BufferedWriter(new FileWriter(cache.journalFile, true), 323a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas IO_BUFFER_SIZE); 324a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return cache; 325a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } catch (IOException journalIsCorrupt) { 326a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas// System.logW("DiskLruCache " + directory + " is corrupt: " 327a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas// + journalIsCorrupt.getMessage() + ", removing"); 328a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas cache.delete(); 329a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 330a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 331a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 332a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas // create a new empty cache 333a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas directory.mkdirs(); 334a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); 335a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas cache.rebuildJournal(); 336a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return cache; 337a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 338a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 339a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private void readJournal() throws IOException { 340a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas InputStream in = new BufferedInputStream(new FileInputStream(journalFile), IO_BUFFER_SIZE); 341a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas try { 342a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas String magic = readAsciiLine(in); 343a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas String version = readAsciiLine(in); 344a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas String appVersionString = readAsciiLine(in); 345a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas String valueCountString = readAsciiLine(in); 346a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas String blank = readAsciiLine(in); 347a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (!MAGIC.equals(magic) 348a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas || !VERSION_1.equals(version) 349a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas || !Integer.toString(appVersion).equals(appVersionString) 350a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas || !Integer.toString(valueCount).equals(valueCountString) 351a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas || !"".equals(blank)) { 352a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw new IOException("unexpected journal header: [" 353a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas + magic + ", " + version + ", " + valueCountString + ", " + blank + "]"); 354a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 355a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 356a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas while (true) { 357a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas try { 358a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas readJournalLine(readAsciiLine(in)); 359a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } catch (EOFException endOfJournal) { 360a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas break; 361a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 362a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 363a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } finally { 364a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas closeQuietly(in); 365a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 366a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 367a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 368a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private void readJournalLine(String line) throws IOException { 369a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas String[] parts = line.split(" "); 370a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (parts.length < 2) { 371a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw new IOException("unexpected journal line: " + line); 372a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 373a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 374a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas String key = parts[1]; 375a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (parts[0].equals(REMOVE) && parts.length == 2) { 376a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas lruEntries.remove(key); 377a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return; 378a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 379a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 380a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas Entry entry = lruEntries.get(key); 381a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (entry == null) { 382a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas entry = new Entry(key); 383a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas lruEntries.put(key, entry); 384a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 385a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 386a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (parts[0].equals(CLEAN) && parts.length == 2 + valueCount) { 387a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas entry.readable = true; 388a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas entry.currentEditor = null; 389a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas entry.setLengths(copyOfRange(parts, 2, parts.length)); 390a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } else if (parts[0].equals(DIRTY) && parts.length == 2) { 391a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas entry.currentEditor = new Editor(entry); 392a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } else if (parts[0].equals(READ) && parts.length == 2) { 393a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas // this work was already done by calling lruEntries.get() 394a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } else { 395a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw new IOException("unexpected journal line: " + line); 396a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 397a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 398a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 399a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 400a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Computes the initial size and collects garbage as a part of opening the 401a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * cache. Dirty entries are assumed to be inconsistent and will be deleted. 402a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 403a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private void processJournal() throws IOException { 404a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas deleteIfExists(journalFileTmp); 405a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas for (Iterator<Entry> i = lruEntries.values().iterator(); i.hasNext(); ) { 406a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas Entry entry = i.next(); 407a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (entry.currentEditor == null) { 408a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas for (int t = 0; t < valueCount; t++) { 409a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas size += entry.lengths[t]; 410a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 411a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } else { 412a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas entry.currentEditor = null; 413a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas for (int t = 0; t < valueCount; t++) { 414a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas deleteIfExists(entry.getCleanFile(t)); 415a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas deleteIfExists(entry.getDirtyFile(t)); 416a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 417a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas i.remove(); 418a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 419a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 420a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 421a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 422a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 423a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Creates a new journal that omits redundant information. This replaces the 424a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * current journal if it exists. 425a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 426a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private synchronized void rebuildJournal() throws IOException { 427a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (journalWriter != null) { 428a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas journalWriter.close(); 429a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 430a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 431a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas Writer writer = new BufferedWriter(new FileWriter(journalFileTmp), IO_BUFFER_SIZE); 432a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas writer.write(MAGIC); 433a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas writer.write("\n"); 434a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas writer.write(VERSION_1); 435a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas writer.write("\n"); 436a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas writer.write(Integer.toString(appVersion)); 437a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas writer.write("\n"); 438a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas writer.write(Integer.toString(valueCount)); 439a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas writer.write("\n"); 440a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas writer.write("\n"); 441a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 442a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas for (Entry entry : lruEntries.values()) { 443a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (entry.currentEditor != null) { 444a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas writer.write(DIRTY + ' ' + entry.key + '\n'); 445a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } else { 446a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas writer.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); 447a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 448a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 449a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 450a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas writer.close(); 451a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas journalFileTmp.renameTo(journalFile); 452a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas journalWriter = new BufferedWriter(new FileWriter(journalFile, true), IO_BUFFER_SIZE); 453a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 454a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 455a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private static void deleteIfExists(File file) throws IOException { 456a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas// try { 457a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas// Libcore.os.remove(file.getPath()); 458a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas// } catch (ErrnoException errnoException) { 459a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas// if (errnoException.errno != OsConstants.ENOENT) { 460a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas// throw errnoException.rethrowAsIOException(); 461a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas// } 462a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas// } 463a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (file.exists() && !file.delete()) { 464a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw new IOException(); 465a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 466a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 467a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 468a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 469a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Returns a snapshot of the entry named {@code key}, or null if it doesn't 470a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * exist is not currently readable. If a value is returned, it is moved to 471a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * the head of the LRU queue. 472a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 473a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public synchronized Snapshot get(String key) throws IOException { 474a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas checkNotClosed(); 475a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas validateKey(key); 476a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas Entry entry = lruEntries.get(key); 477a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (entry == null) { 478a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return null; 479a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 480a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 481a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (!entry.readable) { 482a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return null; 483a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 484a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 485a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /* 486a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Open all streams eagerly to guarantee that we see a single published 487a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * snapshot. If we opened streams lazily then the streams could come 488a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * from different edits. 489a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 490a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas InputStream[] ins = new InputStream[valueCount]; 491a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas try { 492a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas for (int i = 0; i < valueCount; i++) { 493a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas ins[i] = new FileInputStream(entry.getCleanFile(i)); 494a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 495a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } catch (FileNotFoundException e) { 496a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas // a file must have been deleted manually! 497a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return null; 498a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 499a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 500a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas redundantOpCount++; 501a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas journalWriter.append(READ + ' ' + key + '\n'); 502a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (journalRebuildRequired()) { 503a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas executorService.submit(cleanupCallable); 504a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 505a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 506a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return new Snapshot(key, entry.sequenceNumber, ins); 507a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 508a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 509a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 510a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Returns an editor for the entry named {@code key}, or null if another 511a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * edit is in progress. 512a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 513a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public Editor edit(String key) throws IOException { 514a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return edit(key, ANY_SEQUENCE_NUMBER); 515a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 516a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 517a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException { 518a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas checkNotClosed(); 519a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas validateKey(key); 520a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas Entry entry = lruEntries.get(key); 521a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER 522a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas && (entry == null || entry.sequenceNumber != expectedSequenceNumber)) { 523a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return null; // snapshot is stale 524a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 525a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (entry == null) { 526a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas entry = new Entry(key); 527a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas lruEntries.put(key, entry); 528a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } else if (entry.currentEditor != null) { 529a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return null; // another edit is in progress 530a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 531a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 532a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas Editor editor = new Editor(entry); 533a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas entry.currentEditor = editor; 534a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 535a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas // flush the journal before creating files to prevent file leaks 536a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas journalWriter.write(DIRTY + ' ' + key + '\n'); 537a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas journalWriter.flush(); 538a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return editor; 539a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 540a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 541a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 542a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Returns the directory where this cache stores its data. 543a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 544a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public File getDirectory() { 545a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return directory; 546a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 547a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 548a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 549a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Returns the maximum number of bytes that this cache should use to store 550a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * its data. 551a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 552a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public long maxSize() { 553a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return maxSize; 554a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 555a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 556a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 557a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Returns the number of bytes currently being used to store the values in 558a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * this cache. This may be greater than the max size if a background 559a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * deletion is pending. 560a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 561a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public synchronized long size() { 562a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return size; 563a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 564a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 565a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private synchronized void completeEdit(Editor editor, boolean success) throws IOException { 566a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas Entry entry = editor.entry; 567a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (entry.currentEditor != editor) { 568a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw new IllegalStateException(); 569a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 570a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 571a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas // if this edit is creating the entry for the first time, every index must have a value 572a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (success && !entry.readable) { 573a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas for (int i = 0; i < valueCount; i++) { 574a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (!entry.getDirtyFile(i).exists()) { 575a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas editor.abort(); 576a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw new IllegalStateException("edit didn't create file " + i); 577a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 578a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 579a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 580a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 581a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas for (int i = 0; i < valueCount; i++) { 582a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas File dirty = entry.getDirtyFile(i); 583a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (success) { 584a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (dirty.exists()) { 585a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas File clean = entry.getCleanFile(i); 586a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas dirty.renameTo(clean); 587a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas long oldLength = entry.lengths[i]; 588a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas long newLength = clean.length(); 589a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas entry.lengths[i] = newLength; 590a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas size = size - oldLength + newLength; 591a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 592a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } else { 593a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas deleteIfExists(dirty); 594a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 595a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 596a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 597a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas redundantOpCount++; 598a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas entry.currentEditor = null; 599a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (entry.readable | success) { 600a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas entry.readable = true; 601a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); 602a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (success) { 603a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas entry.sequenceNumber = nextSequenceNumber++; 604a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 605a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } else { 606a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas lruEntries.remove(entry.key); 607a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas journalWriter.write(REMOVE + ' ' + entry.key + '\n'); 608a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 609a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 610a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (size > maxSize || journalRebuildRequired()) { 611a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas executorService.submit(cleanupCallable); 612a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 613a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 614a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 615a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 616a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * We only rebuild the journal when it will halve the size of the journal 617a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * and eliminate at least 2000 ops. 618a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 619a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private boolean journalRebuildRequired() { 620a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas final int REDUNDANT_OP_COMPACT_THRESHOLD = 2000; 621a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return redundantOpCount >= REDUNDANT_OP_COMPACT_THRESHOLD 622a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas && redundantOpCount >= lruEntries.size(); 623a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 624a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 625a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 626a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Drops the entry for {@code key} if it exists and can be removed. Entries 627a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * actively being edited cannot be removed. 628a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * 629a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * @return true if an entry was removed. 630a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 631a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public synchronized boolean remove(String key) throws IOException { 632a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas checkNotClosed(); 633a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas validateKey(key); 634a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas Entry entry = lruEntries.get(key); 635a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (entry == null || entry.currentEditor != null) { 636a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return false; 637a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 638a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 639a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas for (int i = 0; i < valueCount; i++) { 640a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas File file = entry.getCleanFile(i); 641a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (!file.delete()) { 642a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw new IOException("failed to delete " + file); 643a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 644a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas size -= entry.lengths[i]; 645a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas entry.lengths[i] = 0; 646a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 647a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 648a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas redundantOpCount++; 649a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas journalWriter.append(REMOVE + ' ' + key + '\n'); 650a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas lruEntries.remove(key); 651a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 652a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (journalRebuildRequired()) { 653a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas executorService.submit(cleanupCallable); 654a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 655a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 656a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return true; 657a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 658a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 659a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 660a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Returns true if this cache has been closed. 661a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 662a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public boolean isClosed() { 663a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return journalWriter == null; 664a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 665a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 666a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private void checkNotClosed() { 667a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (journalWriter == null) { 668a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw new IllegalStateException("cache is closed"); 669a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 670a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 671a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 672a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 673a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Force buffered operations to the filesystem. 674a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 675a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public synchronized void flush() throws IOException { 676a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas checkNotClosed(); 677a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas trimToSize(); 678a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas journalWriter.flush(); 679a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 680a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 681a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 682a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Closes this cache. Stored values will remain on the filesystem. 683a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 684a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public synchronized void close() throws IOException { 685a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (journalWriter == null) { 686a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return; // already closed 687a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 688a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas for (Entry entry : new ArrayList<Entry>(lruEntries.values())) { 689a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (entry.currentEditor != null) { 690a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas entry.currentEditor.abort(); 691a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 692a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 693a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas trimToSize(); 694a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas journalWriter.close(); 695a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas journalWriter = null; 696a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 697a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 698a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private void trimToSize() throws IOException { 699a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas while (size > maxSize) { 700a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas// Map.Entry<String, Entry> toEvict = lruEntries.eldest(); 701a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas final Map.Entry<String, Entry> toEvict = lruEntries.entrySet().iterator().next(); 702a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas remove(toEvict.getKey()); 703a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 704a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 705a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 706a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 707a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Closes the cache and deletes all of its stored values. This will delete 708a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * all files in the cache directory including files that weren't created by 709a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * the cache. 710a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 711a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public void delete() throws IOException { 712a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas close(); 713a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas deleteContents(directory); 714a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 715a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 716a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private void validateKey(String key) { 717a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (key.contains(" ") || key.contains("\n") || key.contains("\r")) { 718a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw new IllegalArgumentException( 719a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas "keys must not contain spaces or newlines: \"" + key + "\""); 720a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 721a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 722a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 723a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private static String inputStreamToString(InputStream in) throws IOException { 724a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return readFully(new InputStreamReader(in, UTF_8)); 725a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 726a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 727a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 728a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * A snapshot of the values for an entry. 729a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 730a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public final class Snapshot implements Closeable { 731a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private final String key; 732a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private final long sequenceNumber; 733a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private final InputStream[] ins; 734a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 735a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private Snapshot(String key, long sequenceNumber, InputStream[] ins) { 736a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas this.key = key; 737a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas this.sequenceNumber = sequenceNumber; 738a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas this.ins = ins; 739a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 740a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 741a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 742a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Returns an editor for this snapshot's entry, or null if either the 743a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * entry has changed since this snapshot was created or if another edit 744a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * is in progress. 745a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 746a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public Editor edit() throws IOException { 747a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return DiskLruCache.this.edit(key, sequenceNumber); 748a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 749a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 750a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 751a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Returns the unbuffered stream with the value for {@code index}. 752a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 753a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public InputStream getInputStream(int index) { 754a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return ins[index]; 755a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 756a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 757a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 758a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Returns the string value for {@code index}. 759a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 760a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public String getString(int index) throws IOException { 761a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return inputStreamToString(getInputStream(index)); 762a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 763a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 764a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas @Override public void close() { 765a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas for (InputStream in : ins) { 766a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas closeQuietly(in); 767a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 768a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 769a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 770a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 771a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 772a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Edits the values for an entry. 773a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 774a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public final class Editor { 775a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private final Entry entry; 776a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private boolean hasErrors; 777a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 778a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private Editor(Entry entry) { 779a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas this.entry = entry; 780a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 781a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 782a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 783a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Returns an unbuffered input stream to read the last committed value, 784a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * or null if no value has been committed. 785a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 786a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public InputStream newInputStream(int index) throws IOException { 787a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas synchronized (DiskLruCache.this) { 788a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (entry.currentEditor != this) { 789a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw new IllegalStateException(); 790a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 791a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (!entry.readable) { 792a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return null; 793a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 794a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return new FileInputStream(entry.getCleanFile(index)); 795a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 796a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 797a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 798a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 799a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Returns the last committed value as a string, or null if no value 800a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * has been committed. 801a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 802a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public String getString(int index) throws IOException { 803a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas InputStream in = newInputStream(index); 804a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return in != null ? inputStreamToString(in) : null; 805a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 806a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 807a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 808a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Returns a new unbuffered output stream to write the value at 809a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * {@code index}. If the underlying output stream encounters errors 810a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * when writing to the filesystem, this edit will be aborted when 811a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * {@link #commit} is called. The returned output stream does not throw 812a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * IOExceptions. 813a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 814a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public OutputStream newOutputStream(int index) throws IOException { 815a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas synchronized (DiskLruCache.this) { 816a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (entry.currentEditor != this) { 817a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw new IllegalStateException(); 818a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 819a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return new FaultHidingOutputStream(new FileOutputStream(entry.getDirtyFile(index))); 820a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 821a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 822a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 823a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 824a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Sets the value at {@code index} to {@code value}. 825a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 826a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public void set(int index, String value) throws IOException { 827a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas Writer writer = null; 828a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas try { 829a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas writer = new OutputStreamWriter(newOutputStream(index), UTF_8); 830a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas writer.write(value); 831a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } finally { 832a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas closeQuietly(writer); 833a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 834a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 835a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 836a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 837a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Commits this edit so it is visible to readers. This releases the 838a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * edit lock so another edit may be started on the same key. 839a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 840a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public void commit() throws IOException { 841a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (hasErrors) { 842a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas completeEdit(this, false); 843a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas remove(entry.key); // the previous entry is stale 844a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } else { 845a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas completeEdit(this, true); 846a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 847a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 848a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 849a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 850a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Aborts this edit. This releases the edit lock so another edit may be 851a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * started on the same key. 852a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 853a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public void abort() throws IOException { 854a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas completeEdit(this, false); 855a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 856a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 857a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private class FaultHidingOutputStream extends FilterOutputStream { 858a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private FaultHidingOutputStream(OutputStream out) { 859a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas super(out); 860a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 861a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 862a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas @Override public void write(int oneByte) { 863a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas try { 864a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas out.write(oneByte); 865a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } catch (IOException e) { 866a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas hasErrors = true; 867a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 868a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 869a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 870a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas @Override public void write(byte[] buffer, int offset, int length) { 871a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas try { 872a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas out.write(buffer, offset, length); 873a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } catch (IOException e) { 874a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas hasErrors = true; 875a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 876a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 877a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 878a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas @Override public void close() { 879a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas try { 880a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas out.close(); 881a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } catch (IOException e) { 882a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas hasErrors = true; 883a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 884a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 885a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 886a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas @Override public void flush() { 887a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas try { 888a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas out.flush(); 889a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } catch (IOException e) { 890a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas hasErrors = true; 891a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 892a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 893a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 894a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 895a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 896a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private final class Entry { 897a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private final String key; 898a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 899a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** Lengths of this entry's files. */ 900a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private final long[] lengths; 901a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 902a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** True if this entry has ever been published */ 903a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private boolean readable; 904a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 905a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** The ongoing edit or null if this entry is not being edited. */ 906a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private Editor currentEditor; 907a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 908a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** The sequence number of the most recently committed edit to this entry. */ 909a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private long sequenceNumber; 910a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 911a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private Entry(String key) { 912a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas this.key = key; 913a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas this.lengths = new long[valueCount]; 914a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 915a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 916a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public String getLengths() throws IOException { 917a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas StringBuilder result = new StringBuilder(); 918a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas for (long size : lengths) { 919a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas result.append(' ').append(size); 920a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 921a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return result.toString(); 922a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 923a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 924a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas /** 925a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas * Set lengths using decimal numbers like "10123". 926a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas */ 927a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private void setLengths(String[] strings) throws IOException { 928a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas if (strings.length != valueCount) { 929a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw invalidLengths(strings); 930a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 931a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 932a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas try { 933a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas for (int i = 0; i < strings.length; i++) { 934a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas lengths[i] = Long.parseLong(strings[i]); 935a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 936a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } catch (NumberFormatException e) { 937a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw invalidLengths(strings); 938a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 939a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 940a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 941a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas private IOException invalidLengths(String[] strings) throws IOException { 942a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas throw new IOException("unexpected journal line: " + Arrays.toString(strings)); 943a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 944a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 945a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public File getCleanFile(int i) { 946a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return new File(directory, key + "." + i); 947a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 948a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas 949a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas public File getDirtyFile(int i) { 950a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas return new File(directory, key + "." + i + ".tmp"); 951a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 952a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas } 953a780ba4b15cbe69e7ad74c34c21ccef5e8cdce23Alexander Lucas} 954