public class FileSnapshot
extends java.lang.Object
This object tracks the last modified time of a file. Later during an
invocation of isModified(File)
the object will return true if the
file may have been modified and should be re-read from disk.
A snapshot does not "live update" when the underlying filesystem changes.
Callers must poll for updates by periodically invoking
isModified(File)
.
To work around the "racy git" problem (where a file may be modified multiple times within the granularity of the filesystem modification clock) this class may return true from isModified(File) if the last modification time of the file is less than 3 seconds ago.
Modifier and Type | Field and Description |
---|---|
private boolean |
cannotBeRacilyClean
True once
lastRead is far later than lastModified . |
static FileSnapshot |
DIRTY
A FileSnapshot that is considered to always be modified.
|
private java.lang.Object |
fileKey
Object that uniquely identifies the given file, or
null if a file key is not available |
private boolean |
fileKeyChanged |
private java.time.Duration |
fsTimestampResolution
measured filesystem timestamp resolution
|
private long |
lastModified
Last observed modification time of the path.
|
private boolean |
lastModifiedChanged |
private long |
lastRead
Last wall-clock time the path was read.
|
static FileSnapshot |
MISSING_FILE
A FileSnapshot that is clean if the file does not exist.
|
private static java.lang.Object |
MISSING_FILEKEY |
private long |
size
Underlying file-system size in bytes.
|
private boolean |
sizeChanged |
static long |
UNKNOWN_SIZE
An unknown file size.
|
private boolean |
wasRacyClean |
Modifier | Constructor and Description |
---|---|
protected |
FileSnapshot(java.io.File path)
Record a snapshot for a specific file path.
|
private |
FileSnapshot(long read,
long modified,
long size,
java.time.Duration fsTimestampResolution,
java.lang.Object fileKey) |
Modifier and Type | Method and Description |
---|---|
boolean |
equals(FileSnapshot other)
Compare two snapshots to see if they cache the same information.
|
boolean |
equals(java.lang.Object obj) |
private static java.lang.Object |
getFileKey(java.nio.file.attribute.BasicFileAttributes fileAttributes) |
int |
hashCode() |
private boolean |
isFileKeyChanged(java.lang.Object currFileKey) |
boolean |
isModified(java.io.File path)
Check if the path may have been modified since the snapshot was saved.
|
private boolean |
isModified(long currLastModified) |
private boolean |
isRacyClean(long read) |
private boolean |
isSizeChanged(long currSize) |
long |
lastModified()
Get time of last snapshot update
|
static FileSnapshot |
save(java.io.File path)
Record a snapshot for a specific file path.
|
static FileSnapshot |
save(long modified)
Record a snapshot for a file for which the last modification time is
already known.
|
void |
setClean(FileSnapshot other)
Update this snapshot when the content hasn't changed.
|
long |
size() |
java.lang.String |
toString() |
void |
waitUntilNotRacy()
Wait until this snapshot's file can't be racy anymore
|
(package private) boolean |
wasFileKeyChanged() |
(package private) boolean |
wasLastModifiedChanged() |
(package private) boolean |
wasLastModifiedRacilyClean() |
(package private) boolean |
wasSizeChanged() |
public static final long UNKNOWN_SIZE
private static final java.lang.Object MISSING_FILEKEY
public static final FileSnapshot DIRTY
This instance is useful for application code that wants to lazily read a
file, but only after isModified(File)
gets invoked. The returned
snapshot contains only invalid status information.
public static final FileSnapshot MISSING_FILE
This instance is useful if the application wants to consider a missing
file to be clean. isModified(File)
will return false if the file
path does not exist.
private final long lastModified
private volatile long lastRead
private boolean cannotBeRacilyClean
lastRead
is far later than lastModified
.private final long size
UNKNOWN_SIZE
the size is not considered for modification checks.private java.time.Duration fsTimestampResolution
private final java.lang.Object fileKey
null
if a file key is not availableprivate boolean sizeChanged
private boolean fileKeyChanged
private boolean lastModifiedChanged
private boolean wasRacyClean
protected FileSnapshot(java.io.File path)
This method should be invoked before the file is accessed.
path
- the path to later remember. The path's current status
information is saved.public static FileSnapshot save(java.io.File path)
This method should be invoked before the file is accessed.
path
- the path to later remember. The path's current status
information is saved.private static java.lang.Object getFileKey(java.nio.file.attribute.BasicFileAttributes fileAttributes)
public static FileSnapshot save(long modified)
This method should be invoked before the file is accessed.
Note that this method cannot rely on measuring file timestamp resolution to avoid racy git issues caused by finite file timestamp resolution since it's unknown in which filesystem the file is located. Hence the worst case fallback for timestamp resolution is used.
modified
- the last modification time of the filepublic long lastModified()
public long size()
public boolean isModified(java.io.File path)
path
- the path the snapshot describes.public void setClean(FileSnapshot other)
If the caller gets true from isModified(File)
, re-reads the
content, discovers the content is identical, and
equals(FileSnapshot)
is true, it can use
setClean(FileSnapshot)
to make a future
isModified(File)
return false. The logic goes something like
this:
if (snapshot.isModified(path)) { FileSnapshot other = FileSnapshot.save(path); Content newContent = ...; if (oldContent.equals(newContent) && snapshot.equals(other)) snapshot.setClean(other); }
other
- the other snapshot.public void waitUntilNotRacy() throws java.lang.InterruptedException
java.lang.InterruptedException
- if sleep was interruptedpublic boolean equals(FileSnapshot other)
other
- the other snapshot.public boolean equals(java.lang.Object obj)
equals
in class java.lang.Object
public int hashCode()
hashCode
in class java.lang.Object
boolean wasSizeChanged()
true
if FileSnapshot.isModified(File) found the file size
changedboolean wasFileKeyChanged()
true
if FileSnapshot.isModified(File) found the file key
changedboolean wasLastModifiedChanged()
true
if FileSnapshot.isModified(File) found the file's
lastModified changedboolean wasLastModifiedRacilyClean()
true
if FileSnapshot.isModified(File) detected that
lastModified is racily cleanpublic java.lang.String toString()
toString
in class java.lang.Object
private boolean isRacyClean(long read)
private boolean isModified(long currLastModified)
private boolean isFileKeyChanged(java.lang.Object currFileKey)
private boolean isSizeChanged(long currSize)