blob: 3bd393f068041399f7e2dce5574e45b89f203fbe [file] [log] [blame]
Cody Northrop6cca6c22023-02-08 20:23:13 -07001/*
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
Cody Northropbe163732023-03-22 10:14:26 -060023#include <android-base/thread_annotations.h>
Cody Northrop027f2422023-11-12 22:51:01 -070024#include <cutils/properties.h>
Cody Northrop6cca6c22023-02-08 20:23:13 -070025#include <future>
26#include <map>
27#include <queue>
28#include <string>
29#include <thread>
30#include <unordered_map>
31#include <unordered_set>
32
Cody Northrop999db232023-02-27 17:02:50 -070033#include "FileBlobCache.h"
34
Cody Northrop4ee63862024-11-19 22:41:23 -070035#include <com_android_graphics_egl_flags.h>
36
37using namespace com::android::graphics::egl;
38
Cody Northrop6cca6c22023-02-08 20:23:13 -070039namespace android {
40
Jisun Lee88a1b762024-10-17 20:12:29 +090041constexpr uint32_t kMultifileBlobCacheVersion = 2;
Cody Northrop027f2422023-11-12 22:51:01 -070042constexpr char kMultifileBlobCacheStatusFile[] = "cache.status";
43
Cody Northrop6cca6c22023-02-08 20:23:13 -070044struct MultifileHeader {
Cody Northrop999db232023-02-27 17:02:50 -070045 uint32_t magic;
46 uint32_t crc;
Cody Northrop6cca6c22023-02-08 20:23:13 -070047 EGLsizeiANDROID keySize;
48 EGLsizeiANDROID valueSize;
49};
50
51struct MultifileEntryStats {
Cody Northrop99e8f2c2024-11-21 15:32:32 -070052 uint32_t entryHash;
Cody Northrop6cca6c22023-02-08 20:23:13 -070053 EGLsizeiANDROID valueSize;
54 size_t fileSize;
Cody Northrop6cca6c22023-02-08 20:23:13 -070055};
56
Cody Northrop027f2422023-11-12 22:51:01 -070057struct MultifileStatus {
58 uint32_t magic;
59 uint32_t crc;
60 uint32_t cacheVersion;
61 char buildId[PROP_VALUE_MAX];
62};
63
Cody Northrop6cca6c22023-02-08 20:23:13 -070064struct MultifileHotCache {
65 int entryFd;
66 uint8_t* entryBuffer;
67 size_t entrySize;
68};
69
70enum class TaskCommand {
71 Invalid = 0,
72 WriteToDisk,
73 Exit,
74};
75
76class DeferredTask {
77public:
78 DeferredTask(TaskCommand command)
79 : mCommand(command), mEntryHash(0), mBuffer(nullptr), mBufferSize(0) {}
80
81 TaskCommand getTaskCommand() { return mCommand; }
82
83 void initWriteToDisk(uint32_t entryHash, std::string fullPath, uint8_t* buffer,
84 size_t bufferSize) {
85 mCommand = TaskCommand::WriteToDisk;
86 mEntryHash = entryHash;
87 mFullPath = std::move(fullPath);
88 mBuffer = buffer;
89 mBufferSize = bufferSize;
90 }
91
92 uint32_t getEntryHash() { return mEntryHash; }
93 std::string& getFullPath() { return mFullPath; }
94 uint8_t* getBuffer() { return mBuffer; }
95 size_t getBufferSize() { return mBufferSize; };
96
97private:
98 TaskCommand mCommand;
99
100 // Parameters for WriteToDisk
101 uint32_t mEntryHash;
102 std::string mFullPath;
103 uint8_t* mBuffer;
104 size_t mBufferSize;
105};
106
Cody Northrop99e8f2c2024-11-21 15:32:32 -0700107#if COM_ANDROID_GRAPHICS_EGL_FLAGS(MULTIFILE_BLOBCACHE_ADVANCED_USAGE)
108struct MultifileTimeLess {
109 bool operator()(const struct timespec& t1, const struct timespec& t2) const {
110 if (t1.tv_sec == t2.tv_sec) {
111 // If seconds are equal, check nanoseconds
112 return t1.tv_nsec < t2.tv_nsec;
113 } else {
114 // Otherwise, compare seconds
115 return t1.tv_sec < t2.tv_sec;
116 }
117 }
118};
119
120// The third parameter here causes all entries to be sorted by access time,
121// so oldest will be accessed first in applyLRU
122using MultifileEntryStatsMap =
123 std::multimap<struct timespec, MultifileEntryStats, MultifileTimeLess>;
124using MultifileEntryStatsMapIter = MultifileEntryStatsMap::iterator;
125#endif // COM_ANDROID_GRAPHICS_EGL_FLAGS(MULTIFILE_BLOBCACHE_ADVANCED_USAGE)
126
Cody Northrop6cca6c22023-02-08 20:23:13 -0700127class MultifileBlobCache {
128public:
Cody Northrop5dbcfa72023-03-24 15:34:09 -0600129 MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize,
Cody Northropb5267032023-10-24 10:11:21 -0600130 size_t maxTotalEntries, const std::string& baseDir);
Cody Northrop6cca6c22023-02-08 20:23:13 -0700131 ~MultifileBlobCache();
132
133 void set(const void* key, EGLsizeiANDROID keySize, const void* value,
134 EGLsizeiANDROID valueSize);
135 EGLsizeiANDROID get(const void* key, EGLsizeiANDROID keySize, void* value,
136 EGLsizeiANDROID valueSize);
137
138 void finish();
139
140 size_t getTotalSize() const { return mTotalCacheSize; }
Cody Northropb5267032023-10-24 10:11:21 -0600141 size_t getTotalEntries() const { return mTotalCacheEntries; }
Cody Northrop99e8f2c2024-11-21 15:32:32 -0700142 size_t getTotalCacheSizeDivisor() const { return mTotalCacheSizeDivisor; }
Cody Northrop6cca6c22023-02-08 20:23:13 -0700143
Cody Northrop027f2422023-11-12 22:51:01 -0700144 const std::string& getCurrentBuildId() const { return mBuildId; }
145 void setCurrentBuildId(const std::string& buildId) { mBuildId = buildId; }
146
147 uint32_t getCurrentCacheVersion() const { return mCacheVersion; }
148 void setCurrentCacheVersion(uint32_t cacheVersion) { mCacheVersion = cacheVersion; }
149
Cody Northrop6cca6c22023-02-08 20:23:13 -0700150private:
151 void trackEntry(uint32_t entryHash, EGLsizeiANDROID valueSize, size_t fileSize,
Cody Northrop99e8f2c2024-11-21 15:32:32 -0700152 const timespec& accessTime);
Cody Northrop6cca6c22023-02-08 20:23:13 -0700153 bool contains(uint32_t entryHash) const;
154 bool removeEntry(uint32_t entryHash);
155 MultifileEntryStats getEntryStats(uint32_t entryHash);
Cody Northrop99e8f2c2024-11-21 15:32:32 -0700156 void updateEntryTime(uint32_t entryHash, const timespec& newTime);
Cody Northrop6cca6c22023-02-08 20:23:13 -0700157
Cody Northrop027f2422023-11-12 22:51:01 -0700158 bool createStatus(const std::string& baseDir);
159 bool checkStatus(const std::string& baseDir);
160
Cody Northrop6cca6c22023-02-08 20:23:13 -0700161 size_t getFileSize(uint32_t entryHash);
162 size_t getValueSize(uint32_t entryHash);
163
164 void increaseTotalCacheSize(size_t fileSize);
165 void decreaseTotalCacheSize(size_t fileSize);
166
167 bool addToHotCache(uint32_t entryHash, int fd, uint8_t* entryBufer, size_t entrySize);
168 bool removeFromHotCache(uint32_t entryHash);
169
Cody Northrop027f2422023-11-12 22:51:01 -0700170 bool clearCache();
Cody Northropf2588a82023-03-27 23:03:49 -0600171 void trimCache();
Cody Northropb5267032023-10-24 10:11:21 -0600172 bool applyLRU(size_t cacheSizeLimit, size_t cacheEntryLimit);
Cody Northrop6cca6c22023-02-08 20:23:13 -0700173
174 bool mInitialized;
175 std::string mMultifileDirName;
176
Cody Northrop027f2422023-11-12 22:51:01 -0700177 std::string mBuildId;
178 uint32_t mCacheVersion;
179
Cody Northrop99e8f2c2024-11-21 15:32:32 -0700180#if COM_ANDROID_GRAPHICS_EGL_FLAGS(MULTIFILE_BLOBCACHE_ADVANCED_USAGE)
181 std::unordered_map<uint32_t, MultifileEntryStatsMapIter> mEntries;
182 MultifileEntryStatsMap mEntryStats;
183#else
Cody Northrop6cca6c22023-02-08 20:23:13 -0700184 std::unordered_set<uint32_t> mEntries;
185 std::unordered_map<uint32_t, MultifileEntryStats> mEntryStats;
Cody Northrop99e8f2c2024-11-21 15:32:32 -0700186#endif // COM_ANDROID_GRAPHICS_EGL_FLAGS(MULTIFILE_BLOBCACHE_ADVANCED_USAGE)
187
Cody Northrop6cca6c22023-02-08 20:23:13 -0700188 std::unordered_map<uint32_t, MultifileHotCache> mHotCache;
189
190 size_t mMaxKeySize;
191 size_t mMaxValueSize;
192 size_t mMaxTotalSize;
Cody Northropb5267032023-10-24 10:11:21 -0600193 size_t mMaxTotalEntries;
Cody Northrop6cca6c22023-02-08 20:23:13 -0700194 size_t mTotalCacheSize;
Cody Northropb5267032023-10-24 10:11:21 -0600195 size_t mTotalCacheEntries;
Cody Northrop99e8f2c2024-11-21 15:32:32 -0700196 size_t mTotalCacheSizeDivisor;
Cody Northrop6cca6c22023-02-08 20:23:13 -0700197 size_t mHotCacheLimit;
198 size_t mHotCacheEntryLimit;
199 size_t mHotCacheSize;
200
201 // Below are the components used for deferred writes
202
203 // Track whether we have pending writes for an entry
Cody Northropbe163732023-03-22 10:14:26 -0600204 std::mutex mDeferredWriteStatusMutex;
205 std::multimap<uint32_t, uint8_t*> mDeferredWrites GUARDED_BY(mDeferredWriteStatusMutex);
Cody Northrop6cca6c22023-02-08 20:23:13 -0700206
207 // Functions to work through tasks in the queue
208 void processTasks();
209 void processTasksImpl(bool* exitThread);
210 void processTask(DeferredTask& task);
211
212 // Used by main thread to create work for the worker thread
213 void queueTask(DeferredTask&& task);
214
215 // Used by main thread to wait for worker thread to complete all outstanding work.
216 void waitForWorkComplete();
217
218 std::thread mTaskThread;
219 std::queue<DeferredTask> mTasks;
220 std::mutex mWorkerMutex;
221
222 // This condition will block the worker thread until a task is queued
223 std::condition_variable mWorkAvailableCondition;
224
225 // This condition will block the main thread while the worker thread still has tasks
226 std::condition_variable mWorkerIdleCondition;
227
228 // This bool will track whether all tasks have been completed
229 bool mWorkerThreadIdle;
230};
231
232}; // namespace android
233
234#endif // ANDROID_MULTIFILE_BLOB_CACHE_H