From ad2e6b3f2094d2419a00bd3beb5258e26e57624d Mon Sep 17 00:00:00 2001 From: Dave Borowitz Date: Fri, 27 Jan 2017 12:40:04 -0500 Subject: [PATCH] AllProjectsCreator: Seed refs/sequences/changes if applicable This isn't called in normal initialization of an empty site, since the admin won't have had a chance to set the necessary config option. However, it is still useful so tests can avoid calling the db.nextChangeId() method. Change-Id: Ic298845571faa0024b0d6e295f961d4d5aae08f0 --- .../com/google/gerrit/server/Sequences.java | 4 +- .../gerrit/server/notedb/RepoSequence.java | 19 +++++++- .../server/schema/AllProjectsCreator.java | 43 ++++++++++++++++++- .../server/schema/SchemaUpdaterTest.java | 2 + 4 files changed, 64 insertions(+), 4 deletions(-) diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/Sequences.java b/gerrit-server/src/main/java/com/google/gerrit/server/Sequences.java index 6b3a58f6c3..4ab42f30f7 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/Sequences.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/Sequences.java @@ -35,6 +35,8 @@ import org.eclipse.jgit.lib.Config; @SuppressWarnings("deprecation") @Singleton public class Sequences { + public static final String CHANGES = "changes"; + private final Provider db; private final NotesMigration migration; private final RepoSequence changeSeq; @@ -54,7 +56,7 @@ public class Sequences { new RepoSequence( repoManager, allProjects, - "changes", + CHANGES, new RepoSequence.Seed() { @Override public int get() throws OrmException { diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RepoSequence.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RepoSequence.java index 0101cd7d0d..0b097d3e47 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RepoSequence.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RepoSequence.java @@ -16,6 +16,8 @@ package com.google.gerrit.server.notedb; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.gerrit.reviewdb.client.RefNames.REFS; +import static com.google.gerrit.reviewdb.client.RefNames.REFS_SEQUENCES; import static java.nio.charset.StandardCharsets.UTF_8; import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; @@ -52,6 +54,7 @@ import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.transport.ReceiveCommand; /** * Class for managing an incrementing sequence backed by a git repository. @@ -117,7 +120,15 @@ public class RepoSequence { Retryer retryer) { this.repoManager = checkNotNull(repoManager, "repoManager"); this.projectName = checkNotNull(projectName, "projectName"); - this.refName = RefNames.REFS_SEQUENCES + checkNotNull(name, "name"); + + checkArgument( + name != null + && !name.startsWith(REFS) + && !name.startsWith(REFS_SEQUENCES.substring(REFS.length())), + "name should be a suffix to follow \"refs/sequences/\", got: %s", + name); + this.refName = RefNames.REFS_SEQUENCES + name; + this.seed = checkNotNull(seed, "seed"); checkArgument(batchSize > 0, "expected batchSize > 0, got: %s", batchSize); @@ -265,4 +276,10 @@ public class RepoSequence { ru.setForceUpdate(true); // Required for non-commitish updates. return ru.update(rw); } + + public static ReceiveCommand storeNew(ObjectInserter ins, String name, int val) + throws IOException { + ObjectId newId = ins.insert(OBJ_BLOB, Integer.toString(val).getBytes(UTF_8)); + return new ReceiveCommand(ObjectId.zeroId(), newId, RefNames.REFS_SEQUENCES + name); + } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/AllProjectsCreator.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/AllProjectsCreator.java index 3f1d32c297..9157b5214d 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/AllProjectsCreator.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/AllProjectsCreator.java @@ -14,6 +14,7 @@ package com.google.gerrit.server.schema; +import static com.google.gerrit.reviewdb.client.RefNames.REFS_SEQUENCES; import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS; import static com.google.gerrit.server.group.SystemGroupBackend.PROJECT_OWNERS; import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS; @@ -35,27 +36,37 @@ import com.google.gerrit.common.data.PermissionRule.Action; import com.google.gerrit.extensions.client.InheritableBoolean; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.RefNames; +import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.GerritPersonIdent; +import com.google.gerrit.server.Sequences; import com.google.gerrit.server.config.AllProjectsName; import com.google.gerrit.server.extensions.events.GitReferenceUpdated; import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.MetaDataUpdate; import com.google.gerrit.server.git.ProjectConfig; import com.google.gerrit.server.group.SystemGroupBackend; +import com.google.gerrit.server.notedb.NotesMigration; +import com.google.gerrit.server.notedb.RepoSequence; import com.google.inject.Inject; import java.io.IOException; import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.errors.RepositoryNotFoundException; +import org.eclipse.jgit.lib.BatchRefUpdate; import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.lib.ObjectInserter; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.transport.ReceiveCommand; /** Creates the {@code All-Projects} repository and initial ACLs. */ public class AllProjectsCreator { private final GitRepositoryManager mgr; private final AllProjectsName allProjectsName; private final PersonIdent serverUser; + private final NotesMigration notesMigration; private String message; private GroupReference admin; @@ -69,10 +80,12 @@ public class AllProjectsCreator { GitRepositoryManager mgr, AllProjectsName allProjectsName, SystemGroupBackend systemGroupBackend, - @GerritPersonIdent PersonIdent serverUser) { + @GerritPersonIdent PersonIdent serverUser, + NotesMigration notesMigration) { this.mgr = mgr; this.allProjectsName = allProjectsName; this.serverUser = serverUser; + this.notesMigration = notesMigration; this.anonymous = systemGroupBackend.getGroup(ANONYMOUS_USERS); this.registered = systemGroupBackend.getGroup(REGISTERED_USERS); @@ -112,8 +125,9 @@ public class AllProjectsCreator { } private void initAllProjects(Repository git) throws IOException, ConfigInvalidException { + BatchRefUpdate bru = git.getRefDatabase().newBatchUpdate(); try (MetaDataUpdate md = - new MetaDataUpdate(GitReferenceUpdated.DISABLED, allProjectsName, git)) { + new MetaDataUpdate(GitReferenceUpdated.DISABLED, allProjectsName, git, bru)) { md.getCommitBuilder().setAuthor(serverUser); md.getCommitBuilder().setCommitter(serverUser); md.setMessage( @@ -177,6 +191,8 @@ public class AllProjectsCreator { grant(config, meta, Permission.SUBMIT, admin, owners); config.commitToNewRef(md, RefNames.REFS_CONFIG); + initSequences(git, bru); + execute(git, bru); } } @@ -195,4 +211,27 @@ public class AllProjectsCreator { c.getLabelSections().put(type.getName(), type); return type; } + + private void initSequences(Repository git, BatchRefUpdate bru) throws IOException { + if (notesMigration.readChangeSequence() + && git.exactRef(REFS_SEQUENCES + Sequences.CHANGES) == null) { + // Can't easily reuse the inserter from MetaDataUpdate, but this shouldn't slow down site + // initialization unduly. + try (ObjectInserter ins = git.newObjectInserter()) { + bru.addCommand(RepoSequence.storeNew(ins, Sequences.CHANGES, ReviewDb.FIRST_CHANGE_ID)); + ins.flush(); + } + } + } + + private void execute(Repository git, BatchRefUpdate bru) throws IOException { + try (RevWalk rw = new RevWalk(git)) { + bru.execute(rw, NullProgressMonitor.INSTANCE); + } + for (ReceiveCommand cmd : bru.getCommands()) { + if (cmd.getResult() != ReceiveCommand.Result.OK) { + throw new IOException("Failed to initialize " + allProjectsName + " refs:\n" + bru); + } + } + } } diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java index 112fdd60aa..9a32365fba 100644 --- a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java +++ b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java @@ -30,6 +30,7 @@ import com.google.gerrit.server.config.GerritServerConfig; import com.google.gerrit.server.config.SitePaths; import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.group.SystemGroupBackend; +import com.google.gerrit.server.notedb.ConfigNotesMigration; import com.google.gerrit.testutil.InMemoryDatabase; import com.google.gerrit.testutil.InMemoryH2Type; import com.google.gerrit.testutil.InMemoryRepositoryManager; @@ -108,6 +109,7 @@ public class SchemaUpdaterTest { bind(DataSourceType.class).to(InMemoryH2Type.class); bind(SystemGroupBackend.class); + install(new ConfigNotesMigration.Module()); } }) .getInstance(SchemaUpdater.class);