Skip to content

Commit aa69ea4

Browse files
committed
Fix race condition in metadata changes API
1 parent b5a3cc0 commit aa69ea4

File tree

2 files changed

+19
-0
lines changed

2 files changed

+19
-0
lines changed

src/Controller/PackageController.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ public function metadataChangesAction(Request $req, RedisClient $redis): JsonRes
177177
{
178178
$topDump = $redis->zrevrange('metadata-dumps', 0, 0, ['WITHSCORES' => true]) ?: ['foo' => 0];
179179
$topDelete = $redis->zrevrange('metadata-deletes', 0, 0, ['WITHSCORES' => true]) ?: ['foo' => 0];
180+
// to force a resync of all clients, set metadata-oldest manually to time()*10000
180181
$oldestSyncPoint = (int) $redis->get('metadata-oldest') ?: 15850612240000;
181182
$now = max((int) current($topDump), (int) current($topDelete)) + 1;
182183

src/Package/V2Dumper.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,24 @@ private function writeV2File(Package $package, string $name, string $path, strin
386386

387387
assert(isset($filemtime));
388388

389+
// we need to make sure dumps happen always with incrementing times to avoid race conditions when
390+
// fetching metadata changes in the currently elapsing second (new items dumped after the fetch can then
391+
// be skipped as they appear to have been dumped before the "since" param)
392+
// so this ensures a sequence even when we cannot rely on sub-second timing info in the filemtime
393+
if (str_ends_with((string) $filemtime, '0000')) {
394+
$counterKey = 'metadata:'.substr((string) $filemtime, 0, -4);
395+
$counter = $this->redis->incrby($counterKey, 10);
396+
if ($counter === 10) {
397+
$this->redis->expire($counterKey, 10);
398+
}
399+
// safe-guard to avoid going beyond the current second in the very unlikely
400+
// case we'd dump more than 1000 packages in one second
401+
if ($counter > 9950) {
402+
sleep(1);
403+
}
404+
$filemtime += $counter;
405+
}
406+
389407
$timeUnix = intval(ceil($filemtime/10000));
390408
$this->writeFileAtomic($path, $contents, $timeUnix);
391409

0 commit comments

Comments
 (0)