• 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 <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