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