1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/extras/sqlite/sqlite_persistent_shared_dictionary_store.h"
6
7 #include "base/containers/span.h"
8 #include "base/debug/dump_without_crashing.h"
9 #include "base/files/file_path.h"
10 #include "base/metrics/histogram_functions.h"
11 #include "base/pickle.h"
12 #include "base/strings/strcat.h"
13 #include "base/task/sequenced_task_runner.h"
14 #include "base/types/expected_macros.h"
15 #include "net/base/network_isolation_key.h"
16 #include "net/extras/shared_dictionary/shared_dictionary_isolation_key.h"
17 #include "net/extras/sqlite/sqlite_persistent_store_backend_base.h"
18 #include "sql/database.h"
19 #include "sql/statement.h"
20 #include "sql/transaction.h"
21
22 namespace net {
23
24 namespace {
25
26 constexpr char kHistogramTag[] = "SharedDictionary";
27
28 constexpr char kHistogramPrefix[] = "Net.SharedDictionaryStore.";
29
30 constexpr char kTableName[] = "dictionaries";
31
32 // The key for storing the total dictionary size in MetaTable. It is utilized
33 // when determining whether cache eviction needs to be performed. We store it as
34 // metadata because calculating the total size is an expensive operation.
35 constexpr char kTotalDictSizeKey[] = "total_dict_size";
36
37 const int kCurrentVersionNumber = 1;
38 const int kCompatibleVersionNumber = 1;
39
CreateV1Schema(sql::Database * db,sql::MetaTable * meta_table)40 bool CreateV1Schema(sql::Database* db, sql::MetaTable* meta_table) {
41 CHECK(!db->DoesTableExist(kTableName));
42
43 static constexpr char kCreateTableQuery[] =
44 // clang-format off
45 "CREATE TABLE dictionaries("
46 "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
47 "frame_origin TEXT NOT NULL,"
48 "top_frame_site TEXT NOT NULL,"
49 "host TEXT NOT NULL,"
50 "match TEXT NOT NULL,"
51 "url TEXT NOT NULL,"
52 "res_time INTEGER NOT NULL,"
53 "exp_time INTEGER NOT NULL,"
54 "last_used_time INTEGER NOT NULL,"
55 "size INTEGER NOT NULL,"
56 "sha256 BLOB NOT NULL,"
57 "token_high INTEGER NOT NULL,"
58 "token_low INTEGER NOT NULL)";
59 // clang-format on
60
61 static constexpr char kCreateUniqueIndexQuery[] =
62 // clang-format off
63 "CREATE UNIQUE INDEX unique_index ON dictionaries("
64 "frame_origin,"
65 "top_frame_site,"
66 "host,"
67 "match)";
68 // clang-format on
69
70 // This index is used for the size and count limitation per top_frame_site.
71 static constexpr char kCreateTopFrameSiteIndexQuery[] =
72 // clang-format off
73 "CREATE INDEX top_frame_site_index ON dictionaries("
74 "top_frame_site)";
75 // clang-format on
76
77 // This index is used for GetDictionaries().
78 static constexpr char kCreateIsolationIndexQuery[] =
79 // clang-format off
80 "CREATE INDEX isolation_index ON dictionaries("
81 "frame_origin,"
82 "top_frame_site)";
83 // clang-format on
84
85 // This index will be used when implementing garbage collection logic of
86 // SharedDictionaryDiskCache.
87 static constexpr char kCreateTokenIndexQuery[] =
88 // clang-format off
89 "CREATE INDEX token_index ON dictionaries("
90 "token_high, token_low)";
91 // clang-format on
92
93 // This index will be used when implementing clearing expired dictionary
94 // logic.
95 static constexpr char kCreateExpirationTimeIndexQuery[] =
96 // clang-format off
97 "CREATE INDEX exp_time_index ON dictionaries("
98 "exp_time)";
99 // clang-format on
100
101 // This index will be used when implementing clearing dictionary logic which
102 // will be called from BrowsingDataRemover.
103 static constexpr char kCreateLastUsedTimeIndexQuery[] =
104 // clang-format off
105 "CREATE INDEX last_used_time_index ON dictionaries("
106 "last_used_time)";
107 // clang-format on
108
109 if (!db->Execute(kCreateTableQuery) ||
110 !db->Execute(kCreateUniqueIndexQuery) ||
111 !db->Execute(kCreateTopFrameSiteIndexQuery) ||
112 !db->Execute(kCreateIsolationIndexQuery) ||
113 !db->Execute(kCreateTokenIndexQuery) ||
114 !db->Execute(kCreateExpirationTimeIndexQuery) ||
115 !db->Execute(kCreateLastUsedTimeIndexQuery) ||
116 !meta_table->SetValue(kTotalDictSizeKey, 0)) {
117 return false;
118 }
119 return true;
120 }
121
ToSHA256HashValue(base::span<const uint8_t> sha256_bytes)122 absl::optional<SHA256HashValue> ToSHA256HashValue(
123 base::span<const uint8_t> sha256_bytes) {
124 SHA256HashValue sha256_hash;
125 if (sha256_bytes.size() != sizeof(sha256_hash.data)) {
126 return absl::nullopt;
127 }
128 memcpy(sha256_hash.data, sha256_bytes.data(), sha256_bytes.size());
129 return sha256_hash;
130 }
131
ToUnguessableToken(int64_t token_high,int64_t token_low)132 absl::optional<base::UnguessableToken> ToUnguessableToken(int64_t token_high,
133 int64_t token_low) {
134 // There is no `sql::Statement::ColumnUint64()` method. So we cast to
135 // uint64_t.
136 return base::UnguessableToken::Deserialize(static_cast<uint64_t>(token_high),
137 static_cast<uint64_t>(token_low));
138 }
139
140 template <typename ResultType>
WrapCallbackWithWeakPtrCheck(base::WeakPtr<SQLitePersistentSharedDictionaryStore> weak_ptr,base::OnceCallback<void (ResultType)> callback)141 base::OnceCallback<void(ResultType)> WrapCallbackWithWeakPtrCheck(
142 base::WeakPtr<SQLitePersistentSharedDictionaryStore> weak_ptr,
143 base::OnceCallback<void(ResultType)> callback) {
144 return base::BindOnce(
145 [](base::WeakPtr<SQLitePersistentSharedDictionaryStore> weak_ptr,
146 base::OnceCallback<void(ResultType)> callback, ResultType result) {
147 if (!weak_ptr) {
148 return;
149 }
150 std::move(callback).Run(std::move(result));
151 },
152 std::move(weak_ptr), std::move(callback));
153 }
154
RecordErrorHistogram(const char * method_name,SQLitePersistentSharedDictionaryStore::Error error)155 void RecordErrorHistogram(const char* method_name,
156 SQLitePersistentSharedDictionaryStore::Error error) {
157 base::UmaHistogramEnumeration(
158 base::StrCat({kHistogramPrefix, method_name, ".Error"}), error);
159 }
160
161 template <typename ResultType>
RecordErrorHistogram(const char * method_name,base::expected<ResultType,SQLitePersistentSharedDictionaryStore::Error> result)162 void RecordErrorHistogram(
163 const char* method_name,
164 base::expected<ResultType, SQLitePersistentSharedDictionaryStore::Error>
165 result) {
166 RecordErrorHistogram(method_name,
167 result.has_value()
168 ? SQLitePersistentSharedDictionaryStore::Error::kOk
169 : result.error());
170 }
171
172 } // namespace
173
174 SQLitePersistentSharedDictionaryStore::RegisterDictionaryResult::
RegisterDictionaryResult(int64_t primary_key_in_database,absl::optional<base::UnguessableToken> replaced_disk_cache_key_token,std::set<base::UnguessableToken> evicted_disk_cache_key_tokens,uint64_t total_dictionary_size,uint64_t total_dictionary_count)175 RegisterDictionaryResult(
176 int64_t primary_key_in_database,
177 absl::optional<base::UnguessableToken> replaced_disk_cache_key_token,
178 std::set<base::UnguessableToken> evicted_disk_cache_key_tokens,
179 uint64_t total_dictionary_size,
180 uint64_t total_dictionary_count)
181 : primary_key_in_database_(primary_key_in_database),
182 replaced_disk_cache_key_token_(std::move(replaced_disk_cache_key_token)),
183 evicted_disk_cache_key_tokens_(std::move(evicted_disk_cache_key_tokens)),
184 total_dictionary_size_(total_dictionary_size),
185 total_dictionary_count_(total_dictionary_count) {}
186
187 SQLitePersistentSharedDictionaryStore::RegisterDictionaryResult::
188 ~RegisterDictionaryResult() = default;
189
190 SQLitePersistentSharedDictionaryStore::RegisterDictionaryResult::
191 RegisterDictionaryResult(const RegisterDictionaryResult& other) = default;
192
193 SQLitePersistentSharedDictionaryStore::RegisterDictionaryResult::
194 RegisterDictionaryResult(RegisterDictionaryResult&& other) = default;
195
196 SQLitePersistentSharedDictionaryStore::RegisterDictionaryResult&
197 SQLitePersistentSharedDictionaryStore::RegisterDictionaryResult::operator=(
198 const RegisterDictionaryResult& other) = default;
199
200 SQLitePersistentSharedDictionaryStore::RegisterDictionaryResult&
201 SQLitePersistentSharedDictionaryStore::RegisterDictionaryResult::operator=(
202 RegisterDictionaryResult&& other) = default;
203
204 class SQLitePersistentSharedDictionaryStore::Backend
205 : public SQLitePersistentStoreBackendBase {
206 public:
Backend(const base::FilePath & path,const scoped_refptr<base::SequencedTaskRunner> & client_task_runner,const scoped_refptr<base::SequencedTaskRunner> & background_task_runner)207 Backend(
208 const base::FilePath& path,
209 const scoped_refptr<base::SequencedTaskRunner>& client_task_runner,
210 const scoped_refptr<base::SequencedTaskRunner>& background_task_runner)
211 : SQLitePersistentStoreBackendBase(path,
212 kHistogramTag,
213 kCurrentVersionNumber,
214 kCompatibleVersionNumber,
215 background_task_runner,
216 client_task_runner,
217 /*enable_exclusive_access=*/false) {}
218
219 Backend(const Backend&) = delete;
220 Backend& operator=(const Backend&) = delete;
221
222 #define DEFINE_CROSS_SEQUENCE_CALL_METHOD(Name) \
223 template <typename ResultType, typename... Args> \
224 void Name(base::OnceCallback<void(ResultType)> callback, Args&&... args) { \
225 CHECK(client_task_runner()->RunsTasksInCurrentSequence()); \
226 PostBackgroundTask( \
227 FROM_HERE, \
228 base::BindOnce( \
229 [](scoped_refptr<Backend> backend, \
230 base::OnceCallback<void(ResultType)> callback, \
231 Args&&... args) { \
232 auto result = backend->Name##Impl(std::forward<Args>(args)...); \
233 RecordErrorHistogram(#Name, result); \
234 backend->PostClientTask( \
235 FROM_HERE, \
236 base::BindOnce(std::move(callback), std::move(result))); \
237 }, \
238 scoped_refptr<Backend>(this), std::move(callback), \
239 std::forward<Args>(args)...)); \
240 }
241
242 // The following methods call *Impl() method in the background task runner,
243 // and call the passed `callback` with the result in the client task runner.
244 DEFINE_CROSS_SEQUENCE_CALL_METHOD(GetTotalDictionarySize)
245 DEFINE_CROSS_SEQUENCE_CALL_METHOD(RegisterDictionary)
246 DEFINE_CROSS_SEQUENCE_CALL_METHOD(GetDictionaries)
247 DEFINE_CROSS_SEQUENCE_CALL_METHOD(GetAllDictionaries)
248 DEFINE_CROSS_SEQUENCE_CALL_METHOD(GetUsageInfo)
249 DEFINE_CROSS_SEQUENCE_CALL_METHOD(GetOriginsBetween)
250 DEFINE_CROSS_SEQUENCE_CALL_METHOD(ClearAllDictionaries)
251 DEFINE_CROSS_SEQUENCE_CALL_METHOD(ClearDictionaries)
252 DEFINE_CROSS_SEQUENCE_CALL_METHOD(ClearDictionariesForIsolationKey)
253 DEFINE_CROSS_SEQUENCE_CALL_METHOD(DeleteExpiredDictionaries)
254 DEFINE_CROSS_SEQUENCE_CALL_METHOD(ProcessEviction)
255 DEFINE_CROSS_SEQUENCE_CALL_METHOD(GetAllDiskCacheKeyTokens)
256 DEFINE_CROSS_SEQUENCE_CALL_METHOD(DeleteDictionariesByDiskCacheKeyTokens)
257 #undef DEFINE_CROSS_SEQUENCE_CALL_METHOD
258
259 void UpdateDictionaryLastUsedTime(int64_t primary_key_in_database,
260 base::Time last_used_time);
261
262 private:
263 ~Backend() override = default;
264
265 // Gets the total dictionary size in MetaTable.
266 SizeOrError GetTotalDictionarySizeImpl();
267
268 RegisterDictionaryResultOrError RegisterDictionaryImpl(
269 const SharedDictionaryIsolationKey& isolation_key,
270 const SharedDictionaryInfo& dictionary_info,
271 uint64_t max_size_per_site,
272 uint64_t max_count_per_site);
273 DictionaryListOrError GetDictionariesImpl(
274 const SharedDictionaryIsolationKey& isolation_key);
275 DictionaryMapOrError GetAllDictionariesImpl();
276 UsageInfoOrError GetUsageInfoImpl();
277 OriginListOrError GetOriginsBetweenImpl(const base::Time start_time,
278 const base::Time end_time);
279 UnguessableTokenSetOrError ClearAllDictionariesImpl();
280 UnguessableTokenSetOrError ClearDictionariesImpl(
281 base::Time start_time,
282 base::Time end_time,
283 base::RepeatingCallback<bool(const GURL&)> url_matcher);
284 UnguessableTokenSetOrError ClearDictionariesForIsolationKeyImpl(
285 const SharedDictionaryIsolationKey& isolation_key);
286 UnguessableTokenSetOrError DeleteExpiredDictionariesImpl(base::Time now);
287 UnguessableTokenSetOrError ProcessEvictionImpl(uint64_t cache_max_size,
288 uint64_t size_low_watermark,
289 uint64_t cache_max_count,
290 uint64_t count_low_watermark);
291 UnguessableTokenSetOrError GetAllDiskCacheKeyTokensImpl();
292 Error DeleteDictionariesByDiskCacheKeyTokensImpl(
293 const std::set<base::UnguessableToken>& disk_cache_key_tokens);
294
295 // If a matching dictionary exists, populates 'size_out' and
296 // 'disk_cache_key_out' with the dictionary's respective values and returns
297 // true. Otherwise returns false.
298 bool GetExistingDictionarySizeAndDiskCacheKeyToken(
299 const SharedDictionaryIsolationKey& isolation_key,
300 const url::SchemeHostPort& host,
301 const std::string& match,
302 int64_t* size_out,
303 absl::optional<base::UnguessableToken>* disk_cache_key_out);
304
305 // Updates the total dictionary size in MetaTable by `size_delta` and returns
306 // the updated total dictionary size.
307 Error UpdateTotalDictionarySizeInMetaTable(
308 int64_t size_delta,
309 uint64_t* total_dictionary_size_out);
310
311 // Gets the total dictionary count.
312 SizeOrError GetTotalDictionaryCount();
313
314 // SQLitePersistentStoreBackendBase implementation
315 bool CreateDatabaseSchema() override;
316 absl::optional<int> DoMigrateDatabaseSchema() override;
317 void DoCommit() override;
318
319 // Commits the last used time update.
320 Error CommitDictionaryLastUsedTimeUpdate(int64_t primary_key_in_database,
321 base::Time last_used_time);
322
323 // Selects dictionaries which `res_time` is between `start_time` and
324 // `end_time`. And fills their primary keys and tokens and total size.
325 Error SelectMatchingDictionaries(
326 base::Time start_time,
327 base::Time end_time,
328 std::vector<int64_t>* primary_keys_out,
329 std::vector<base::UnguessableToken>* tokens_out,
330 int64_t* total_size_out);
331 // Selects dictionaries which `res_time` is between `start_time` and
332 // `end_time`, and which `frame_origin` or `top_frame_site` or `host` matches
333 // with `url_matcher`. And fills their primary keys and tokens and total size.
334 Error SelectMatchingDictionariesWithUrlMatcher(
335 base::Time start_time,
336 base::Time end_time,
337 base::RepeatingCallback<bool(const GURL&)> url_matcher,
338 std::vector<int64_t>* primary_keys_out,
339 std::vector<base::UnguessableToken>* tokens_out,
340 int64_t* total_size_out);
341 // Selects dictionaries in order of `last_used_time` if the total size of all
342 // dictionaries exceeds `cache_max_size` or the total dictionary count exceeds
343 // `cache_max_count` until the total size reaches `size_low_watermark` and the
344 // total count reaches `count_low_watermark`, and fills their primary keys and
345 // tokens and total size. If `cache_max_size` is zero, the size limitation is
346 // ignored.
347 Error SelectEvictionCandidates(
348 uint64_t cache_max_size,
349 uint64_t size_low_watermark,
350 uint64_t cache_max_count,
351 uint64_t count_low_watermark,
352 std::vector<int64_t>* primary_keys_out,
353 std::vector<base::UnguessableToken>* tokens_out,
354 int64_t* total_size_after_eviction_out);
355 // Deletes a dictionary with `primary_key`.
356 Error DeleteDictionaryByPrimaryKey(int64_t primary_key);
357 // Deletes a dictionary with `disk_cache_key_token` and returns the deleted
358 // dictionarie's size.
359 SizeOrError DeleteDictionaryByDiskCacheToken(
360 const base::UnguessableToken& disk_cache_key_token);
361
362 Error MaybeEvictDictionariesForPerSiteLimit(
363 const SchemefulSite& top_frame_site,
364 uint64_t max_size_per_site,
365 uint64_t max_count_per_site,
366 std::vector<base::UnguessableToken>* evicted_disk_cache_key_tokens,
367 uint64_t* total_dictionary_size_out);
368 SizeOrError GetDictionaryCountPerSite(const SchemefulSite& top_frame_site);
369 SizeOrError GetDictionarySizePerSite(const SchemefulSite& top_frame_site);
370 Error SelectCandidatesForPerSiteEviction(
371 const SchemefulSite& top_frame_site,
372 uint64_t max_size_per_site,
373 uint64_t max_count_per_site,
374 std::vector<int64_t>* primary_keys_out,
375 std::vector<base::UnguessableToken>* tokens_out,
376 int64_t* total_candidate_dictionary_size_out);
377
378 // Total number of pending last used time update operations (may not match the
379 // size of `pending_last_used_time_updates_`, due to operation coalescing).
380 size_t num_pending_ GUARDED_BY(lock_) = 0;
381 std::map<int64_t, base::Time> pending_last_used_time_updates_
382 GUARDED_BY(lock_);
383 // Protects `num_pending_`, and `pending_last_used_time_updates_`.
384 mutable base::Lock lock_;
385 };
386
CreateDatabaseSchema()387 bool SQLitePersistentSharedDictionaryStore::Backend::CreateDatabaseSchema() {
388 if (!db()->DoesTableExist(kTableName) &&
389 !CreateV1Schema(db(), meta_table())) {
390 return false;
391 }
392 return true;
393 }
394
395 absl::optional<int>
DoMigrateDatabaseSchema()396 SQLitePersistentSharedDictionaryStore::Backend::DoMigrateDatabaseSchema() {
397 int cur_version = meta_table()->GetVersionNumber();
398 if (cur_version != kCurrentVersionNumber) {
399 return absl::nullopt;
400 }
401
402 // Future database upgrade statements go here.
403
404 return absl::make_optional(cur_version);
405 }
406
DoCommit()407 void SQLitePersistentSharedDictionaryStore::Backend::DoCommit() {
408 std::map<int64_t, base::Time> pending_last_used_time_updates;
409 {
410 base::AutoLock locked(lock_);
411 pending_last_used_time_updates_.swap(pending_last_used_time_updates);
412 num_pending_ = 0;
413 }
414 if (!db() || pending_last_used_time_updates.empty()) {
415 return;
416 }
417
418 sql::Transaction transaction(db());
419 if (!transaction.Begin()) {
420 return;
421 }
422 for (const auto& it : pending_last_used_time_updates) {
423 if (CommitDictionaryLastUsedTimeUpdate(it.first, it.second) != Error::kOk) {
424 return;
425 }
426 }
427 transaction.Commit();
428 }
429
430 SQLitePersistentSharedDictionaryStore::Error
431 SQLitePersistentSharedDictionaryStore::Backend::
CommitDictionaryLastUsedTimeUpdate(int64_t primary_key_in_database,base::Time last_used_time)432 CommitDictionaryLastUsedTimeUpdate(int64_t primary_key_in_database,
433 base::Time last_used_time) {
434 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
435 if (!InitializeDatabase()) {
436 return Error::kFailedToInitializeDatabase;
437 }
438 static constexpr char kQuery[] =
439 "UPDATE dictionaries SET last_used_time=? WHERE id=?";
440
441 if (!db()->IsSQLValid(kQuery)) {
442 return Error::kInvalidSql;
443 }
444 sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery));
445 statement.BindTime(0, last_used_time);
446 statement.BindInt64(1, primary_key_in_database);
447 if (!statement.Run()) {
448 return Error::kFailedToExecuteSql;
449 }
450 return Error::kOk;
451 }
452
453 base::expected<uint64_t, SQLitePersistentSharedDictionaryStore::Error>
GetTotalDictionarySizeImpl()454 SQLitePersistentSharedDictionaryStore::Backend::GetTotalDictionarySizeImpl() {
455 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
456 if (!InitializeDatabase()) {
457 return base::unexpected(Error::kFailedToInitializeDatabase);
458 }
459
460 int64_t unsigned_total_dictionary_size = 0;
461 if (!meta_table()->GetValue(kTotalDictSizeKey,
462 &unsigned_total_dictionary_size)) {
463 return base::unexpected(Error::kFailedToGetTotalDictSize);
464 }
465
466 // There is no `sql::Statement::ColumnUint64()` method. So we cast to
467 // uint64_t.
468 return base::ok(static_cast<uint64_t>(unsigned_total_dictionary_size));
469 }
470
471 SQLitePersistentSharedDictionaryStore::RegisterDictionaryResultOrError
RegisterDictionaryImpl(const SharedDictionaryIsolationKey & isolation_key,const SharedDictionaryInfo & dictionary_info,uint64_t max_size_per_site,uint64_t max_count_per_site)472 SQLitePersistentSharedDictionaryStore::Backend::RegisterDictionaryImpl(
473 const SharedDictionaryIsolationKey& isolation_key,
474 const SharedDictionaryInfo& dictionary_info,
475 uint64_t max_size_per_site,
476 uint64_t max_count_per_site) {
477 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
478 CHECK_NE(0u, max_count_per_site);
479 if (max_size_per_site != 0 && dictionary_info.size() > max_size_per_site) {
480 return base::unexpected(Error::kTooBigDictionary);
481 }
482
483 if (!InitializeDatabase()) {
484 return base::unexpected(Error::kFailedToInitializeDatabase);
485 }
486
487 // Commit `pending_last_used_time_updates_`.
488 DoCommit();
489
490 sql::Transaction transaction(db());
491 if (!transaction.Begin()) {
492 return base::unexpected(Error::kFailedToBeginTransaction);
493 }
494
495 int64_t size_of_removed_dict = 0;
496 absl::optional<base::UnguessableToken> replaced_disk_cache_key_token;
497 int64_t size_delta = dictionary_info.size();
498 if (GetExistingDictionarySizeAndDiskCacheKeyToken(
499 isolation_key, url::SchemeHostPort(dictionary_info.url()),
500 dictionary_info.match(), &size_of_removed_dict,
501 &replaced_disk_cache_key_token)) {
502 size_delta -= size_of_removed_dict;
503 }
504
505 static constexpr char kQuery[] =
506 // clang-format off
507 "INSERT OR REPLACE INTO dictionaries("
508 "frame_origin,"
509 "top_frame_site,"
510 "host,"
511 "match,"
512 "url,"
513 "res_time,"
514 "exp_time,"
515 "last_used_time,"
516 "size,"
517 "sha256,"
518 "token_high,"
519 "token_low) "
520 "VALUES(?,?,?,?,?,?,?,?,?,?,?,?)";
521 // clang-format on
522
523 if (!db()->IsSQLValid(kQuery)) {
524 return base::unexpected(Error::kInvalidSql);
525 }
526
527 sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery));
528 statement.BindString(0, isolation_key.frame_origin().Serialize());
529 statement.BindString(1, isolation_key.top_frame_site().Serialize());
530 statement.BindString(2,
531 url::SchemeHostPort(dictionary_info.url()).Serialize());
532 statement.BindString(3, dictionary_info.match());
533 statement.BindString(4, dictionary_info.url().spec());
534 statement.BindTime(5, dictionary_info.response_time());
535 statement.BindTime(6, dictionary_info.GetExpirationTime());
536 statement.BindTime(7, dictionary_info.last_used_time());
537 statement.BindInt64(8, dictionary_info.size());
538 statement.BindBlob(9, base::make_span(dictionary_info.hash().data));
539 // There is no `sql::Statement::BindUint64()` method. So we cast to int64_t.
540 int64_t token_high = static_cast<int64_t>(
541 dictionary_info.disk_cache_key_token().GetHighForSerialization());
542 int64_t token_low = static_cast<int64_t>(
543 dictionary_info.disk_cache_key_token().GetLowForSerialization());
544 statement.BindInt64(10, token_high);
545 statement.BindInt64(11, token_low);
546
547 if (!statement.Run()) {
548 return base::unexpected(Error::kFailedToExecuteSql);
549 }
550 int64_t id = db()->GetLastInsertRowId();
551
552 uint64_t total_dictionary_size = 0;
553 Error error =
554 UpdateTotalDictionarySizeInMetaTable(size_delta, &total_dictionary_size);
555 if (error != Error::kOk) {
556 return base::unexpected(error);
557 }
558
559 std::vector<base::UnguessableToken> evicted_disk_cache_key_tokens;
560 error = MaybeEvictDictionariesForPerSiteLimit(
561 isolation_key.top_frame_site(), max_size_per_site, max_count_per_site,
562 &evicted_disk_cache_key_tokens, &total_dictionary_size);
563 if (error != Error::kOk) {
564 return base::unexpected(error);
565 }
566
567 ASSIGN_OR_RETURN(uint64_t total_dictionary_count, GetTotalDictionaryCount());
568
569 if (!transaction.Commit()) {
570 return base::unexpected(Error::kFailedToCommitTransaction);
571 }
572 return base::ok(RegisterDictionaryResult{
573 id, replaced_disk_cache_key_token,
574 std::set<base::UnguessableToken>(evicted_disk_cache_key_tokens.begin(),
575 evicted_disk_cache_key_tokens.end()),
576 total_dictionary_size, total_dictionary_count});
577 }
578
579 SQLitePersistentSharedDictionaryStore::Error
580 SQLitePersistentSharedDictionaryStore::Backend::
MaybeEvictDictionariesForPerSiteLimit(const SchemefulSite & top_frame_site,uint64_t max_size_per_site,uint64_t max_count_per_site,std::vector<base::UnguessableToken> * evicted_disk_cache_key_tokens,uint64_t * total_dictionary_size_out)581 MaybeEvictDictionariesForPerSiteLimit(
582 const SchemefulSite& top_frame_site,
583 uint64_t max_size_per_site,
584 uint64_t max_count_per_site,
585 std::vector<base::UnguessableToken>* evicted_disk_cache_key_tokens,
586 uint64_t* total_dictionary_size_out) {
587 std::vector<int64_t> primary_keys;
588 int64_t total_candidate_dictionary_size = 0;
589 Error error = SelectCandidatesForPerSiteEviction(
590 top_frame_site, max_size_per_site, max_count_per_site, &primary_keys,
591 evicted_disk_cache_key_tokens, &total_candidate_dictionary_size);
592 if (error != Error::kOk) {
593 return error;
594 }
595 CHECK_EQ(primary_keys.size(), evicted_disk_cache_key_tokens->size());
596 if (primary_keys.empty()) {
597 return Error::kOk;
598 }
599 for (int64_t primary_key : primary_keys) {
600 error = DeleteDictionaryByPrimaryKey(primary_key);
601 if (error != Error::kOk) {
602 return error;
603 }
604 }
605 error = UpdateTotalDictionarySizeInMetaTable(-total_candidate_dictionary_size,
606 total_dictionary_size_out);
607 if (error != Error::kOk) {
608 return error;
609 }
610 return Error::kOk;
611 }
612
613 SQLitePersistentSharedDictionaryStore::Error
614 SQLitePersistentSharedDictionaryStore::Backend::
SelectCandidatesForPerSiteEviction(const SchemefulSite & top_frame_site,uint64_t max_size_per_site,uint64_t max_count_per_site,std::vector<int64_t> * primary_keys_out,std::vector<base::UnguessableToken> * tokens_out,int64_t * total_size_of_candidates_out)615 SelectCandidatesForPerSiteEviction(
616 const SchemefulSite& top_frame_site,
617 uint64_t max_size_per_site,
618 uint64_t max_count_per_site,
619 std::vector<int64_t>* primary_keys_out,
620 std::vector<base::UnguessableToken>* tokens_out,
621 int64_t* total_size_of_candidates_out) {
622 CHECK(primary_keys_out->empty());
623 CHECK(tokens_out->empty());
624 CHECK_EQ(0, *total_size_of_candidates_out);
625
626 ASSIGN_OR_RETURN(uint64_t size_per_site,
627 GetDictionarySizePerSite(top_frame_site));
628 ASSIGN_OR_RETURN(uint64_t count_per_site,
629 GetDictionaryCountPerSite(top_frame_site));
630
631 base::UmaHistogramMemoryKB(
632 base::StrCat({kHistogramPrefix, "DictionarySizeKBPerSiteWhenAdded"}),
633 size_per_site);
634 base::UmaHistogramCounts1000(
635 base::StrCat({kHistogramPrefix, "DictionaryCountPerSiteWhenAdded"}),
636 count_per_site);
637
638 if ((max_size_per_site == 0 || size_per_site <= max_size_per_site) &&
639 count_per_site <= max_count_per_site) {
640 return Error::kOk;
641 }
642
643 uint64_t to_be_removed_count = 0;
644 if (count_per_site > max_count_per_site) {
645 to_be_removed_count = count_per_site - max_count_per_site;
646 }
647
648 int64_t to_be_removed_size = 0;
649 if (max_size_per_site != 0 && size_per_site > max_size_per_site) {
650 to_be_removed_size = size_per_site - max_size_per_site;
651 }
652 static constexpr char kQuery[] =
653 // clang-format off
654 "SELECT "
655 "id,"
656 "size,"
657 "token_high,"
658 "token_low FROM dictionaries "
659 "WHERE top_frame_site=? "
660 "ORDER BY last_used_time";
661 // clang-format on
662
663 if (!db()->IsSQLValid(kQuery)) {
664 return Error::kInvalidSql;
665 }
666 sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery));
667 statement.BindString(0, top_frame_site.Serialize());
668
669 base::CheckedNumeric<int64_t> checked_total_size_of_candidates;
670 while (statement.Step()) {
671 const int64_t primary_key_in_database = statement.ColumnInt64(0);
672 const size_t size = statement.ColumnInt64(1);
673 const int64_t token_high = statement.ColumnInt64(2);
674 const int64_t token_low = statement.ColumnInt64(3);
675
676 absl::optional<base::UnguessableToken> disk_cache_key_token =
677 ToUnguessableToken(token_high, token_low);
678 if (!disk_cache_key_token) {
679 LOG(WARNING) << "Invalid token";
680 continue;
681 }
682 checked_total_size_of_candidates += size;
683
684 if (!checked_total_size_of_candidates.IsValid()) {
685 base::debug::DumpWithoutCrashing();
686 return Error::kInvalidTotalDictSize;
687 }
688
689 *total_size_of_candidates_out =
690 checked_total_size_of_candidates.ValueOrDie();
691 primary_keys_out->emplace_back(primary_key_in_database);
692 tokens_out->emplace_back(*disk_cache_key_token);
693
694 if (*total_size_of_candidates_out >= to_be_removed_size &&
695 tokens_out->size() >= to_be_removed_count) {
696 break;
697 }
698 }
699
700 return Error::kOk;
701 }
702
703 base::expected<uint64_t, SQLitePersistentSharedDictionaryStore::Error>
GetDictionaryCountPerSite(const SchemefulSite & top_frame_site)704 SQLitePersistentSharedDictionaryStore::Backend::GetDictionaryCountPerSite(
705 const SchemefulSite& top_frame_site) {
706 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
707 static constexpr char kQuery[] =
708 // clang-format off
709 "SELECT "
710 "COUNT(id) FROM dictionaries "
711 "WHERE top_frame_site=?";
712 // clang-format on
713
714 if (!db()->IsSQLValid(kQuery)) {
715 return base::unexpected(Error::kInvalidSql);
716 }
717 sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery));
718 statement.BindString(0, top_frame_site.Serialize());
719 uint64_t count_per_site = 0;
720 if (statement.Step()) {
721 count_per_site = statement.ColumnInt64(0);
722 }
723 return base::ok(count_per_site);
724 }
725
726 base::expected<uint64_t, SQLitePersistentSharedDictionaryStore::Error>
GetDictionarySizePerSite(const SchemefulSite & top_frame_site)727 SQLitePersistentSharedDictionaryStore::Backend::GetDictionarySizePerSite(
728 const SchemefulSite& top_frame_site) {
729 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
730 static constexpr char kQuery[] =
731 // clang-format off
732 "SELECT "
733 "SUM(size) FROM dictionaries "
734 "WHERE top_frame_site=?";
735 // clang-format on
736
737 if (!db()->IsSQLValid(kQuery)) {
738 return base::unexpected(Error::kInvalidSql);
739 }
740 sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery));
741 statement.BindString(0, top_frame_site.Serialize());
742 uint64_t size_per_site = 0;
743 if (statement.Step()) {
744 size_per_site = statement.ColumnInt64(0);
745 }
746 return base::ok(size_per_site);
747 }
748
749 SQLitePersistentSharedDictionaryStore::DictionaryListOrError
GetDictionariesImpl(const SharedDictionaryIsolationKey & isolation_key)750 SQLitePersistentSharedDictionaryStore::Backend::GetDictionariesImpl(
751 const SharedDictionaryIsolationKey& isolation_key) {
752 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
753 std::vector<SharedDictionaryInfo> result;
754
755 if (!InitializeDatabase()) {
756 return base::unexpected(Error::kFailedToInitializeDatabase);
757 }
758
759 // Commit `pending_last_used_time_updates_`.
760 DoCommit();
761
762 static constexpr char kQuery[] =
763 // clang-format off
764 "SELECT "
765 "id,"
766 "match,"
767 "url,"
768 "res_time,"
769 "exp_time,"
770 "last_used_time,"
771 "size,"
772 "sha256,"
773 "token_high,"
774 "token_low FROM dictionaries "
775 "WHERE frame_origin=? AND top_frame_site=? "
776 "ORDER BY id";
777 // clang-format on
778
779 if (!db()->IsSQLValid(kQuery)) {
780 return base::unexpected(Error::kInvalidSql);
781 }
782
783 sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery));
784 statement.BindString(0, isolation_key.frame_origin().Serialize());
785 statement.BindString(1, isolation_key.top_frame_site().Serialize());
786
787 while (statement.Step()) {
788 const int64_t primary_key_in_database = statement.ColumnInt64(0);
789 const std::string match = statement.ColumnString(1);
790 const std::string url_string = statement.ColumnString(2);
791 const base::Time response_time = statement.ColumnTime(3);
792 const base::Time expiration_time = statement.ColumnTime(4);
793 const base::Time last_used_time = statement.ColumnTime(5);
794 const size_t size = statement.ColumnInt64(6);
795
796 absl::optional<SHA256HashValue> sha256_hash =
797 ToSHA256HashValue(statement.ColumnBlob(7));
798 if (!sha256_hash) {
799 LOG(WARNING) << "Invalid hash";
800 continue;
801 }
802 absl::optional<base::UnguessableToken> disk_cache_key_token =
803 ToUnguessableToken(statement.ColumnInt64(8), statement.ColumnInt64(9));
804 if (!disk_cache_key_token) {
805 LOG(WARNING) << "Invalid token";
806 continue;
807 }
808 result.emplace_back(GURL(url_string), response_time,
809 expiration_time - response_time, match, last_used_time,
810 size, *sha256_hash, *disk_cache_key_token,
811 primary_key_in_database);
812 }
813 return base::ok(std::move(result));
814 }
815
816 SQLitePersistentSharedDictionaryStore::DictionaryMapOrError
GetAllDictionariesImpl()817 SQLitePersistentSharedDictionaryStore::Backend::GetAllDictionariesImpl() {
818 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
819 if (!InitializeDatabase()) {
820 return base::unexpected(Error::kFailedToInitializeDatabase);
821 }
822
823 static constexpr char kQuery[] =
824 // clang-format off
825 "SELECT "
826 "id,"
827 "frame_origin,"
828 "top_frame_site,"
829 "match,"
830 "url,"
831 "res_time,"
832 "exp_time,"
833 "last_used_time,"
834 "size,"
835 "sha256,"
836 "token_high,"
837 "token_low FROM dictionaries "
838 "ORDER BY id";
839 // clang-format on
840
841 if (!db()->IsSQLValid(kQuery)) {
842 return base::unexpected(Error::kInvalidSql);
843 }
844
845 std::map<SharedDictionaryIsolationKey, std::vector<SharedDictionaryInfo>>
846 result;
847 sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery));
848
849 while (statement.Step()) {
850 const int64_t primary_key_in_database = statement.ColumnInt64(0);
851 const std::string frame_origin_string = statement.ColumnString(1);
852 const std::string top_frame_site_string = statement.ColumnString(2);
853 const std::string match = statement.ColumnString(3);
854 const std::string url_string = statement.ColumnString(4);
855 const base::Time response_time = statement.ColumnTime(5);
856 const base::Time expiration_time = statement.ColumnTime(6);
857 const base::Time last_used_time = statement.ColumnTime(7);
858 const size_t size = statement.ColumnInt64(8);
859
860 absl::optional<SHA256HashValue> sha256_hash =
861 ToSHA256HashValue(statement.ColumnBlob(9));
862 if (!sha256_hash) {
863 LOG(WARNING) << "Invalid hash";
864 continue;
865 }
866
867 absl::optional<base::UnguessableToken> disk_cache_key_token =
868 ToUnguessableToken(statement.ColumnInt64(10),
869 statement.ColumnInt64(11));
870 if (!disk_cache_key_token) {
871 LOG(WARNING) << "Invalid token";
872 continue;
873 }
874
875 url::Origin frame_origin = url::Origin::Create(GURL(frame_origin_string));
876 SchemefulSite top_frame_site = SchemefulSite(GURL(top_frame_site_string));
877
878 result[SharedDictionaryIsolationKey(frame_origin, top_frame_site)]
879 .emplace_back(GURL(url_string), response_time,
880 expiration_time - response_time, match, last_used_time,
881 size, *sha256_hash, *disk_cache_key_token,
882 primary_key_in_database);
883 }
884 return base::ok(std::move(result));
885 }
886
887 SQLitePersistentSharedDictionaryStore::UsageInfoOrError
GetUsageInfoImpl()888 SQLitePersistentSharedDictionaryStore::Backend::GetUsageInfoImpl() {
889 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
890 if (!InitializeDatabase()) {
891 return base::unexpected(Error::kFailedToInitializeDatabase);
892 }
893
894 static constexpr char kQuery[] =
895 // clang-format off
896 "SELECT "
897 "frame_origin,"
898 "top_frame_site,"
899 "size FROM dictionaries "
900 "ORDER BY id";
901 // clang-format on
902
903 if (!db()->IsSQLValid(kQuery)) {
904 return base::unexpected(Error::kInvalidSql);
905 }
906
907 std::map<SharedDictionaryIsolationKey, SharedDictionaryUsageInfo> result_map;
908 sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery));
909
910 while (statement.Step()) {
911 const std::string frame_origin_string = statement.ColumnString(0);
912 const std::string top_frame_site_string = statement.ColumnString(1);
913 const size_t size = statement.ColumnInt64(2);
914
915 const SharedDictionaryIsolationKey key = SharedDictionaryIsolationKey(
916 url::Origin::Create(GURL(frame_origin_string)),
917 SchemefulSite(GURL(top_frame_site_string)));
918 auto it = result_map.find(key);
919 if (it != result_map.end()) {
920 it->second.total_size_bytes += size;
921 } else {
922 result_map[key] = SharedDictionaryUsageInfo{.isolation_key = key,
923 .total_size_bytes = size};
924 }
925 }
926
927 std::vector<SharedDictionaryUsageInfo> result;
928 for (auto& it : result_map) {
929 result.push_back(std::move(it.second));
930 }
931 return base::ok(std::move(result));
932 }
933
934 SQLitePersistentSharedDictionaryStore::OriginListOrError
GetOriginsBetweenImpl(const base::Time start_time,const base::Time end_time)935 SQLitePersistentSharedDictionaryStore::Backend::GetOriginsBetweenImpl(
936 const base::Time start_time,
937 const base::Time end_time) {
938 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
939 if (!InitializeDatabase()) {
940 return base::unexpected(Error::kFailedToInitializeDatabase);
941 }
942
943 static constexpr char kQuery[] =
944 // clang-format off
945 "SELECT "
946 "frame_origin FROM dictionaries "
947 "WHERE res_time>=? AND res_time<? "
948 "ORDER BY id";
949 // clang-format on
950
951 if (!db()->IsSQLValid(kQuery)) {
952 return base::unexpected(Error::kInvalidSql);
953 }
954
955 sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery));
956 statement.BindTime(0, start_time);
957 statement.BindTime(1, end_time);
958
959 std::set<url::Origin> origins;
960 while (statement.Step()) {
961 const std::string frame_origin_string = statement.ColumnString(0);
962 origins.insert(url::Origin::Create(GURL(frame_origin_string)));
963 }
964 return base::ok(std::vector<url::Origin>(origins.begin(), origins.end()));
965 }
966
967 SQLitePersistentSharedDictionaryStore::UnguessableTokenSetOrError
ClearAllDictionariesImpl()968 SQLitePersistentSharedDictionaryStore::Backend::ClearAllDictionariesImpl() {
969 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
970
971 if (!InitializeDatabase()) {
972 return base::unexpected(Error::kFailedToInitializeDatabase);
973 }
974
975 sql::Transaction transaction(db());
976 if (!transaction.Begin()) {
977 return base::unexpected(Error::kFailedToBeginTransaction);
978 }
979
980 static constexpr char kQuery[] =
981 "DELETE FROM dictionaries RETURNING token_high, token_low";
982 if (!db()->IsSQLValid(kQuery)) {
983 return base::unexpected(Error::kInvalidSql);
984 }
985 sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery));
986
987 std::vector<base::UnguessableToken> tokens;
988 while (statement.Step()) {
989 const int64_t token_high = statement.ColumnInt64(0);
990 const int64_t token_low = statement.ColumnInt64(1);
991 absl::optional<base::UnguessableToken> disk_cache_key_token =
992 ToUnguessableToken(token_high, token_low);
993 if (!disk_cache_key_token) {
994 continue;
995 }
996 tokens.emplace_back(*disk_cache_key_token);
997 }
998
999 if (!meta_table()->SetValue(kTotalDictSizeKey, 0)) {
1000 return base::unexpected(Error::kFailedToSetTotalDictSize);
1001 }
1002
1003 if (!transaction.Commit()) {
1004 return base::unexpected(Error::kFailedToCommitTransaction);
1005 }
1006 return base::ok(
1007 std::set<base::UnguessableToken>(tokens.begin(), tokens.end()));
1008 }
1009
1010 SQLitePersistentSharedDictionaryStore::UnguessableTokenSetOrError
ClearDictionariesImpl(base::Time start_time,base::Time end_time,base::RepeatingCallback<bool (const GURL &)> url_matcher)1011 SQLitePersistentSharedDictionaryStore::Backend::ClearDictionariesImpl(
1012 base::Time start_time,
1013 base::Time end_time,
1014 base::RepeatingCallback<bool(const GURL&)> url_matcher) {
1015 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
1016 if (!InitializeDatabase()) {
1017 return base::unexpected(Error::kFailedToInitializeDatabase);
1018 }
1019
1020 // Commit `pending_last_used_time_updates_`.
1021 DoCommit();
1022
1023 sql::Transaction transaction(db());
1024 if (!transaction.Begin()) {
1025 return base::unexpected(Error::kFailedToBeginTransaction);
1026 }
1027 std::vector<int64_t> primary_keys;
1028 std::vector<base::UnguessableToken> tokens;
1029 int64_t total_size = 0;
1030 Error error = url_matcher ? SelectMatchingDictionariesWithUrlMatcher(
1031 start_time, end_time, std::move(url_matcher),
1032 &primary_keys, &tokens, &total_size)
1033 : SelectMatchingDictionaries(start_time, end_time,
1034 &primary_keys, &tokens,
1035 &total_size);
1036 if (error != Error::kOk) {
1037 return base::unexpected(error);
1038 }
1039 for (int64_t primary_key : primary_keys) {
1040 error = DeleteDictionaryByPrimaryKey(primary_key);
1041 if (error != Error::kOk) {
1042 return base::unexpected(error);
1043 }
1044 }
1045 if (total_size != 0) {
1046 uint64_t total_dictionary_size = 0;
1047 error = UpdateTotalDictionarySizeInMetaTable(-total_size,
1048 &total_dictionary_size);
1049 if (error != Error::kOk) {
1050 return base::unexpected(error);
1051 }
1052 }
1053
1054 transaction.Commit();
1055 return base::ok(
1056 std::set<base::UnguessableToken>(tokens.begin(), tokens.end()));
1057 }
1058
1059 SQLitePersistentSharedDictionaryStore::Error
SelectMatchingDictionaries(base::Time start_time,base::Time end_time,std::vector<int64_t> * primary_keys_out,std::vector<base::UnguessableToken> * tokens_out,int64_t * total_size_out)1060 SQLitePersistentSharedDictionaryStore::Backend::SelectMatchingDictionaries(
1061 base::Time start_time,
1062 base::Time end_time,
1063 std::vector<int64_t>* primary_keys_out,
1064 std::vector<base::UnguessableToken>* tokens_out,
1065 int64_t* total_size_out) {
1066 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
1067 static constexpr char kQuery[] =
1068 // clang-format off
1069 "SELECT "
1070 "id,"
1071 "size,"
1072 "token_high,"
1073 "token_low FROM dictionaries "
1074 "WHERE res_time>=? AND res_time<? "
1075 "ORDER BY id";
1076 // clang-format on
1077
1078 if (!db()->IsSQLValid(kQuery)) {
1079 return Error::kInvalidSql;
1080 }
1081
1082 sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery));
1083 statement.BindTime(0, start_time);
1084 statement.BindTime(1, end_time.is_null() ? base::Time::Max() : end_time);
1085
1086 base::CheckedNumeric<int64_t> checked_total_size;
1087 while (statement.Step()) {
1088 const int64_t primary_key_in_database = statement.ColumnInt64(0);
1089 const size_t size = statement.ColumnInt64(1);
1090 const int64_t token_high = statement.ColumnInt64(2);
1091 const int64_t token_low = statement.ColumnInt64(3);
1092 absl::optional<base::UnguessableToken> disk_cache_key_token =
1093 ToUnguessableToken(token_high, token_low);
1094 if (!disk_cache_key_token) {
1095 LOG(WARNING) << "Invalid token";
1096 continue;
1097 }
1098 primary_keys_out->emplace_back(primary_key_in_database);
1099 tokens_out->emplace_back(*disk_cache_key_token);
1100 checked_total_size += size;
1101 }
1102 *total_size_out = checked_total_size.ValueOrDie();
1103 return Error::kOk;
1104 }
1105
1106 SQLitePersistentSharedDictionaryStore::Error
1107 SQLitePersistentSharedDictionaryStore::Backend::
SelectMatchingDictionariesWithUrlMatcher(base::Time start_time,base::Time end_time,base::RepeatingCallback<bool (const GURL &)> url_matcher,std::vector<int64_t> * primary_keys_out,std::vector<base::UnguessableToken> * tokens_out,int64_t * total_size_out)1108 SelectMatchingDictionariesWithUrlMatcher(
1109 base::Time start_time,
1110 base::Time end_time,
1111 base::RepeatingCallback<bool(const GURL&)> url_matcher,
1112 std::vector<int64_t>* primary_keys_out,
1113 std::vector<base::UnguessableToken>* tokens_out,
1114 int64_t* total_size_out) {
1115 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
1116 static constexpr char kQuery[] =
1117 // clang-format off
1118 "SELECT "
1119 "id,"
1120 "frame_origin,"
1121 "top_frame_site,"
1122 "host,"
1123 "size,"
1124 "token_high,"
1125 "token_low FROM dictionaries "
1126 "WHERE res_time>=? AND res_time<? "
1127 "ORDER BY id";
1128 // clang-format on
1129
1130 if (!db()->IsSQLValid(kQuery)) {
1131 return Error::kInvalidSql;
1132 }
1133
1134 sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery));
1135 statement.BindTime(0, start_time);
1136 statement.BindTime(1, end_time.is_null() ? base::Time::Max() : end_time);
1137
1138 base::CheckedNumeric<int64_t> checked_total_size;
1139 while (statement.Step()) {
1140 const int64_t primary_key_in_database = statement.ColumnInt64(0);
1141 const std::string frame_origin_string = statement.ColumnString(1);
1142 const std::string top_frame_site_string = statement.ColumnString(2);
1143 const std::string host = statement.ColumnString(3);
1144 const size_t size = statement.ColumnInt64(4);
1145 const int64_t token_high = statement.ColumnInt64(5);
1146 const int64_t token_low = statement.ColumnInt64(6);
1147
1148 if (!url_matcher.Run(GURL(frame_origin_string)) &&
1149 !url_matcher.Run(GURL(top_frame_site_string)) &&
1150 !url_matcher.Run(GURL(host))) {
1151 continue;
1152 }
1153 absl::optional<base::UnguessableToken> disk_cache_key_token =
1154 ToUnguessableToken(token_high, token_low);
1155 if (!disk_cache_key_token) {
1156 LOG(WARNING) << "Invalid token";
1157 continue;
1158 }
1159 primary_keys_out->emplace_back(primary_key_in_database);
1160 tokens_out->emplace_back(*disk_cache_key_token);
1161 checked_total_size += size;
1162 }
1163 *total_size_out = checked_total_size.ValueOrDie();
1164 return Error::kOk;
1165 }
1166
1167 SQLitePersistentSharedDictionaryStore::UnguessableTokenSetOrError
1168 SQLitePersistentSharedDictionaryStore::Backend::
ClearDictionariesForIsolationKeyImpl(const SharedDictionaryIsolationKey & isolation_key)1169 ClearDictionariesForIsolationKeyImpl(
1170 const SharedDictionaryIsolationKey& isolation_key) {
1171 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
1172 if (!InitializeDatabase()) {
1173 return base::unexpected(Error::kFailedToInitializeDatabase);
1174 }
1175 sql::Transaction transaction(db());
1176 if (!transaction.Begin()) {
1177 return base::unexpected(Error::kFailedToBeginTransaction);
1178 }
1179
1180 static constexpr char kQuery[] =
1181 // clang-format off
1182 "DELETE FROM dictionaries "
1183 "WHERE frame_origin=? AND top_frame_site=? "
1184 "RETURNING size, token_high, token_low";
1185 // clang-format on
1186
1187 if (!db()->IsSQLValid(kQuery)) {
1188 return base::unexpected(Error::kInvalidSql);
1189 }
1190
1191 sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery));
1192 statement.BindString(0, isolation_key.frame_origin().Serialize());
1193 statement.BindString(1, isolation_key.top_frame_site().Serialize());
1194
1195 std::vector<base::UnguessableToken> tokens;
1196 base::CheckedNumeric<int64_t> checked_total_size = 0;
1197 while (statement.Step()) {
1198 const size_t size = statement.ColumnInt64(0);
1199 const int64_t token_high = statement.ColumnInt64(1);
1200 const int64_t token_low = statement.ColumnInt64(2);
1201
1202 checked_total_size += size;
1203
1204 absl::optional<base::UnguessableToken> disk_cache_key_token =
1205 ToUnguessableToken(token_high, token_low);
1206 if (!disk_cache_key_token) {
1207 continue;
1208 }
1209 tokens.emplace_back(*disk_cache_key_token);
1210 }
1211
1212 int64_t total_size = checked_total_size.ValueOrDie();
1213 if (total_size != 0) {
1214 uint64_t total_dictionary_size = 0;
1215 Error error = UpdateTotalDictionarySizeInMetaTable(-total_size,
1216 &total_dictionary_size);
1217 if (error != Error::kOk) {
1218 return base::unexpected(error);
1219 }
1220 }
1221 transaction.Commit();
1222 return base::ok(
1223 std::set<base::UnguessableToken>(tokens.begin(), tokens.end()));
1224 }
1225
1226 SQLitePersistentSharedDictionaryStore::UnguessableTokenSetOrError
DeleteExpiredDictionariesImpl(base::Time now)1227 SQLitePersistentSharedDictionaryStore::Backend::DeleteExpiredDictionariesImpl(
1228 base::Time now) {
1229 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
1230 if (!InitializeDatabase()) {
1231 return base::unexpected(Error::kFailedToInitializeDatabase);
1232 }
1233 sql::Transaction transaction(db());
1234 if (!transaction.Begin()) {
1235 return base::unexpected(Error::kFailedToBeginTransaction);
1236 }
1237 static constexpr char kQuery[] =
1238 // clang-format off
1239 "DELETE FROM dictionaries "
1240 "WHERE exp_time<=? "
1241 "RETURNING size, token_high, token_low";
1242 // clang-format on
1243
1244 if (!db()->IsSQLValid(kQuery)) {
1245 return base::unexpected(Error::kInvalidSql);
1246 }
1247
1248 sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery));
1249 statement.BindTime(0, now);
1250
1251 std::vector<base::UnguessableToken> tokens;
1252 base::CheckedNumeric<int64_t> checked_total_size = 0;
1253 while (statement.Step()) {
1254 const size_t size = statement.ColumnInt64(0);
1255 const int64_t token_high = statement.ColumnInt64(1);
1256 const int64_t token_low = statement.ColumnInt64(2);
1257
1258 checked_total_size += size;
1259
1260 absl::optional<base::UnguessableToken> disk_cache_key_token =
1261 ToUnguessableToken(token_high, token_low);
1262 if (!disk_cache_key_token) {
1263 LOG(WARNING) << "Invalid token";
1264 continue;
1265 }
1266 tokens.emplace_back(*disk_cache_key_token);
1267 }
1268
1269 int64_t total_size = checked_total_size.ValueOrDie();
1270 if (total_size != 0) {
1271 uint64_t total_dictionary_size = 0;
1272 Error error = UpdateTotalDictionarySizeInMetaTable(-total_size,
1273 &total_dictionary_size);
1274 if (error != Error::kOk) {
1275 return base::unexpected(error);
1276 }
1277 }
1278 transaction.Commit();
1279 return base::ok(
1280 std::set<base::UnguessableToken>(tokens.begin(), tokens.end()));
1281 }
1282
1283 SQLitePersistentSharedDictionaryStore::UnguessableTokenSetOrError
ProcessEvictionImpl(uint64_t cache_max_size,uint64_t size_low_watermark,uint64_t cache_max_count,uint64_t count_low_watermark)1284 SQLitePersistentSharedDictionaryStore::Backend::ProcessEvictionImpl(
1285 uint64_t cache_max_size,
1286 uint64_t size_low_watermark,
1287 uint64_t cache_max_count,
1288 uint64_t count_low_watermark) {
1289 if (!InitializeDatabase()) {
1290 return base::unexpected(Error::kFailedToInitializeDatabase);
1291 }
1292
1293 // Commit `pending_last_used_time_updates_`.
1294 DoCommit();
1295
1296 sql::Transaction transaction(db());
1297 if (!transaction.Begin()) {
1298 return base::unexpected(Error::kFailedToBeginTransaction);
1299 }
1300 std::vector<int64_t> primary_keys;
1301 std::vector<base::UnguessableToken> tokens;
1302 int64_t total_size_after_eviction = 0;
1303 Error error = SelectEvictionCandidates(
1304 cache_max_size, size_low_watermark, cache_max_count, count_low_watermark,
1305 &primary_keys, &tokens, &total_size_after_eviction);
1306 if (error != Error::kOk) {
1307 return base::unexpected(error);
1308 }
1309 CHECK_EQ(primary_keys.size(), tokens.size());
1310 if (primary_keys.empty()) {
1311 return base::ok(std::set<base::UnguessableToken>());
1312 }
1313 for (int64_t primary_key : primary_keys) {
1314 error = DeleteDictionaryByPrimaryKey(primary_key);
1315 if (error != Error::kOk) {
1316 return base::unexpected(error);
1317 }
1318 }
1319
1320 if (!meta_table()->SetValue(kTotalDictSizeKey, total_size_after_eviction)) {
1321 return base::unexpected(Error::kFailedToSetTotalDictSize);
1322 }
1323
1324 transaction.Commit();
1325 return base::ok(
1326 std::set<base::UnguessableToken>(tokens.begin(), tokens.end()));
1327 }
1328
1329 SQLitePersistentSharedDictionaryStore::Error
SelectEvictionCandidates(uint64_t cache_max_size,uint64_t size_low_watermark,uint64_t cache_max_count,uint64_t count_low_watermark,std::vector<int64_t> * primary_keys_out,std::vector<base::UnguessableToken> * tokens_out,int64_t * total_size_after_eviction_out)1330 SQLitePersistentSharedDictionaryStore::Backend::SelectEvictionCandidates(
1331 uint64_t cache_max_size,
1332 uint64_t size_low_watermark,
1333 uint64_t cache_max_count,
1334 uint64_t count_low_watermark,
1335 std::vector<int64_t>* primary_keys_out,
1336 std::vector<base::UnguessableToken>* tokens_out,
1337 int64_t* total_size_after_eviction_out) {
1338 ASSIGN_OR_RETURN(uint64_t total_dictionary_size,
1339 GetTotalDictionarySizeImpl());
1340 ASSIGN_OR_RETURN(uint64_t total_dictionary_count, GetTotalDictionaryCount());
1341
1342 if ((cache_max_size == 0 || total_dictionary_size <= cache_max_size) &&
1343 total_dictionary_count <= cache_max_count) {
1344 return Error::kOk;
1345 }
1346
1347 uint64_t to_be_removed_count = 0;
1348 if (total_dictionary_count > count_low_watermark) {
1349 to_be_removed_count = total_dictionary_count - count_low_watermark;
1350 }
1351
1352 base::CheckedNumeric<uint64_t> checked_total_dictionary_size =
1353 total_dictionary_size;
1354
1355 static constexpr char kQuery[] =
1356 // clang-format off
1357 "SELECT "
1358 "id,"
1359 "size,"
1360 "token_high,"
1361 "token_low FROM dictionaries "
1362 "ORDER BY last_used_time";
1363 // clang-format on
1364
1365 if (!db()->IsSQLValid(kQuery)) {
1366 return Error::kInvalidSql;
1367 }
1368
1369 sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery));
1370 while (statement.Step()) {
1371 const int64_t primary_key_in_database = statement.ColumnInt64(0);
1372 const size_t size = statement.ColumnInt64(1);
1373 const int64_t token_high = statement.ColumnInt64(2);
1374 const int64_t token_low = statement.ColumnInt64(3);
1375 absl::optional<base::UnguessableToken> disk_cache_key_token =
1376 ToUnguessableToken(token_high, token_low);
1377 if (!disk_cache_key_token) {
1378 LOG(WARNING) << "Invalid token";
1379 continue;
1380 }
1381 checked_total_dictionary_size -= size;
1382
1383 if (!checked_total_dictionary_size.IsValid()) {
1384 base::debug::DumpWithoutCrashing();
1385 return Error::kInvalidTotalDictSize;
1386 }
1387
1388 *total_size_after_eviction_out =
1389 base::checked_cast<int64_t>(checked_total_dictionary_size.ValueOrDie());
1390 primary_keys_out->emplace_back(primary_key_in_database);
1391 tokens_out->emplace_back(*disk_cache_key_token);
1392
1393 if ((cache_max_size == 0 ||
1394 size_low_watermark >= checked_total_dictionary_size.ValueOrDie()) &&
1395 tokens_out->size() >= to_be_removed_count) {
1396 break;
1397 }
1398 }
1399 return Error::kOk;
1400 }
1401
1402 SQLitePersistentSharedDictionaryStore::Error
DeleteDictionaryByPrimaryKey(int64_t primary_key)1403 SQLitePersistentSharedDictionaryStore::Backend::DeleteDictionaryByPrimaryKey(
1404 int64_t primary_key) {
1405 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
1406 static constexpr char kQuery[] = "DELETE FROM dictionaries WHERE id=?";
1407 if (!db()->IsSQLValid(kQuery)) {
1408 return Error::kInvalidSql;
1409 }
1410 sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery));
1411 statement.BindInt64(0, primary_key);
1412
1413 if (!statement.Run()) {
1414 return Error::kFailedToExecuteSql;
1415 }
1416 return Error::kOk;
1417 }
1418
1419 SQLitePersistentSharedDictionaryStore::Error
1420 SQLitePersistentSharedDictionaryStore::Backend::
DeleteDictionariesByDiskCacheKeyTokensImpl(const std::set<base::UnguessableToken> & disk_cache_key_tokens)1421 DeleteDictionariesByDiskCacheKeyTokensImpl(
1422 const std::set<base::UnguessableToken>& disk_cache_key_tokens) {
1423 if (!InitializeDatabase()) {
1424 return Error::kFailedToInitializeDatabase;
1425 }
1426
1427 sql::Transaction transaction(db());
1428 if (!transaction.Begin()) {
1429 return Error::kFailedToBeginTransaction;
1430 }
1431
1432 base::CheckedNumeric<int64_t> checked_total_deleted_dictionary_size;
1433 for (const auto& token : disk_cache_key_tokens) {
1434 ASSIGN_OR_RETURN(uint64_t deleted_dictionary_size,
1435 DeleteDictionaryByDiskCacheToken(token));
1436 checked_total_deleted_dictionary_size += deleted_dictionary_size;
1437 }
1438
1439 int64_t total_deleted_dictionary_size =
1440 checked_total_deleted_dictionary_size.ValueOrDie();
1441 if (total_deleted_dictionary_size != 0) {
1442 uint64_t total_dictionary_size = 0;
1443 Error error = UpdateTotalDictionarySizeInMetaTable(
1444 -total_deleted_dictionary_size, &total_dictionary_size);
1445 if (error != Error::kOk) {
1446 return error;
1447 }
1448 }
1449
1450 if (!transaction.Commit()) {
1451 return Error::kFailedToCommitTransaction;
1452 }
1453 return Error::kOk;
1454 }
1455
1456 base::expected<uint64_t, SQLitePersistentSharedDictionaryStore::Error>
1457 SQLitePersistentSharedDictionaryStore::Backend::
DeleteDictionaryByDiskCacheToken(const base::UnguessableToken & disk_cache_key_token)1458 DeleteDictionaryByDiskCacheToken(
1459 const base::UnguessableToken& disk_cache_key_token) {
1460 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
1461 if (!InitializeDatabase()) {
1462 return base::unexpected(Error::kFailedToInitializeDatabase);
1463 }
1464 static constexpr char kQuery[] =
1465 // clang-format off
1466 "DELETE FROM dictionaries "
1467 "WHERE token_high=? AND token_low=?"
1468 "RETURNING size";
1469 // clang-format on
1470
1471 if (!db()->IsSQLValid(kQuery)) {
1472 return base::unexpected(Error::kInvalidSql);
1473 }
1474
1475 sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery));
1476 // There is no `sql::Statement::BindUint64()` method. So we cast to int64_t.
1477 int64_t token_high =
1478 static_cast<int64_t>(disk_cache_key_token.GetHighForSerialization());
1479 int64_t token_low =
1480 static_cast<int64_t>(disk_cache_key_token.GetLowForSerialization());
1481 statement.BindInt64(0, token_high);
1482 statement.BindInt64(1, token_low);
1483
1484 base::CheckedNumeric<uint64_t> checked_size = 0;
1485 while (statement.Step()) {
1486 const size_t size = statement.ColumnInt64(0);
1487 checked_size += size;
1488 }
1489 return base::ok(checked_size.ValueOrDie());
1490 }
1491
1492 SQLitePersistentSharedDictionaryStore::UnguessableTokenSetOrError
GetAllDiskCacheKeyTokensImpl()1493 SQLitePersistentSharedDictionaryStore::Backend::GetAllDiskCacheKeyTokensImpl() {
1494 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
1495 if (!InitializeDatabase()) {
1496 return base::unexpected(Error::kFailedToInitializeDatabase);
1497 }
1498
1499 static constexpr char kQuery[] =
1500 // clang-format off
1501 "SELECT "
1502 "id,"
1503 "token_high,"
1504 "token_low FROM dictionaries "
1505 "ORDER BY id";
1506 // clang-format on
1507
1508 if (!db()->IsSQLValid(kQuery)) {
1509 return base::unexpected(Error::kInvalidSql);
1510 }
1511
1512 sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery));
1513 std::vector<base::UnguessableToken> tokens;
1514 while (statement.Step()) {
1515 absl::optional<base::UnguessableToken> disk_cache_key_token =
1516 ToUnguessableToken(statement.ColumnInt64(1), statement.ColumnInt64(2));
1517 if (!disk_cache_key_token) {
1518 LOG(WARNING) << "Invalid token";
1519 continue;
1520 }
1521 tokens.emplace_back(*disk_cache_key_token);
1522 }
1523 return base::ok(
1524 std::set<base::UnguessableToken>(tokens.begin(), tokens.end()));
1525 }
1526
1527 void SQLitePersistentSharedDictionaryStore::Backend::
UpdateDictionaryLastUsedTime(int64_t primary_key_in_database,base::Time last_used_time)1528 UpdateDictionaryLastUsedTime(int64_t primary_key_in_database,
1529 base::Time last_used_time) {
1530 CHECK(client_task_runner()->RunsTasksInCurrentSequence());
1531 CHECK(!background_task_runner()->RunsTasksInCurrentSequence());
1532 size_t num_pending;
1533 {
1534 base::AutoLock locked(lock_);
1535 pending_last_used_time_updates_[primary_key_in_database] = last_used_time;
1536 num_pending = ++num_pending_;
1537 }
1538 // Commit every 30 seconds.
1539 static const int kCommitIntervalMs = 30 * 1000;
1540 // Commit right away if we have more than 100 operations.
1541 static const size_t kCommitAfterBatchSize = 100;
1542 if (num_pending == 1) {
1543 // We've gotten our first entry for this batch, fire off the timer.
1544 if (!background_task_runner()->PostDelayedTask(
1545 FROM_HERE, base::BindOnce(&Backend::Commit, this),
1546 base::Milliseconds(kCommitIntervalMs))) {
1547 NOTREACHED() << "background_task_runner_ is not running.";
1548 }
1549 } else if (num_pending >= kCommitAfterBatchSize) {
1550 // We've reached a big enough batch, fire off a commit now.
1551 PostBackgroundTask(FROM_HERE, base::BindOnce(&Backend::Commit, this));
1552 }
1553 }
1554
1555 base::expected<uint64_t, SQLitePersistentSharedDictionaryStore::Error>
GetTotalDictionaryCount()1556 SQLitePersistentSharedDictionaryStore::Backend::GetTotalDictionaryCount() {
1557 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
1558 static constexpr char kQuery[] = "SELECT COUNT(id) FROM dictionaries";
1559
1560 if (!db()->IsSQLValid(kQuery)) {
1561 return base::unexpected(Error::kInvalidSql);
1562 }
1563 uint64_t dictionary_count = 0;
1564 sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery));
1565 if (statement.Step()) {
1566 dictionary_count = statement.ColumnInt64(0);
1567 }
1568 return base::ok(dictionary_count);
1569 }
1570
1571 bool SQLitePersistentSharedDictionaryStore::Backend::
GetExistingDictionarySizeAndDiskCacheKeyToken(const SharedDictionaryIsolationKey & isolation_key,const url::SchemeHostPort & host,const std::string & match,int64_t * size_out,absl::optional<base::UnguessableToken> * disk_cache_key_out)1572 GetExistingDictionarySizeAndDiskCacheKeyToken(
1573 const SharedDictionaryIsolationKey& isolation_key,
1574 const url::SchemeHostPort& host,
1575 const std::string& match,
1576 int64_t* size_out,
1577 absl::optional<base::UnguessableToken>* disk_cache_key_out) {
1578 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
1579
1580 static constexpr char kQuery[] =
1581 // clang-format off
1582 "SELECT "
1583 "size,"
1584 "token_high,"
1585 "token_low FROM dictionaries "
1586 "WHERE frame_origin=? AND top_frame_site=? AND host=? AND match=? "
1587 "ORDER BY id";
1588 // clang-format on
1589
1590 if (!db()->IsSQLValid(kQuery)) {
1591 return false;
1592 }
1593 sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery));
1594 statement.BindString(0, isolation_key.frame_origin().Serialize());
1595 statement.BindString(1, isolation_key.top_frame_site().Serialize());
1596 statement.BindString(2, host.Serialize());
1597 statement.BindString(3, match);
1598
1599 if (statement.Step()) {
1600 *size_out = statement.ColumnInt64(0);
1601 *disk_cache_key_out =
1602 ToUnguessableToken(statement.ColumnInt64(1), statement.ColumnInt64(2));
1603 return true;
1604 }
1605 return false;
1606 }
1607
1608 SQLitePersistentSharedDictionaryStore::Error
1609 SQLitePersistentSharedDictionaryStore::Backend::
UpdateTotalDictionarySizeInMetaTable(int64_t size_delta,uint64_t * total_dictionary_size_out)1610 UpdateTotalDictionarySizeInMetaTable(int64_t size_delta,
1611 uint64_t* total_dictionary_size_out) {
1612 CHECK(background_task_runner()->RunsTasksInCurrentSequence());
1613 ASSIGN_OR_RETURN(uint64_t total_dictionary_size,
1614 GetTotalDictionarySizeImpl());
1615 base::CheckedNumeric<uint64_t> checked_total_dictionary_size =
1616 total_dictionary_size;
1617 checked_total_dictionary_size += size_delta;
1618 if (!checked_total_dictionary_size.IsValid()) {
1619 LOG(ERROR) << "Invalid total_dict_size detected.";
1620 base::debug::DumpWithoutCrashing();
1621 return Error::kInvalidTotalDictSize;
1622 }
1623 *total_dictionary_size_out = checked_total_dictionary_size.ValueOrDie();
1624 if (!meta_table()->SetValue(kTotalDictSizeKey, *total_dictionary_size_out)) {
1625 return Error::kFailedToSetTotalDictSize;
1626 }
1627 return Error::kOk;
1628 }
1629
SQLitePersistentSharedDictionaryStore(const base::FilePath & path,const scoped_refptr<base::SequencedTaskRunner> & client_task_runner,const scoped_refptr<base::SequencedTaskRunner> & background_task_runner)1630 SQLitePersistentSharedDictionaryStore::SQLitePersistentSharedDictionaryStore(
1631 const base::FilePath& path,
1632 const scoped_refptr<base::SequencedTaskRunner>& client_task_runner,
1633 const scoped_refptr<base::SequencedTaskRunner>& background_task_runner)
1634 : backend_(base::MakeRefCounted<Backend>(path,
1635 client_task_runner,
1636 background_task_runner)) {}
1637
1638 SQLitePersistentSharedDictionaryStore::
~SQLitePersistentSharedDictionaryStore()1639 ~SQLitePersistentSharedDictionaryStore() {
1640 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1641 backend_->Close();
1642 }
1643
GetTotalDictionarySize(base::OnceCallback<void (SizeOrError)> callback)1644 void SQLitePersistentSharedDictionaryStore::GetTotalDictionarySize(
1645 base::OnceCallback<void(SizeOrError)> callback) {
1646 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1647 backend_->GetTotalDictionarySize(
1648 WrapCallbackWithWeakPtrCheck(GetWeakPtr(), std::move(callback)));
1649 }
1650
RegisterDictionary(const SharedDictionaryIsolationKey & isolation_key,SharedDictionaryInfo dictionary_info,const uint64_t max_size_per_site,const uint64_t max_count_per_site,base::OnceCallback<void (RegisterDictionaryResultOrError)> callback)1651 void SQLitePersistentSharedDictionaryStore::RegisterDictionary(
1652 const SharedDictionaryIsolationKey& isolation_key,
1653 SharedDictionaryInfo dictionary_info,
1654 const uint64_t max_size_per_site,
1655 const uint64_t max_count_per_site,
1656 base::OnceCallback<void(RegisterDictionaryResultOrError)> callback) {
1657 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1658 backend_->RegisterDictionary(
1659 WrapCallbackWithWeakPtrCheck(GetWeakPtr(), std::move(callback)),
1660 isolation_key, std::move(dictionary_info), max_size_per_site,
1661 max_count_per_site);
1662 }
1663
GetDictionaries(const SharedDictionaryIsolationKey & isolation_key,base::OnceCallback<void (DictionaryListOrError)> callback)1664 void SQLitePersistentSharedDictionaryStore::GetDictionaries(
1665 const SharedDictionaryIsolationKey& isolation_key,
1666 base::OnceCallback<void(DictionaryListOrError)> callback) {
1667 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1668 backend_->GetDictionaries(
1669 WrapCallbackWithWeakPtrCheck(GetWeakPtr(), std::move(callback)),
1670 isolation_key);
1671 }
1672
GetAllDictionaries(base::OnceCallback<void (DictionaryMapOrError)> callback)1673 void SQLitePersistentSharedDictionaryStore::GetAllDictionaries(
1674 base::OnceCallback<void(DictionaryMapOrError)> callback) {
1675 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1676 backend_->GetAllDictionaries(
1677 WrapCallbackWithWeakPtrCheck(GetWeakPtr(), std::move(callback)));
1678 }
1679
GetUsageInfo(base::OnceCallback<void (UsageInfoOrError)> callback)1680 void SQLitePersistentSharedDictionaryStore::GetUsageInfo(
1681 base::OnceCallback<void(UsageInfoOrError)> callback) {
1682 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1683 backend_->GetUsageInfo(
1684 WrapCallbackWithWeakPtrCheck(GetWeakPtr(), std::move(callback)));
1685 }
1686
GetOriginsBetween(const base::Time start_time,const base::Time end_time,base::OnceCallback<void (OriginListOrError)> callback)1687 void SQLitePersistentSharedDictionaryStore::GetOriginsBetween(
1688 const base::Time start_time,
1689 const base::Time end_time,
1690 base::OnceCallback<void(OriginListOrError)> callback) {
1691 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1692 backend_->GetOriginsBetween(
1693 WrapCallbackWithWeakPtrCheck(GetWeakPtr(), std::move(callback)),
1694 start_time, end_time);
1695 }
1696
ClearAllDictionaries(base::OnceCallback<void (UnguessableTokenSetOrError)> callback)1697 void SQLitePersistentSharedDictionaryStore::ClearAllDictionaries(
1698 base::OnceCallback<void(UnguessableTokenSetOrError)> callback) {
1699 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1700 backend_->ClearAllDictionaries(
1701 WrapCallbackWithWeakPtrCheck(GetWeakPtr(), std::move(callback)));
1702 }
1703
ClearDictionaries(const base::Time start_time,const base::Time end_time,base::RepeatingCallback<bool (const GURL &)> url_matcher,base::OnceCallback<void (UnguessableTokenSetOrError)> callback)1704 void SQLitePersistentSharedDictionaryStore::ClearDictionaries(
1705 const base::Time start_time,
1706 const base::Time end_time,
1707 base::RepeatingCallback<bool(const GURL&)> url_matcher,
1708 base::OnceCallback<void(UnguessableTokenSetOrError)> callback) {
1709 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1710 backend_->ClearDictionaries(
1711 WrapCallbackWithWeakPtrCheck(GetWeakPtr(), std::move(callback)),
1712 start_time, end_time, std::move(url_matcher));
1713 }
1714
ClearDictionariesForIsolationKey(const SharedDictionaryIsolationKey & isolation_key,base::OnceCallback<void (UnguessableTokenSetOrError)> callback)1715 void SQLitePersistentSharedDictionaryStore::ClearDictionariesForIsolationKey(
1716 const SharedDictionaryIsolationKey& isolation_key,
1717 base::OnceCallback<void(UnguessableTokenSetOrError)> callback) {
1718 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1719 backend_->ClearDictionariesForIsolationKey(
1720 WrapCallbackWithWeakPtrCheck(GetWeakPtr(), std::move(callback)),
1721 isolation_key);
1722 }
1723
DeleteExpiredDictionaries(const base::Time now,base::OnceCallback<void (UnguessableTokenSetOrError)> callback)1724 void SQLitePersistentSharedDictionaryStore::DeleteExpiredDictionaries(
1725 const base::Time now,
1726 base::OnceCallback<void(UnguessableTokenSetOrError)> callback) {
1727 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1728 backend_->DeleteExpiredDictionaries(
1729 WrapCallbackWithWeakPtrCheck(GetWeakPtr(), std::move(callback)), now);
1730 }
1731
ProcessEviction(const uint64_t cache_max_size,const uint64_t size_low_watermark,const uint64_t cache_max_count,const uint64_t count_low_watermark,base::OnceCallback<void (UnguessableTokenSetOrError)> callback)1732 void SQLitePersistentSharedDictionaryStore::ProcessEviction(
1733 const uint64_t cache_max_size,
1734 const uint64_t size_low_watermark,
1735 const uint64_t cache_max_count,
1736 const uint64_t count_low_watermark,
1737 base::OnceCallback<void(UnguessableTokenSetOrError)> callback) {
1738 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1739 backend_->ProcessEviction(
1740 WrapCallbackWithWeakPtrCheck(GetWeakPtr(), std::move(callback)),
1741 cache_max_size, size_low_watermark, cache_max_count, count_low_watermark);
1742 }
1743
GetAllDiskCacheKeyTokens(base::OnceCallback<void (UnguessableTokenSetOrError)> callback)1744 void SQLitePersistentSharedDictionaryStore::GetAllDiskCacheKeyTokens(
1745 base::OnceCallback<void(UnguessableTokenSetOrError)> callback) {
1746 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1747 backend_->GetAllDiskCacheKeyTokens(
1748 WrapCallbackWithWeakPtrCheck(GetWeakPtr(), std::move(callback)));
1749 }
1750
1751 void SQLitePersistentSharedDictionaryStore::
DeleteDictionariesByDiskCacheKeyTokens(std::set<base::UnguessableToken> disk_cache_key_tokens,base::OnceCallback<void (Error)> callback)1752 DeleteDictionariesByDiskCacheKeyTokens(
1753 std::set<base::UnguessableToken> disk_cache_key_tokens,
1754 base::OnceCallback<void(Error)> callback) {
1755 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1756 backend_->DeleteDictionariesByDiskCacheKeyTokens(
1757 WrapCallbackWithWeakPtrCheck(GetWeakPtr(), std::move(callback)),
1758 std::move(disk_cache_key_tokens));
1759 }
1760
UpdateDictionaryLastUsedTime(int64_t primary_key_in_database,base::Time last_used_time)1761 void SQLitePersistentSharedDictionaryStore::UpdateDictionaryLastUsedTime(
1762 int64_t primary_key_in_database,
1763 base::Time last_used_time) {
1764 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1765 backend_->UpdateDictionaryLastUsedTime(primary_key_in_database,
1766 last_used_time);
1767 }
1768
1769 base::WeakPtr<SQLitePersistentSharedDictionaryStore>
GetWeakPtr()1770 SQLitePersistentSharedDictionaryStore::GetWeakPtr() {
1771 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1772 return weak_factory_.GetWeakPtr();
1773 }
1774
1775 } // namespace net
1776