Add ssh command to set new sequence value

Change-Id: I9e7f1d79939a52f44e72a6823fe9ca4c8a5064c6
This commit is contained in:
David Ostrovsky
2019-11-10 11:59:16 -08:00
parent 4f8df3399b
commit 87ad3858e9
7 changed files with 152 additions and 1 deletions

View File

@@ -0,0 +1,54 @@
= gerrit sequence set
== NAME
gerrit sequence set - Set new sequence value.
== SYNOPSIS
[verse]
--
_ssh_ -p <port> <host> _gerrit sequence set_ <NAME> <VALUE>
--
== 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
<NAME>::
Sequence name to set a new value for.
Currently supported values:
* accounts
* groups
* changes
<VALUE>::
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
---------

View File

@@ -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.

View File

@@ -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<IntBlob> 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);

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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<String, List<String>> SLAVE_COMMANDS =