blob: 4492761df25570d3b814e57d8fb39035b48c5a09 [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 resources("
// Unique ID for the resource
"res_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
// 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 checksum `crc32(head + cache_key_hash)`.
"check_sum INTEGER NOT NULL,"
// The hash of `cache_key` created by simple_util::GetEntryHashKey()
"cache_key_hash 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 blobs("
// Unique ID for the blob
"blob_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
// Foreign key to resources.res_id
"res_id INTEGER NOT NULL,"
// Start offset of this blob chunk
"start INTEGER NOT NULL,"
// End offset of this blob chunk
"end INTEGER NOT NULL,"
// The checksum `crc32(blob + cache_key_hash)`.
"check_sum INTEGER NOT NULL,"
// The actual data chunk
"blob BLOB NOT NULL)";
// clang-format on
// An index on `(cache_key_hash, 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_ResourcesCacheKeyHashDoomed[] =
"CREATE INDEX index_resources_cache_key_hash_doomed ON "
"resources(cache_key_hash, doomed)";
// An index on `last_used` and `bytes_usage` for live entries (`doomed=0`). This
// is crucial for eviction logic, which targets the least recently used entries.
// To avoid looking at the actual resources table during eviction, this creates
// a covering index.
inline constexpr const char kIndex_LiveResourcesLastUsed[] =
"CREATE INDEX index_live_resources_last_used_bytes_usage ON "
"resources(last_used, bytes_usage) WHERE doomed=0";
// A unique index on `(res_id, 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_BlobsResIdStart[] =
"CREATE UNIQUE INDEX index_blobs_res_id_start ON "
"blobs(res_id, start)";
inline constexpr const char kOpenEntry_SelectLiveResources[] =
// clang-format off
"SELECT "
"res_id," // 0
"last_used," // 1
"body_end," // 2
"check_sum," // 3
"head " // 4
"FROM resources "
"WHERE "
"cache_key_hash=? AND " // 0
"cache_key=? AND " // 1
"doomed=0 "
"ORDER BY res_id DESC";
// clang-format on
inline constexpr const char kCreateEntry_InsertIntoResources[] =
// clang-format off
"INSERT INTO resources("
"last_used," // 0
"body_end," // 1
"bytes_usage," // 2
"doomed,"
"check_sum," // 3
"cache_key_hash," // 4
"cache_key) " // 5
"VALUES(?,?,?,0,?,?,?) "
"RETURNING res_id";
// clang-format on
inline constexpr const char kDoomEntry_MarkDoomedResources[] =
// clang-format off
"UPDATE resources "
"SET "
"doomed=1 "
"WHERE "
"res_id=? AND " // 0
"doomed=0 "
"RETURNING "
"bytes_usage"; // 0
// clang-format on
inline constexpr const char kDeleteDoomedEntry_DeleteFromResources[] =
// clang-format off
"DELETE FROM resources "
"WHERE "
"res_id=? AND " // 0
"doomed=1";
// clang-format on
inline constexpr const char kDeleteLiveEntry_DeleteFromResources[] =
// clang-format off
"DELETE FROM resources "
"WHERE "
"cache_key_hash=? AND " // 0
"cache_key=? AND " // 1
"doomed=0 "
"RETURNING "
"res_id," // 0
"bytes_usage"; // 1
// 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
"bytes_usage " // 1
"FROM resources "
"WHERE "
"last_used>=? AND " // 0
"last_used<? AND " // 1
"doomed=0";
// clang-format on
inline constexpr const char kDeleteResourceByResIds_DeleteFromResources[] =
"DELETE FROM resources WHERE res_id=?";
inline constexpr const char kUpdateEntryLastUsedByKey_UpdateResourceLastUsed[] =
// clang-format off
"UPDATE resources "
"SET "
"last_used=? " // 0
"WHERE "
"cache_key_hash=? AND " // 1
"cache_key=? AND " // 2
"doomed=0";
// clang-format on
inline constexpr const char
kUpdateEntryLastUsedByResId_UpdateResourceLastUsed[] =
// clang-format off
"UPDATE resources "
"SET "
"last_used=? " // 0
"WHERE "
"res_id=? 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
"check_sum=?, " // 2
"head=? " // 3
"WHERE "
"res_id=? AND " // 3
"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 "
"res_id=? " // 2
"RETURNING "
"body_end," // 0
"doomed"; // 1
// clang-format on
inline constexpr const char kTrimOverlappingBlobs_DeleteContained[] =
// clang-format off
"DELETE FROM blobs "
"WHERE "
"res_id=? AND " // 0
"start>=? AND " // 1
"end<=? " // 2
"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
"check_sum," // 3
"blob " // 4
"FROM blobs "
"WHERE "
"res_id=? AND " // 0
"start<? AND " // 1
"end>?"; // 2
// clang-format on
inline constexpr const char kTruncateBlobsAfter_DeleteAfter[] =
// clang-format off
"DELETE FROM blobs "
"WHERE "
"res_id=? AND " // 0
"start>=? " // 1
"RETURNING "
"start," // 0
"end"; // 1
// clang-format on
inline constexpr const char kInsertNewBlob_InsertIntoBlobs[] =
// clang-format off
"INSERT INTO blobs("
"res_id," // 0
"start," // 1
"end," // 2
"check_sum," // 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 kDeleteBlobsByResId_DeleteFromBlobs[] =
// clang-format off
"DELETE FROM blobs "
"WHERE "
"res_id=?"; // 0
// clang-format on
inline constexpr const char kReadEntryData_SelectOverlapping[] =
// clang-format off
"SELECT "
"start," // 0
"end," // 1
"check_sum," // 2
"blob " // 3
"FROM blobs "
"WHERE "
"res_id=? AND " // 0
"start<? AND " // 1
"end>? " // 2
"ORDER BY start";
// clang-format on
inline constexpr const char kGetEntryAvailableRange_SelectOverlapping[] =
// clang-format off
"SELECT "
"start," // 0
"end " // 1
"FROM blobs "
"WHERE "
"res_id=? AND " // 0
"start<? AND " // 1
"end>? " // 2
"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 kOpenNextEntry_SelectLiveResources[] =
// clang-format off
"SELECT "
"res_id," // 0
"last_used," // 1
"body_end," // 2
"check_sum," // 3
"cache_key," // 4
"head " // 5
"FROM resources "
"WHERE "
"res_id<? AND " // 0
"doomed=0 "
"ORDER BY res_id DESC";
// clang-format on
inline constexpr const char kStartEviction_SelectLiveResources[] =
// clang-format off
"SELECT "
"res_id," // 0
"bytes_usage, " // 1
"last_used " // 2
"FROM resources "
"WHERE "
"doomed=0 "
"ORDER BY last_used";
// 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";
inline constexpr const char
kGetCacheKeyHashes_SelectCacheKeyHashFromLiveResources[] =
// clang-format off
"SELECT "
"res_id, " // 0
"cache_key_hash, " // 1
"doomed " // 2
"FROM resources "
"ORDER BY cache_key_hash";
// clang-format on
} // namespace internal
// An enum for all SQL queries. This helps ensure that all queries are tested.
enum class Query {
kInitSchema_CreateTableResources,
kInitSchema_CreateTableBlobs,
kIndex_ResourcesCacheKeyHashDoomed,
kIndex_LiveResourcesLastUsed,
kIndex_BlobsResIdStart,
kOpenEntry_SelectLiveResources,
kCreateEntry_InsertIntoResources,
kDoomEntry_MarkDoomedResources,
kDeleteDoomedEntry_DeleteFromResources,
kDeleteLiveEntry_DeleteFromResources,
kDeleteAllEntries_DeleteFromResources,
kDeleteAllEntries_DeleteFromBlobs,
kDeleteLiveEntriesBetween_SelectLiveResources,
kDeleteResourceByResIds_DeleteFromResources,
kUpdateEntryLastUsedByKey_UpdateResourceLastUsed,
kUpdateEntryLastUsedByResId_UpdateResourceLastUsed,
kUpdateEntryHeaderAndLastUsed_UpdateResource,
kWriteEntryData_UpdateResource,
kTrimOverlappingBlobs_DeleteContained,
kTrimOverlappingBlobs_SelectOverlapping,
kTruncateBlobsAfter_DeleteAfter,
kInsertNewBlob_InsertIntoBlobs,
kDeleteBlobById_DeleteFromBlobs,
kDeleteBlobsByResId_DeleteFromBlobs,
kReadEntryData_SelectOverlapping,
kGetEntryAvailableRange_SelectOverlapping,
kCalculateSizeOfEntriesBetween_SelectLiveResources,
kOpenNextEntry_SelectLiveResources,
kStartEviction_SelectLiveResources,
kCalculateResourceEntryCount_SelectCountFromLiveResources,
kCalculateTotalSize_SelectTotalSizeFromLiveResources,
kGetCacheKeyHashes_SelectCacheKeyHashFromLiveResources,
kMaxValue = kGetCacheKeyHashes_SelectCacheKeyHashFromLiveResources,
};
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_ResourcesCacheKeyHashDoomed:
return internal::kIndex_ResourcesCacheKeyHashDoomed;
case Query::kIndex_LiveResourcesLastUsed:
return internal::kIndex_LiveResourcesLastUsed;
case Query::kIndex_BlobsResIdStart:
return internal::kIndex_BlobsResIdStart;
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::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::kDeleteResourceByResIds_DeleteFromResources:
return internal::kDeleteResourceByResIds_DeleteFromResources;
case Query::kUpdateEntryLastUsedByKey_UpdateResourceLastUsed:
return internal::kUpdateEntryLastUsedByKey_UpdateResourceLastUsed;
case Query::kUpdateEntryLastUsedByResId_UpdateResourceLastUsed:
return internal::kUpdateEntryLastUsedByResId_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::kDeleteBlobsByResId_DeleteFromBlobs:
return internal::kDeleteBlobsByResId_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::kOpenNextEntry_SelectLiveResources:
return internal::kOpenNextEntry_SelectLiveResources;
case Query::kStartEviction_SelectLiveResources:
return internal::kStartEviction_SelectLiveResources;
case Query::kCalculateResourceEntryCount_SelectCountFromLiveResources:
return internal::
kCalculateResourceEntryCount_SelectCountFromLiveResources;
case Query::kCalculateTotalSize_SelectTotalSizeFromLiveResources:
return internal::kCalculateTotalSize_SelectTotalSizeFromLiveResources;
case Query::kGetCacheKeyHashes_SelectCacheKeyHashFromLiveResources:
return internal::kGetCacheKeyHashes_SelectCacheKeyHashFromLiveResources;
}
NOTREACHED();
}
} // namespace disk_cache_sql_queries
#endif // NET_DISK_CACHE_SQL_SQL_PERSISTENT_STORE_QUERIES_H_