1 /* 2 ** Copyright 2022, 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 17 #ifndef ANDROID_MULTIFILE_BLOB_CACHE_H 18 #define ANDROID_MULTIFILE_BLOB_CACHE_H 19 20 #include <EGL/egl.h> 21 #include <EGL/eglext.h> 22 23 #include <android-base/thread_annotations.h> 24 #include <cutils/properties.h> 25 #include <future> 26 #include <map> 27 #include <queue> 28 #include <string> 29 #include <thread> 30 #include <unordered_map> 31 #include <unordered_set> 32 33 #include "FileBlobCache.h" 34 35 namespace android { 36 37 constexpr uint32_t kMultifileBlobCacheVersion = 1; 38 constexpr char kMultifileBlobCacheStatusFile[] = "cache.status"; 39 40 struct MultifileHeader { 41 uint32_t magic; 42 uint32_t crc; 43 EGLsizeiANDROID keySize; 44 EGLsizeiANDROID valueSize; 45 }; 46 47 struct MultifileEntryStats { 48 EGLsizeiANDROID valueSize; 49 size_t fileSize; 50 time_t accessTime; 51 }; 52 53 struct MultifileStatus { 54 uint32_t magic; 55 uint32_t crc; 56 uint32_t cacheVersion; 57 char buildId[PROP_VALUE_MAX]; 58 }; 59 60 struct MultifileHotCache { 61 int entryFd; 62 uint8_t* entryBuffer; 63 size_t entrySize; 64 }; 65 66 enum class TaskCommand { 67 Invalid = 0, 68 WriteToDisk, 69 Exit, 70 }; 71 72 class DeferredTask { 73 public: DeferredTask(TaskCommand command)74 DeferredTask(TaskCommand command) 75 : mCommand(command), mEntryHash(0), mBuffer(nullptr), mBufferSize(0) {} 76 getTaskCommand()77 TaskCommand getTaskCommand() { return mCommand; } 78 initWriteToDisk(uint32_t entryHash,std::string fullPath,uint8_t * buffer,size_t bufferSize)79 void initWriteToDisk(uint32_t entryHash, std::string fullPath, uint8_t* buffer, 80 size_t bufferSize) { 81 mCommand = TaskCommand::WriteToDisk; 82 mEntryHash = entryHash; 83 mFullPath = std::move(fullPath); 84 mBuffer = buffer; 85 mBufferSize = bufferSize; 86 } 87 getEntryHash()88 uint32_t getEntryHash() { return mEntryHash; } getFullPath()89 std::string& getFullPath() { return mFullPath; } getBuffer()90 uint8_t* getBuffer() { return mBuffer; } getBufferSize()91 size_t getBufferSize() { return mBufferSize; }; 92 93 private: 94 TaskCommand mCommand; 95 96 // Parameters for WriteToDisk 97 uint32_t mEntryHash; 98 std::string mFullPath; 99 uint8_t* mBuffer; 100 size_t mBufferSize; 101 }; 102 103 class MultifileBlobCache { 104 public: 105 MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize, 106 size_t maxTotalEntries, const std::string& baseDir); 107 ~MultifileBlobCache(); 108 109 void set(const void* key, EGLsizeiANDROID keySize, const void* value, 110 EGLsizeiANDROID valueSize); 111 EGLsizeiANDROID get(const void* key, EGLsizeiANDROID keySize, void* value, 112 EGLsizeiANDROID valueSize); 113 114 void finish(); 115 getTotalSize()116 size_t getTotalSize() const { return mTotalCacheSize; } getTotalEntries()117 size_t getTotalEntries() const { return mTotalCacheEntries; } 118 getCurrentBuildId()119 const std::string& getCurrentBuildId() const { return mBuildId; } setCurrentBuildId(const std::string & buildId)120 void setCurrentBuildId(const std::string& buildId) { mBuildId = buildId; } 121 getCurrentCacheVersion()122 uint32_t getCurrentCacheVersion() const { return mCacheVersion; } setCurrentCacheVersion(uint32_t cacheVersion)123 void setCurrentCacheVersion(uint32_t cacheVersion) { mCacheVersion = cacheVersion; } 124 125 private: 126 void trackEntry(uint32_t entryHash, EGLsizeiANDROID valueSize, size_t fileSize, 127 time_t accessTime); 128 bool contains(uint32_t entryHash) const; 129 bool removeEntry(uint32_t entryHash); 130 MultifileEntryStats getEntryStats(uint32_t entryHash); 131 132 bool createStatus(const std::string& baseDir); 133 bool checkStatus(const std::string& baseDir); 134 135 size_t getFileSize(uint32_t entryHash); 136 size_t getValueSize(uint32_t entryHash); 137 138 void increaseTotalCacheSize(size_t fileSize); 139 void decreaseTotalCacheSize(size_t fileSize); 140 141 bool addToHotCache(uint32_t entryHash, int fd, uint8_t* entryBufer, size_t entrySize); 142 bool removeFromHotCache(uint32_t entryHash); 143 144 bool clearCache(); 145 void trimCache(); 146 bool applyLRU(size_t cacheSizeLimit, size_t cacheEntryLimit); 147 148 bool mInitialized; 149 std::string mMultifileDirName; 150 151 std::string mBuildId; 152 uint32_t mCacheVersion; 153 154 std::unordered_set<uint32_t> mEntries; 155 std::unordered_map<uint32_t, MultifileEntryStats> mEntryStats; 156 std::unordered_map<uint32_t, MultifileHotCache> mHotCache; 157 158 size_t mMaxKeySize; 159 size_t mMaxValueSize; 160 size_t mMaxTotalSize; 161 size_t mMaxTotalEntries; 162 size_t mTotalCacheSize; 163 size_t mTotalCacheEntries; 164 size_t mHotCacheLimit; 165 size_t mHotCacheEntryLimit; 166 size_t mHotCacheSize; 167 168 // Below are the components used for deferred writes 169 170 // Track whether we have pending writes for an entry 171 std::mutex mDeferredWriteStatusMutex; 172 std::multimap<uint32_t, uint8_t*> mDeferredWrites GUARDED_BY(mDeferredWriteStatusMutex); 173 174 // Functions to work through tasks in the queue 175 void processTasks(); 176 void processTasksImpl(bool* exitThread); 177 void processTask(DeferredTask& task); 178 179 // Used by main thread to create work for the worker thread 180 void queueTask(DeferredTask&& task); 181 182 // Used by main thread to wait for worker thread to complete all outstanding work. 183 void waitForWorkComplete(); 184 185 std::thread mTaskThread; 186 std::queue<DeferredTask> mTasks; 187 std::mutex mWorkerMutex; 188 189 // This condition will block the worker thread until a task is queued 190 std::condition_variable mWorkAvailableCondition; 191 192 // This condition will block the main thread while the worker thread still has tasks 193 std::condition_variable mWorkerIdleCondition; 194 195 // This bool will track whether all tasks have been completed 196 bool mWorkerThreadIdle; 197 }; 198 199 }; // namespace android 200 201 #endif // ANDROID_MULTIFILE_BLOB_CACHE_H 202