1 // This file is part of Desktop App Toolkit,
2 // a set of libraries for developing nice desktop applications.
3 //
4 // For license and copyright information please follow this link:
5 // https://github.com/desktop-app/legal/blob/master/LEGAL
6 //
7 #pragma once
8
9 #include "base/basic_types.h"
10 #include "base/flat_map.h"
11 #include "base/optional.h"
12 #include <crl/crl_time.h>
13 #include <QtCore/QString>
14 #include <QtCore/QByteArray>
15
16 namespace Storage {
17 namespace Cache {
18
19 struct Key {
20 uint64 high = 0;
21 uint64 low = 0;
22
validKey23 [[nodiscard]] bool valid() const {
24 return (high != 0) || (low != 0);
25 }
26 explicit operator bool() const {
27 return valid();
28 }
29 };
30
31 inline bool operator==(const Key &a, const Key &b) {
32 return (a.high == b.high) && (a.low == b.low);
33 }
34
35 inline bool operator!=(const Key &a, const Key &b) {
36 return !(a == b);
37 }
38
39 inline bool operator<(const Key &a, const Key &b) {
40 return std::tie(a.high, a.low) < std::tie(b.high, b.low);
41 }
42
43 struct Error {
44 enum class Type {
45 None,
46 IO,
47 WrongKey,
48 LockFailed,
49 };
50 Type type = Type::None;
51 QString path;
52
53 static Error NoError();
54 };
55
NoError()56 inline Error Error::NoError() {
57 return Error();
58 }
59
60 namespace details {
61
62 using RecordType = uint8;
63 using PlaceId = std::array<uint8, 7>;
64 using EntrySize = std::array<uint8, 3>;
65 using RecordsCount = std::array<uint8, 3>;
66
67 constexpr auto kRecordSizeUnknown = size_type(-1);
68 constexpr auto kRecordSizeInvalid = size_type(-2);
69 constexpr auto kBundledRecordsLimit
70 = size_type(1 << (RecordsCount().size() * 8));
71 constexpr auto kDataSizeLimit = size_type(1 << (EntrySize().size() * 8));
72
73 struct Settings {
74 size_type maxBundledRecords = 16 * 1024;
75 size_type readBlockSize = 8 * 1024 * 1024;
76 size_type maxDataSize = (kDataSizeLimit - 1);
77 crl::time writeBundleDelay = 15 * 60 * crl::time(1000);
78 size_type staleRemoveChunk = 256;
79
80 int64 compactAfterExcess = 8 * 1024 * 1024;
81 int64 compactAfterFullSize = 0;
82 size_type compactChunkSize = 16 * 1024;
83
84 bool trackEstimatedTime = true;
85 int64 totalSizeLimit = 1024 * 1024 * 1024;
86 size_type totalTimeLimit = 31 * 24 * 60 * 60; // One month in seconds.
87 crl::time pruneTimeout = 5 * crl::time(1000);
88 crl::time maxPruneCheckTimeout = 3600 * crl::time(1000);
89
90 bool clearOnWrongKey = false;
91 };
92
93 struct SettingsUpdate {
94 int64 totalSizeLimit = Settings().totalSizeLimit;
95 size_type totalTimeLimit = Settings().totalTimeLimit;
96 };
97
98 struct TaggedValue {
99 TaggedValue() = default;
100 TaggedValue(QByteArray &&bytes, uint8 tag);
101
102 QByteArray bytes;
103 uint8 tag = 0;
104 };
105
106 struct TaggedSummary {
107 size_type count = 0;
108 int64 totalSize = 0;
109 };
110 struct Stats {
111 TaggedSummary full;
112 base::flat_map<uint8, TaggedSummary> tagged;
113 bool clearing = false;
114 };
115
116 using Version = int32;
117
118 QString ComputeBasePath(const QString &original);
119 QString VersionFilePath(const QString &base);
120 std::optional<Version> ReadVersionValue(const QString &base);
121 bool WriteVersionValue(const QString &base, Version value);
122
123 template <typename Record>
124 constexpr auto GoodForEncryption = ((sizeof(Record) & 0x0F) == 0);
125
126 enum class Format : uint32 {
127 Format_0,
128 };
129
130 struct BasicHeader {
131 BasicHeader();
132
133 static constexpr auto kTrackEstimatedTime = 0x01U;
134
getFormatBasicHeader135 Format getFormat() const {
136 return static_cast<Format>(format);
137 }
setFormatBasicHeader138 void setFormat(Format format) {
139 this->format = static_cast<uint32>(format);
140 }
141
142 uint32 format : 8;
143 uint32 flags : 24;
144 uint32 systemTime = 0;
145 uint32 reserved1 = 0;
146 uint32 reserved2 = 0;
147 };
148
149 struct EstimatedTimePoint {
150 uint32 relative1 = 0;
151 uint32 relative2 = 0;
152 uint32 system = 0;
153
setRelativeEstimatedTimePoint154 void setRelative(uint64 value) {
155 relative1 = uint32(value & 0xFFFFFFFFU);
156 relative2 = uint32((value >> 32) & 0xFFFFFFFFU);
157 }
getRelativeEstimatedTimePoint158 uint64 getRelative() const {
159 return uint64(relative1) | (uint64(relative2) << 32);
160 }
161 };
162
163 struct Store {
164 static constexpr auto kType = RecordType(0x01);
165
166 void setSize(size_type size);
167 size_type getSize() const;
168
169 RecordType type = kType;
170 uint8 tag = 0;
171 EntrySize size = { { 0 } };
172 PlaceId place = { { 0 } };
173 uint32 checksum = 0;
174 Key key;
175 };
176
177 struct StoreWithTime : Store {
178 EstimatedTimePoint time;
179 uint32 reserved = 0;
180 };
181
182 struct MultiStore {
183 static constexpr auto kType = RecordType(0x02);
184
185 explicit MultiStore(size_type count = 0);
186
187 RecordType type = kType;
188 RecordsCount count = { { 0 } };
189 uint32 reserved1 = 0;
190 uint32 reserved2 = 0;
191 uint32 reserved3 = 0;
192
193 using Part = Store;
194 size_type validateCount() const;
195 };
196 struct MultiStoreWithTime : MultiStore {
197 using MultiStore::MultiStore;
198
199 using Part = StoreWithTime;
200 };
201
202 struct MultiRemove {
203 static constexpr auto kType = RecordType(0x03);
204
205 explicit MultiRemove(size_type count = 0);
206
207 RecordType type = kType;
208 RecordsCount count = { { 0 } };
209 uint32 reserved1 = 0;
210 uint32 reserved2 = 0;
211 uint32 reserved3 = 0;
212
213 using Part = Key;
214 size_type validateCount() const;
215 };
216
217 struct MultiAccess {
218 static constexpr auto kType = RecordType(0x04);
219
220 explicit MultiAccess(
221 EstimatedTimePoint time,
222 size_type count = 0);
223
224 RecordType type = kType;
225 RecordsCount count = { { 0 } };
226 EstimatedTimePoint time;
227
228 using Part = Key;
229 size_type validateCount() const;
230 };
231
232 } // namespace details
233 } // namespace Cache
234 } // namespace Storage
235
236 namespace std {
237
238 template <>
239 struct hash<Storage::Cache::Key> {
240 size_t operator()(const Storage::Cache::Key &key) const {
241 return (hash<uint64>()(key.high) ^ hash<uint64>()(key.low));
242 }
243 };
244
245 } // namespace std
246