1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.mozilla.thirdparty.com.google.android.exoplayer2.upstream.cache;
17 
18 import androidx.annotation.Nullable;
19 import androidx.annotation.WorkerThread;
20 import org.mozilla.thirdparty.com.google.android.exoplayer2.C;
21 import java.io.File;
22 import java.io.IOException;
23 import java.util.NavigableSet;
24 import java.util.Set;
25 
26 /**
27  * An interface for cache.
28  */
29 public interface Cache {
30 
31   /**
32    * Listener of {@link Cache} events.
33    */
34   interface Listener {
35 
36     /**
37      * Called when a {@link CacheSpan} is added to the cache.
38      *
39      * @param cache The source of the event.
40      * @param span The added {@link CacheSpan}.
41      */
onSpanAdded(Cache cache, CacheSpan span)42     void onSpanAdded(Cache cache, CacheSpan span);
43 
44     /**
45      * Called when a {@link CacheSpan} is removed from the cache.
46      *
47      * @param cache The source of the event.
48      * @param span The removed {@link CacheSpan}.
49      */
onSpanRemoved(Cache cache, CacheSpan span)50     void onSpanRemoved(Cache cache, CacheSpan span);
51 
52     /**
53      * Called when an existing {@link CacheSpan} is touched, causing it to be replaced. The new
54      * {@link CacheSpan} is guaranteed to represent the same data as the one it replaces, however
55      * {@link CacheSpan#file} and {@link CacheSpan#lastTouchTimestamp} may have changed.
56      *
57      * <p>Note that for span replacement, {@link #onSpanAdded(Cache, CacheSpan)} and {@link
58      * #onSpanRemoved(Cache, CacheSpan)} are not called in addition to this method.
59      *
60      * @param cache The source of the event.
61      * @param oldSpan The old {@link CacheSpan}, which has been removed from the cache.
62      * @param newSpan The new {@link CacheSpan}, which has been added to the cache.
63      */
onSpanTouched(Cache cache, CacheSpan oldSpan, CacheSpan newSpan)64     void onSpanTouched(Cache cache, CacheSpan oldSpan, CacheSpan newSpan);
65   }
66 
67   /**
68    * Thrown when an error is encountered when writing data.
69    */
70   class CacheException extends IOException {
71 
CacheException(String message)72     public CacheException(String message) {
73       super(message);
74     }
75 
CacheException(Throwable cause)76     public CacheException(Throwable cause) {
77       super(cause);
78     }
79 
CacheException(String message, Throwable cause)80     public CacheException(String message, Throwable cause) {
81       super(message, cause);
82     }
83   }
84 
85   /**
86    * Returned by {@link #getUid()} if initialization failed before the unique identifier was read or
87    * generated.
88    */
89   long UID_UNSET = -1;
90 
91   /**
92    * Returns a non-negative unique identifier for the cache, or {@link #UID_UNSET} if initialization
93    * failed before the unique identifier was determined.
94    *
95    * <p>Implementations are expected to generate and store the unique identifier alongside the
96    * cached content. If the location of the cache is deleted or swapped, it is expected that a new
97    * unique identifier will be generated when the cache is recreated.
98    */
getUid()99   long getUid();
100 
101   /**
102    * Releases the cache. This method must be called when the cache is no longer required. The cache
103    * must not be used after calling this method.
104    *
105    * <p>This method may be slow and shouldn't normally be called on the main thread.
106    */
107   @WorkerThread
release()108   void release();
109 
110   /**
111    * Registers a listener to listen for changes to a given key.
112    *
113    * <p>No guarantees are made about the thread or threads on which the listener is called, but it
114    * is guaranteed that listener methods will be called in a serial fashion (i.e. one at a time) and
115    * in the same order as events occurred.
116    *
117    * @param key The key to listen to.
118    * @param listener The listener to add.
119    * @return The current spans for the key.
120    */
addListener(String key, Listener listener)121   NavigableSet<CacheSpan> addListener(String key, Listener listener);
122 
123   /**
124    * Unregisters a listener.
125    *
126    * @param key The key to stop listening to.
127    * @param listener The listener to remove.
128    */
removeListener(String key, Listener listener)129   void removeListener(String key, Listener listener);
130 
131   /**
132    * Returns the cached spans for a given cache key.
133    *
134    * @param key The key for which spans should be returned.
135    * @return The spans for the key.
136    */
getCachedSpans(String key)137   NavigableSet<CacheSpan> getCachedSpans(String key);
138 
139   /**
140    * Returns all keys in the cache.
141    *
142    * @return All the keys in the cache.
143    */
getKeys()144   Set<String> getKeys();
145 
146   /**
147    * Returns the total disk space in bytes used by the cache.
148    *
149    * @return The total disk space in bytes.
150    */
getCacheSpace()151   long getCacheSpace();
152 
153   /**
154    * A caller should invoke this method when they require data from a given position for a given
155    * key.
156    *
157    * <p>If there is a cache entry that overlaps the position, then the returned {@link CacheSpan}
158    * defines the file in which the data is stored. {@link CacheSpan#isCached} is true. The caller
159    * may read from the cache file, but does not acquire any locks.
160    *
161    * <p>If there is no cache entry overlapping {@code offset}, then the returned {@link CacheSpan}
162    * defines a hole in the cache starting at {@code position} into which the caller may write as it
163    * obtains the data from some other source. The returned {@link CacheSpan} serves as a lock.
164    * Whilst the caller holds the lock it may write data into the hole. It may split data into
165    * multiple files. When the caller has finished writing a file it should commit it to the cache by
166    * calling {@link #commitFile(File, long)}. When the caller has finished writing, it must release
167    * the lock by calling {@link #releaseHoleSpan}.
168    *
169    * <p>This method may be slow and shouldn't normally be called on the main thread.
170    *
171    * @param key The key of the data being requested.
172    * @param position The position of the data being requested.
173    * @return The {@link CacheSpan}.
174    * @throws InterruptedException If the thread was interrupted.
175    * @throws CacheException If an error is encountered.
176    */
177   @WorkerThread
startReadWrite(String key, long position)178   CacheSpan startReadWrite(String key, long position) throws InterruptedException, CacheException;
179 
180   /**
181    * Same as {@link #startReadWrite(String, long)}. However, if the cache entry is locked, then
182    * instead of blocking, this method will return null as the {@link CacheSpan}.
183    *
184    * <p>This method may be slow and shouldn't normally be called on the main thread.
185    *
186    * @param key The key of the data being requested.
187    * @param position The position of the data being requested.
188    * @return The {@link CacheSpan}. Or null if the cache entry is locked.
189    * @throws CacheException If an error is encountered.
190    */
191   @WorkerThread
192   @Nullable
startReadWriteNonBlocking(String key, long position)193   CacheSpan startReadWriteNonBlocking(String key, long position) throws CacheException;
194 
195   /**
196    * Obtains a cache file into which data can be written. Must only be called when holding a
197    * corresponding hole {@link CacheSpan} obtained from {@link #startReadWrite(String, long)}.
198    *
199    * <p>This method may be slow and shouldn't normally be called on the main thread.
200    *
201    * @param key The cache key for the data.
202    * @param position The starting position of the data.
203    * @param length The length of the data being written, or {@link C#LENGTH_UNSET} if unknown. Used
204    *     only to ensure that there is enough space in the cache.
205    * @return The file into which data should be written.
206    * @throws CacheException If an error is encountered.
207    */
208   @WorkerThread
startFile(String key, long position, long length)209   File startFile(String key, long position, long length) throws CacheException;
210 
211   /**
212    * Commits a file into the cache. Must only be called when holding a corresponding hole {@link
213    * CacheSpan} obtained from {@link #startReadWrite(String, long)}.
214    *
215    * <p>This method may be slow and shouldn't normally be called on the main thread.
216    *
217    * @param file A newly written cache file.
218    * @param length The length of the newly written cache file in bytes.
219    * @throws CacheException If an error is encountered.
220    */
221   @WorkerThread
commitFile(File file, long length)222   void commitFile(File file, long length) throws CacheException;
223 
224   /**
225    * Releases a {@link CacheSpan} obtained from {@link #startReadWrite(String, long)} which
226    * corresponded to a hole in the cache.
227    *
228    * @param holeSpan The {@link CacheSpan} being released.
229    */
releaseHoleSpan(CacheSpan holeSpan)230   void releaseHoleSpan(CacheSpan holeSpan);
231 
232   /**
233    * Removes a cached {@link CacheSpan} from the cache, deleting the underlying file.
234    *
235    * <p>This method may be slow and shouldn't normally be called on the main thread.
236    *
237    * @param span The {@link CacheSpan} to remove.
238    * @throws CacheException If an error is encountered.
239    */
240   @WorkerThread
removeSpan(CacheSpan span)241   void removeSpan(CacheSpan span) throws CacheException;
242 
243   /**
244    * Queries if a range is entirely available in the cache.
245    *
246    * @param key The cache key for the data.
247    * @param position The starting position of the data.
248    * @param length The length of the data.
249    * @return true if the data is available in the Cache otherwise false;
250    */
isCached(String key, long position, long length)251   boolean isCached(String key, long position, long length);
252 
253   /**
254    * Returns the length of the cached data block starting from the {@code position} to the block end
255    * up to {@code length} bytes. If the {@code position} isn't cached then -(the length of the gap
256    * to the next cached data up to {@code length} bytes) is returned.
257    *
258    * @param key The cache key for the data.
259    * @param position The starting position of the data.
260    * @param length The maximum length of the data to be returned.
261    * @return The length of the cached or not cached data block length.
262    */
getCachedLength(String key, long position, long length)263   long getCachedLength(String key, long position, long length);
264 
265   /**
266    * Applies {@code mutations} to the {@link ContentMetadata} for the given key. A new {@link
267    * CachedContent} is added if there isn't one already with the given key.
268    *
269    * <p>This method may be slow and shouldn't normally be called on the main thread.
270    *
271    * @param key The cache key for the data.
272    * @param mutations Contains mutations to be applied to the metadata.
273    * @throws CacheException If an error is encountered.
274    */
275   @WorkerThread
applyContentMetadataMutations(String key, ContentMetadataMutations mutations)276   void applyContentMetadataMutations(String key, ContentMetadataMutations mutations)
277       throws CacheException;
278 
279   /**
280    * Returns a {@link ContentMetadata} for the given key.
281    *
282    * @param key The cache key for the data.
283    * @return A {@link ContentMetadata} for the given key.
284    */
getContentMetadata(String key)285   ContentMetadata getContentMetadata(String key);
286 }
287