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