Skip to content

Commit

Permalink
Create cache files with CREATE_NEW & SPARSE options (#79371) (#79465)
Browse files Browse the repository at this point in the history
Backport of #79371
  • Loading branch information
tlrx committed Oct 19, 2021
1 parent c77b0ea commit 49f7318
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,14 @@ public interface ModificationListener {
void onCacheFileDelete(CacheFile cacheFile);
}

private static final StandardOpenOption[] OPEN_OPTIONS = new StandardOpenOption[] {
private static final StandardOpenOption[] CREATE_OPTIONS = new StandardOpenOption[] {
StandardOpenOption.READ,
StandardOpenOption.WRITE,
StandardOpenOption.CREATE,
StandardOpenOption.CREATE_NEW,
StandardOpenOption.SPARSE };

private static final StandardOpenOption[] OPEN_OPTIONS = new StandardOpenOption[] { StandardOpenOption.READ, StandardOpenOption.WRITE };

/**
* Reference counter that counts the number of eviction listeners referencing this cache file plus the number of open file channels
* for it. Once this instance has been evicted, all listeners notified and all {@link FileChannelReference} for it released,
Expand Down Expand Up @@ -114,9 +116,9 @@ private final class FileChannelReference extends AbstractRefCounted {

private final FileChannel fileChannel;

FileChannelReference() throws IOException {
FileChannelReference(StandardOpenOption[] options) throws IOException {
super("FileChannel[" + file + "]");
this.fileChannel = FileChannel.open(file, OPEN_OPTIONS);
this.fileChannel = FileChannel.open(file, options);
refCounter.incRef();
}

Expand All @@ -139,19 +141,26 @@ protected void closeInternal() {
@Nullable
private volatile FileChannelReference channelRef;

/**
* {@code true} if the physical cache file exists on disk
*/
private volatile boolean fileExists;

public CacheFile(CacheKey cacheKey, long length, Path file, ModificationListener listener) {
this(cacheKey, new SparseFileTracker(file.toString(), length), file, listener);
this(cacheKey, new SparseFileTracker(file.toString(), length), file, listener, false);
}

public CacheFile(CacheKey cacheKey, long length, Path file, SortedSet<ByteRange> ranges, ModificationListener listener) {
this(cacheKey, new SparseFileTracker(file.toString(), length, ranges), file, listener);
this(cacheKey, new SparseFileTracker(file.toString(), length, ranges), file, listener, true);
}

private CacheFile(CacheKey cacheKey, SparseFileTracker tracker, Path file, ModificationListener listener) {
private CacheFile(CacheKey cacheKey, SparseFileTracker tracker, Path file, ModificationListener listener, boolean fileExists) {
this.cacheKey = Objects.requireNonNull(cacheKey);
this.tracker = Objects.requireNonNull(tracker);
this.file = Objects.requireNonNull(file);
this.listener = Objects.requireNonNull(listener);
assert fileExists == Files.exists(file) : file + " exists? " + fileExists;
this.fileExists = fileExists;
assert invariant();
}

Expand Down Expand Up @@ -197,7 +206,8 @@ public void acquire(final EvictionListener listener) throws IOException {
ensureOpen();
if (listeners.isEmpty()) {
assert channelRef == null;
channelRef = new FileChannelReference();
channelRef = new FileChannelReference(fileExists ? OPEN_OPTIONS : CREATE_OPTIONS);
fileExists = true;
}
final boolean added = listeners.add(listener);
assert added : "listener already exists " + listener;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,15 @@ public void onCacheFileDelete(CacheFile cacheFile) {}
private static final CacheKey CACHE_KEY = new CacheKey("_snap_uuid", "_snap_index", new ShardId("_name", "_uuid", 0), "_filename");

public void testGetCacheKey() throws Exception {
final Path file = createTempDir().resolve("file.new");
final CacheKey cacheKey = new CacheKey(
UUIDs.randomBase64UUID(random()),
randomAlphaOfLength(5).toLowerCase(Locale.ROOT),
new ShardId(randomAlphaOfLength(5).toLowerCase(Locale.ROOT), UUIDs.randomBase64UUID(random()), randomInt(5)),
randomAlphaOfLength(105).toLowerCase(Locale.ROOT)
);

final CacheFile cacheFile = new CacheFile(cacheKey, randomLongBetween(1, 100), createTempFile(), NOOP);
final CacheFile cacheFile = new CacheFile(cacheKey, randomLongBetween(1, 100), file, NOOP);
assertThat(cacheFile.getCacheKey(), sameInstance(cacheKey));
}

Expand Down

0 comments on commit 49f7318

Please sign in to comment.