/** * Closes the cache and deletes all of its stored values. This will delete * all files in the cache directory including files that weren't created by * the cache. */ public void delete() throws IOException { close(); Util.deleteContents(directory); }
/** * Returns an editor for the entry named {@code key}, or null if another * edit is in progress. */ public Editor edit(String key) throws IOException { return edit(key, ANY_SEQUENCE_NUMBER); }
/** * Returns the last committed value as a string, or null if no value * has been committed. */ public String getString(int index) throws IOException { InputStream in = newInputStream(index); return in != null ? inputStreamToString(in) : null; }
/** Sets the value at {@code index} to {@code value}. */ public void set(int index, String value) throws IOException { Writer writer = null; try { writer = new OutputStreamWriter(newOutputStream(index), Util.UTF_8); writer.write(value); } finally { Util.closeQuietly(writer); } }
/** Returns the string value for {@code index}. */ public String getString(int index) throws IOException { return inputStreamToString(getInputStream(index)); }
/** * Commits this edit so it is visible to readers. This releases the * edit lock so another edit may be started on the same key. */ public void commit() throws IOException { if (hasErrors) { completeEdit(this, false); remove(entry.key); // The previous entry is stale. } else { completeEdit(this, true); } committed = true; }
public void abortUnlessCommitted() { if (!committed) { try { abort(); } catch (IOException ignored) { } } }
/** Closes this cache. Stored values will remain on the filesystem. */ public synchronized void close() throws IOException { if (journalWriter == null) { return; // Already closed. } for (Entry entry : new ArrayList<Entry>(lruEntries.values())) { if (entry.currentEditor != null) { entry.currentEditor.abort(); } } trimToSize(); journalWriter.close(); journalWriter = null; }
checkNotClosed(); validateKey(key); Entry entry = lruEntries.get(key); if (entry == null) { try { for (int i = 0; i < valueCount; i++) { ins[i] = new FileInputStream(entry.getCleanFile(i)); Util.closeQuietly(ins[i]); } else { break; if (journalRebuildRequired()) { executorService.submit(cleanupCallable); return new Snapshot(key, entry.sequenceNumber, ins, entry.lengths);
private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException { checkNotClosed(); validateKey(key); Entry entry = lruEntries.get(key); if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER && (entry == null || entry.sequenceNumber != expectedSequenceNumber)) { return null; // Snapshot is stale. } if (entry == null) { entry = new Entry(key); lruEntries.put(key, entry); } else if (entry.currentEditor != null) { return null; // Another edit is in progress. } Editor editor = new Editor(entry); entry.currentEditor = editor; // Flush the journal before creating files to prevent file leaks. journalWriter.write(DIRTY + ' ' + key + '\n'); journalWriter.flush(); return editor; }
/** * 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]; } } else { entry.currentEditor = null; for (int t = 0; t < valueCount; t++) { deleteIfExists(entry.getCleanFile(t)); deleteIfExists(entry.getDirtyFile(t)); } i.remove(); } } }
/** Force buffered operations to the filesystem. */ public synchronized void flush() throws IOException { checkNotClosed(); trimToSize(); journalWriter.flush(); }
public void close() { for (InputStream in : ins) { Util.closeQuietly(in); } } }
/** Set lengths using decimal numbers like "10123". */ private void setLengths(String[] strings) throws IOException { if (strings.length != valueCount) { throw invalidLengths(strings); } try { for (int i = 0; i < strings.length; i++) { lengths[i] = Long.parseLong(strings[i]); } } catch (NumberFormatException e) { throw invalidLengths(strings); } }
private static String inputStreamToString(InputStream in) throws IOException { return Util.readFully(new InputStreamReader(in, Util.UTF_8)); }
private static void renameTo(File from, File to, boolean deleteDestination) throws IOException { if (deleteDestination) { deleteIfExists(to); } if (!from.renameTo(to)) { throw new IOException(); } }
/** * Returns an unbuffered input stream to read the last committed value, * or null if no value has been committed. */ public InputStream newInputStream(int index) throws IOException { synchronized (DiskLruCache.this) { if (entry.currentEditor != this) { throw new IllegalStateException(); } if (!entry.readable) { return null; } try { return new FileInputStream(entry.getCleanFile(index)); } catch (FileNotFoundException e) { return null; } } }
/** * Deletes the contents of {@code dir}. Throws an IOException if any file * could not be deleted, or if {@code dir} is not a readable directory. */ static void deleteContents(File dir) throws IOException { File[] files = dir.listFiles(); if (files == null) { throw new IOException("not a readable directory: " + dir); } for (File file : files) { if (file.isDirectory()) { deleteContents(file); } if (!file.delete()) { throw new IOException("failed to delete file: " + file); } } }
private void trimToSize() throws IOException { while (size > maxSize) { Map.Entry<String, Entry> toEvict = lruEntries.entrySet().iterator().next(); remove(toEvict.getKey()); } }