diff --git a/Documentation/cmd-sequence-set.txt b/Documentation/cmd-sequence-set.txt new file mode 100644 index 0000000000..9023ceb173 --- /dev/null +++ b/Documentation/cmd-sequence-set.txt @@ -0,0 +1,54 @@ += gerrit sequence set + +== NAME +gerrit sequence set - Set new sequence value. + +== SYNOPSIS +[verse] +-- +_ssh_ -p _gerrit sequence set_ +-- + +== DESCRIPTION +Gerrit maintains the generation of the next available sequence numbers for +account, group and change entities. The sequences are stored as UTF-8 text in +a blob pointed to by the `refs/sequences/accounts`, `refs/sequences/groups` +and `refs/sequences/changes` refs. Those refs are stored in `All-Users` and +`All-Projects` git repositories correspondingly. + +This command allows to set a new sequence value for those sequences. + +The link:cmd-sequence-show.html[sequence-show] command displays current +sequence value. + +== ACCESS +Caller must be a member of the privileged 'Administrators' group. + +== SCRIPTING +This command is intended to be used in scripts. + +== OPTIONS +:: + Sequence name to set a new value for. + Currently supported values: + * accounts + * groups + * changes + +:: + New value for the sequence. + +== EXAMPLES +Set a new value for the 'changes' sequence: + +---- +$ ssh -p 29418 review.example.com gerrit sequence set changes 42 +The value for the changes sequence was set to 42. +---- + +GERRIT +------ +Part of link:index.html[Gerrit Code Review] + +SEARCHBOX +--------- diff --git a/Documentation/cmd-sequence-show.txt b/Documentation/cmd-sequence-show.txt index a3ec02e4aa..6b9371f670 100644 --- a/Documentation/cmd-sequence-show.txt +++ b/Documentation/cmd-sequence-show.txt @@ -18,6 +18,9 @@ and `refs/sequences/changes` refs. Those refs are stored in `All-Users` and This command allows to display the current sequence value for those sequences. +The link:cmd-sequence-set.html[sequence-set] command allows to set a new +sequence value. + == ACCESS Caller must be a member of the privileged 'Administrators' group. diff --git a/java/com/google/gerrit/server/notedb/RepoSequence.java b/java/com/google/gerrit/server/notedb/RepoSequence.java index 27aefb998d..11ba8cd2a1 100644 --- a/java/com/google/gerrit/server/notedb/RepoSequence.java +++ b/java/com/google/gerrit/server/notedb/RepoSequence.java @@ -292,6 +292,31 @@ public class RepoSequence { return new ReceiveCommand(ObjectId.zeroId(), newId, RefNames.REFS_SEQUENCES + name); } + public void storeNew(int value) { + counterLock.lock(); + try (Repository repo = repoManager.openRepository(projectName); + RevWalk rw = new RevWalk(repo)) { + Optional blob = IntBlob.parse(repo, refName, rw); + afterReadRef.run(); + ObjectId oldId; + if (!blob.isPresent()) { + oldId = ObjectId.zeroId(); + } else { + oldId = blob.get().id(); + } + RefUpdate refUpdate = + IntBlob.tryStore(repo, rw, projectName, refName, oldId, value, gitRefUpdated); + RefUpdateUtil.checkResult(refUpdate); + counter = value; + limit = counter + batchSize; + acquireCount++; + } catch (IOException e) { + throw new StorageException(e); + } finally { + counterLock.unlock(); + } + } + public int current() { counterLock.lock(); try (Repository repo = repoManager.openRepository(projectName); diff --git a/java/com/google/gerrit/server/notedb/Sequences.java b/java/com/google/gerrit/server/notedb/Sequences.java index b89064d0b7..be68592f00 100644 --- a/java/com/google/gerrit/server/notedb/Sequences.java +++ b/java/com/google/gerrit/server/notedb/Sequences.java @@ -140,4 +140,16 @@ public class Sequences { public int currentGroupId() { return groupSeq.current(); } + + public void setChangeIdValue(int value) { + changeSeq.storeNew(value); + } + + public void setAccountIdValue(int value) { + accountSeq.storeNew(value); + } + + public void setGroupIdValue(int value) { + groupSeq.storeNew(value); + } } diff --git a/java/com/google/gerrit/sshd/commands/SequenceCommandsModule.java b/java/com/google/gerrit/sshd/commands/SequenceCommandsModule.java index 7f78f4aa5f..e71624042b 100644 --- a/java/com/google/gerrit/sshd/commands/SequenceCommandsModule.java +++ b/java/com/google/gerrit/sshd/commands/SequenceCommandsModule.java @@ -26,6 +26,7 @@ public class SequenceCommandsModule extends CommandModule { CommandName gerrit = Commands.named("gerrit"); CommandName sequence = Commands.named(gerrit, "sequence"); command(sequence).toProvider(new DispatchCommandProvider(sequence)); + command(sequence, SequenceSetCommand.class); command(sequence, SequenceShowCommand.class); } } diff --git a/java/com/google/gerrit/sshd/commands/SequenceSetCommand.java b/java/com/google/gerrit/sshd/commands/SequenceSetCommand.java new file mode 100644 index 0000000000..197d61c0a3 --- /dev/null +++ b/java/com/google/gerrit/sshd/commands/SequenceSetCommand.java @@ -0,0 +1,56 @@ +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.sshd.commands; + +import com.google.gerrit.common.data.GlobalCapability; +import com.google.gerrit.extensions.annotations.RequiresCapability; +import com.google.gerrit.server.notedb.Sequences; +import com.google.gerrit.sshd.CommandMetaData; +import com.google.gerrit.sshd.SshCommand; +import com.google.inject.Inject; +import org.kohsuke.args4j.Argument; + +/** Set sequence value. */ +@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER) +@CommandMetaData(name = "set", description = "Set the sequence value") +final class SequenceSetCommand extends SshCommand { + @Argument(index = 0, metaVar = "NAME", required = true, usage = "sequence name") + private String name; + + @Argument(index = 1, metaVar = "VALUE", required = true, usage = "sequence value") + private int value; + + @Inject Sequences sequences; + + @Override + public void run() throws Exception { + switch (name) { + case "changes": + sequences.setChangeIdValue(value); + break; + case "accounts": + sequences.setAccountIdValue(value); + break; + case "groups": + sequences.setGroupIdValue(value); + break; + default: + throw die("Unknown sequence name: " + name); + } + stdout.print("The value for the " + name + " sequence was set to " + value + "."); + stdout.print('\n'); + stdout.flush(); + } +} diff --git a/javatests/com/google/gerrit/acceptance/ssh/SshCommandsIT.java b/javatests/com/google/gerrit/acceptance/ssh/SshCommandsIT.java index f43b5bf2e3..9b8b19c2c9 100644 --- a/javatests/com/google/gerrit/acceptance/ssh/SshCommandsIT.java +++ b/javatests/com/google/gerrit/acceptance/ssh/SshCommandsIT.java @@ -97,7 +97,7 @@ public class SshCommandsIT extends AbstractDaemonTest { "gerrit plugin", ImmutableList.of("add", "enable", "install", "ls", "reload", "remove", "rm")) .put("gerrit test-submit", ImmutableList.of("rule", "type")) - .put("gerrit sequence", ImmutableList.of("show")) + .put("gerrit sequence", ImmutableList.of("set", "show")) .build(); private static final ImmutableMap> SLAVE_COMMANDS =