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