Code example for LinkedHashMap

Methods: values

0
    private final long maxSize;
    private final int valueCount;
    private long size = 0;
    private Writer journalWriter;
    private final LinkedHashMap<String, Entry> lruEntries
            = new LinkedHashMap<String, Entry>(0, 0.75f, true);
    private int redundantOpCount;
 
    /** 
     * To differentiate between old and current snapshots, each entry is given 
     * a sequence number each time an edit is committed. A snapshot is stale if 
     * its sequence number is not equal to its entry's sequence number. 
     */ 
    private long nextSequenceNumber = 0;
 
    /* From java.util.Arrays */ 
    @SuppressWarnings("unchecked") 
    private static <T> T[] copyOfRange(T[] original, int start, int end) {
        final int originalLength = original.length; // For exception priority compatibility.
        if (start > end) {
            throw new IllegalArgumentException();
        } 
        if (start < 0 || start > originalLength) {
            throw new ArrayIndexOutOfBoundsException();
        } 
        final int resultLength = end - start;
        final int copyLength = Math.min(resultLength, originalLength - start);
        final T[] result = (T[]) Array
                .newInstance(original.getClass().getComponentType(), resultLength);
        System.arraycopy(original, start, result, 0, copyLength);
        return result;
    } 
 
    /** 
     * Returns the remainder of 'reader' as a string, closing it when done. 
     */ 
    public static String readFully(Reader reader) throws IOException {
        try { 
            StringWriter writer = new StringWriter();
            char[] buffer = new char[1024];
            int count;
            while ((count = reader.read(buffer)) != -1) {
                writer.write(buffer, 0, count);
            } 
            return writer.toString();
        } finally { 
            reader.close();
        } 
    } 
 
    /** 
     * Returns the ASCII characters up to but not including the next "\r\n", or 
     * "\n". 
     * 
     * @throws java.io.EOFException if the stream is exhausted before the next newline 
     *                              character. 
     */ 
    public static String readAsciiLine(InputStream in) throws IOException {
        // TODO: support UTF-8 here instead 
 
        StringBuilder result = new StringBuilder(80);
        while (true) { 
            int c = in.read();
            if (c == -1) {
                throw new EOFException();
            } else if (c == '\n') {
                break; 
            } 
 
            result.append((char) c);
        } 
        int length = result.length();
        if (length > 0 && result.charAt(length - 1) == '\r') {
            result.setLength(length - 1);
        } 
        return result.toString();
    } 
 
    /** 
     * Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null. 
     */ 
    public static void closeQuietly(Closeable closeable) {
        if (closeable != null) {
            try { 
                closeable.close();
            } catch (RuntimeException rethrown) {
                throw rethrown;
            } catch (Exception ignored) {
            } 
        } 
    } 
 
    /** 
     * Recursively delete everything in {@code dir}. 
     */ 
    // TODO: this should specify paths as Strings rather than as Files 
    public static void deleteContents(File dir) throws IOException {
        File[] files = dir.listFiles();
        if (files == null) {
            throw new IllegalArgumentException("not a directory: " + dir);
        } 
        for (File file : files) {
            if (file.isDirectory()) {
                deleteContents(file);
            } 
            if (!file.delete()) {
                throw new IOException("failed to delete file: " + file);
            } 
        } 
    } 
 
    /** 
     * This cache uses a single background thread to evict entries. 
     */ 
    private final ExecutorService executorService = new ThreadPoolExecutor(0, 1,
            60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
    private final Callable<Void> cleanupCallable = new Callable<Void>() {
        @Override 
        public Void call() throws Exception { 
            synchronized (DiskLruCache.this) { 
                if (journalWriter == null) { 
                    return null; // closed 
                } 
                trimToSize(); 
                if (journalRebuildRequired()) { 
                    rebuildJournal(); 
                    redundantOpCount = 0; 
                } 
            } 
            return null; 
        } 
    }; 
 
    private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) {
        this.directory = directory;
        this.appVersion = appVersion;
        this.journalFile = new File(directory, JOURNAL_FILE);
        this.journalFileTmp = new File(directory, JOURNAL_FILE_TMP);
        this.valueCount = valueCount;
        this.maxSize = maxSize;
    } 
 
    /** 
     * Opens the cache in {@code directory}, creating a cache if none exists 
     * there. 
     * 
     * @param directory  a writable directory 
     * @param appVersion 
     * @param valueCount the number of values per cache entry. Must be positive. 
     * @param maxSize    the maximum number of bytes this cache should use to store 
     * @throws IOException if reading or writing the cache directory fails 
     */ 
    public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
            throws IOException { 
        if (maxSize <= 0) {
            throw new IllegalArgumentException("maxSize <= 0");
        } 
        if (valueCount <= 0) {
            throw new IllegalArgumentException("valueCount <= 0");
        } 
 
        // prefer to pick up where we left off 
        DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
        if (cache.journalFile.exists()) {
            try { 
                cache.readJournal();
                cache.processJournal();
                cache.journalWriter = new BufferedWriter(new FileWriter(cache.journalFile, true),
                        IO_BUFFER_SIZE);
                return cache;
            } catch (IOException journalIsCorrupt) {
//                System.logW("DiskLruCache " + directory + " is corrupt: " 
//                        + journalIsCorrupt.getMessage() + ", removing"); 
                cache.delete();
            } 
        } 
 
        // create a new empty cache 
        directory.mkdirs();
        cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
        cache.rebuildJournal();
        return cache;
    } 
 
    private void readJournal() throws IOException { 
        InputStream in = new BufferedInputStream(new FileInputStream(journalFile), IO_BUFFER_SIZE);
        try { 
            String magic = readAsciiLine(in);
            String version = readAsciiLine(in);
            String appVersionString = readAsciiLine(in);
            String valueCountString = readAsciiLine(in);
            String blank = readAsciiLine(in);
            if (!MAGIC.equals(magic)
                    || !VERSION_1.equals(version)
                    || !Integer.toString(appVersion).equals(appVersionString)
                    || !Integer.toString(valueCount).equals(valueCountString)
                    || !"".equals(blank)) {
                throw new IOException("unexpected journal header: ["
                        + magic + ", " + version + ", " + valueCountString + ", " + blank + "]");
            } 
 
            while (true) { 
                try { 
                    readJournalLine(readAsciiLine(in));
                } catch (EOFException endOfJournal) {
                    break; 
                } 
            } 
        } finally { 
            closeQuietly(in);
        } 
    } 
 
    private void readJournalLine(String line) throws IOException {
        String[] parts = line.split(" ");
        if (parts.length < 2) {
            throw new IOException("unexpected journal line: " + line);
        } 
 
        String key = parts[1];
        if (parts[0].equals(REMOVE) && parts.length == 2) {
            lruEntries.remove(key);
            return; 
        } 
 
        Entry entry = lruEntries.get(key);
        if (entry == null) {
            entry = new Entry(key);
            lruEntries.put(key, entry);
        } 
 
        if (parts[0].equals(CLEAN) && parts.length == 2 + valueCount) {
            entry.readable = true;
            entry.currentEditor = null;
            entry.setLengths(copyOfRange(parts, 2, parts.length));
        } else if (parts[0].equals(DIRTY) && parts.length == 2) {
            entry.currentEditor = new Editor(entry);
        } else if (parts[0].equals(READ) && parts.length == 2) {
            // this work was already done by calling lruEntries.get() 
        } else { 
            throw new IOException("unexpected journal line: " + line);
        } 
    } 
 
    /** 
     * Computes the initial size and collects garbage as a part of opening the 
     * cache. Dirty entries are assumed to be inconsistent and will be deleted. 
     */ 
    private void processJournal() throws IOException { 
        deleteIfExists(journalFileTmp);
        for (Iterator<Entry> i = lruEntries.values().iterator(); i.hasNext(); ) {
            Entry entry = i.next();
            if (entry.currentEditor == null) {
                for (int t = 0; t < valueCount; t++) {
                    size += entry.lengths[t];
                }