gerrit/gerrit-reviewdb
Edwin Kempin 5be9c31001 Move account sequence to NoteDb
Accounts have been migrated to NoteDb, hence also the account sequence
should be moved to NoteDb. In NoteDb the current account sequence number
is stored as UTF-8 text in a blob pointed to by the
'refs/sequences/accounts' ref in the 'All-Users' repository. Multiple
processes share the same sequence by incrementing the counter using
normal git ref updates. To amortize the cost of these ref updates,
processes can increment the counter by a larger number and hand out
numbers from that range in memory until they run out. The size of the
account ID batch that each process retrieves at once is controlled by
the 'notedb.accounts.sequenceBatchSize' configuration parameter in
'gerrit.config'. By default the value is 1 since it's unlikely that a
process ever creates more than one account.

This follows the example of storing the change sequence in NoteDb. A
difference is that the account sequence is stored in the 'All-Users'
repository while the change sequence is stored in the 'All-Projects'
repository. Storing the account sequence in the 'All-Users' repository
makes more sense since this repository already contains all of the other
account data.

Injecting the Sequences class that provides new sequences numbers
requires request scope. There are 2 places outsite of request scope
where new account sequence numbers are required, AccountManager and
AccountCreator (only used for tests). These classes need to create a
request context to get an account sequence number. For AccountManager
the request scope is only created when a new account is created and not
when an existing account is authenticated.

Since there is an init step that creates an initial admin user we must
make the account sequence available during the init phase. For this the
class SequencesOnInit is added which can only generate account IDs, but
only depends on classes that are available during the init phase. For
this class the account ID batch size is hard-coded to 1, since init only
creates a single account and we don't want to waste account IDs when a
new Gerrit server is initialized.

This change also contains a schema migration that ensures that the
account sequence is created in NoteDb.

To support a live migration on a multi-master Gerrit installation, there
is a configuration parameter ('notedb.accounts.readSequenceFromNoteDb')
that controls whether account sequence numbers are read from NoteDb or
ReviewDb. By default the value for this parameter is `false` so account
sequence numbers are read from ReviewDb.

If account sequence numbers are read from ReviewDb the sequence numbers
in NoteDb will be kept in sync. This is achieved by writing the next
available sequence number to NoteDb whenever a sequence number from
ReviewDb is retrieved. If writing to NoteDb fails, an exception is
raised to the caller and the sequence number that was retrieved from
ReviewDb is not used. Writing to NoteDb is retried several times so that
the caller only gets an exception if writing to NoteDb fails
permanently.

For the case where two threads try to update the sequence number in
NoteDb concurrently we must make sure that the value in NoteDb is never
decreased. E.g.:

1. Thread 1 retrieves account ID 14 from ReviewDb
2. Thread 2 retrieves account ID 15 from ReviewDb
3. Thread 2 writes the next available account ID 16 to NoteDb
4. Thread 1 tries to write the next available account ID 15 to NoteDb
   but fails since Thread 2 updated the value concurrently.
5. Thread 1 finds that it doesn't need to update the account ID in
   NoteDb anymore since Thread 2 already updated the account ID to a
   higher value

This means at any point in time it is safe to switch to reading account
IDs from NoteDb. However once this switch is done it is not possible to
switch back to reading account IDs from ReviewDb, since ReviewDb will be
out of sync as soon as the first account ID was retrieved from NoteDb.

The migration on a multi-master Gerrit installation will be done with
the following steps:
1. rollout this change to all nodes:
   - account sequence numbers are read from ReviewDb
   - the sequence numbers in NoteDb are kept in sync
2. wait some time until we are sure that we don't need to roll back to a
   release that doesn't contain this change
3. run an offline migration to ensure that the account sequence number
   in NoteDb is initialized on all nodes
4. set 'notedb.accounts.readSequenceFromNoteDb' to true so that account
   sequence numbers are now read from NoteDb (this setting cannot be
   reverted since the account sequence in ReviewDb will be outdated once
   account IDs are retrieved from NoteDb)

After this is done a follow-up change can remove the handling for
'notedb.accounts.readSequenceFromNoteDb' so that account IDs are now
always retrieved from NoteDb.

Change-Id: I023d2de643ed0c15197c09fa19105cc2acb5091e
Signed-off-by: Edwin Kempin <ekempin@google.com>
2017-07-14 08:50:35 +02:00
..
src Move account sequence to NoteDb 2017-07-14 08:50:35 +02:00
BUILD Bazel: Reformat build files 2016-12-07 11:33:07 +00:00