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