|
13 | 13 | use OCP\ITempManager; |
14 | 14 | use Override; |
15 | 15 |
|
| 16 | +/** |
| 17 | + * Sequence IDs shared between processes through lock files in the temporary directory. |
| 18 | + * |
| 19 | + * Each lock file is a table of counters. To get a sequence ID, the file chosen by the |
| 20 | + * millisecond (ms % NB_FILES) is locked and the slot of that second and millisecond is |
| 21 | + * read: ((seconds % SEQUENCE_TTL) * (1000 / NB_FILES) + ms / NB_FILES). A slot holds the |
| 22 | + * seconds it was last used for and the last sequence ID handed out. If the seconds match, |
| 23 | + * the next sequence ID is that one plus one, otherwise it starts at 0. The result is |
| 24 | + * written back and the file unlocked. |
| 25 | + * |
| 26 | + * A slot is reused SEQUENCE_TTL seconds later, the seconds mismatch then resets its counter. |
| 27 | + * No fsync is needed, as the files only coordinate processes running at the same time. |
| 28 | + */ |
16 | 29 | class FileSequence implements ISequence { |
17 | 30 | /** Number of files to use */ |
18 | 31 | private const NB_FILES = 20; |
@@ -72,22 +85,20 @@ public function nextId(int $serverId, int $seconds, int $milliseconds): int { |
72 | 85 | } |
73 | 86 |
|
74 | 87 | // Each file holds one slot per second of the TTL window and per millisecond mapped to it |
75 | | - $slot = (($seconds % self::SEQUENCE_TTL + self::SEQUENCE_TTL) % self::SEQUENCE_TTL) * intdiv(1000, self::NB_FILES) |
76 | | - + intdiv($milliseconds, self::NB_FILES); |
77 | | - $slotSecondsKey = $seconds & 0xFFFFFFFF; |
| 88 | + $slot = ($seconds % self::SEQUENCE_TTL) * intdiv(1000, self::NB_FILES) + intdiv($milliseconds, self::NB_FILES); |
78 | 89 | fseek($fp, $slot * self::SLOT_SIZE); |
79 | 90 | $data = fread($fp, self::SLOT_SIZE); |
80 | 91 | $sequenceId = 0; |
81 | 92 | if (is_string($data) && strlen($data) === self::SLOT_SIZE) { |
82 | 93 | ['seconds' => $slotSeconds, 'sequence' => $slotSequenceId] = unpack('Nseconds/Nsequence', $data); |
83 | | - if ($slotSeconds === $slotSecondsKey) { |
| 94 | + if ($slotSeconds === $seconds) { |
84 | 95 | $sequenceId = $slotSequenceId + 1; |
85 | 96 | } |
86 | 97 | } |
87 | 98 |
|
88 | 99 | // No fsync needed, the file only coordinates processes running at the same time |
89 | 100 | fseek($fp, $slot * self::SLOT_SIZE); |
90 | | - fwrite($fp, pack('NN', $slotSecondsKey, $sequenceId)); |
| 101 | + fwrite($fp, pack('NN', $seconds, $sequenceId)); |
91 | 102 |
|
92 | 103 | // Release lock |
93 | 104 | fclose($fp); |
|
0 commit comments