xref: /aosp_15_r20/frameworks/native/opengl/libs/EGL/BlobCache.h (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  ** Copyright 2011, The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  **
4*38e8c45fSAndroid Build Coastguard Worker  ** Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  ** you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  ** You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  **
8*38e8c45fSAndroid Build Coastguard Worker  **     http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  **
10*38e8c45fSAndroid Build Coastguard Worker  ** Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  ** distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  ** See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  ** limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #ifndef ANDROID_BLOB_CACHE_H
18*38e8c45fSAndroid Build Coastguard Worker #define ANDROID_BLOB_CACHE_H
19*38e8c45fSAndroid Build Coastguard Worker 
20*38e8c45fSAndroid Build Coastguard Worker #include <stddef.h>
21*38e8c45fSAndroid Build Coastguard Worker 
22*38e8c45fSAndroid Build Coastguard Worker #include <memory>
23*38e8c45fSAndroid Build Coastguard Worker #include <vector>
24*38e8c45fSAndroid Build Coastguard Worker 
25*38e8c45fSAndroid Build Coastguard Worker namespace android {
26*38e8c45fSAndroid Build Coastguard Worker 
27*38e8c45fSAndroid Build Coastguard Worker // A BlobCache is an in-memory cache for binary key/value pairs.  A BlobCache
28*38e8c45fSAndroid Build Coastguard Worker // does NOT provide any thread-safety guarantees.
29*38e8c45fSAndroid Build Coastguard Worker //
30*38e8c45fSAndroid Build Coastguard Worker // The cache contents can be serialized to an in-memory buffer or mmap'd file
31*38e8c45fSAndroid Build Coastguard Worker // and then reloaded in a subsequent execution of the program.  This
32*38e8c45fSAndroid Build Coastguard Worker // serialization is non-portable and the data should only be used by the device
33*38e8c45fSAndroid Build Coastguard Worker // that generated it.
34*38e8c45fSAndroid Build Coastguard Worker class BlobCache {
35*38e8c45fSAndroid Build Coastguard Worker public:
36*38e8c45fSAndroid Build Coastguard Worker     // Create an empty blob cache. The blob cache will cache key/value pairs
37*38e8c45fSAndroid Build Coastguard Worker     // with key and value sizes less than or equal to maxKeySize and
38*38e8c45fSAndroid Build Coastguard Worker     // maxValueSize, respectively. The total combined size of ALL cache entries
39*38e8c45fSAndroid Build Coastguard Worker     // (key sizes plus value sizes) will not exceed maxTotalSize.
40*38e8c45fSAndroid Build Coastguard Worker     BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize);
41*38e8c45fSAndroid Build Coastguard Worker 
42*38e8c45fSAndroid Build Coastguard Worker     // Return value from set(), below.
43*38e8c45fSAndroid Build Coastguard Worker     enum class InsertResult {
44*38e8c45fSAndroid Build Coastguard Worker         // The key is larger than maxKeySize specified in the constructor.
45*38e8c45fSAndroid Build Coastguard Worker         kKeyTooBig,
46*38e8c45fSAndroid Build Coastguard Worker         // The value is larger than maxValueSize specified in the constructor.
47*38e8c45fSAndroid Build Coastguard Worker         kValueTooBig,
48*38e8c45fSAndroid Build Coastguard Worker         // The combined key + value is larger than maxTotalSize specified in the constructor.
49*38e8c45fSAndroid Build Coastguard Worker         kCombinedTooBig,
50*38e8c45fSAndroid Build Coastguard Worker         // keySize is 0
51*38e8c45fSAndroid Build Coastguard Worker         kInvalidKeySize,
52*38e8c45fSAndroid Build Coastguard Worker         // valueSize is 0
53*38e8c45fSAndroid Build Coastguard Worker         kInvalidValueSize,
54*38e8c45fSAndroid Build Coastguard Worker         // Unable to free enough space to fit the new entry.
55*38e8c45fSAndroid Build Coastguard Worker         kNotEnoughSpace,
56*38e8c45fSAndroid Build Coastguard Worker         // The new entry was inserted, but an old entry had to be evicted.
57*38e8c45fSAndroid Build Coastguard Worker         kDidClean,
58*38e8c45fSAndroid Build Coastguard Worker         // There was enough room in the cache and the new entry was inserted.
59*38e8c45fSAndroid Build Coastguard Worker         kInserted,
60*38e8c45fSAndroid Build Coastguard Worker 
61*38e8c45fSAndroid Build Coastguard Worker     };
62*38e8c45fSAndroid Build Coastguard Worker     // set inserts a new binary value into the cache and associates it with the
63*38e8c45fSAndroid Build Coastguard Worker     // given binary key.  If the key or value are too large for the cache then
64*38e8c45fSAndroid Build Coastguard Worker     // the cache remains unchanged.  This includes the case where a different
65*38e8c45fSAndroid Build Coastguard Worker     // value was previously associated with the given key - the old value will
66*38e8c45fSAndroid Build Coastguard Worker     // remain in the cache.  If the given key and value are small enough to be
67*38e8c45fSAndroid Build Coastguard Worker     // put in the cache (based on the maxKeySize, maxValueSize, and maxTotalSize
68*38e8c45fSAndroid Build Coastguard Worker     // values specified to the BlobCache constructor), then the key/value pair
69*38e8c45fSAndroid Build Coastguard Worker     // will be in the cache after set returns.  Note, however, that a subsequent
70*38e8c45fSAndroid Build Coastguard Worker     // call to set may evict old key/value pairs from the cache.
71*38e8c45fSAndroid Build Coastguard Worker     //
72*38e8c45fSAndroid Build Coastguard Worker     // Preconditions:
73*38e8c45fSAndroid Build Coastguard Worker     //   key != NULL
74*38e8c45fSAndroid Build Coastguard Worker     //   0 < keySize
75*38e8c45fSAndroid Build Coastguard Worker     //   value != NULL
76*38e8c45fSAndroid Build Coastguard Worker     //   0 < valueSize
77*38e8c45fSAndroid Build Coastguard Worker     InsertResult set(const void* key, size_t keySize, const void* value, size_t valueSize);
78*38e8c45fSAndroid Build Coastguard Worker 
79*38e8c45fSAndroid Build Coastguard Worker     // get retrieves from the cache the binary value associated with a given
80*38e8c45fSAndroid Build Coastguard Worker     // binary key.  If the key is present in the cache then the length of the
81*38e8c45fSAndroid Build Coastguard Worker     // binary value associated with that key is returned.  If the value argument
82*38e8c45fSAndroid Build Coastguard Worker     // is non-NULL and the size of the cached value is less than valueSize bytes
83*38e8c45fSAndroid Build Coastguard Worker     // then the cached value is copied into the buffer pointed to by the value
84*38e8c45fSAndroid Build Coastguard Worker     // argument.  If the key is not present in the cache then 0 is returned and
85*38e8c45fSAndroid Build Coastguard Worker     // the buffer pointed to by the value argument is not modified.
86*38e8c45fSAndroid Build Coastguard Worker     //
87*38e8c45fSAndroid Build Coastguard Worker     // Note that when calling get multiple times with the same key, the later
88*38e8c45fSAndroid Build Coastguard Worker     // calls may fail, returning 0, even if earlier calls succeeded.  The return
89*38e8c45fSAndroid Build Coastguard Worker     // value must be checked for each call.
90*38e8c45fSAndroid Build Coastguard Worker     //
91*38e8c45fSAndroid Build Coastguard Worker     // Preconditions:
92*38e8c45fSAndroid Build Coastguard Worker     //   key != NULL
93*38e8c45fSAndroid Build Coastguard Worker     //   0 < keySize
94*38e8c45fSAndroid Build Coastguard Worker     //   0 <= valueSize
95*38e8c45fSAndroid Build Coastguard Worker     size_t get(const void* key, size_t keySize, void* value, size_t valueSize);
96*38e8c45fSAndroid Build Coastguard Worker 
97*38e8c45fSAndroid Build Coastguard Worker     // getFlattenedSize returns the number of bytes needed to store the entire
98*38e8c45fSAndroid Build Coastguard Worker     // serialized cache.
99*38e8c45fSAndroid Build Coastguard Worker     size_t getFlattenedSize() const;
100*38e8c45fSAndroid Build Coastguard Worker 
101*38e8c45fSAndroid Build Coastguard Worker     // flatten serializes the current contents of the cache into the memory
102*38e8c45fSAndroid Build Coastguard Worker     // pointed to by 'buffer'.  The serialized cache contents can later be
103*38e8c45fSAndroid Build Coastguard Worker     // loaded into a BlobCache object using the unflatten method.  The contents
104*38e8c45fSAndroid Build Coastguard Worker     // of the BlobCache object will not be modified.
105*38e8c45fSAndroid Build Coastguard Worker     //
106*38e8c45fSAndroid Build Coastguard Worker     // Preconditions:
107*38e8c45fSAndroid Build Coastguard Worker     //   size >= this.getFlattenedSize()
108*38e8c45fSAndroid Build Coastguard Worker     int flatten(void* buffer, size_t size) const;
109*38e8c45fSAndroid Build Coastguard Worker 
110*38e8c45fSAndroid Build Coastguard Worker     // unflatten replaces the contents of the cache with the serialized cache
111*38e8c45fSAndroid Build Coastguard Worker     // contents in the memory pointed to by 'buffer'.  The previous contents of
112*38e8c45fSAndroid Build Coastguard Worker     // the BlobCache will be evicted from the cache.  If an error occurs while
113*38e8c45fSAndroid Build Coastguard Worker     // unflattening the serialized cache contents then the BlobCache will be
114*38e8c45fSAndroid Build Coastguard Worker     // left in an empty state.
115*38e8c45fSAndroid Build Coastguard Worker     //
116*38e8c45fSAndroid Build Coastguard Worker     int unflatten(void const* buffer, size_t size);
117*38e8c45fSAndroid Build Coastguard Worker 
118*38e8c45fSAndroid Build Coastguard Worker     // clear flushes out all contents of the cache then the BlobCache, leaving
119*38e8c45fSAndroid Build Coastguard Worker     // it in an empty state.
clear()120*38e8c45fSAndroid Build Coastguard Worker     void clear() {
121*38e8c45fSAndroid Build Coastguard Worker         mCacheEntries.clear();
122*38e8c45fSAndroid Build Coastguard Worker         mTotalSize = 0;
123*38e8c45fSAndroid Build Coastguard Worker     }
124*38e8c45fSAndroid Build Coastguard Worker 
125*38e8c45fSAndroid Build Coastguard Worker protected:
126*38e8c45fSAndroid Build Coastguard Worker     // mMaxTotalSize is the maximum size that all cache entries can occupy. This
127*38e8c45fSAndroid Build Coastguard Worker     // includes space for both keys and values. When a call to BlobCache::set
128*38e8c45fSAndroid Build Coastguard Worker     // would otherwise cause this limit to be exceeded, either the key/value
129*38e8c45fSAndroid Build Coastguard Worker     // pair passed to BlobCache::set will not be cached or other cache entries
130*38e8c45fSAndroid Build Coastguard Worker     // will be evicted from the cache to make room for the new entry.
131*38e8c45fSAndroid Build Coastguard Worker     const size_t mMaxTotalSize;
132*38e8c45fSAndroid Build Coastguard Worker 
133*38e8c45fSAndroid Build Coastguard Worker private:
134*38e8c45fSAndroid Build Coastguard Worker     // Copying is disallowed.
135*38e8c45fSAndroid Build Coastguard Worker     BlobCache(const BlobCache&);
136*38e8c45fSAndroid Build Coastguard Worker     void operator=(const BlobCache&);
137*38e8c45fSAndroid Build Coastguard Worker 
138*38e8c45fSAndroid Build Coastguard Worker     // A random function helper to get around MinGW not having nrand48()
139*38e8c45fSAndroid Build Coastguard Worker     long int blob_random();
140*38e8c45fSAndroid Build Coastguard Worker 
141*38e8c45fSAndroid Build Coastguard Worker     // clean evicts a randomly chosen set of entries from the cache such that
142*38e8c45fSAndroid Build Coastguard Worker     // the total size of all remaining entries is less than mMaxTotalSize/2.
143*38e8c45fSAndroid Build Coastguard Worker     void clean();
144*38e8c45fSAndroid Build Coastguard Worker 
145*38e8c45fSAndroid Build Coastguard Worker     // isCleanable returns true if the cache is full enough for the clean method
146*38e8c45fSAndroid Build Coastguard Worker     // to have some effect, and false otherwise.
147*38e8c45fSAndroid Build Coastguard Worker     bool isCleanable() const;
148*38e8c45fSAndroid Build Coastguard Worker 
149*38e8c45fSAndroid Build Coastguard Worker     // A Blob is an immutable sized unstructured data blob.
150*38e8c45fSAndroid Build Coastguard Worker     class Blob {
151*38e8c45fSAndroid Build Coastguard Worker     public:
152*38e8c45fSAndroid Build Coastguard Worker         Blob(const void* data, size_t size, bool copyData);
153*38e8c45fSAndroid Build Coastguard Worker         ~Blob();
154*38e8c45fSAndroid Build Coastguard Worker 
155*38e8c45fSAndroid Build Coastguard Worker         bool operator<(const Blob& rhs) const;
156*38e8c45fSAndroid Build Coastguard Worker 
157*38e8c45fSAndroid Build Coastguard Worker         const void* getData() const;
158*38e8c45fSAndroid Build Coastguard Worker         size_t getSize() const;
159*38e8c45fSAndroid Build Coastguard Worker 
160*38e8c45fSAndroid Build Coastguard Worker     private:
161*38e8c45fSAndroid Build Coastguard Worker         // Copying is not allowed.
162*38e8c45fSAndroid Build Coastguard Worker         Blob(const Blob&);
163*38e8c45fSAndroid Build Coastguard Worker         void operator=(const Blob&);
164*38e8c45fSAndroid Build Coastguard Worker 
165*38e8c45fSAndroid Build Coastguard Worker         // mData points to the buffer containing the blob data.
166*38e8c45fSAndroid Build Coastguard Worker         const void* mData;
167*38e8c45fSAndroid Build Coastguard Worker 
168*38e8c45fSAndroid Build Coastguard Worker         // mSize is the size of the blob data in bytes.
169*38e8c45fSAndroid Build Coastguard Worker         size_t mSize;
170*38e8c45fSAndroid Build Coastguard Worker 
171*38e8c45fSAndroid Build Coastguard Worker         // mOwnsData indicates whether or not this Blob object should free the
172*38e8c45fSAndroid Build Coastguard Worker         // memory pointed to by mData when the Blob gets destructed.
173*38e8c45fSAndroid Build Coastguard Worker         bool mOwnsData;
174*38e8c45fSAndroid Build Coastguard Worker     };
175*38e8c45fSAndroid Build Coastguard Worker 
176*38e8c45fSAndroid Build Coastguard Worker     // A CacheEntry is a single key/value pair in the cache.
177*38e8c45fSAndroid Build Coastguard Worker     class CacheEntry {
178*38e8c45fSAndroid Build Coastguard Worker     public:
179*38e8c45fSAndroid Build Coastguard Worker         CacheEntry();
180*38e8c45fSAndroid Build Coastguard Worker         CacheEntry(const std::shared_ptr<Blob>& key, const std::shared_ptr<Blob>& value);
181*38e8c45fSAndroid Build Coastguard Worker         CacheEntry(const CacheEntry& ce);
182*38e8c45fSAndroid Build Coastguard Worker 
183*38e8c45fSAndroid Build Coastguard Worker         bool operator<(const CacheEntry& rhs) const;
184*38e8c45fSAndroid Build Coastguard Worker         const CacheEntry& operator=(const CacheEntry&);
185*38e8c45fSAndroid Build Coastguard Worker 
186*38e8c45fSAndroid Build Coastguard Worker         std::shared_ptr<Blob> getKey() const;
187*38e8c45fSAndroid Build Coastguard Worker         std::shared_ptr<Blob> getValue() const;
188*38e8c45fSAndroid Build Coastguard Worker 
189*38e8c45fSAndroid Build Coastguard Worker         void setValue(const std::shared_ptr<Blob>& value);
190*38e8c45fSAndroid Build Coastguard Worker 
191*38e8c45fSAndroid Build Coastguard Worker     private:
192*38e8c45fSAndroid Build Coastguard Worker         // mKey is the key that identifies the cache entry.
193*38e8c45fSAndroid Build Coastguard Worker         std::shared_ptr<Blob> mKey;
194*38e8c45fSAndroid Build Coastguard Worker 
195*38e8c45fSAndroid Build Coastguard Worker         // mValue is the cached data associated with the key.
196*38e8c45fSAndroid Build Coastguard Worker         std::shared_ptr<Blob> mValue;
197*38e8c45fSAndroid Build Coastguard Worker     };
198*38e8c45fSAndroid Build Coastguard Worker 
199*38e8c45fSAndroid Build Coastguard Worker     // A Header is the header for the entire BlobCache serialization format. No
200*38e8c45fSAndroid Build Coastguard Worker     // need to make this portable, so we simply write the struct out.
201*38e8c45fSAndroid Build Coastguard Worker     struct Header {
202*38e8c45fSAndroid Build Coastguard Worker         // mMagicNumber is the magic number that identifies the data as
203*38e8c45fSAndroid Build Coastguard Worker         // serialized BlobCache contents.  It must always contain 'Blb$'.
204*38e8c45fSAndroid Build Coastguard Worker         uint32_t mMagicNumber;
205*38e8c45fSAndroid Build Coastguard Worker 
206*38e8c45fSAndroid Build Coastguard Worker         // mBlobCacheVersion is the serialization format version.
207*38e8c45fSAndroid Build Coastguard Worker         uint32_t mBlobCacheVersion;
208*38e8c45fSAndroid Build Coastguard Worker 
209*38e8c45fSAndroid Build Coastguard Worker         // mDeviceVersion is the device-specific version of the cache.  This can
210*38e8c45fSAndroid Build Coastguard Worker         // be used to invalidate the cache.
211*38e8c45fSAndroid Build Coastguard Worker         uint32_t mDeviceVersion;
212*38e8c45fSAndroid Build Coastguard Worker 
213*38e8c45fSAndroid Build Coastguard Worker         // mNumEntries is number of cache entries following the header in the
214*38e8c45fSAndroid Build Coastguard Worker         // data.
215*38e8c45fSAndroid Build Coastguard Worker         size_t mNumEntries;
216*38e8c45fSAndroid Build Coastguard Worker 
217*38e8c45fSAndroid Build Coastguard Worker         // mBuildId is the build id of the device when the cache was created.
218*38e8c45fSAndroid Build Coastguard Worker         // When an update to the build happens (via an OTA or other update) this
219*38e8c45fSAndroid Build Coastguard Worker         // is used to invalidate the cache.
220*38e8c45fSAndroid Build Coastguard Worker         int mBuildIdLength;
221*38e8c45fSAndroid Build Coastguard Worker         char mBuildId[];
222*38e8c45fSAndroid Build Coastguard Worker     };
223*38e8c45fSAndroid Build Coastguard Worker 
224*38e8c45fSAndroid Build Coastguard Worker     // An EntryHeader is the header for a serialized cache entry.  No need to
225*38e8c45fSAndroid Build Coastguard Worker     // make this portable, so we simply write the struct out.  Each EntryHeader
226*38e8c45fSAndroid Build Coastguard Worker     // is followed imediately by the key data and then the value data.
227*38e8c45fSAndroid Build Coastguard Worker     //
228*38e8c45fSAndroid Build Coastguard Worker     // The beginning of each serialized EntryHeader is 4-byte aligned, so the
229*38e8c45fSAndroid Build Coastguard Worker     // number of bytes that a serialized cache entry will occupy is:
230*38e8c45fSAndroid Build Coastguard Worker     //
231*38e8c45fSAndroid Build Coastguard Worker     //   ((sizeof(EntryHeader) + keySize + valueSize) + 3) & ~3
232*38e8c45fSAndroid Build Coastguard Worker     //
233*38e8c45fSAndroid Build Coastguard Worker     struct EntryHeader {
234*38e8c45fSAndroid Build Coastguard Worker         // mKeySize is the size of the entry key in bytes.
235*38e8c45fSAndroid Build Coastguard Worker         size_t mKeySize;
236*38e8c45fSAndroid Build Coastguard Worker 
237*38e8c45fSAndroid Build Coastguard Worker         // mValueSize is the size of the entry value in bytes.
238*38e8c45fSAndroid Build Coastguard Worker         size_t mValueSize;
239*38e8c45fSAndroid Build Coastguard Worker 
240*38e8c45fSAndroid Build Coastguard Worker         // mData contains both the key and value data for the cache entry.  The
241*38e8c45fSAndroid Build Coastguard Worker         // key comes first followed immediately by the value.
242*38e8c45fSAndroid Build Coastguard Worker         uint8_t mData[];
243*38e8c45fSAndroid Build Coastguard Worker     };
244*38e8c45fSAndroid Build Coastguard Worker 
245*38e8c45fSAndroid Build Coastguard Worker     // mMaxKeySize is the maximum key size that will be cached. Calls to
246*38e8c45fSAndroid Build Coastguard Worker     // BlobCache::set with a keySize parameter larger than mMaxKeySize will
247*38e8c45fSAndroid Build Coastguard Worker     // simply not add the key/value pair to the cache.
248*38e8c45fSAndroid Build Coastguard Worker     const size_t mMaxKeySize;
249*38e8c45fSAndroid Build Coastguard Worker 
250*38e8c45fSAndroid Build Coastguard Worker     // mMaxValueSize is the maximum value size that will be cached. Calls to
251*38e8c45fSAndroid Build Coastguard Worker     // BlobCache::set with a valueSize parameter larger than mMaxValueSize will
252*38e8c45fSAndroid Build Coastguard Worker     // simply not add the key/value pair to the cache.
253*38e8c45fSAndroid Build Coastguard Worker     const size_t mMaxValueSize;
254*38e8c45fSAndroid Build Coastguard Worker 
255*38e8c45fSAndroid Build Coastguard Worker     // mTotalSize is the total combined size of all keys and values currently in
256*38e8c45fSAndroid Build Coastguard Worker     // the cache.
257*38e8c45fSAndroid Build Coastguard Worker     size_t mTotalSize;
258*38e8c45fSAndroid Build Coastguard Worker 
259*38e8c45fSAndroid Build Coastguard Worker     // mRandState is the pseudo-random number generator state. It is passed to
260*38e8c45fSAndroid Build Coastguard Worker     // nrand48 to generate random numbers when needed.
261*38e8c45fSAndroid Build Coastguard Worker     unsigned short mRandState[3];
262*38e8c45fSAndroid Build Coastguard Worker 
263*38e8c45fSAndroid Build Coastguard Worker     // mCacheEntries stores all the cache entries that are resident in memory.
264*38e8c45fSAndroid Build Coastguard Worker     // Cache entries are added to it by the 'set' method.
265*38e8c45fSAndroid Build Coastguard Worker     std::vector<CacheEntry> mCacheEntries;
266*38e8c45fSAndroid Build Coastguard Worker };
267*38e8c45fSAndroid Build Coastguard Worker 
268*38e8c45fSAndroid Build Coastguard Worker } // namespace android
269*38e8c45fSAndroid Build Coastguard Worker 
270*38e8c45fSAndroid Build Coastguard Worker #endif // ANDROID_BLOB_CACHE_H
271