From 76e4f6648da9c1d5535af7d05b4ba20bcafa2ffd Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 13 May 2026 01:54:48 +0000 Subject: [PATCH] feat(usage): add databases.operations.reads.cached metric MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a new metric family that counts only reads served from the query cache layer: - databases.operations.reads.cached (project-level) - {databaseInternalId}.databases.operations.reads.cached (per-database) The existing databases.operations.reads continues to count every read regardless of source, so direct reads can be derived as total - cached. Increments fire from List Documents only when the cache returned a result. The Get Documents endpoint has no query cache, so it never increments the cached counter. Scope is the base databases.* family; documentsdb.* and vectorsdb.* variants are intentionally untouched for now. No response model changes — the metric is stored only. Co-Authored-By: Claude Opus 4.7 (1M context) --- app/init/constants.php | 2 ++ .../Databases/Collections/Documents/Action.php | 16 ++++++++++++++++ .../Databases/Collections/Documents/XList.php | 12 +++++++++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/app/init/constants.php b/app/init/constants.php index 17afc35ae9..ff1d6771ee 100644 --- a/app/init/constants.php +++ b/app/init/constants.php @@ -290,6 +290,8 @@ const METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS = '{databaseInternalId}.{collec const METRIC_DATABASE_ID_COLLECTION_ID_STORAGE = '{databaseInternalId}.{collectionInternalId}.databases.storage'; const METRIC_DATABASES_OPERATIONS_READS = 'databases.operations.reads'; const METRIC_DATABASE_ID_OPERATIONS_READS = '{databaseInternalId}.databases.operations.reads'; +const METRIC_DATABASES_OPERATIONS_READS_CACHED = 'databases.operations.reads.cached'; +const METRIC_DATABASE_ID_OPERATIONS_READS_CACHED = '{databaseInternalId}.databases.operations.reads.cached'; const METRIC_DATABASES_OPERATIONS_WRITES = 'databases.operations.writes'; const METRIC_DATABASE_ID_OPERATIONS_WRITES = '{databaseInternalId}.databases.operations.writes'; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php index 8100a2c51b..fd6d584dfa 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php @@ -67,6 +67,22 @@ abstract class Action extends DatabasesAction return $this->databaseType.'.'.METRIC_DATABASE_ID_OPERATIONS_READS; } + protected function getDatabasesOperationReadCachedMetric(): ?string + { + if ($this->databaseType === DATABASE_TYPE_LEGACY || $this->databaseType === DATABASE_TYPE_TABLESDB) { + return METRIC_DATABASES_OPERATIONS_READS_CACHED; + } + return null; + } + + protected function getDatabasesIdOperationReadCachedMetric(): ?string + { + if ($this->databaseType === DATABASE_TYPE_LEGACY || $this->databaseType === DATABASE_TYPE_TABLESDB) { + return METRIC_DATABASE_ID_OPERATIONS_READS_CACHED; + } + return null; + } + protected function getDatabasesOperationWriteMetric(): string { if ($this->databaseType === DATABASE_TYPE_LEGACY || $this->databaseType === DATABASE_TYPE_TABLESDB) { diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php index 3a49d6c665..165d2d7493 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php @@ -129,6 +129,7 @@ class XList extends Action } $dbStart = \microtime(true); + $documentsCacheHit = false; try { $hasSelects = ! empty(Query::groupByType($queries)['selections']); @@ -148,7 +149,6 @@ class XList extends Action $roles = $dbForProject->getAuthorization()->getRoles(); $documentsField = $this->getListCacheField($collection, $roles, $queries, self::LIST_CACHE_FIELD_DOCUMENTS); - $documentsCacheHit = false; try { $cachedDocuments = $dbForProject->getCache()->load($cacheKey, $ttl, $documentsField); } catch (\Throwable) { @@ -230,6 +230,16 @@ class XList extends Action ->addMetric($this->getDatabasesOperationReadMetric(), max($operations, 1)) ->addMetric(str_replace('{databaseInternalId}', $database->getSequence(), $this->getDatabasesIdOperationReadMetric()), $operations); + if ($documentsCacheHit) { + $cachedMetric = $this->getDatabasesOperationReadCachedMetric(); + $cachedIdMetric = $this->getDatabasesIdOperationReadCachedMetric(); + if ($cachedMetric !== null && $cachedIdMetric !== null) { + $usage + ->addMetric($cachedMetric, max($operations, 1)) + ->addMetric(str_replace('{databaseInternalId}', $database->getSequence(), $cachedIdMetric), $operations); + } + } + $response->dynamic(new Document([ 'total' => $total, // rows or documents