blob: e7c7275c29a4255c0a76a86df65ea3daa438e124 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_DISK_CACHE_SQL_SQL_PERSISTENT_STORE_QUERIES_H_
#define NET_DISK_CACHE_SQL_SQL_PERSISTENT_STORE_QUERIES_H_
#include "base/notreached.h"
#include "base/strings/cstring_view.h"
namespace disk_cache_sql_queries {
namespace internal {
// The query strings are defined in this namespace to hide them from the public
// API. Callers should use `GetQuery()` instead.
//
// The query strings are defined as `inline constexpr` variables in this header
// file. This allows for compile-time optimization.
// The `resources` table stores the main metadata for each cache entry.
inline constexpr const char kInitSchema_CreateTableResources[] =
// clang-format off
"CREATE TABLE IF NOT EXISTS resources("
// Unique ID for the resource
"res_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
// High part of an unguessable token
"token_high INTEGER NOT NULL,"
// Low part of an unguessable token
"token_low INTEGER NOT NULL,"
// Timestamp for LRU
"last_used INTEGER NOT NULL,"
// End offset of the body
"body_end INTEGER NOT NULL,"
// Total bytes consumed by the entry
"bytes_usage INTEGER NOT NULL,"
// Flag for entries pending deletion
"doomed INTEGER NOT NULL,"
// The cache key created by HttpCache::GenerateCacheKeyForRequest()
"cache_key TEXT NOT NULL,"
// Serialized response headers
"head BLOB)";
// clang-format on
// The `blobs` table stores the data chunks of the cached body.
inline constexpr const char kInitSchema_CreateTableBlobs[] =
// clang-format off
"CREATE TABLE IF NOT EXISTS blobs("
// Unique ID for the blob
"blob_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
// Foreign key to resources.token_high
"token_high INTEGER NOT NULL,"
// Foreign key to resources.token_low
"token_low INTEGER NOT NULL,"
// Start offset of this blob chunk
"start INTEGER NOT NULL,"
// End offset of this blob chunk
"end INTEGER NOT NULL,"
// The actual data chunk
"blob BLOB NOT NULL)";
// clang-format on
// A unique index on the entry's token. This is used to quickly look up or
// update a resource entry using its unique token, which is essential for
// operations like `DoomEntry`, `UpdateEntryHeaderAndLastUsed`, and
// `WriteEntryData`. The `UNIQUE` constraint ensures data integrity by
// preventing duplicate tokens.
inline constexpr const char kIndex_ResourcesToken[] =
"CREATE UNIQUE INDEX IF NOT EXISTS index_resources_token ON "
"resources(token_high, token_low)";
// An index on `(cache_key, doomed)` to speed up lookups for live entries. This
// is frequently used in operations like `OpenEntry` to quickly find a
// non-doomed entry for a given cache key.
inline constexpr const char kIndex_ResourcesCacheKeyDoomed[] =
"CREATE INDEX IF NOT EXISTS index_resources_cache_key_doomed ON "
"resources(cache_key, doomed)";
// An index on `(doomed, last_used)` to optimize eviction logic. Eviction
// typically targets the least recently used (`last_used`) live (`doomed=false`)
// entries. This index significantly speeds up queries that select entries for
// eviction.
inline constexpr const char kIndex_ResourcesDoomedLastUsed[] =
"CREATE INDEX IF NOT EXISTS index_resources_doomed_last_used ON "
"resources(doomed, last_used)";
// An index on `(doomed, res_id)` to optimize iterating through entries while
// filtering for live (`doomed=false`) entries. `res_id` is a monotonically
// increasing primary key, making this index ideal for ordered traversals like
// in `OpenLatestEntryBeforeResId`.
inline constexpr const char kIndex_ResourcesDoomedResId[] =
"CREATE INDEX IF NOT EXISTS index_resources_doomed_res_id ON "
"resources(doomed, res_id)";
// A unique index on `(token_high, token_low, start)` in the `blobs` table. This
// is critical for quickly finding the correct data blobs for a given entry when
// reading or writing data at a specific offset. The `UNIQUE` constraint
// ensures that there are no overlapping blobs starting at the same offset for
// the same entry, which is important for data integrity.
inline constexpr const char kIndex_BlobsTokenStart[] =
"CREATE UNIQUE INDEX IF NOT EXISTS index_blobs_token_start ON "
"blobs(token_high, token_low, start)";
inline constexpr const char kOpenEntry_SelectLiveResources[] =
// clang-format off
"SELECT "
"token_high," // 0
"token_low," // 1
"last_used," // 2
"body_end," // 3
"head " // 4
"FROM resources "
"WHERE "
"cache_key=? AND " // 0
"doomed=0 "
"ORDER BY res_id DESC";
// clang-format on
inline constexpr const char kCreateEntry_InsertIntoResources[] =
// clang-format off
"INSERT INTO resources("
"token_high," // 0
"token_low," // 1
"last_used," // 2
"body_end," // 3
"bytes_usage," // 4
"doomed,"
"cache_key) " // 5
"VALUES(?,?,?,?,?,0,?)";
// clang-format on
inline constexpr const char kDoomEntry_MarkDoomedResources[] =
// clang-format off
"UPDATE resources "
"SET "
"doomed=1 "
"WHERE "
"cache_key=? AND " // 0
"token_high=? AND " // 1
"token_low=? AND " // 2
"doomed=0 "
"RETURNING "
"bytes_usage"; // 0
// clang-format on
inline constexpr const char kDeleteDoomedEntry_DeleteFromResources[] =
// clang-format off
"DELETE FROM resources "
"WHERE "
"cache_key=? AND " // 0
"token_high=? AND " // 1
"token_low=? AND " // 2
"doomed=1";
// clang-format on
inline constexpr const char kDeleteDoomedEntries_SelectDoomedResources[] =
// clang-format off
"SELECT "
"res_id," // 0
"token_high," // 1
"token_low " // 2
"FROM resources "
"WHERE doomed=1";
// clang-format on
inline constexpr const char kDeleteLiveEntry_DeleteFromResources[] =
// clang-format off
"DELETE FROM resources "
"WHERE "
"cache_key=? AND " // 0
"doomed=0 "
"RETURNING "
"token_high," // 0
"token_low," // 1
"bytes_usage"; // 2
// clang-format on
inline constexpr const char kDeleteAllEntries_DeleteFromResources[] =
"DELETE FROM resources";
inline constexpr const char kDeleteAllEntries_DeleteFromBlobs[] =
"DELETE FROM blobs";
inline constexpr const char kDeleteLiveEntriesBetween_SelectLiveResources[] =
// clang-format off
"SELECT "
"res_id," // 0
"token_high," // 1
"token_low," // 2
"bytes_usage," // 3
"cache_key " // 4
"FROM resources "
"WHERE "
"last_used>=? AND " // 0
"last_used<? AND " // 1
"doomed=0";
// clang-format on
inline constexpr const char kDeleteResourcesByResIds_DeleteFromResources[] =
"DELETE FROM resources WHERE res_id=?";
inline constexpr const char kUpdateEntryLastUsed_UpdateResourceLastUsed[] =
// clang-format off
"UPDATE resources "
"SET "
"last_used=? " // 0
"WHERE "
"cache_key=? AND " // 1
"doomed=0";
// clang-format on
inline constexpr const char kUpdateEntryHeaderAndLastUsed_UpdateResource[] =
// clang-format off
"UPDATE resources "
"SET "
"last_used=?, " // 0
"bytes_usage=bytes_usage+?, " // 1
"head=? " // 2
"WHERE "
"cache_key=? AND " // 3
"token_high=? AND " // 4
"token_low=? AND " // 5
"doomed=0 "
"RETURNING "
"bytes_usage"; // 0
// clang-format on
inline constexpr const char kWriteEntryData_UpdateResource[] =
// clang-format off
"UPDATE resources "
"SET "
"body_end=body_end+?, " // 0
"bytes_usage=bytes_usage+? " // 1
"WHERE "
"cache_key=? AND " // 2
"token_high=? AND " // 3
"token_low=? " // 4
"RETURNING "
"body_end," // 0
"doomed"; // 1
// clang-format on
inline constexpr const char kTrimOverlappingBlobs_DeleteContained[] =
// clang-format off
"DELETE FROM blobs "
"WHERE "
"token_high=? AND " // 0
"token_low=? AND " // 1
"start>=? AND " // 2
"end<=? " // 3
"RETURNING "
"start," // 0
"end"; // 1
// clang-format on
inline constexpr const char kTrimOverlappingBlobs_SelectOverlapping[] =
// clang-format off
"SELECT "
"blob_id," // 0
"start," // 1
"end," // 2
"blob " // 3
"FROM blobs "
"WHERE "
"token_high=? AND " // 0
"token_low=? AND " // 1
"start<? AND " // 2
"end>?"; // 3
// clang-format on
inline constexpr const char kTruncateBlobsAfter_DeleteAfter[] =
// clang-format off
"DELETE FROM blobs "
"WHERE "
"token_high=? AND " // 0
"token_low=? AND " // 1
"start>=? " // 2
"RETURNING "
"start," // 0
"end"; // 1
// clang-format on
inline constexpr const char kInsertNewBlob_InsertIntoBlobs[] =
// clang-format off
"INSERT INTO blobs("
"token_high," // 0
"token_low," // 1
"start," // 2
"end," // 3
"blob) " // 4
"VALUES(?,?,?,?,?)";
// clang-format on
inline constexpr const char kDeleteBlobById_DeleteFromBlobs[] =
// clang-format off
"DELETE FROM blobs "
"WHERE "
"blob_id=? " // 0
"RETURNING "
"start," // 0
"end"; // 1
// clang-format on
inline constexpr const char kDeleteBlobsByToken_DeleteFromBlobs[] =
// clang-format off
"DELETE FROM blobs "
"WHERE "
"token_high=? AND " // 0
"token_low=?"; // 1
// clang-format on
inline constexpr const char kReadEntryData_SelectOverlapping[] =
// clang-format off
"SELECT "
"start," // 0
"end," // 1
"blob " // 2
"FROM blobs "
"WHERE "
"token_high=? AND " // 0
"token_low=? AND " // 1
"start<? AND " // 2
"end>? " // 3
"ORDER BY start";
// clang-format on
inline constexpr const char kGetEntryAvailableRange_SelectOverlapping[] =
// clang-format off
"SELECT "
"start," // 0
"end " // 1
"FROM blobs "
"WHERE "
"token_high=? AND " // 0
"token_low=? AND " // 1
"start<? AND " // 2
"end>? " // 3
"ORDER BY start";
// clang-format on
inline constexpr const char
kCalculateSizeOfEntriesBetween_SelectLiveResources[] =
// clang-format off
"SELECT "
"bytes_usage " // 0
"FROM resources "
"WHERE "
"last_used>=? AND " // 0
"last_used<? AND " // 1
"doomed=0";
// clang-format on
inline constexpr const char kOpenLatestEntryBeforeResId_SelectLiveResources[] =
// clang-format off
"SELECT "
"res_id," // 0
"token_high," // 1
"token_low," // 2
"last_used," // 3
"body_end," // 4
"cache_key," // 5
"head " // 6
"FROM resources "
"WHERE "
"res_id<? AND " // 0
"doomed=0 "
"ORDER BY res_id DESC";
// clang-format on
inline constexpr const char kRunEviction_SelectLiveResources[] =
// clang-format off
"SELECT "
"token_high," // 0
"token_low," // 1
"cache_key," // 2
"bytes_usage " // 3
"FROM resources "
"WHERE "
"doomed=0 "
"ORDER BY last_used";
// clang-format on
inline constexpr const char kRunEviction_DeleteFromResources[] =
// clang-format off
"DELETE FROM resources "
"WHERE "
"token_high=? AND " // 0
"token_low=?"; // 1
// clang-format on
inline constexpr const char
kCalculateResourceEntryCount_SelectCountFromLiveResources[] =
"SELECT COUNT(*) FROM resources WHERE doomed=0";
inline constexpr const char
kCalculateTotalSize_SelectTotalSizeFromLiveResources[] =
"SELECT SUM(bytes_usage) FROM resources WHERE doomed=0";
} // namespace internal
// An enum for all SQL queries. This helps ensure that all queries are tested.
enum class Query {
kInitSchema_CreateTableResources,
kInitSchema_CreateTableBlobs,
kIndex_ResourcesToken,
kIndex_ResourcesCacheKeyDoomed,
kIndex_ResourcesDoomedLastUsed,
kIndex_ResourcesDoomedResId,
kIndex_BlobsTokenStart,
kOpenEntry_SelectLiveResources,
kCreateEntry_InsertIntoResources,
kDoomEntry_MarkDoomedResources,
kDeleteDoomedEntry_DeleteFromResources,
kDeleteDoomedEntries_SelectDoomedResources,
kDeleteLiveEntry_DeleteFromResources,
kDeleteAllEntries_DeleteFromResources,
kDeleteAllEntries_DeleteFromBlobs,
kDeleteLiveEntriesBetween_SelectLiveResources,
kDeleteResourcesByResIds_DeleteFromResources,
kUpdateEntryLastUsed_UpdateResourceLastUsed,
kUpdateEntryHeaderAndLastUsed_UpdateResource,
kWriteEntryData_UpdateResource,
kTrimOverlappingBlobs_DeleteContained,
kTrimOverlappingBlobs_SelectOverlapping,
kTruncateBlobsAfter_DeleteAfter,
kInsertNewBlob_InsertIntoBlobs,
kDeleteBlobById_DeleteFromBlobs,
kDeleteBlobsByToken_DeleteFromBlobs,
kReadEntryData_SelectOverlapping,
kGetEntryAvailableRange_SelectOverlapping,
kCalculateSizeOfEntriesBetween_SelectLiveResources,
kOpenLatestEntryBeforeResId_SelectLiveResources,
kRunEviction_SelectLiveResources,
kRunEviction_DeleteFromResources,
kCalculateResourceEntryCount_SelectCountFromLiveResources,
kCalculateTotalSize_SelectTotalSizeFromLiveResources,
kMaxValue = kCalculateTotalSize_SelectTotalSizeFromLiveResources,
};
inline base::cstring_view GetQuery(Query query) {
switch (query) {
case Query::kInitSchema_CreateTableResources:
return internal::kInitSchema_CreateTableResources;
case Query::kInitSchema_CreateTableBlobs:
return internal::kInitSchema_CreateTableBlobs;
case Query::kIndex_ResourcesToken:
return internal::kIndex_ResourcesToken;
case Query::kIndex_ResourcesCacheKeyDoomed:
return internal::kIndex_ResourcesCacheKeyDoomed;
case Query::kIndex_ResourcesDoomedLastUsed:
return internal::kIndex_ResourcesDoomedLastUsed;
case Query::kIndex_ResourcesDoomedResId:
return internal::kIndex_ResourcesDoomedResId;
case Query::kIndex_BlobsTokenStart:
return internal::kIndex_BlobsTokenStart;
case Query::kOpenEntry_SelectLiveResources:
return internal::kOpenEntry_SelectLiveResources;
case Query::kCreateEntry_InsertIntoResources:
return internal::kCreateEntry_InsertIntoResources;
case Query::kDoomEntry_MarkDoomedResources:
return internal::kDoomEntry_MarkDoomedResources;
case Query::kDeleteDoomedEntry_DeleteFromResources:
return internal::kDeleteDoomedEntry_DeleteFromResources;
case Query::kDeleteDoomedEntries_SelectDoomedResources:
return internal::kDeleteDoomedEntries_SelectDoomedResources;
case Query::kDeleteLiveEntry_DeleteFromResources:
return internal::kDeleteLiveEntry_DeleteFromResources;
case Query::kDeleteAllEntries_DeleteFromResources:
return internal::kDeleteAllEntries_DeleteFromResources;
case Query::kDeleteAllEntries_DeleteFromBlobs:
return internal::kDeleteAllEntries_DeleteFromBlobs;
case Query::kDeleteLiveEntriesBetween_SelectLiveResources:
return internal::kDeleteLiveEntriesBetween_SelectLiveResources;
case Query::kDeleteResourcesByResIds_DeleteFromResources:
return internal::kDeleteResourcesByResIds_DeleteFromResources;
case Query::kUpdateEntryLastUsed_UpdateResourceLastUsed:
return internal::kUpdateEntryLastUsed_UpdateResourceLastUsed;
case Query::kUpdateEntryHeaderAndLastUsed_UpdateResource:
return internal::kUpdateEntryHeaderAndLastUsed_UpdateResource;
case Query::kWriteEntryData_UpdateResource:
return internal::kWriteEntryData_UpdateResource;
case Query::kTrimOverlappingBlobs_DeleteContained:
return internal::kTrimOverlappingBlobs_DeleteContained;
case Query::kTrimOverlappingBlobs_SelectOverlapping:
return internal::kTrimOverlappingBlobs_SelectOverlapping;
case Query::kTruncateBlobsAfter_DeleteAfter:
return internal::kTruncateBlobsAfter_DeleteAfter;
case Query::kInsertNewBlob_InsertIntoBlobs:
return internal::kInsertNewBlob_InsertIntoBlobs;
case Query::kDeleteBlobById_DeleteFromBlobs:
return internal::kDeleteBlobById_DeleteFromBlobs;
case Query::kDeleteBlobsByToken_DeleteFromBlobs:
return internal::kDeleteBlobsByToken_DeleteFromBlobs;
case Query::kReadEntryData_SelectOverlapping:
return internal::kReadEntryData_SelectOverlapping;
case Query::kGetEntryAvailableRange_SelectOverlapping:
return internal::kGetEntryAvailableRange_SelectOverlapping;
case Query::kCalculateSizeOfEntriesBetween_SelectLiveResources:
return internal::kCalculateSizeOfEntriesBetween_SelectLiveResources;
case Query::kOpenLatestEntryBeforeResId_SelectLiveResources:
return internal::kOpenLatestEntryBeforeResId_SelectLiveResources;
case Query::kRunEviction_SelectLiveResources:
return internal::kRunEviction_SelectLiveResources;
case Query::kRunEviction_DeleteFromResources:
return internal::kRunEviction_DeleteFromResources;
case Query::kCalculateResourceEntryCount_SelectCountFromLiveResources:
return internal::
kCalculateResourceEntryCount_SelectCountFromLiveResources;
case Query::kCalculateTotalSize_SelectTotalSizeFromLiveResources:
return internal::kCalculateTotalSize_SelectTotalSizeFromLiveResources;
}
NOTREACHED();
}
} // namespace disk_cache_sql_queries
#endif // NET_DISK_CACHE_SQL_SQL_PERSISTENT_STORE_QUERIES_H_