• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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