Skip to content

Commit 9d5df60

Browse files
cursoragentabnegate
andcommitted
Improve cache versioning with sub-second precision and uniqueness
Co-authored-by: jakeb994 <jakeb994@gmail.com>
1 parent 6b08be8 commit 9d5df60

File tree

2 files changed

+19
-13
lines changed

2 files changed

+19
-13
lines changed

CACHE_IMPLEMENTATION_SUMMARY.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ This implementation adds efficient caching to the `find` method in the Database
1414

1515
### 2. Version Tracking for O(1) Invalidation
1616
- **Purpose**: Enable aggressive cache invalidation without expensive cache scanning
17-
- **Implementation**: Each collection has a version number that increments on any change
18-
- **Storage**: Version numbers are cached persistently with 1-year TTL
19-
- **Benefits**: O(1) invalidation time complexity
17+
- **Implementation**: Each collection has a version string that changes on any modification
18+
- **Format**: `{microtime}-{random_hex}` for sub-second precision and uniqueness
19+
- **Storage**: Version strings are cached persistently with 1-year TTL
20+
- **Benefits**: O(1) invalidation time complexity with sub-second granularity
2021

2122
### 3. Find Method Caching
2223
- **Cache Key Generation**: Uses xxh3 hash of all query parameters plus collection version
@@ -26,7 +27,8 @@ This implementation adds efficient caching to the `find` method in the Database
2627

2728
### 4. Aggressive Invalidation
2829
- **Trigger Points**: Any document create, update, or delete operation
29-
- **Method**: Increments collection version, making all cached queries invalid
30+
- **Method**: Changes collection version, making all cached queries invalid instantly
31+
- **Granularity**: Sub-second precision prevents cache inconsistencies during rapid operations
3032
- **Priority**: Correctness over performance (as requested)
3133
- **Implementation**: Updated `purgeCachedDocument()` and `purgeCachedCollection()` methods
3234

@@ -49,8 +51,8 @@ protected array $collectionVersions = [];
4951
### New Methods
5052
1. `generateCacheHash(string $data): string` - xxh3 hash implementation using PHP's built-in hash function
5153
2. `getFindCacheKey(...)` - Generate cache keys for find queries
52-
3. `getCollectionVersion(string $collectionId): int` - Get/initialize collection version
53-
4. `incrementCollectionVersion(string $collectionId): void` - Increment version for invalidation
54+
3. `getCollectionVersion(string $collectionId): string` - Get/initialize collection version
55+
4. `incrementCollectionVersion(string $collectionId): void` - Change version for invalidation
5456
5. `getCollectionVersionKey(string $collectionId): string` - Generate version cache key
5557

5658
### Modified Methods
@@ -65,7 +67,7 @@ protected array $collectionVersions = [];
6567

6668
Example:
6769
```
68-
default-cache-:::find:users:7a8b9c2d1e3f4567:v1691234567
70+
default-cache-:::find:users:7a8b9c2d1e3f4567:v1691234567.123456-a1b2c3d4
6971
```
7072

7173
## Performance Characteristics
@@ -81,8 +83,9 @@ default-cache-:::find:users:7a8b9c2d1e3f4567:v1691234567
8183
- **No degradation**: Database query performance unchanged
8284

8385
### Invalidation Performance
84-
- **Time Complexity**: O(1) for version increment
86+
- **Time Complexity**: O(1) for version change
8587
- **Space Complexity**: O(1) additional storage per collection
88+
- **Granularity**: Sub-second precision with microsecond accuracy
8689
- **Immediate**: All cached queries become invalid instantly
8790

8891
## Usage Example
@@ -104,6 +107,7 @@ $results2 = $database->find('users', [
104107
$database->updateDocument('users', 'user_id', $updatedDoc);
105108

106109
// Next call - cache miss (version changed), queries database
110+
// Works correctly even for rapid successive operations within the same second
107111
$results3 = $database->find('users', [
108112
Query::equal('status', 'active'),
109113
Query::limit(25)

src/Database/Database.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7060,21 +7060,22 @@ private function getFindCacheKey(
70607060
* Get collection version for cache invalidation
70617061
*
70627062
* @param string $collectionId
7063-
* @return int
7063+
* @return string
70647064
*/
7065-
private function getCollectionVersion(string $collectionId): int
7065+
private function getCollectionVersion(string $collectionId): string
70667066
{
70677067
if (!isset($this->collectionVersions[$collectionId])) {
70687068
// Try to load from cache first
70697069
$versionKey = $this->getCollectionVersionKey($collectionId);
70707070
$version = $this->cache->load($versionKey, self::TTL * 365); // Store versions for a year
70717071

70727072
if ($version === null) {
7073-
$version = \time(); // Use current timestamp as initial version
7073+
// Use microtime + random component for sub-second precision and uniqueness
7074+
$version = \sprintf('%.6f-%s', \microtime(true), \bin2hex(\random_bytes(4)));
70747075
$this->cache->save($versionKey, $version, null, self::TTL * 365);
70757076
}
70767077

7077-
$this->collectionVersions[$collectionId] = (int)$version;
7078+
$this->collectionVersions[$collectionId] = $version;
70787079
}
70797080

70807081
return $this->collectionVersions[$collectionId];
@@ -7088,7 +7089,8 @@ private function getCollectionVersion(string $collectionId): int
70887089
*/
70897090
private function incrementCollectionVersion(string $collectionId): void
70907091
{
7091-
$newVersion = \time();
7092+
// Generate new version with microtime + random component for uniqueness
7093+
$newVersion = \sprintf('%.6f-%s', \microtime(true), \bin2hex(\random_bytes(4)));
70927094
$this->collectionVersions[$collectionId] = $newVersion;
70937095

70947096
$versionKey = $this->getCollectionVersionKey($collectionId);

0 commit comments

Comments
 (0)