blob: f266011fda595a07c6fff536e2559b1a0fcc82f0 [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 Northrop6cca6c22023-02-08 20:23:13 -070024#include <future>
25#include <map>
26#include <queue>
27#include <string>
28#include <thread>
29#include <unordered_map>
30#include <unordered_set>
31
Cody Northrop999db232023-02-27 17:02:50 -070032#include "FileBlobCache.h"
33
Cody Northrop6cca6c22023-02-08 20:23:13 -070034namespace android {
35
36struct MultifileHeader {
Cody Northrop999db232023-02-27 17:02:50 -070037 uint32_t magic;
38 uint32_t crc;
Cody Northrop6cca6c22023-02-08 20:23:13 -070039 EGLsizeiANDROID keySize;
40 EGLsizeiANDROID valueSize;
41};
42
43struct MultifileEntryStats {
44 EGLsizeiANDROID valueSize;
45 size_t fileSize;
46 time_t accessTime;
47};
48
49struct MultifileHotCache {
50 int entryFd;
51 uint8_t* entryBuffer;
52 size_t entrySize;
53};
54
55enum class TaskCommand {
56 Invalid = 0,
57 WriteToDisk,
58 Exit,
59};
60
61class DeferredTask {
62public:
63 DeferredTask(TaskCommand command)
64 : mCommand(command), mEntryHash(0), mBuffer(nullptr), mBufferSize(0) {}
65
66 TaskCommand getTaskCommand() { return mCommand; }
67
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
77 uint32_t getEntryHash() { return mEntryHash; }
78 std::string& getFullPath() { return mFullPath; }
79 uint8_t* getBuffer() { return mBuffer; }
80 size_t getBufferSize() { return mBufferSize; };
81
82private:
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
92class MultifileBlobCache {
93public:
94 MultifileBlobCache(size_t maxTotalSize, size_t maxHotCacheSize, const std::string& baseDir);
95 ~MultifileBlobCache();
96
97 void set(const void* key, EGLsizeiANDROID keySize, const void* value,
98 EGLsizeiANDROID valueSize);
99 EGLsizeiANDROID get(const void* key, EGLsizeiANDROID keySize, void* value,
100 EGLsizeiANDROID valueSize);
101
102 void finish();
103
104 size_t getTotalSize() const { return mTotalCacheSize; }
105
106private:
107 void trackEntry(uint32_t entryHash, EGLsizeiANDROID valueSize, size_t fileSize,
108 time_t accessTime);
109 bool contains(uint32_t entryHash) const;
110 bool removeEntry(uint32_t entryHash);
111 MultifileEntryStats getEntryStats(uint32_t entryHash);
112
113 size_t getFileSize(uint32_t entryHash);
114 size_t getValueSize(uint32_t entryHash);
115
116 void increaseTotalCacheSize(size_t fileSize);
117 void decreaseTotalCacheSize(size_t fileSize);
118
119 bool addToHotCache(uint32_t entryHash, int fd, uint8_t* entryBufer, size_t entrySize);
120 bool removeFromHotCache(uint32_t entryHash);
121
Cody Northropf2588a82023-03-27 23:03:49 -0600122 void trimCache();
Cody Northrop6cca6c22023-02-08 20:23:13 -0700123 bool applyLRU(size_t cacheLimit);
124
125 bool mInitialized;
126 std::string mMultifileDirName;
127
128 std::unordered_set<uint32_t> mEntries;
129 std::unordered_map<uint32_t, MultifileEntryStats> mEntryStats;
130 std::unordered_map<uint32_t, MultifileHotCache> mHotCache;
131
132 size_t mMaxKeySize;
133 size_t mMaxValueSize;
134 size_t mMaxTotalSize;
135 size_t mTotalCacheSize;
136 size_t mHotCacheLimit;
137 size_t mHotCacheEntryLimit;
138 size_t mHotCacheSize;
139
140 // Below are the components used for deferred writes
141
142 // Track whether we have pending writes for an entry
Cody Northropbe163732023-03-22 10:14:26 -0600143 std::mutex mDeferredWriteStatusMutex;
144 std::multimap<uint32_t, uint8_t*> mDeferredWrites GUARDED_BY(mDeferredWriteStatusMutex);
Cody Northrop6cca6c22023-02-08 20:23:13 -0700145
146 // Functions to work through tasks in the queue
147 void processTasks();
148 void processTasksImpl(bool* exitThread);
149 void processTask(DeferredTask& task);
150
151 // Used by main thread to create work for the worker thread
152 void queueTask(DeferredTask&& task);
153
154 // Used by main thread to wait for worker thread to complete all outstanding work.
155 void waitForWorkComplete();
156
157 std::thread mTaskThread;
158 std::queue<DeferredTask> mTasks;
159 std::mutex mWorkerMutex;
160
161 // This condition will block the worker thread until a task is queued
162 std::condition_variable mWorkAvailableCondition;
163
164 // This condition will block the main thread while the worker thread still has tasks
165 std::condition_variable mWorkerIdleCondition;
166
167 // This bool will track whether all tasks have been completed
168 bool mWorkerThreadIdle;
169};
170
171}; // namespace android
172
173#endif // ANDROID_MULTIFILE_BLOB_CACHE_H