Snowflake IDs

Added in version 33.

Nextcloud integrates a customized version of Snowflake IDs (https://en.wikipedia.org/wiki/Snowflake_ID).

It allows to generates unique IDs in advance and also contains information about creation:
  • creation time at millisecond precision

  • identifier of server which created the ID. It’s usually a hash of server hostname or random if not hostname found.

  • whether the ID was created from CLI or not

Store a Snowflake ID in database

Snowflake IDs are designed to be used as primary key in database. They should be stored as UNSIGNED BIGINT (64 bits integer, always positive)

In Nextcloud migrations it looks like:

public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
    /** @var ISchemaWrapper $schema */
    $schema = $schemaClosure();

    if (!$schema->hasTable('my_table')) {
        $table = $schema->createTable('my_table');
        $table->addColumn(
            'id',
            Types::BIGINT,
            ['notnull' => true, 'unsigned' => true]
        );
        $table->setPrimaryKey(['id']);

        // TODO Add other fields
    }

Generate a Snowflake ID

To generate a new ID, call nextId function on the generator:

<?php
declare(strict_types=1);

namespace OCA\MyApp;

use OCP\Snowflake\IGenerator;

class MyObjectFactory {
    public function __construct(
            private readonly IGenerator $generator,
    ) {
      // TODO Add your implementation
    }

    public function create(): MyObject {
        /** @var string $id */
        $id = $this->generator->nextId();

        // TODO Create other properties and insert into database
    }
}

Decode a Snowflake ID

Use the occ snowflake:decode command to inspect a Snowflake ID from the command line:

sudo -E -u www-data php occ snowflake:decode 6768789079123765868
+--------------------+-------------------------+
| Snowflake ID       | 6768789079123765868     |
| Seconds            | 1575981518              |
| Milliseconds       | 50                      |
| Created from CLI   | no                      |
| Server ID          | 441                     |
| Sequence ID        | 12                      |
| Creation timestamp | 1575981518.050          |
| Creation date      | 2019-12-10 13:38:38.050 |
+--------------------+-------------------------+

It’s also possible to decode IDs in your code, for example to get the creation time of your object:

<?php
declare(strict_types=1);

namespace OCA\MyApp;

use DateTimeImmutable;
use OCP\Snowflake\IDecoder;

class MyObject {
    private string $id;

    public function __construct(
            private readonly IDecoder $decoder,
    ) {
      // TODO Add your implementation
    }

    public function createdAt(): DateTimeImmutable {
        return $this->decoder->decode($this->id)['createdAt'];
    }
}