1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
|
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef STORAGE_BROWSER_QUOTA_QUOTA_DATABASE_H_
#define STORAGE_BROWSER_QUOTA_QUOTA_DATABASE_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include "base/component_export.h"
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/sequence_checker.h"
#include "base/thread_annotations.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/types/id_type.h"
#include "components/services/storage/public/cpp/buckets/bucket_id.h"
#include "components/services/storage/public/cpp/buckets/bucket_info.h"
#include "components/services/storage/public/cpp/buckets/bucket_init_params.h"
#include "components/services/storage/public/cpp/buckets/bucket_locator.h"
#include "components/services/storage/public/cpp/buckets/constants.h"
#include "components/services/storage/public/cpp/quota_error_or.h"
#include "storage/browser/quota/quota_internals.mojom-forward.h"
#include "storage/browser/quota/storage_directory.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/mojom/quota/quota_types.mojom-shared.h"
namespace base {
class Clock;
}
namespace sql {
class Database;
class MetaTable;
class Statement;
} // namespace sql
namespace storage {
class SpecialStoragePolicy;
// These values are logged to UMA. Entries should not be renumbered and numeric
// values should never be reused. Please keep in sync with "DatabaseResetReason"
// in tools/metrics/histograms/enums.xml.
enum class DatabaseResetReason {
kOpenDatabase = 0,
kOpenInMemoryDatabase = 1,
kCreateSchema = 2,
kDatabaseMigration = 3,
kDatabaseVersionTooNew = 4,
kInitMetaTable = 5,
kCreateDirectory = 6,
kMaxValue = kCreateDirectory
};
// Stores all quota managed origin bucket data and metadata.
//
// Instances are owned by QuotaManagerImpl. There is one instance per
// QuotaManagerImpl instance. All the methods of this class, except the
// constructor, must called on the DB thread.
class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaDatabase {
public:
static constexpr char kDatabaseName[] = "QuotaManager";
// If `profile_path` is empty, an in-memory database will be used.
explicit QuotaDatabase(const base::FilePath& profile_path);
QuotaDatabase(const QuotaDatabase&) = delete;
QuotaDatabase& operator=(const QuotaDatabase&) = delete;
~QuotaDatabase();
// Gets the bucket described by `params.storage_key` and `params.name`
// for StorageType kTemporary and returns the BucketInfo. If a bucket fitting
// the params doesn't exist, it creates a new bucket with the policies in
// `params`. If the bucket exists but policies don't match what's provided in
// `params`, the existing bucket will be updated and returned (for those
// policies that are possible to modify --- expiration and persistence).
// Returns a QuotaError if the operation has failed. If `max_bucket_count` is
// greater than zero, and this operation would create a new bucket, then fail
// to create the new bucket if the total bucket count for this storage key is
// already at or above the max.
QuotaErrorOr<BucketInfo> UpdateOrCreateBucket(const BucketInitParams& params,
int max_bucket_count);
QuotaErrorOr<BucketInfo> CreateBucketForTesting(
const blink::StorageKey& storage_key,
const std::string& bucket_name);
// Retrieves BucketInfo of the bucket with `bucket_name` for `storage_key`.
// Returns a QuotaError::kEntryNotFound if the bucket does not exist, or
// a QuotaError::kDatabaseError if the operation has failed.
QuotaErrorOr<BucketInfo> GetBucket(const blink::StorageKey& storage_key,
const std::string& bucket_name);
// Retrieves BucketInfo of the bucket with `bucket_id`.
// Returns a QuotaError::kEntryNotFound if the bucket does not exist, or
// a QuotaError::kDatabaseError if the operation has failed.
QuotaErrorOr<BucketInfo> GetBucketById(BucketId bucket_id);
// Returns all buckets in the buckets table. Returns a QuotaError if the
// operation has failed.
QuotaErrorOr<std::set<BucketInfo>> GetAllBuckets();
// Retrieves all buckets for `host`. Returns a QuotaError if the operation
// has failed.
QuotaErrorOr<std::set<BucketInfo>> GetBucketsForHost(const std::string& host);
// Returns all buckets for `storage_key` in the buckets table. Returns a
// QuotaError if the operation has failed.
QuotaErrorOr<std::set<BucketInfo>> GetBucketsForStorageKey(
const blink::StorageKey& storage_key);
// Updates the expiration for the designated bucket.
QuotaErrorOr<BucketInfo> UpdateBucketExpiration(BucketId bucket,
const base::Time& expiration);
// Updates the persistence bit for the designated bucket.
QuotaErrorOr<BucketInfo> UpdateBucketPersistence(BucketId bucket,
bool persistent);
// TODO(crbug.com/40179024): Remove once all usages have updated to use
// SetBucketLastAccessTime.
[[nodiscard]] QuotaError SetStorageKeyLastAccessTime(
const blink::StorageKey& storage_key,
base::Time last_accessed);
// Called by QuotaClient implementers to update when the bucket was last
// accessed. If `bucket_id` refers to a bucket with an opaque StorageKey, the
// bucket's last access time will not be updated and the function will return
// QuotaError::kNotFound. Returns QuotaError::kNone on a successful update.
[[nodiscard]] QuotaError SetBucketLastAccessTime(BucketId bucket_id,
base::Time last_accessed);
// Called by QuotaClient implementers to update when the bucket was last
// modified. Returns QuotaError::kNone on a successful update.
[[nodiscard]] QuotaError SetBucketLastModifiedTime(BucketId bucket_id,
base::Time last_modified);
// Register initial `storage_keys` into the database.
// This method is assumed to be called only after the installation or
// the database schema reset.
QuotaError RegisterInitialStorageKeyInfo(
std::set<blink::StorageKey> storage_keys);
// Returns the BucketTableEntry for `bucket` if one exists. Returns a
// QuotaError if not found or the operation has failed.
QuotaErrorOr<mojom::BucketTableEntryPtr> GetBucketInfoForTest(
BucketId bucket_id);
// Deletes the bucket from the database as well as the bucket directory in the
// storage directory. Returns the bucket data that was deleted.
QuotaErrorOr<mojom::BucketTableEntryPtr> DeleteBucketData(
const BucketLocator& bucket);
// Returns BucketLocators for the least recently used buckets, to clear at
// least `target_usage` space. Will exclude buckets with ids in
// `bucket_exceptions`, buckets marked persistent, and origins that have the
// special unlimited storage policy. Returns a QuotaError if the operation has
// failed. `usage_map` describes the amount of space used by each bucket; any
// bucket missing from this map will be considered to use only 1b.
QuotaErrorOr<std::set<BucketLocator>> GetBucketsForEviction(
int64_t target_usage,
const std::map<BucketLocator, int64_t>& usage_map,
const std::set<BucketId>& bucket_exceptions,
SpecialStoragePolicy* special_storage_policy);
// Returns all storage keys in the buckets table.
QuotaErrorOr<std::set<blink::StorageKey>> GetAllStorageKeys();
// Returns a set of buckets that have been modified since the `begin` and
// until the `end`. Returns a QuotaError if the operations has failed.
QuotaErrorOr<std::set<BucketLocator>> GetBucketsModifiedBetween(
base::Time begin,
base::Time end);
// Returns a set of all expired or stale (not accessed or modified in 400 days
// and not persisted) buckets.
// See crbug.com/40281870 for more info.
QuotaErrorOr<std::set<BucketInfo>> GetExpiredBuckets(
SpecialStoragePolicy* special_storage_policy);
base::FilePath GetStoragePath() const { return storage_directory_->path(); }
// Returns false if SetIsBootstrapped() has never been called before, which
// means existing storage keys may not have been registered. Bootstrapping
// ensures that there is a bucket entry in the buckets table for all storage
// keys that have stored data by quota managed Storage APIs.
bool IsBootstrapped();
QuotaError SetIsBootstrapped(bool bootstrap_flag);
// Returns false if SetIsMediaLicensedDatabaseRemoved() has never been called
// before, which means that Media License Databases still potentially exist
// within the bucket directories.
bool IsMediaLicenseDatabaseRemoved();
QuotaError SetIsMediaLicenseDatabaseRemoved(bool removed_flag);
// If the database has failed to open, this will attempt to reopen it.
// Otherwise, it will attempt to recover the database. If recovery is
// attempted but fails, the database will be razed. In all cases, this will
// attempt to reopen the database and return true on success.
bool RecoverOrRaze(int error_code);
// Flushes previously scheduled commits.
void CommitNow();
// The given callback will be invoked whenever the database encounters an
// error.
void SetDbErrorCallback(
const base::RepeatingCallback<void(int)>& db_error_callback);
// Testing support for database corruption handling.
//
// Runs `corrupter` on the same sequence used to do database I/O,
// guaranteeing that no other database operation is performed at the same
// time. `corrupter` receives the path to the underlying SQLite database
// as an argument. The underlying SQLite database is closed while
// `corrupter` runs, and reopened afterwards.
// Returns QuotaError::kNone if the database was successfully reopened
// after `corrupter` was run, or QuotaError::kDatabaseError otherwise.
QuotaError CorruptForTesting(
base::OnceCallback<void(const base::FilePath&)> corrupter);
// Manually disable database to test database error scenarios for testing.
void SetDisabledForTesting(bool disable);
static base::Time GetNow();
static void SetClockForTesting(const base::Clock* clock);
void SetAlreadyEvictedStaleStorageForTesting(
bool already_evicted_stale_storage);
private:
// Structures used for CreateSchema.
struct TableSchema {
const char* table_name;
const char* columns;
};
struct IndexSchema {
const char* index_name;
const char* table_name;
const char* columns;
bool unique;
};
using BucketTableCallback =
base::RepeatingCallback<bool(mojom::BucketTableEntryPtr)>;
// For long-running transactions support. We always keep a transaction open
// so that multiple transactions can be batched. They are flushed
// with a delay after a modification has been made. We support neither
// nested transactions nor rollback (as we don't need them for now).
void Commit();
void ScheduleCommit();
QuotaError EnsureOpened();
void OnSqliteError(int sqlite_error_code, sql::Statement* statement);
bool MoveLegacyDatabase();
bool OpenDatabase();
bool EnsureDatabaseVersion();
bool ResetStorage();
bool CreateSchema();
bool CreateTable(const TableSchema& table);
bool CreateIndex(const IndexSchema& index);
// Dumps table entries for chrome://quota-internals page.
// `callback` may return false to stop reading data.
QuotaError DumpBucketTable(const BucketTableCallback& callback);
// Adds a new bucket entry in the buckets table. Will return a
// QuotaError::kDatabaseError if the query fails. Will fail if adding the new
// bucket would cause the count of buckets for that storage key and type to
// exceed `max_bucket_count`, if `max_bucket_count` is greater than zero.
QuotaErrorOr<BucketInfo> CreateBucketInternal(const BucketInitParams& params,
int max_bucket_count = 0);
SEQUENCE_CHECKER(sequence_checker_);
const std::unique_ptr<StorageDirectory> storage_directory_;
const base::FilePath db_file_path_;
const base::FilePath legacy_db_file_path_;
std::unique_ptr<sql::Database> db_ GUARDED_BY_CONTEXT(sequence_checker_);
std::unique_ptr<sql::MetaTable> meta_table_
GUARDED_BY_CONTEXT(sequence_checker_);
bool is_recreating_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
bool is_disabled_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
int sqlite_error_code_ = 0;
base::OneShotTimer timer_ GUARDED_BY_CONTEXT(sequence_checker_);
friend class QuotaDatabaseTest;
friend class QuotaDatabaseMigrations;
friend class QuotaDatabaseMigrationsTest;
friend class QuotaManagerImpl;
static const TableSchema kTables[];
static const size_t kTableCount;
static const IndexSchema kIndexes[];
static const size_t kIndexCount;
// A descriptor of the last SQL statement that was executed, used for metrics.
std::optional<std::string> last_operation_;
base::RepeatingCallback<void(int)> db_error_callback_;
// We need to delay evicting stale buckets until after any session
// restore has taken place, otherwise we might fail to record current usage.
// See crbug.com/40281870 for more info.
base::Time evict_stale_buckets_after_{GetNow() + base::Minutes(1)};
// We only need to evict stale storage once per profile load. Unlike
// expired storage, there is no contract with the site to evict storage
// on a specific timeline. Saving on latency here is more important than
// cleaning ASAP in long-lived browsing sessions. Also, where possible we
// should parallel the stale storage clearing efforts in local storage,
// and once per profile load is the standard there.
bool already_evicted_stale_storage_{false};
};
} // namespace storage
#endif // STORAGE_BROWSER_QUOTA_QUOTA_DATABASE_H_
|