feat: track cache changes with sequence numbers and tombstones

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-10-07 21:21:14 -04:00
parent c20dde6633
commit eea9b5630a
10 changed files with 511 additions and 46 deletions
+32 -1
View File
@@ -10,6 +10,8 @@ declare(strict_types=1);
namespace KTXM\ProviderImap\Stores;
use KTXC\Db\DataStore;
use MongoDB\Operation\FindOneAndUpdate;
use RuntimeException;
use KTXM\ProviderImap\Providers\CollectionResource;
/**
@@ -29,6 +31,7 @@ class MailboxStore
'uidNext' => null,
'highestModSeq' => null,
'changeSeq' => 0,
'purgedSeq' => 0,
'harmonizedAt' => null,
'harmonizationComplete' => false,
];
@@ -112,7 +115,7 @@ class MailboxStore
/**
* Harmonization state of a mailbox; defaults when the mailbox is not cached.
*
* @return array{uidValidity: ?int, uidNext: ?int, highestModSeq: ?int, changeSeq: int, harmonizedAt: ?int, harmonizationComplete: bool}
* @return array{uidValidity: ?int, uidNext: ?int, highestModSeq: ?int, changeSeq: int, purgedSeq: int, harmonizedAt: ?int, harmonizationComplete: bool}
*/
public function state(string $serviceId, string $name): array
{
@@ -137,6 +140,34 @@ class MailboxStore
);
}
/**
* Reserve a range of change sequence numbers for a mailbox.
*
* Atomically advances the mailbox's changeSeq by $count and returns the first
* number of the reserved range (range = first .. first + count - 1).
*
* @throws RuntimeException when the mailbox is not cached
*/
public function reserveSequence(string $serviceId, string $name, int $count = 1): int
{
$count = max(1, $count);
$document = $this->dataStore->selectCollection(self::COLLECTION_NAME)->getMongoCollection()->findOneAndUpdate(
['sid' => $serviceId, 'name' => $name],
['$inc' => ['changeSeq' => $count]],
[
'projection' => ['changeSeq' => 1],
'returnDocument' => FindOneAndUpdate::RETURN_DOCUMENT_AFTER,
],
);
if ($document === null) {
throw new RuntimeException("Mailbox is not cached: {$name}");
}
return (int) ((array) $document)['changeSeq'] - $count + 1;
}
/**
* Take the harmonization lock of a mailbox when it is free or expired.
*