Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create cache files with CREATE_NEW & SPARSE options #79371

Merged
merged 4 commits into from
Oct 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -100,8 +102,8 @@ private final class FileChannelReference extends AbstractRefCounted {

private final FileChannel fileChannel;

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

Expand All @@ -124,19 +126,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 @@ -182,7 +191,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