示例#1
0
  /**
   * Allocates the requested space in the file.
   *
   * @param len requested space
   * @return allocated file position and length as FileEntry object
   */
  private FileEntry allocate(int len) {
    synchronized (freeList) {
      // lookup a free entry of sufficient size
      SortedSet<FileEntry> candidates = freeList.tailSet(new FileEntry(0, len));
      for (Iterator<FileEntry> it = candidates.iterator(); it.hasNext(); ) {
        FileEntry free = it.next();
        // ignore entries that are still in use by concurrent readers
        if (free.isLocked()) continue;

        // There's no race condition risk between locking the entry on
        // loading and checking whether it's locked (or store allocation),
        // because for the entry to be lockable, it needs to be in the
        // entries collection, in which case it's not in the free list.
        // The only way an entry can be found in the free list is if it's
        // been removed, and to remove it, lock on "entries" needs to be
        // acquired, which is also a pre-requisite for loading data.

        // found one, remove from freeList
        it.remove();
        return allocateExistingEntry(free, len);
      }

      // no appropriate free section available, append at end of file
      FileEntry fe = new FileEntry(filePos, len);
      filePos += len;
      if (trace)
        log.tracef(
            "New entry allocated at %d:%d, %d free entries, file size is %d",
            fe.offset, fe.size, freeList.size(), filePos);
      return fe;
    }
  }
示例#2
0
  /**
   * Coalesces adjacent free entries to create larger free entries (so that the probability of
   * finding a free entry during allocation increases)
   */
  private void mergeFreeEntries(List<FileEntry> entries) {
    long startTime = 0;
    if (trace) startTime = timeService.wallClockTime();
    FileEntry lastEntry = null;
    FileEntry newEntry = null;
    int mergeCounter = 0;
    for (Iterator<FileEntry> it = entries.iterator(); it.hasNext(); ) {
      FileEntry fe = it.next();
      if (fe.isLocked()) {
        continue;
      }

      // Merge any holes created (consecutive free entries) in the file
      if ((lastEntry != null) && (lastEntry.offset == (fe.offset + fe.size))) {
        if (newEntry == null) {
          newEntry = new FileEntry(fe.offset, fe.size + lastEntry.size);
          freeList.remove(lastEntry);
          mergeCounter++;
        } else {
          newEntry = new FileEntry(fe.offset, fe.size + newEntry.size);
        }
        freeList.remove(fe);
        mergeCounter++;
      } else {
        if (newEntry != null) {
          try {
            addNewFreeEntry(newEntry);
            if (trace)
              log.tracef(
                  "Merged %d entries at %d:%d, %d free entries",
                  mergeCounter, newEntry.offset, newEntry.size, freeList.size());
          } catch (IOException e) {
            throw new PersistenceException("Could not add new merged entry", e);
          }
          newEntry = null;
          mergeCounter = 0;
        }
      }
      lastEntry = fe;
    }

    if (newEntry != null) {
      try {
        addNewFreeEntry(newEntry);
        if (trace)
          log.tracef(
              "Merged %d entries at %d:%d, %d free entries",
              mergeCounter, newEntry.offset, newEntry.size, freeList.size());
      } catch (IOException e) {
        throw new PersistenceException("Could not add new merged entry", e);
      }
    }

    if (trace)
      log.tracef(
          "Total time taken for mergeFreeEntries: "
              + (timeService.wallClockTime() - startTime)
              + " (ms)");
  }
示例#3
0
  /** Removes free entries towards the end of the file and truncates the file. */
  private void truncateFile(List<FileEntry> entries) {
    long startTime = 0;
    if (trace) startTime = timeService.wallClockTime();

    int reclaimedSpace = 0;
    int removedEntries = 0;
    long truncateOffset = -1;
    for (Iterator<FileEntry> it = entries.iterator(); it.hasNext(); ) {
      FileEntry fe = it.next();
      // Till we have free entries at the end of the file,
      // we can remove them and contract the file to release disk
      // space.
      if (!fe.isLocked() && ((fe.offset + fe.size) == filePos)) {
        truncateOffset = fe.offset;
        filePos = fe.offset;
        freeList.remove(fe);
        it.remove();
        reclaimedSpace += fe.size;
        removedEntries++;
      } else {
        break;
      }
    }

    if (truncateOffset > 0) {
      try {
        channel.truncate(truncateOffset);
      } catch (IOException e) {
        throw new PersistenceException("Error while truncating file", e);
      }
    }

    if (trace) {
      log.tracef("Removed entries: " + removedEntries + ", Reclaimed Space: " + reclaimedSpace);
      log.tracef(
          "Time taken for truncateFile: " + (timeService.wallClockTime() - startTime) + " (ms)");
    }
  }