Skip to content

Commit

Permalink
Merge pull request #80 from cryptomator/feature/relaxed-inUse-definition
Browse files Browse the repository at this point in the history
Relaxed inUse definition
  • Loading branch information
infeo authored Oct 10, 2023
2 parents 3f6d8a3 + a4e330b commit 070a921
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 7 deletions.
22 changes: 21 additions & 1 deletion src/main/java/org/cryptomator/frontend/fuse/OpenFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,19 @@ public class OpenFile implements Closeable {
private final Path path;
private final FileChannel channel;

/**
* Whether any data has been changed on this file.
*
* This value only changes while holding a write lock, see {@link org.cryptomator.frontend.fuse.locks.LockManager}.
*/
private volatile boolean dirty;

private OpenFile(Path path, FileChannel channel) {
this.path = path;
this.channel = channel;
this.dirty = false;
}

static OpenFile create(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {
FileChannel ch = FileChannel.open(path, options, attrs);
return new OpenFile(path, ch);
Expand Down Expand Up @@ -69,6 +77,7 @@ public int read(ByteBuffer buf, long num, long offset) throws IOException {
* @throws IOException If an exception occurs during write.
*/
public int write(ByteBuffer buf, long num, long offset) throws IOException {
dirty = true;
if (num > Integer.MAX_VALUE) {
throw new IOException("Requested too many bytes");
}
Expand All @@ -80,13 +89,24 @@ public int write(ByteBuffer buf, long num, long offset) throws IOException {
return written;
}

/**
* Tests, if this OpenFile is <em>dirty</em>.
* An OpenFile is dirty, if its write method is called at least once.
*
* @return {@code true} if {@link OpenFile#write(ByteBuffer, long, long)} was called on this object, otherwise {@code false}
*/
boolean isDirty() {
return dirty;
}

@Override
public void close() throws IOException {
channel.close();
}

public void fsync(boolean metaData) throws IOException {
channel.force(metaData);
dirty = false;
}

public void truncate(long size) throws IOException {
Expand Down
11 changes: 9 additions & 2 deletions src/main/java/org/cryptomator/frontend/fuse/OpenFileFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,15 @@ public void close(long fileHandle) throws ClosedChannelException, IOException {
}
}

public int getOpenFileCount(){
return openFiles.size();
/**
* Tests, if any {@link OpenFile} is considered <em>dirty</em>, e.g. might have pending changes.
* This method is neither atomic regarding the set of OpenFiles nor regarding each OpenFile individually. Therefore, external synchronization is required.
*
* @return {@code true} if and only if at least one dirty {@link OpenFile} exists. Otherwise {@code false}.
* @see OpenFile#isDirty()
*/
boolean hasDirtyFiles() {
return openFiles.entrySet().stream().anyMatch(entry -> entry.getValue().isDirty());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;
import java.util.function.BooleanSupplier;

public sealed class ReadOnlyAdapter implements FuseNioAdapter permits ReadWriteAdapter {

Expand All @@ -48,7 +47,6 @@ public sealed class ReadOnlyAdapter implements FuseNioAdapter permits ReadWriteA
private final ReadOnlyDirectoryHandler dirHandler;
private final ReadOnlyFileHandler fileHandler;
private final ReadOnlyLinkHandler linkHandler;
private final BooleanSupplier hasOpenFiles;

protected ReadOnlyAdapter(Errno errno, Path root, int maxFileNameLength, FileNameTranscoder fileNameTranscoder, FileStore fileStore, OpenFileFactory openFiles, ReadOnlyDirectoryHandler dirHandler, ReadOnlyFileHandler fileHandler) {
this.errno = errno;
Expand All @@ -61,7 +59,6 @@ protected ReadOnlyAdapter(Errno errno, Path root, int maxFileNameLength, FileNam
this.dirHandler = dirHandler;
this.fileHandler = fileHandler;
this.linkHandler = new ReadOnlyLinkHandler(fileNameTranscoder);
this.hasOpenFiles = () -> openFiles.getOpenFileCount() != 0;
}

public static ReadOnlyAdapter create(Errno errno, Path root, int maxFileNameLength, FileNameTranscoder fileNameTranscoder) {
Expand Down Expand Up @@ -305,7 +302,7 @@ public void destroy() {
@Override
public boolean isInUse() {
try (PathLock pLock = lockManager.tryLockForWriting("/")) {
return hasOpenFiles.getAsBoolean();
return openFiles.hasDirtyFiles();
} catch (AlreadyLockedException e) {
return true;
}
Expand Down

0 comments on commit 070a921

Please sign in to comment.