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