Пример #1
0
  /**
   * Drops the entry for {@code key} if it exists and can be removed. Entries actively being edited
   * cannot be removed.
   *
   * @return true if an entry was removed.
   */
  public synchronized boolean remove(String key) throws IOException {
    checkNotClosed();
    validateKey(key);
    Entry entry = lruEntries.get(key);
    if (entry == null || entry.currentEditor != null) {
      return false;
    }

    for (int i = 0; i < valueCount; i++) {
      File file = entry.getCleanFile(i);
      if (!file.delete()) {
        throw new IOException("failed to delete " + file);
      }
      size -= entry.lengths[i];
      entry.lengths[i] = 0;
    }

    redundantOpCount++;
    journalWriter.append(REMOVE + ' ' + key + '\n');
    lruEntries.remove(key);

    if (journalRebuildRequired()) {
      executorService.submit(cleanupCallable);
    }

    return true;
  }
Пример #2
0
  /**
   * Returns a snapshot of the entry named {@code key}, or null if it doesn't exist is not currently
   * readable. If a value is returned, it is moved to the head of the LRU queue.
   */
  public synchronized Snapshot get(String key) throws IOException {
    checkNotClosed();
    validateKey(key);
    Entry entry = lruEntries.get(key);
    if (entry == null) {
      return null;
    }

    if (!entry.readable) {
      return null;
    }

    /*
     * Open all streams eagerly to guarantee that we see a single published
     * snapshot. If we opened streams lazily then the streams could come
     * from different edits.
     */
    InputStream[] ins = new InputStream[valueCount];
    try {
      for (int i = 0; i < valueCount; i++) {
        ins[i] = new FileInputStream(entry.getCleanFile(i));
      }
    } catch (FileNotFoundException e) {
      // a file must have been deleted manually!
      return null;
    }

    redundantOpCount++;
    journalWriter.append(READ + ' ' + key + '\n');
    if (journalRebuildRequired()) {
      executorService.submit(cleanupCallable);
    }

    return new Snapshot(key, entry.sequenceNumber, ins);
  }
Пример #3
0
 /**
  * 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];
         Logger.d(BitmapLoader.class.getSimpleName(), entry.getCleanFile(0).getName());
       }
     } else {
       entry.currentEditor = null;
       for (int t = 0; t < valueCount; t++) {
         deleteIfExists(entry.getCleanFile(t));
         deleteIfExists(entry.getDirtyFile(t));
       }
       i.remove();
     }
   }
 }
Пример #4
0
  private synchronized void completeEdit(Editor editor, boolean success) throws IOException {
    Entry entry = editor.entry;
    if (entry.currentEditor != editor) {
      throw new IllegalStateException();
    }

    // If this edit is creating the entry for the first time, every index must have a value.
    if (success && !entry.readable) {
      for (int i = 0; i < valueCount; i++) {
        if (!editor.written[i]) {
          editor.abort();
          throw new IllegalStateException("Newly created entry didn't create value for index " + i);
        }
        if (!entry.getDirtyFile(i).exists()) {
          editor.abort();
          return;
        }
      }
    }

    for (int i = 0; i < valueCount; i++) {
      File dirty = entry.getDirtyFile(i);
      if (success) {
        if (dirty.exists()) {
          File clean = entry.getCleanFile(i);
          dirty.renameTo(clean);
          long oldLength = entry.lengths[i];
          long newLength = clean.length();
          entry.lengths[i] = newLength;
          size = size - oldLength + newLength;
          fileCount++;
        }
      } else {
        deleteIfExists(dirty);
      }
    }

    redundantOpCount++;
    entry.currentEditor = null;
    if (entry.readable | success) {
      entry.readable = true;
      journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n');
      if (success) {
        entry.sequenceNumber = nextSequenceNumber++;
      }
    } else {
      lruEntries.remove(entry.key);
      journalWriter.write(REMOVE + ' ' + entry.key + '\n');
    }
    journalWriter.flush();

    if (size > maxSize || fileCount > maxFileCount || journalRebuildRequired()) {
      executorService.submit(cleanupCallable);
    }
  }
Пример #5
0
 /**
  * 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;
     }
     return new FileInputStream(entry.getCleanFile(index));
   }
 }
Пример #6
0
 /**
  * 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 (final Iterator<Entry> i = lruEntries.values().iterator(); i.hasNext(); ) {
     final 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();
     }
   }
 }
Пример #7
0
  /**
   * Returns a snapshot of the entry named {@code key}, or null if it doesn't exist is not currently
   * readable. If a value is returned, it is moved to the head of the LRU queue.
   */
  public synchronized Snapshot get(String key) throws IOException {
    checkNotClosed();
    validateKey(key);
    Entry entry = lruEntries.get(key);
    if (entry == null) {
      return null;
    }

    if (!entry.readable) {
      return null;
    }

    // Open all streams eagerly to guarantee that we see a single published
    // snapshot. If we opened streams lazily then the streams could come
    // from different edits.
    File[] files = new File[valueCount];
    InputStream[] ins = new InputStream[valueCount];
    try {
      File file;
      for (int i = 0; i < valueCount; i++) {
        file = entry.getCleanFile(i);
        files[i] = file;
        ins[i] = new FileInputStream(file);
      }
    } catch (FileNotFoundException e) {
      // A file must have been deleted manually!
      for (int i = 0; i < valueCount; i++) {
        if (ins[i] != null) {
          Util.closeQuietly(ins[i]);
        } else {
          break;
        }
      }
      return null;
    }

    redundantOpCount++;
    journalWriter.append(READ + ' ' + key + '\n');
    if (journalRebuildRequired()) {
      executorService.submit(cleanupCallable);
    }

    return new Snapshot(key, entry.sequenceNumber, files, ins, entry.lengths);
  }