| /* |
| ** Copyright 2022, The Android Open Source Project |
| ** |
| ** Licensed under the Apache License, Version 2.0 (the "License"); |
| ** you may not use this file except in compliance with the License. |
| ** You may obtain a copy of the License at |
| ** |
| ** http://www.apache.org/licenses/LICENSE-2.0 |
| ** |
| ** Unless required by applicable law or agreed to in writing, software |
| ** distributed under the License is distributed on an "AS IS" BASIS, |
| ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| ** See the License for the specific language governing permissions and |
| ** limitations under the License. |
| */ |
| |
| #ifndef ANDROID_MULTIFILE_BLOB_CACHE_H |
| #define ANDROID_MULTIFILE_BLOB_CACHE_H |
| |
| #include <EGL/egl.h> |
| #include <EGL/eglext.h> |
| |
| #include <android-base/thread_annotations.h> |
| #include <cutils/properties.h> |
| #include <future> |
| #include <map> |
| #include <queue> |
| #include <string> |
| #include <thread> |
| #include <unordered_map> |
| #include <unordered_set> |
| |
| #include "FileBlobCache.h" |
| |
| namespace android { |
| |
| constexpr uint32_t kMultifileBlobCacheVersion = 1; |
| constexpr char kMultifileBlobCacheStatusFile[] = "cache.status"; |
| |
| struct MultifileHeader { |
| uint32_t magic; |
| uint32_t crc; |
| EGLsizeiANDROID keySize; |
| EGLsizeiANDROID valueSize; |
| }; |
| |
| struct MultifileEntryStats { |
| EGLsizeiANDROID valueSize; |
| size_t fileSize; |
| time_t accessTime; |
| }; |
| |
| struct MultifileStatus { |
| uint32_t magic; |
| uint32_t crc; |
| uint32_t cacheVersion; |
| char buildId[PROP_VALUE_MAX]; |
| }; |
| |
| struct MultifileHotCache { |
| int entryFd; |
| uint8_t* entryBuffer; |
| size_t entrySize; |
| }; |
| |
| enum class TaskCommand { |
| Invalid = 0, |
| WriteToDisk, |
| Exit, |
| }; |
| |
| class DeferredTask { |
| public: |
| DeferredTask(TaskCommand command) |
| : mCommand(command), mEntryHash(0), mBuffer(nullptr), mBufferSize(0) {} |
| |
| TaskCommand getTaskCommand() { return mCommand; } |
| |
| void initWriteToDisk(uint32_t entryHash, std::string fullPath, uint8_t* buffer, |
| size_t bufferSize) { |
| mCommand = TaskCommand::WriteToDisk; |
| mEntryHash = entryHash; |
| mFullPath = std::move(fullPath); |
| mBuffer = buffer; |
| mBufferSize = bufferSize; |
| } |
| |
| uint32_t getEntryHash() { return mEntryHash; } |
| std::string& getFullPath() { return mFullPath; } |
| uint8_t* getBuffer() { return mBuffer; } |
| size_t getBufferSize() { return mBufferSize; }; |
| |
| private: |
| TaskCommand mCommand; |
| |
| // Parameters for WriteToDisk |
| uint32_t mEntryHash; |
| std::string mFullPath; |
| uint8_t* mBuffer; |
| size_t mBufferSize; |
| }; |
| |
| class MultifileBlobCache { |
| public: |
| MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize, |
| size_t maxTotalEntries, const std::string& baseDir); |
| ~MultifileBlobCache(); |
| |
| void set(const void* key, EGLsizeiANDROID keySize, const void* value, |
| EGLsizeiANDROID valueSize); |
| EGLsizeiANDROID get(const void* key, EGLsizeiANDROID keySize, void* value, |
| EGLsizeiANDROID valueSize); |
| |
| void finish(); |
| |
| size_t getTotalSize() const { return mTotalCacheSize; } |
| size_t getTotalEntries() const { return mTotalCacheEntries; } |
| |
| const std::string& getCurrentBuildId() const { return mBuildId; } |
| void setCurrentBuildId(const std::string& buildId) { mBuildId = buildId; } |
| |
| uint32_t getCurrentCacheVersion() const { return mCacheVersion; } |
| void setCurrentCacheVersion(uint32_t cacheVersion) { mCacheVersion = cacheVersion; } |
| |
| private: |
| void trackEntry(uint32_t entryHash, EGLsizeiANDROID valueSize, size_t fileSize, |
| time_t accessTime); |
| bool contains(uint32_t entryHash) const; |
| bool removeEntry(uint32_t entryHash); |
| MultifileEntryStats getEntryStats(uint32_t entryHash); |
| |
| bool createStatus(const std::string& baseDir); |
| bool checkStatus(const std::string& baseDir); |
| |
| size_t getFileSize(uint32_t entryHash); |
| size_t getValueSize(uint32_t entryHash); |
| |
| void increaseTotalCacheSize(size_t fileSize); |
| void decreaseTotalCacheSize(size_t fileSize); |
| |
| bool addToHotCache(uint32_t entryHash, int fd, uint8_t* entryBufer, size_t entrySize); |
| bool removeFromHotCache(uint32_t entryHash); |
| |
| bool clearCache(); |
| void trimCache(); |
| bool applyLRU(size_t cacheSizeLimit, size_t cacheEntryLimit); |
| |
| bool mInitialized; |
| std::string mMultifileDirName; |
| |
| std::string mBuildId; |
| uint32_t mCacheVersion; |
| |
| std::unordered_set<uint32_t> mEntries; |
| std::unordered_map<uint32_t, MultifileEntryStats> mEntryStats; |
| std::unordered_map<uint32_t, MultifileHotCache> mHotCache; |
| |
| size_t mMaxKeySize; |
| size_t mMaxValueSize; |
| size_t mMaxTotalSize; |
| size_t mMaxTotalEntries; |
| size_t mTotalCacheSize; |
| size_t mTotalCacheEntries; |
| size_t mHotCacheLimit; |
| size_t mHotCacheEntryLimit; |
| size_t mHotCacheSize; |
| |
| // Below are the components used for deferred writes |
| |
| // Track whether we have pending writes for an entry |
| std::mutex mDeferredWriteStatusMutex; |
| std::multimap<uint32_t, uint8_t*> mDeferredWrites GUARDED_BY(mDeferredWriteStatusMutex); |
| |
| // Functions to work through tasks in the queue |
| void processTasks(); |
| void processTasksImpl(bool* exitThread); |
| void processTask(DeferredTask& task); |
| |
| // Used by main thread to create work for the worker thread |
| void queueTask(DeferredTask&& task); |
| |
| // Used by main thread to wait for worker thread to complete all outstanding work. |
| void waitForWorkComplete(); |
| |
| std::thread mTaskThread; |
| std::queue<DeferredTask> mTasks; |
| std::mutex mWorkerMutex; |
| |
| // This condition will block the worker thread until a task is queued |
| std::condition_variable mWorkAvailableCondition; |
| |
| // This condition will block the main thread while the worker thread still has tasks |
| std::condition_variable mWorkerIdleCondition; |
| |
| // This bool will track whether all tasks have been completed |
| bool mWorkerThreadIdle; |
| }; |
| |
| }; // namespace android |
| |
| #endif // ANDROID_MULTIFILE_BLOB_CACHE_H |