fix(snowflake): fix wrong documentation about serverId

Maximum value of a server ID is 511 (9 bits) and not 1023.
Also adjust SetupCheck

Signed-off-by: Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
This commit is contained in:
Benjamin Gaussorgues 2026-05-12 09:49:35 +02:00
parent ac15544703
commit 9e36754429
No known key found for this signature in database
6 changed files with 18 additions and 20 deletions

View file

@ -40,14 +40,16 @@ final class ServerIdConfig implements ISetupCheck {
if ($serverid === PHP_INT_MIN) {
return SetupResult::info(
$this->l10n->t('Server identifier isnt configured. It is recommended if your Nextcloud instance is running on several PHP servers. Add a server ID in your configuration.'),
$this->l10n->t(
'Server identifier isnt configured. It is recommended if your Nextcloud instance is running on several PHP servers. Add a server ID in your configuration.',
),
$linkToDoc,
);
}
if ($serverid < 0 || $serverid > 1023) {
if ($serverid < 0 || $serverid > 511) {
return SetupResult::error(
$this->l10n->t('"%d" is not a valid server identifier. It must be between 0 and 1023.', [$serverid]),
$this->l10n->t('"%d" is not a valid server identifier. It must be between 0 and 511.', [$serverid]),
$linkToDoc,
);
}

View file

@ -50,7 +50,7 @@ $CONFIG = [
* It is useful when your Nextcloud instance is using different PHP servers.
* Once it's set it shouldn't be changed.
*
* Value must be an integer, comprised between 0 and 1023.
* Value must be an integer, comprised between 0 and 511.
*
* When config.php is shared between different servers, this value should be overriden with "NC_serverid=<int>" on each server.
* Note that it must be overriden for CLI and for your webserver.

View file

@ -28,7 +28,7 @@ final class SnowflakeDecoder implements ISnowflakeDecoder {
throw new \Exception('Invalid Snowflake ID: ' . $snowflakeId);
}
/** @var array{seconds: positive-int, milliseconds: int<0,999>, serverId: int<0, 1023>, sequenceId: int<0,4095>, isCli: bool} $data */
/** @var array{seconds: positive-int, milliseconds: int<0,999>, serverId: int<0, 511>, sequenceId: int<0,4095>, isCli: bool} $data */
$data = PHP_INT_SIZE === 8
? $this->decode64bits((int)$snowflakeId)
: $this->decode32bits($snowflakeId);

View file

@ -16,17 +16,16 @@ use OCP\AppFramework\Attribute\Consumable;
*
* Customized version of Snowflake IDs for Nextcloud:
* 1 bit : Unused, always 0, avoid issue with PHP signed integers.
* 31 bits: Timestamp from 2025-10-01. Allows to store a bit more than 68 years. Allows to find creation time.
* 10 bits: Milliseconds (between 0 and 999)
* 9 bits: Server ID, identify server which generated the ID (between 0 and 1023)
* 1 bit : CLI or Web (0 or 1)
* 12 bits: Sequence ID, usually a serial number of objects created in the same number on same server (between 0 and 4095)
* 31 bits: Timestamp from 2025-10-01. Allows to store a bit more than 68 years. Allows to find creation time.
* 10 bits: Milliseconds (between 0 and 999)
* 9 bits: Server ID, identify server which generated the ID (between 0 and 511)
* 1 bit : CLI or Web (0 or 1)
* 12 bits: Sequence ID, usually a serial number of objects created in the same number on same server (between 0 and 4095)
*
* @since 33.0.0
*/
#[Consumable(since: '33.0.0')]
interface ISnowflakeGenerator {
/**
* Offset applied on timestamps to keep it short
* Start from 2025-10-01 at 00:00:00

View file

@ -19,7 +19,7 @@ use OCP\AppFramework\Attribute\Consumable;
#[Consumable(since: '33.0.0')]
final readonly class Snowflake {
/**
* @psalm-param int<0,1023> $serverId
* @psalm-param int<0,511> $serverId
* @psalm-param int<0,4095> $sequenceId
* @psalm-param non-negative-int $seconds
* @psalm-param int<0,999> $milliseconds
@ -36,7 +36,7 @@ final readonly class Snowflake {
}
/**
* @psalm-return int<0,1023>
* @psalm-return int<0,511>
* @since 33.0.0
*/
public function getServerId(): int {

View file

@ -29,18 +29,15 @@ class GeneratorTest extends TestCase {
private ISequence&MockObject $sequence;
#[\Override]
public function setUp():void {
public function setUp(): void {
$this->decoder = new SnowflakeDecoder();
$this->config = $this->createMock(IConfig::class);
$this->config->method('getSystemValueInt')
->with('serverid')
->willReturn(42);
$this->config->method('getSystemValueInt')->with('serverid')->willReturn(42);
$this->sequence = $this->createMock(ISequence::class);
$this->sequence->method('isAvailable')->willReturn(true);
$this->sequence->method('nextId')->willReturn(421);
}
public function testGenerator(): void {
@ -54,7 +51,7 @@ class GeneratorTest extends TestCase {
// Check serverId
$this->assertGreaterThanOrEqual(0, $data->getServerId());
$this->assertLessThanOrEqual(1023, $data->getServerId());
$this->assertLessThanOrEqual(511, $data->getServerId());
// Check sequenceId
$this->assertGreaterThanOrEqual(0, $data->getSequenceId());
@ -76,7 +73,7 @@ class GeneratorTest extends TestCase {
$generator = new SnowflakeGenerator($timeFactory, $this->config, $this->sequence);
$data = $this->decoder->decode($generator->nextId());
$this->assertEquals($expectedSeconds, ($data->getCreatedAt()->format('U') - ISnowflakeGenerator::TS_OFFSET));
$this->assertEquals($expectedSeconds, $data->getCreatedAt()->format('U') - ISnowflakeGenerator::TS_OFFSET);
$this->assertEquals($expectedMilliseconds, (int)$data->getCreatedAt()->format('v'));
$this->assertEquals(42, $data->getServerId());
}