@Immutable
public class FileCache
extends java.lang.Object
This class is used to avoid creating the same file/directory multiple times. The main API
method createFile(File, Inputs, Callable) creates an output file/directory by either
copying it from the cache, or creating it first and caching it if the cached file/directory does
not yet exist. Similarly, the createFileInCacheIfAbsent(Inputs, ExceptionConsumer)
method returns the cached output file/directory, and creates it first if the cached
file/directory does not yet exist.
Note that if a cache entry exists but is found to be corrupted, the cache entry will be deleted and recreated.
This class is thread-safe.
| Modifier and Type | Class and Description |
|---|---|
static class |
FileCache.Command
Command to be provided by the client when using
FileCache. |
static class |
FileCache.Inputs
List of input parameters to be provided by the client when using
FileCache. |
static class |
FileCache.QueryEvent
The event that happens when the client queries a cache entry: the cache entry may be hit,
missed, or corrupted.
|
static class |
FileCache.QueryResult
The result of a cache query, which includes a
FileCache.QueryEvent indicating whether the cache
is hit, missed, or corrupted, a cause if the cache is corrupted, and an (optional) path to
the cached output file/directory. |
| Modifier and Type | Method and Description |
|---|---|
FileCache.QueryResult |
createFile(java.io.File outputFile,
FileCache.Inputs inputs,
java.util.concurrent.Callable<java.lang.Void> fileCreator)
Creates an output file/directory by either copying it from the cache, or creating it first
via the given file creator callback function and caching it if the cached file/directory does
not yet exist.
|
FileCache.QueryResult |
createFileInCacheIfAbsent(FileCache.Inputs inputs,
ExceptionConsumer<java.io.File> fileCreator)
Creates the cached output file/directory via the given file creator callback function if it
does not yet exist.
|
void |
delete()
Deletes the cache directory and its contents.
|
java.io.File |
getCacheDirectory() |
java.io.File |
getFileInCache(FileCache.Inputs inputs)
Returns the path of the cached output file/directory that is unique to the given list of
inputs (different lists of inputs correspond to different cached files/directories).
|
static FileCache |
getInstanceWithInterProcessLocking(java.io.File cacheDirectory)
Returns a
FileCache instance with LockingScope#INTER_PROCESS. |
static FileCache |
getInstanceWithSingleProcessLocking(java.io.File cacheDirectory)
Returns a
FileCache instance with LockingScope#SINGLE_PROCESS. |
java.lang.String |
toString() |
@NonNull public static FileCache getInstanceWithInterProcessLocking(@NonNull java.io.File cacheDirectory) throws java.io.IOException
FileCache instance with LockingScope#INTER_PROCESS.
Threads of the same process as well as those across different processes can read same the
cache entry concurrently, but only one of them can write to the same cache entry or the same
output file/directory at a time, without any other thread concurrently reading that cache
entry. If the cache is being deleted by another thread of any process, then any read or write
access to the cache will block until the deletion completes. The user must access the cache
via FileCache's API; otherwise, the previous concurrency guarantees will no longer
hold.
Note that if this cache is never used by more than one process at a time, it may be
preferable to configure the cache with SINGLE_PROCESS locking scope instead since
there will be less synchronization overhead.
cacheDirectory - the directory that will contain the cached files/directories (may not
already exist)java.io.IOExceptiongetInstanceWithSingleProcessLocking(File)@NonNull public static FileCache getInstanceWithSingleProcessLocking(@NonNull java.io.File cacheDirectory) throws java.io.IOException
FileCache instance with LockingScope#SINGLE_PROCESS.
Threads of the same process as well as those across different processes can read same the
cache entry concurrently; however, only one thread in the current process can write to the
same cache entry or the same output file/directory at a time, without any other thread in the
current process concurrently reading that cache entry, but there is no guarantee that that
cache entry is not being read or written to by another thread of another process. If the
cache is being deleted by another thread of the current process, then any read or write
access to the cache will block until the deletion completes. The user must access the cache
via FileCache's API; otherwise, the previous concurrency guarantees will no longer
hold.
Note that if this cache may be used by more than one process at a time, the client must
configure the cache with INTER_PROCESS locking scope instead, even though there
will be more synchronization overhead.
cacheDirectory - the directory that will contain the cached files/directories (may not
already exist)java.io.IOExceptiongetInstanceWithInterProcessLocking(File)@NonNull public java.io.File getCacheDirectory()
@NonNull public FileCache.QueryResult createFile(@NonNull java.io.File outputFile, @NonNull FileCache.Inputs inputs, @NonNull java.util.concurrent.Callable<java.lang.Void> fileCreator) throws java.util.concurrent.ExecutionException, java.io.IOException
The output file/directory must not reside in, contain, or be identical to the cache directory.
To determine whether to reuse a cached file/directory or create a new file/directory, the
client needs to provide all the inputs that affect the creation of the output file/directory
to the FileCache.Inputs object.
If this method is called multiple times on the same list of inputs, on the first call, the cache will delete the output file/directory (if it exists), create its parent directories, invoke the file creator to create the output file/directory, and copy the output file/directory to the cache. On subsequent calls, the cache will create/replace the output file/directory with the cached result without invoking the file creator.
Note that the file creator is not required to always create an output. If the file creator does not create an output on the first call, the cache will remember this result and produce no output on subsequent calls (it will still delete the output file/directory if it exists and creates its parent directory on both the first and subsequent calls).
Depending on whether there are other threads/processes concurrently accessing this cache and the type of locking scope configured for this cache, this method may block until it is allowed to continue.
outputFile - the output file/directoryinputs - all the inputs that affect the creation of the output file/directoryfileCreator - the callback function to create the output file/directoryjava.util.concurrent.ExecutionException - if an exception occurred during the execution of the file creatorjava.io.IOException - if an I/O exception occurred, but not during the execution of the file
creator (or the file creator was not executed)java.lang.RuntimeException - if a runtime exception occurred, but not during the execution of the
file creator (or the file creator was not executed)@NonNull public FileCache.QueryResult createFileInCacheIfAbsent(@NonNull FileCache.Inputs inputs, @NonNull ExceptionConsumer<java.io.File> fileCreator) throws java.util.concurrent.ExecutionException, java.io.IOException
To determine whether a cached file/directory exists, the client needs to provide all the
inputs that affect the creation of the output file/directory to the FileCache.Inputs object.
If this method is called multiple times on the same list of inputs, the first call will invoke the file creator to create the cached output file/directory (which is given as the argument to the file creator callback function), and subsequent calls will return the cached file/directory without invoking the file creator.
Note that the file creator is not required to always create an output. If the file creator does not create an output on the first call, the cache will remember this result and return a cached file that does not exist on subsequent calls.
Depending on whether there are other threads/processes concurrently accessing this cache and the type of locking scope configured for this cache, this method may block until it is allowed to continue.
Note that this method returns a cached file/directory that is located inside the cache directory. To avoid corrupting the cache, the client must never write to the returned cached file/directory (or any other files/directories inside the cache directory) without using the cache's API. If the client wants to read the returned cached file/directory, it must ensure that another thread (of the same or a different process) is not overwriting or deleting the same cached file/directory at the same time.
WARNING: DO NOT use this method if the returned cached file/directory will be annotated
with Gradle's @OutputFile or @OutputDirectory annotations as it is undefined
behavior of Gradle incremental builds when multiple Gradle tasks have the same
output-annotated file/directory.
inputs - all the inputs that affect the creation of the output file/directoryfileCreator - the callback function to create the output file/directoryjava.util.concurrent.ExecutionException - if an exception occurred during the execution of the file creatorjava.io.IOException - if an I/O exception occurred, but not during the execution of the file
creator (or the file creator was not executed)java.lang.RuntimeException - if a runtime exception occurred, but not during the execution of the
file creator (or the file creator was not executed)@NonNull
public java.io.File getFileInCache(@NonNull
FileCache.Inputs inputs)
Note that this method returns the path only, the cached file/directory may or may not have been created.
This method is typically used together with the
createFileInCacheIfAbsent(Inputs, ExceptionConsumer) method to get the path of the
cached file/directory in advance, before attempting to create it at a later time. The
returned path of this method is guaranteed to be the same as the returned path by that
method. The client calling this method should take precautions in handling the returned
cached file/directory; refer to the javadoc of
createFileInCacheIfAbsent(Inputs, ExceptionConsumer) for more details.
inputs - all the inputs that affect the creation of the output file/directorypublic void delete()
throws java.io.IOException
If the cache is being used by another thread of any process in the case of INTER_PROCESS locking scope, or by another thread of the current process in the case of
SINGLE_PROCESS locking scope, then this method will block until that operation
completes.
java.io.IOExceptionpublic java.lang.String toString()
toString in class java.lang.Object