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