Merge changes from topic 'local-disk-tests'
* changes: GerritServer: Support forcing local disk for all tests Rework NotesMigration hierarchy and get rid of test impl ConfigNotesMigration: Remove rambling comment about sequences NoteDbMode: Remove barely-used readWrite() method AbstractDaemonTest: Don't delete common server path too early Daemon: Rename test -> inMemoryTest for clarity SiteProgram: Remove unnecessary finals NoteDbMigrator: Actually close thread-local cached open ReviewDb ChangeIT: Properly unwrap ReviewDb GerritServer: Skip @UseLocalDisk tests with FUSED StandaloneNoteDbMigrationIT: Only run when GERRIT_NOTEDB=off
This commit is contained in:
commit
35e0df1d94
@ -95,6 +95,7 @@ import com.google.gerrit.server.mail.Address;
|
||||
import com.google.gerrit.server.mail.send.EmailHeader;
|
||||
import com.google.gerrit.server.notedb.ChangeNoteUtil;
|
||||
import com.google.gerrit.server.notedb.ChangeNotes;
|
||||
import com.google.gerrit.server.notedb.MutableNotesMigration;
|
||||
import com.google.gerrit.server.project.ChangeControl;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.project.Util;
|
||||
@ -104,9 +105,9 @@ import com.google.gerrit.server.update.BatchUpdate;
|
||||
import com.google.gerrit.testutil.ConfigSuite;
|
||||
import com.google.gerrit.testutil.FakeEmailSender;
|
||||
import com.google.gerrit.testutil.FakeEmailSender.Message;
|
||||
import com.google.gerrit.testutil.NoteDbMode;
|
||||
import com.google.gerrit.testutil.SshMode;
|
||||
import com.google.gerrit.testutil.TempFileUtil;
|
||||
import com.google.gerrit.testutil.TestNotesMigration;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.gwtorm.server.SchemaFactory;
|
||||
@ -156,8 +157,6 @@ import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.rules.RuleChain;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -172,9 +171,8 @@ public abstract class AbstractDaemonTest {
|
||||
|
||||
@Rule public ExpectedException exception = ExpectedException.none();
|
||||
|
||||
protected final TemporaryFolder tempSiteDir = new TemporaryFolder();
|
||||
|
||||
private final TestRule testRunner =
|
||||
@Rule
|
||||
public TestRule testRunner =
|
||||
new TestRule() {
|
||||
@Override
|
||||
public Statement apply(Statement base, Description description) {
|
||||
@ -192,8 +190,6 @@ public abstract class AbstractDaemonTest {
|
||||
}
|
||||
};
|
||||
|
||||
@Rule public RuleChain ruleChain = RuleChain.outerRule(tempSiteDir).around(testRunner);
|
||||
|
||||
@Inject @CanonicalWebUrl protected Provider<String> canonicalWebUrl;
|
||||
@Inject @GerritPersonIdent protected Provider<PersonIdent> serverIdent;
|
||||
@Inject @GerritServerConfig protected Config cfg;
|
||||
@ -220,7 +216,7 @@ public abstract class AbstractDaemonTest {
|
||||
@Inject protected PluginConfigFactory pluginConfig;
|
||||
@Inject protected Revisions revisions;
|
||||
@Inject protected SystemGroupBackend systemGroupBackend;
|
||||
@Inject protected TestNotesMigration notesMigration;
|
||||
@Inject protected MutableNotesMigration notesMigration;
|
||||
@Inject protected ChangeNotes.Factory notesFactory;
|
||||
@Inject protected Abandon changeAbandoner;
|
||||
|
||||
@ -315,7 +311,6 @@ public abstract class AbstractDaemonTest {
|
||||
GerritServer.Description methodDesc =
|
||||
GerritServer.Description.forTestMethod(description, configName);
|
||||
|
||||
baseConfig.setString("gerrit", null, "tempSiteDir", tempSiteDir.getRoot().getPath());
|
||||
baseConfig.setInt("receive", null, "changeUpdateThreads", 4);
|
||||
if (classDesc.equals(methodDesc) && !classDesc.sandboxed() && !methodDesc.sandboxed()) {
|
||||
if (commonServer == null) {
|
||||
@ -504,7 +499,7 @@ public abstract class AbstractDaemonTest {
|
||||
server.close();
|
||||
server = null;
|
||||
}
|
||||
notesMigration.resetFromEnv();
|
||||
NoteDbMode.resetFromEnv(notesMigration);
|
||||
}
|
||||
|
||||
protected TestRepository<?>.CommitBuilder commitBuilder() throws Exception {
|
||||
@ -728,12 +723,12 @@ public abstract class AbstractDaemonTest {
|
||||
}
|
||||
|
||||
protected Context disableDb() {
|
||||
notesMigration.setFailOnLoad(true);
|
||||
notesMigration.setFailOnLoadForTest(true);
|
||||
return atrScope.disableDb();
|
||||
}
|
||||
|
||||
protected void enableDb(Context preDisableContext) {
|
||||
notesMigration.setFailOnLoad(false);
|
||||
notesMigration.setFailOnLoadForTest(false);
|
||||
atrScope.set(preDisableContext);
|
||||
}
|
||||
|
||||
|
@ -16,9 +16,11 @@ package com.google.gerrit.acceptance;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.truth.TruthJUnit.assume;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gerrit.common.Nullable;
|
||||
import com.google.gerrit.extensions.config.FactoryModule;
|
||||
@ -36,6 +38,7 @@ import com.google.gerrit.testutil.FakeEmailSender;
|
||||
import com.google.gerrit.testutil.NoteDbChecker;
|
||||
import com.google.gerrit.testutil.NoteDbMode;
|
||||
import com.google.gerrit.testutil.SshMode;
|
||||
import com.google.gerrit.testutil.TempFileUtil;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Key;
|
||||
import com.google.inject.Module;
|
||||
@ -45,9 +48,9 @@ import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.BrokenBarrierException;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
@ -78,7 +81,7 @@ public class GerritServer implements AutoCloseable {
|
||||
return new AutoValue_GerritServer_Description(
|
||||
testDesc,
|
||||
configName,
|
||||
!has(UseLocalDisk.class, testDesc.getTestClass()),
|
||||
!has(UseLocalDisk.class, testDesc.getTestClass()) && !forceLocalDisk(),
|
||||
!has(NoHttpd.class, testDesc.getTestClass()),
|
||||
has(Sandboxed.class, testDesc.getTestClass()),
|
||||
has(UseSsh.class, testDesc.getTestClass()),
|
||||
@ -93,8 +96,9 @@ public class GerritServer implements AutoCloseable {
|
||||
return new AutoValue_GerritServer_Description(
|
||||
testDesc,
|
||||
configName,
|
||||
testDesc.getAnnotation(UseLocalDisk.class) == null
|
||||
&& !has(UseLocalDisk.class, testDesc.getTestClass()),
|
||||
(testDesc.getAnnotation(UseLocalDisk.class) == null
|
||||
&& !has(UseLocalDisk.class, testDesc.getTestClass()))
|
||||
&& !forceLocalDisk(),
|
||||
testDesc.getAnnotation(NoHttpd.class) == null
|
||||
&& !has(NoHttpd.class, testDesc.getTestClass()),
|
||||
testDesc.getAnnotation(Sandboxed.class) != null
|
||||
@ -178,6 +182,21 @@ public class GerritServer implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean forceLocalDisk() {
|
||||
String value = Strings.nullToEmpty(System.getenv("GERRIT_FORCE_LOCAL_DISK"));
|
||||
if (value.isEmpty()) {
|
||||
value = Strings.nullToEmpty(System.getProperty("gerrit.forceLocalDisk"));
|
||||
}
|
||||
switch (value.trim().toLowerCase(Locale.US)) {
|
||||
case "1":
|
||||
case "yes":
|
||||
case "true":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes on-disk site but does not start server.
|
||||
*
|
||||
@ -189,6 +208,10 @@ public class GerritServer implements AutoCloseable {
|
||||
*/
|
||||
public static void init(Description desc, Config baseConfig, Path site) throws Exception {
|
||||
checkArgument(!desc.memory(), "can't initialize site path for in-memory test: %s", desc);
|
||||
assume()
|
||||
.withMessage("FUSED mode not yet supported for on-disk sites")
|
||||
.that(NoteDbMode.get())
|
||||
.isNotEqualTo(NoteDbMode.FUSED);
|
||||
Config cfg = desc.buildConfig(baseConfig);
|
||||
Map<String, Config> pluginConfigs = desc.buildPluginConfigs();
|
||||
Init init = new Init();
|
||||
@ -222,20 +245,29 @@ public class GerritServer implements AutoCloseable {
|
||||
/**
|
||||
* Initializes new Gerrit site and returns started server.
|
||||
*
|
||||
* <p>A new temporary directory for the site will be created with {@link TempFileUtil}, even in
|
||||
* the server is otherwise configured in-memory. Closing the server stops the daemon but does not
|
||||
* delete the temporary directory. Callers may either get the directory with {@link
|
||||
* #getSitePath()} and delete it manually, or call {@link TempFileUtil#cleanup()}.
|
||||
*
|
||||
* @param desc server description.
|
||||
* @param baseConfig default config values; merged with config from {@code desc}. Must contain a
|
||||
* value for {@code gerrit.tempSiteDir} pointing to a temporary directory. This directory is
|
||||
* only actually used for on-disk sites ({@link Description#memory()} returns false), but it
|
||||
* must nonetheless exist for in-memory sites.
|
||||
* @param baseConfig default config values; merged with config from {@code desc}.
|
||||
* @return started server.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static GerritServer initAndStart(Description desc, Config baseConfig) throws Exception {
|
||||
Path site = Paths.get(baseConfig.getString("gerrit", null, "tempSiteDir"));
|
||||
if (!desc.memory()) {
|
||||
init(desc, baseConfig, site);
|
||||
Path site = TempFileUtil.createTempDirectory().toPath();
|
||||
baseConfig = new Config(baseConfig);
|
||||
baseConfig.setString("gerrit", null, "tempSiteDir", site.toString());
|
||||
try {
|
||||
if (!desc.memory()) {
|
||||
init(desc, baseConfig, site);
|
||||
}
|
||||
return start(desc, baseConfig, site, null);
|
||||
} catch (Exception e) {
|
||||
TempFileUtil.recursivelyDelete(site.toFile());
|
||||
throw e;
|
||||
}
|
||||
return start(desc, baseConfig, site, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -245,7 +277,8 @@ public class GerritServer implements AutoCloseable {
|
||||
* @param baseConfig default config values; merged with config from {@code desc}.
|
||||
* @param site existing temporary directory for site. Required, but may be empty, for in-memory
|
||||
* servers. For on-disk servers, assumes that {@link #init} was previously called to
|
||||
* initialize this directory.
|
||||
* initialize this directory. Can be retrieved from the returned instance via {@link
|
||||
* #getSitePath()}.
|
||||
* @param testSysModule optional additional module to add to the system injector.
|
||||
* @param additionalArgs additional command-line arguments for the daemon program; only allowed if
|
||||
* the test is not in-memory.
|
||||
@ -279,13 +312,13 @@ public class GerritServer implements AutoCloseable {
|
||||
|
||||
if (desc.memory()) {
|
||||
checkArgument(additionalArgs.length == 0, "cannot pass args to in-memory server");
|
||||
return startInMemory(desc, baseConfig, daemon);
|
||||
return startInMemory(desc, site, baseConfig, daemon);
|
||||
}
|
||||
return startOnDisk(desc, site, daemon, serverStarted, additionalArgs);
|
||||
}
|
||||
|
||||
private static GerritServer startInMemory(Description desc, Config baseConfig, Daemon daemon)
|
||||
throws Exception {
|
||||
private static GerritServer startInMemory(
|
||||
Description desc, Path site, Config baseConfig, Daemon daemon) throws Exception {
|
||||
Config cfg = desc.buildConfig(baseConfig);
|
||||
mergeTestConfig(cfg);
|
||||
// Set the log4j configuration to an invalid one to prevent system logs
|
||||
@ -297,9 +330,10 @@ public class GerritServer implements AutoCloseable {
|
||||
cfg.setString("gitweb", null, "cgi", "");
|
||||
daemon.setEnableHttpd(desc.httpd());
|
||||
daemon.setLuceneModule(LuceneIndexModule.singleVersionAllLatest(0));
|
||||
daemon.setDatabaseForTesting(ImmutableList.<Module>of(new InMemoryTestingDatabaseModule(cfg)));
|
||||
daemon.setDatabaseForTesting(
|
||||
ImmutableList.<Module>of(new InMemoryTestingDatabaseModule(cfg, site)));
|
||||
daemon.start();
|
||||
return new GerritServer(desc, createTestInjector(daemon), daemon, null);
|
||||
return new GerritServer(desc, null, createTestInjector(daemon), daemon, null);
|
||||
}
|
||||
|
||||
private static GerritServer startOnDisk(
|
||||
@ -336,7 +370,7 @@ public class GerritServer implements AutoCloseable {
|
||||
}
|
||||
System.out.println("Gerrit Server Started");
|
||||
|
||||
return new GerritServer(desc, createTestInjector(daemon), daemon, daemonService);
|
||||
return new GerritServer(desc, site, createTestInjector(daemon), daemon, daemonService);
|
||||
}
|
||||
|
||||
private static void mergeTestConfig(Config cfg) {
|
||||
@ -358,6 +392,8 @@ public class GerritServer implements AutoCloseable {
|
||||
cfg.setInt("receive", null, "threadPoolSize", 1);
|
||||
cfg.setInt("index", null, "threads", 1);
|
||||
cfg.setBoolean("index", null, "reindexAfterRefUpdate", false);
|
||||
|
||||
NoteDbMode.newNotesMigrationFromEnv().setConfigValues(cfg);
|
||||
}
|
||||
|
||||
private static Injector createTestInjector(Daemon daemon) throws Exception {
|
||||
@ -391,6 +427,7 @@ public class GerritServer implements AutoCloseable {
|
||||
}
|
||||
|
||||
private final Description desc;
|
||||
private final Path sitePath;
|
||||
|
||||
private Daemon daemon;
|
||||
private ExecutorService daemonService;
|
||||
@ -400,10 +437,15 @@ public class GerritServer implements AutoCloseable {
|
||||
private InetSocketAddress httpAddress;
|
||||
|
||||
private GerritServer(
|
||||
Description desc, Injector testInjector, Daemon daemon, ExecutorService daemonService) {
|
||||
this.desc = desc;
|
||||
this.testInjector = testInjector;
|
||||
this.daemon = daemon;
|
||||
Description desc,
|
||||
@Nullable Path sitePath,
|
||||
Injector testInjector,
|
||||
Daemon daemon,
|
||||
@Nullable ExecutorService daemonService) {
|
||||
this.desc = checkNotNull(desc);
|
||||
this.sitePath = sitePath;
|
||||
this.testInjector = checkNotNull(testInjector);
|
||||
this.daemon = checkNotNull(daemon);
|
||||
this.daemonService = daemonService;
|
||||
|
||||
Config cfg = testInjector.getInstance(Key.get(Config.class, GerritServerConfig.class));
|
||||
@ -449,6 +491,10 @@ public class GerritServer implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
public Path getSitePath() {
|
||||
return sitePath;
|
||||
}
|
||||
|
||||
private void checkNoteDbState() throws Exception {
|
||||
NoteDbMode mode = NoteDbMode.get();
|
||||
if (mode != NoteDbMode.CHECK && mode != NoteDbMode.PRIMARY) {
|
||||
|
@ -38,7 +38,6 @@ import com.google.gerrit.server.schema.SchemaVersion;
|
||||
import com.google.gerrit.testutil.InMemoryDatabase;
|
||||
import com.google.gerrit.testutil.InMemoryH2Type;
|
||||
import com.google.gerrit.testutil.InMemoryRepositoryManager;
|
||||
import com.google.gerrit.testutil.TestNotesMigration;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.gwtorm.server.OrmRuntimeException;
|
||||
import com.google.gwtorm.server.SchemaFactory;
|
||||
@ -51,16 +50,18 @@ import com.google.inject.TypeLiteral;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import org.apache.sshd.common.keyprovider.KeyPairProvider;
|
||||
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
|
||||
class InMemoryTestingDatabaseModule extends LifecycleModule {
|
||||
private final Config cfg;
|
||||
private final Path sitePath;
|
||||
|
||||
InMemoryTestingDatabaseModule(Config cfg) {
|
||||
InMemoryTestingDatabaseModule(Config cfg, Path sitePath) {
|
||||
this.cfg = cfg;
|
||||
this.sitePath = sitePath;
|
||||
makeSiteDirs(sitePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -68,9 +69,7 @@ class InMemoryTestingDatabaseModule extends LifecycleModule {
|
||||
bind(Config.class).annotatedWith(GerritServerConfig.class).toInstance(cfg);
|
||||
|
||||
// TODO(dborowitz): Use jimfs.
|
||||
Path p = Paths.get(cfg.getString("gerrit", null, "tempSiteDir"));
|
||||
bind(Path.class).annotatedWith(SitePath.class).toInstance(p);
|
||||
makeSiteDirs(p);
|
||||
bind(Path.class).annotatedWith(SitePath.class).toInstance(sitePath);
|
||||
|
||||
bind(GitRepositoryManager.class).to(InMemoryRepositoryManager.class);
|
||||
bind(InMemoryRepositoryManager.class).in(SINGLETON);
|
||||
@ -78,7 +77,7 @@ class InMemoryTestingDatabaseModule extends LifecycleModule {
|
||||
bind(MetricMaker.class).to(DisabledMetricMaker.class);
|
||||
bind(DataSourceType.class).to(InMemoryH2Type.class);
|
||||
|
||||
bind(NotesMigration.class).to(TestNotesMigration.class);
|
||||
install(new NotesMigration.Module());
|
||||
TypeLiteral<SchemaFactory<ReviewDb>> schemaFactory =
|
||||
new TypeLiteral<SchemaFactory<ReviewDb>>() {};
|
||||
bind(schemaFactory).to(NotesMigrationSchemaFactory.class);
|
||||
|
@ -31,10 +31,10 @@ import com.google.gerrit.reviewdb.client.PatchSet;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.ApprovalsUtil;
|
||||
import com.google.gerrit.server.notedb.ChangeNotes;
|
||||
import com.google.gerrit.server.notedb.NotesMigration;
|
||||
import com.google.gerrit.server.notedb.ReviewerStateInternal;
|
||||
import com.google.gerrit.server.query.change.ChangeData;
|
||||
import com.google.gerrit.server.query.change.InternalChangeQuery;
|
||||
import com.google.gerrit.testutil.TestNotesMigration;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
@ -144,7 +144,7 @@ public class PushOneCommit {
|
||||
private final ChangeNotes.Factory notesFactory;
|
||||
private final ApprovalsUtil approvalsUtil;
|
||||
private final Provider<InternalChangeQuery> queryProvider;
|
||||
private final TestNotesMigration notesMigration;
|
||||
private final NotesMigration notesMigration;
|
||||
private final ReviewDb db;
|
||||
private final TestRepository<?> testRepo;
|
||||
|
||||
@ -162,7 +162,7 @@ public class PushOneCommit {
|
||||
ChangeNotes.Factory notesFactory,
|
||||
ApprovalsUtil approvalsUtil,
|
||||
Provider<InternalChangeQuery> queryProvider,
|
||||
TestNotesMigration notesMigration,
|
||||
NotesMigration notesMigration,
|
||||
@Assisted ReviewDb db,
|
||||
@Assisted PersonIdent i,
|
||||
@Assisted TestRepository<?> testRepo)
|
||||
@ -185,7 +185,7 @@ public class PushOneCommit {
|
||||
ChangeNotes.Factory notesFactory,
|
||||
ApprovalsUtil approvalsUtil,
|
||||
Provider<InternalChangeQuery> queryProvider,
|
||||
TestNotesMigration notesMigration,
|
||||
NotesMigration notesMigration,
|
||||
@Assisted ReviewDb db,
|
||||
@Assisted PersonIdent i,
|
||||
@Assisted TestRepository<?> testRepo,
|
||||
@ -210,7 +210,7 @@ public class PushOneCommit {
|
||||
ChangeNotes.Factory notesFactory,
|
||||
ApprovalsUtil approvalsUtil,
|
||||
Provider<InternalChangeQuery> queryProvider,
|
||||
TestNotesMigration notesMigration,
|
||||
NotesMigration notesMigration,
|
||||
@Assisted ReviewDb db,
|
||||
@Assisted PersonIdent i,
|
||||
@Assisted TestRepository<?> testRepo,
|
||||
@ -237,7 +237,7 @@ public class PushOneCommit {
|
||||
ChangeNotes.Factory notesFactory,
|
||||
ApprovalsUtil approvalsUtil,
|
||||
Provider<InternalChangeQuery> queryProvider,
|
||||
TestNotesMigration notesMigration,
|
||||
NotesMigration notesMigration,
|
||||
@Assisted ReviewDb db,
|
||||
@Assisted PersonIdent i,
|
||||
@Assisted TestRepository<?> testRepo,
|
||||
@ -262,7 +262,7 @@ public class PushOneCommit {
|
||||
ChangeNotes.Factory notesFactory,
|
||||
ApprovalsUtil approvalsUtil,
|
||||
Provider<InternalChangeQuery> queryProvider,
|
||||
TestNotesMigration notesMigration,
|
||||
NotesMigration notesMigration,
|
||||
@Assisted ReviewDb db,
|
||||
@Assisted PersonIdent i,
|
||||
@Assisted TestRepository<?> testRepo,
|
||||
@ -288,7 +288,7 @@ public class PushOneCommit {
|
||||
ChangeNotes.Factory notesFactory,
|
||||
ApprovalsUtil approvalsUtil,
|
||||
Provider<InternalChangeQuery> queryProvider,
|
||||
TestNotesMigration notesMigration,
|
||||
NotesMigration notesMigration,
|
||||
ReviewDb db,
|
||||
PersonIdent i,
|
||||
TestRepository<?> testRepo,
|
||||
|
@ -25,6 +25,7 @@ import static com.google.gerrit.extensions.client.ReviewerState.CC;
|
||||
import static com.google.gerrit.extensions.client.ReviewerState.REMOVED;
|
||||
import static com.google.gerrit.extensions.client.ReviewerState.REVIEWER;
|
||||
import static com.google.gerrit.reviewdb.client.RefNames.changeMetaRef;
|
||||
import static com.google.gerrit.reviewdb.server.ReviewDbUtil.unwrapDb;
|
||||
import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
|
||||
import static com.google.gerrit.server.group.SystemGroupBackend.CHANGE_OWNER;
|
||||
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
|
||||
@ -722,7 +723,10 @@ public class ChangeIT extends AbstractDaemonTest {
|
||||
if (notesMigration.changePrimaryStorage() == PrimaryStorage.REVIEW_DB) {
|
||||
// Ensure record was actually copied under ReviewDb
|
||||
List<PatchSetApproval> psas =
|
||||
db.patchSetApprovals().byPatchSet(new PatchSet.Id(new Change.Id(c2._number), 2)).toList();
|
||||
unwrapDb(db)
|
||||
.patchSetApprovals()
|
||||
.byPatchSet(new PatchSet.Id(new Change.Id(c2._number), 2))
|
||||
.toList();
|
||||
assertThat(psas).hasSize(1);
|
||||
assertThat(psas.get(0).getValue()).isEqualTo((short) 1);
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ package com.google.gerrit.acceptance.pgm;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth8.assertThat;
|
||||
import static com.google.common.truth.TruthJUnit.assume;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
@ -31,12 +32,12 @@ import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.index.GerritIndexStatus;
|
||||
import com.google.gerrit.server.index.change.ChangeIndexCollection;
|
||||
import com.google.gerrit.server.index.change.ChangeSchemaDefinitions;
|
||||
import com.google.gerrit.server.notedb.ConfigNotesMigration;
|
||||
import com.google.gerrit.server.notedb.NoteDbChangeState;
|
||||
import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage;
|
||||
import com.google.gerrit.server.notedb.NoteDbChangeState.RefState;
|
||||
import com.google.gerrit.server.notedb.NotesMigrationState;
|
||||
import com.google.gerrit.server.schema.ReviewDbFactory;
|
||||
import com.google.gerrit.testutil.NoteDbMode;
|
||||
import com.google.gwtorm.server.SchemaFactory;
|
||||
import com.google.inject.Key;
|
||||
import com.google.inject.TypeLiteral;
|
||||
@ -66,6 +67,7 @@ public class StandaloneNoteDbMigrationIT extends StandaloneSiteTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
assume().that(NoteDbMode.get()).isEqualTo(NoteDbMode.OFF);
|
||||
gerritConfig = new FileBasedConfig(sitePaths.gerrit_config.toFile(), FS.detect());
|
||||
}
|
||||
|
||||
@ -198,8 +200,7 @@ public class StandaloneNoteDbMigrationIT extends StandaloneSiteTest {
|
||||
|
||||
private void assertNotesMigrationState(NotesMigrationState expected) throws Exception {
|
||||
gerritConfig.load();
|
||||
assertThat(NotesMigrationState.forNotesMigration(new ConfigNotesMigration(gerritConfig)))
|
||||
.hasValue(expected);
|
||||
assertThat(NotesMigrationState.forConfig(gerritConfig)).hasValue(expected);
|
||||
}
|
||||
|
||||
private ReviewDb openUnderlyingReviewDb(ServerContext ctx) throws Exception {
|
||||
|
@ -325,7 +325,7 @@ public class ChangeReviewersByEmailIT extends AbstractDaemonTest {
|
||||
input.state = state;
|
||||
gApi.changes().id(r.getChangeId()).addReviewer(input);
|
||||
|
||||
notesMigration.setFailOnLoad(true);
|
||||
notesMigration.setFailOnLoadForTest(true);
|
||||
try {
|
||||
ChangeInfo info =
|
||||
Iterables.getOnlyElement(
|
||||
@ -335,7 +335,7 @@ public class ChangeReviewersByEmailIT extends AbstractDaemonTest {
|
||||
.get());
|
||||
assertThat(info.reviewers).isEqualTo(ImmutableMap.of(state, ImmutableList.of(acc)));
|
||||
} finally {
|
||||
notesMigration.setFailOnLoad(false);
|
||||
notesMigration.setFailOnLoadForTest(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,12 +27,15 @@ import com.google.gerrit.extensions.common.ServerInfo;
|
||||
import com.google.gerrit.server.config.AllProjectsNameProvider;
|
||||
import com.google.gerrit.server.config.AllUsersNameProvider;
|
||||
import com.google.gerrit.server.config.AnonymousCowardNameProvider;
|
||||
import com.google.gerrit.server.config.SitePaths;
|
||||
import com.google.inject.Inject;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import org.junit.Test;
|
||||
|
||||
@NoHttpd
|
||||
public class ServerInfoIT extends AbstractDaemonTest {
|
||||
@Inject private SitePaths sitePaths;
|
||||
|
||||
@Test
|
||||
// auth
|
||||
@ -132,7 +135,8 @@ public class ServerInfoIT extends AbstractDaemonTest {
|
||||
@UseSsh
|
||||
@GerritConfig(name = "plugins.allowRemoteAdmin", value = "true")
|
||||
public void serverConfigWithPlugin() throws Exception {
|
||||
Path plugins = tempSiteDir.newFolder("plugins").toPath();
|
||||
Path plugins = sitePaths.plugins_dir;
|
||||
Files.createDirectory(plugins);
|
||||
Path jsplugin = plugins.resolve("js-plugin-1.js");
|
||||
Files.write(jsplugin, "Gerrit.install(function(self){});\n".getBytes(UTF_8));
|
||||
adminSshSession.exec("gerrit plugin reload");
|
||||
|
@ -151,7 +151,7 @@ public class ChangeRebuilderIT extends AbstractDaemonTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
assume().that(NoteDbMode.readWrite()).isFalse();
|
||||
assume().that(NoteDbMode.get()).isEqualTo(NoteDbMode.OFF);
|
||||
TestTimeUtil.resetWithClockStep(1, SECONDS);
|
||||
setNotesMigration(false, false);
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ public class NoteDbOnlyIT extends AbstractDaemonTest {
|
||||
String master = "refs/heads/master";
|
||||
ObjectId initial;
|
||||
try (Repository repo = repoManager.openRepository(project)) {
|
||||
((InMemoryRepository) repo).setPerformsAtomicTransactions(true);
|
||||
ensureAtomicTransactions(repo);
|
||||
initial = repo.exactRef(master).getObjectId();
|
||||
}
|
||||
|
||||
@ -344,4 +344,14 @@ public class NoteDbOnlyIT extends AbstractDaemonTest {
|
||||
return Streams.stream(rw).map(c -> c.getShortMessage()).collect(toList());
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureAtomicTransactions(Repository repo) throws Exception {
|
||||
if (repo instanceof InMemoryRepository) {
|
||||
((InMemoryRepository) repo).setPerformsAtomicTransactions(true);
|
||||
} else {
|
||||
assertThat(repo.getRefDatabase().performsAtomicTransactions())
|
||||
.named("performsAtomicTransactions on %s", repo)
|
||||
.isTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,6 @@ import com.google.gerrit.reviewdb.client.RefNames;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.Sequences;
|
||||
import com.google.gerrit.server.config.SitePaths;
|
||||
import com.google.gerrit.server.notedb.ConfigNotesMigration;
|
||||
import com.google.gerrit.server.notedb.NoteDbChangeState;
|
||||
import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage;
|
||||
import com.google.gerrit.server.notedb.NoteDbChangeState.RefState;
|
||||
@ -380,15 +379,14 @@ public class OnlineNoteDbMigrationIT extends AbstractDaemonTest {
|
||||
private void assertNotesMigrationState(NotesMigrationState expected) throws Exception {
|
||||
assertThat(NotesMigrationState.forNotesMigration(notesMigration)).hasValue(expected);
|
||||
gerritConfig.load();
|
||||
assertThat(NotesMigrationState.forNotesMigration(new ConfigNotesMigration(gerritConfig)))
|
||||
.hasValue(expected);
|
||||
assertThat(NotesMigrationState.forConfig(gerritConfig)).hasValue(expected);
|
||||
}
|
||||
|
||||
private void setNotesMigrationState(NotesMigrationState state) throws Exception {
|
||||
gerritConfig.load();
|
||||
ConfigNotesMigration.setConfigValues(gerritConfig, state.migration());
|
||||
state.setConfigValues(gerritConfig);
|
||||
gerritConfig.save();
|
||||
notesMigration.setFrom(state.migration());
|
||||
notesMigration.setFrom(state);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
|
@ -46,7 +46,7 @@ import com.google.gerrit.server.util.RequestContext;
|
||||
import com.google.gerrit.server.util.ThreadLocalRequestContext;
|
||||
import com.google.gerrit.testutil.InMemoryDatabase;
|
||||
import com.google.gerrit.testutil.InMemoryModule;
|
||||
import com.google.gerrit.testutil.TestNotesMigration;
|
||||
import com.google.gerrit.testutil.NoteDbMode;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
@ -104,7 +104,8 @@ public class GerritPublicKeyCheckerTest {
|
||||
ImmutableList.of(
|
||||
Fingerprint.toString(keyB().getPublicKey().getFingerprint()),
|
||||
Fingerprint.toString(keyD().getPublicKey().getFingerprint())));
|
||||
Injector injector = Guice.createInjector(new InMemoryModule(cfg, new TestNotesMigration()));
|
||||
Injector injector =
|
||||
Guice.createInjector(new InMemoryModule(cfg, NoteDbMode.newNotesMigrationFromEnv()));
|
||||
|
||||
lifecycle = new LifecycleManager();
|
||||
lifecycle.add(injector);
|
||||
|
@ -184,7 +184,7 @@ public class Daemon extends SiteProgram {
|
||||
private Injector webInjector;
|
||||
private Injector httpdInjector;
|
||||
private Path runFile;
|
||||
private boolean test;
|
||||
private boolean inMemoryTest;
|
||||
private AbstractModule luceneModule;
|
||||
private Module emailModule;
|
||||
private Module testSysModule;
|
||||
@ -295,7 +295,7 @@ public class Daemon extends SiteProgram {
|
||||
@VisibleForTesting
|
||||
public void setDatabaseForTesting(List<Module> modules) {
|
||||
dbInjector = Guice.createInjector(Stage.PRODUCTION, modules);
|
||||
test = true;
|
||||
inMemoryTest = true;
|
||||
headless = true;
|
||||
}
|
||||
|
||||
@ -307,7 +307,7 @@ public class Daemon extends SiteProgram {
|
||||
@VisibleForTesting
|
||||
public void setLuceneModule(LuceneIndexModule m) {
|
||||
luceneModule = m;
|
||||
test = true;
|
||||
inMemoryTest = true;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@ -398,7 +398,7 @@ public class Daemon extends SiteProgram {
|
||||
modules.add(new StreamEventsApiListener.Module());
|
||||
modules.add(new EventBroker.Module());
|
||||
modules.add(
|
||||
test
|
||||
inMemoryTest
|
||||
? new H2AccountPatchReviewStore.InMemoryModule()
|
||||
: new JdbcAccountPatchReviewStore.Module(config));
|
||||
modules.add(new ReceiveCommitsExecutorModule());
|
||||
@ -448,7 +448,7 @@ public class Daemon extends SiteProgram {
|
||||
protected void configure() {
|
||||
bind(GerritOptions.class)
|
||||
.toInstance(new GerritOptions(config, headless, slave, polyGerritDev));
|
||||
if (test) {
|
||||
if (inMemoryTest) {
|
||||
bind(String.class)
|
||||
.annotatedWith(SecureStoreClassName.class)
|
||||
.toInstance(DefaultSecureStore.class.getName());
|
||||
@ -519,7 +519,7 @@ public class Daemon extends SiteProgram {
|
||||
private Injector createSshInjector() {
|
||||
final List<Module> modules = new ArrayList<>();
|
||||
modules.add(sysInjector.getInstance(SshModule.class));
|
||||
if (!test) {
|
||||
if (!inMemoryTest) {
|
||||
modules.add(new SshHostKeyModule());
|
||||
}
|
||||
modules.add(
|
||||
|
@ -14,15 +14,15 @@
|
||||
|
||||
package com.google.gerrit.pgm.init;
|
||||
|
||||
import static com.google.gerrit.server.notedb.ConfigNotesMigration.SECTION_NOTE_DB;
|
||||
import static com.google.gerrit.server.notedb.NoteDbTable.CHANGES;
|
||||
import static com.google.gerrit.server.notedb.NotesMigration.SECTION_NOTE_DB;
|
||||
|
||||
import com.google.gerrit.extensions.client.UiType;
|
||||
import com.google.gerrit.pgm.init.api.ConsoleUI;
|
||||
import com.google.gerrit.pgm.init.api.InitFlags;
|
||||
import com.google.gerrit.pgm.init.api.InitStep;
|
||||
import com.google.gerrit.pgm.init.api.Section;
|
||||
import com.google.gerrit.server.notedb.ConfigNotesMigration;
|
||||
import com.google.gerrit.server.notedb.NotesMigrationState;
|
||||
import com.google.inject.Inject;
|
||||
import java.util.Locale;
|
||||
import javax.inject.Singleton;
|
||||
@ -66,7 +66,8 @@ class InitExperimental implements InitStep {
|
||||
return;
|
||||
}
|
||||
|
||||
Config defaultConfig = ConfigNotesMigration.allEnabledConfig();
|
||||
Config defaultConfig = new Config();
|
||||
NotesMigrationState.FINAL.setConfigValues(defaultConfig);
|
||||
for (String name : defaultConfig.getNames(SECTION_NOTE_DB, CHANGES.key())) {
|
||||
noteDbChanges.set(name, defaultConfig.getString(SECTION_NOTE_DB, CHANGES.key(), name));
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ import com.google.gerrit.server.config.GerritServerConfig;
|
||||
import com.google.gerrit.server.config.GerritServerConfigModule;
|
||||
import com.google.gerrit.server.config.SitePath;
|
||||
import com.google.gerrit.server.git.GitRepositoryManagerModule;
|
||||
import com.google.gerrit.server.notedb.ConfigNotesMigration;
|
||||
import com.google.gerrit.server.notedb.NotesMigration;
|
||||
import com.google.gerrit.server.schema.DataSourceModule;
|
||||
import com.google.gerrit.server.schema.DataSourceProvider;
|
||||
import com.google.gerrit.server.schema.DataSourceType;
|
||||
@ -105,10 +105,9 @@ public abstract class SiteProgram extends AbstractProgram {
|
||||
}
|
||||
|
||||
/** @return provides database connectivity and site path. */
|
||||
protected Injector createDbInjector(
|
||||
final boolean enableMetrics, DataSourceProvider.Context context) {
|
||||
final Path sitePath = getSitePath();
|
||||
final List<Module> modules = new ArrayList<>();
|
||||
protected Injector createDbInjector(boolean enableMetrics, DataSourceProvider.Context context) {
|
||||
Path sitePath = getSitePath();
|
||||
List<Module> modules = new ArrayList<>();
|
||||
|
||||
Module sitePathModule =
|
||||
new AbstractModule() {
|
||||
@ -169,7 +168,7 @@ public abstract class SiteProgram extends AbstractProgram {
|
||||
throw new ProvisionException("database.type must be defined");
|
||||
}
|
||||
|
||||
final DataSourceType dst =
|
||||
DataSourceType dst =
|
||||
Guice.createInjector(new DataSourceModule(), configModule, sitePathModule)
|
||||
.getInstance(Key.get(DataSourceType.class, Names.named(dbType.toLowerCase())));
|
||||
|
||||
@ -183,12 +182,12 @@ public abstract class SiteProgram extends AbstractProgram {
|
||||
modules.add(new DatabaseModule());
|
||||
modules.add(new SchemaModule());
|
||||
modules.add(cfgInjector.getInstance(GitRepositoryManagerModule.class));
|
||||
modules.add(new ConfigNotesMigration.Module());
|
||||
modules.add(new NotesMigration.Module());
|
||||
|
||||
try {
|
||||
return Guice.createInjector(PRODUCTION, modules);
|
||||
} catch (CreationException ce) {
|
||||
final Message first = ce.getErrorMessages().iterator().next();
|
||||
Message first = ce.getErrorMessages().iterator().next();
|
||||
Throwable why = first.getCause();
|
||||
|
||||
if (why instanceof SQLException) {
|
||||
@ -204,7 +203,7 @@ public abstract class SiteProgram extends AbstractProgram {
|
||||
throw die("Cannot connect to SQL database", why);
|
||||
}
|
||||
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
StringBuilder buf = new StringBuilder();
|
||||
if (why != null) {
|
||||
buf.append(why.getMessage());
|
||||
why = why.getCause();
|
||||
|
@ -151,7 +151,7 @@ public abstract class AbstractChangeNotes<T> {
|
||||
loadDefaults();
|
||||
return self();
|
||||
}
|
||||
if (args.migration.failOnLoad()) {
|
||||
if (args.migration.failOnLoadForTest()) {
|
||||
throw new OrmException("Reading from NoteDb is disabled");
|
||||
}
|
||||
try (Timer1.Context timer = args.metrics.readLatency.start(CHANGES);
|
||||
|
@ -1,184 +0,0 @@
|
||||
// Copyright (C) 2013 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.server.notedb;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.gerrit.server.notedb.NoteDbTable.CHANGES;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.gerrit.server.config.GerritServerConfig;
|
||||
import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
|
||||
/**
|
||||
* Implement NoteDb migration stages using {@code gerrit.config}.
|
||||
*
|
||||
* <p>This class controls the state of the migration according to options in {@code gerrit.config}.
|
||||
* In general, any changes to these options should only be made by adventurous administrators, who
|
||||
* know what they're doing, on non-production data, for the purposes of testing the NoteDb
|
||||
* implementation. Changing options quite likely requires re-running {@code MigrateToNoteDb}. For
|
||||
* these reasons, the options remain undocumented.
|
||||
*/
|
||||
@Singleton
|
||||
public class ConfigNotesMigration extends NotesMigration {
|
||||
public static class Module extends AbstractModule {
|
||||
@Override
|
||||
public void configure() {
|
||||
bind(NotesMigration.class).to(ConfigNotesMigration.class);
|
||||
}
|
||||
}
|
||||
|
||||
public static final String SECTION_NOTE_DB = "noteDb";
|
||||
|
||||
private static final String DISABLE_REVIEW_DB = "disableReviewDb";
|
||||
private static final String FUSE_UPDATES = "fuseUpdates";
|
||||
private static final String PRIMARY_STORAGE = "primaryStorage";
|
||||
private static final String READ = "read";
|
||||
private static final String SEQUENCE = "sequence";
|
||||
private static final String WRITE = "write";
|
||||
|
||||
public static Config allEnabledConfig() {
|
||||
Config cfg = new Config();
|
||||
cfg.setBoolean(SECTION_NOTE_DB, CHANGES.key(), WRITE, true);
|
||||
cfg.setBoolean(SECTION_NOTE_DB, CHANGES.key(), READ, true);
|
||||
cfg.setBoolean(SECTION_NOTE_DB, CHANGES.key(), SEQUENCE, true);
|
||||
cfg.setString(SECTION_NOTE_DB, CHANGES.key(), PRIMARY_STORAGE, PrimaryStorage.NOTE_DB.name());
|
||||
cfg.setBoolean(SECTION_NOTE_DB, CHANGES.key(), DISABLE_REVIEW_DB, true);
|
||||
// TODO(dborowitz): Set to true when FileRepository supports it.
|
||||
cfg.setBoolean(SECTION_NOTE_DB, CHANGES.key(), FUSE_UPDATES, false);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
public static void setConfigValues(Config cfg, NotesMigration migration) {
|
||||
cfg.setBoolean(SECTION_NOTE_DB, CHANGES.key(), WRITE, migration.rawWriteChangesSetting());
|
||||
cfg.setBoolean(SECTION_NOTE_DB, CHANGES.key(), READ, migration.readChanges());
|
||||
cfg.setBoolean(SECTION_NOTE_DB, CHANGES.key(), SEQUENCE, migration.readChangeSequence());
|
||||
cfg.setEnum(SECTION_NOTE_DB, CHANGES.key(), PRIMARY_STORAGE, migration.changePrimaryStorage());
|
||||
cfg.setBoolean(
|
||||
SECTION_NOTE_DB, CHANGES.key(), DISABLE_REVIEW_DB, migration.disableChangeReviewDb());
|
||||
cfg.setBoolean(SECTION_NOTE_DB, CHANGES.key(), FUSE_UPDATES, migration.fuseUpdates());
|
||||
}
|
||||
|
||||
public static String toText(NotesMigration migration) {
|
||||
Config cfg = new Config();
|
||||
setConfigValues(cfg, migration);
|
||||
return cfg.toText();
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
abstract static class Snapshot {
|
||||
static Snapshot create(Config cfg) {
|
||||
boolean writeChanges = cfg.getBoolean(SECTION_NOTE_DB, CHANGES.key(), WRITE, false);
|
||||
boolean readChanges = cfg.getBoolean(SECTION_NOTE_DB, CHANGES.key(), READ, false);
|
||||
|
||||
// Reading change sequence numbers from NoteDb is not the default even if
|
||||
// reading changes themselves is. Once this is enabled, it's not easy to
|
||||
// undo: ReviewDb might hand out numbers that have already been assigned by
|
||||
// NoteDb. This decision for the default may be reevaluated later.
|
||||
boolean readChangeSequence = cfg.getBoolean(SECTION_NOTE_DB, CHANGES.key(), SEQUENCE, false);
|
||||
|
||||
PrimaryStorage changePrimaryStorage =
|
||||
cfg.getEnum(SECTION_NOTE_DB, CHANGES.key(), PRIMARY_STORAGE, PrimaryStorage.REVIEW_DB);
|
||||
boolean disableChangeReviewDb =
|
||||
cfg.getBoolean(SECTION_NOTE_DB, CHANGES.key(), DISABLE_REVIEW_DB, false);
|
||||
boolean fuseUpdates = cfg.getBoolean(SECTION_NOTE_DB, CHANGES.key(), FUSE_UPDATES, false);
|
||||
|
||||
checkArgument(
|
||||
!(disableChangeReviewDb && changePrimaryStorage != PrimaryStorage.NOTE_DB),
|
||||
"cannot disable ReviewDb for changes if default change primary storage is ReviewDb");
|
||||
|
||||
return new AutoValue_ConfigNotesMigration_Snapshot(
|
||||
writeChanges,
|
||||
readChanges,
|
||||
readChangeSequence,
|
||||
changePrimaryStorage,
|
||||
disableChangeReviewDb,
|
||||
fuseUpdates);
|
||||
}
|
||||
|
||||
abstract boolean writeChanges();
|
||||
|
||||
abstract boolean readChanges();
|
||||
|
||||
abstract boolean readChangeSequence();
|
||||
|
||||
abstract PrimaryStorage changePrimaryStorage();
|
||||
|
||||
abstract boolean disableChangeReviewDb();
|
||||
|
||||
abstract boolean fuseUpdates();
|
||||
}
|
||||
|
||||
private volatile Snapshot snapshot;
|
||||
|
||||
@Inject
|
||||
public ConfigNotesMigration(@GerritServerConfig Config cfg) {
|
||||
this.snapshot = Snapshot.create(cfg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean rawWriteChangesSetting() {
|
||||
return snapshot.writeChanges();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readChanges() {
|
||||
return snapshot.readChanges();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readChangeSequence() {
|
||||
return snapshot.readChangeSequence();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrimaryStorage changePrimaryStorage() {
|
||||
return snapshot.changePrimaryStorage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean disableChangeReviewDb() {
|
||||
return snapshot.disableChangeReviewDb();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fuseUpdates() {
|
||||
return snapshot.fuseUpdates();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the in-memory values returned by this instance to match another instance.
|
||||
*
|
||||
* <p>This method is only intended for use by {@link
|
||||
* com.google.gerrit.server.notedb.rebuild.NoteDbMigrator}.
|
||||
*
|
||||
* <p>This <em>only</em> modifies the in-memory state; if this instance was initialized from a
|
||||
* file-based config, the underlying storage is not updated. Callers are responsible for managing
|
||||
* the underlying storage on their own. This method is synchronized to aid in such
|
||||
* implementations.
|
||||
*
|
||||
* @see NotesMigration#setFrom(NotesMigration)
|
||||
*/
|
||||
@Override
|
||||
public synchronized ConfigNotesMigration setFrom(NotesMigration other) {
|
||||
Config cfg = new Config();
|
||||
setConfigValues(cfg, other);
|
||||
snapshot = Snapshot.create(cfg);
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
// Copyright (C) 2017 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.server.notedb;
|
||||
|
||||
import com.google.gerrit.server.config.GerritServerConfig;
|
||||
import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import java.util.function.Function;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
|
||||
/**
|
||||
* {@link NotesMigration} with additional methods for altering the migration state at runtime.
|
||||
*
|
||||
* <p>Almost all callers care only about inspecting the migration state, and for safety should not
|
||||
* have access to mutation methods, which must be used with extreme care. Those callers should
|
||||
* inject {@link NotesMigration}.
|
||||
*
|
||||
* <p>Some callers, namely the NoteDb migration pipeline and tests, do need to alter the migration
|
||||
* state at runtime, and those callers are expected to take the necessary precautions such as
|
||||
* keeping the in-memory and on-disk config state in sync. Those callers use this class.
|
||||
*
|
||||
* <p>Mutations to the {@link MutableNotesMigration} are guaranteed to be instantly visible to all
|
||||
* callers that use the non-mutable {@link NotesMigration}. The current implementation accomplishes
|
||||
* this by always binding {@link NotesMigration} to {@link MutableNotesMigration} in Guice, so there
|
||||
* is just one {@link NotesMigration} instance process-wide.
|
||||
*/
|
||||
@Singleton
|
||||
public class MutableNotesMigration extends NotesMigration {
|
||||
public static MutableNotesMigration newDisabled() {
|
||||
return new MutableNotesMigration(new Config());
|
||||
}
|
||||
|
||||
public static MutableNotesMigration fromConfig(Config cfg) {
|
||||
return new MutableNotesMigration(cfg);
|
||||
}
|
||||
|
||||
@Inject
|
||||
MutableNotesMigration(@GerritServerConfig Config cfg) {
|
||||
super(Snapshot.create(cfg));
|
||||
}
|
||||
|
||||
public MutableNotesMigration setReadChanges(boolean readChanges) {
|
||||
return set(b -> b.setReadChanges(readChanges));
|
||||
}
|
||||
|
||||
public MutableNotesMigration setWriteChanges(boolean writeChanges) {
|
||||
return set(b -> b.setWriteChanges(writeChanges));
|
||||
}
|
||||
|
||||
public MutableNotesMigration setReadChangeSequence(boolean readChangeSequence) {
|
||||
return set(b -> b.setReadChangeSequence(readChangeSequence));
|
||||
}
|
||||
|
||||
public MutableNotesMigration setChangePrimaryStorage(PrimaryStorage changePrimaryStorage) {
|
||||
return set(b -> b.setChangePrimaryStorage(changePrimaryStorage));
|
||||
}
|
||||
|
||||
public MutableNotesMigration setDisableChangeReviewDb(boolean disableChangeReviewDb) {
|
||||
return set(b -> b.setDisableChangeReviewDb(disableChangeReviewDb));
|
||||
}
|
||||
|
||||
public MutableNotesMigration setFuseUpdates(boolean fuseUpdates) {
|
||||
return set(b -> b.setFuseUpdates(fuseUpdates));
|
||||
}
|
||||
|
||||
public MutableNotesMigration setFailOnLoadForTest(boolean failOnLoadForTest) {
|
||||
return set(b -> b.setFailOnLoadForTest(failOnLoadForTest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the in-memory values returned by this instance to match the given state.
|
||||
*
|
||||
* <p>This method is only intended for use by {@link
|
||||
* com.google.gerrit.server.notedb.rebuild.NoteDbMigrator}.
|
||||
*
|
||||
* <p>This <em>only</em> modifies the in-memory state; if this instance was initialized from a
|
||||
* file-based config, the underlying storage is not updated. Callers are responsible for managing
|
||||
* the underlying storage on their own.
|
||||
*/
|
||||
public MutableNotesMigration setFrom(NotesMigrationState state) {
|
||||
snapshot.set(state.snapshot());
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @see #setFrom(NotesMigrationState) */
|
||||
public MutableNotesMigration setFrom(NotesMigration other) {
|
||||
snapshot.set(other.snapshot.get());
|
||||
return this;
|
||||
}
|
||||
|
||||
private MutableNotesMigration set(Function<Snapshot.Builder, Snapshot.Builder> f) {
|
||||
snapshot.updateAndGet(s -> f.apply(s.toBuilder()).build());
|
||||
return this;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2016 The Android Open Source Project
|
||||
// Copyright (C) 2017 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.
|
||||
@ -14,8 +14,14 @@
|
||||
|
||||
package com.google.gerrit.server.notedb;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.gerrit.server.notedb.NoteDbTable.CHANGES;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage;
|
||||
import java.util.Objects;
|
||||
import com.google.inject.AbstractModule;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
|
||||
/**
|
||||
* Current low-level settings of the NoteDb migration for changes.
|
||||
@ -47,6 +53,100 @@ import java.util.Objects;
|
||||
* NotesMigration}'s methods will not change in a running server.
|
||||
*/
|
||||
public abstract class NotesMigration {
|
||||
public static final String SECTION_NOTE_DB = "noteDb";
|
||||
|
||||
private static final String DISABLE_REVIEW_DB = "disableReviewDb";
|
||||
private static final String FUSE_UPDATES = "fuseUpdates";
|
||||
private static final String PRIMARY_STORAGE = "primaryStorage";
|
||||
private static final String READ = "read";
|
||||
private static final String SEQUENCE = "sequence";
|
||||
private static final String WRITE = "write";
|
||||
|
||||
public static class Module extends AbstractModule {
|
||||
@Override
|
||||
public void configure() {
|
||||
bind(MutableNotesMigration.class);
|
||||
bind(NotesMigration.class).to(MutableNotesMigration.class);
|
||||
}
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
abstract static class Snapshot {
|
||||
static Builder builder() {
|
||||
// Default values are defined as what we would read from an empty config.
|
||||
return create(new Config()).toBuilder();
|
||||
}
|
||||
|
||||
static Snapshot create(Config cfg) {
|
||||
return new AutoValue_NotesMigration_Snapshot.Builder()
|
||||
.setWriteChanges(cfg.getBoolean(SECTION_NOTE_DB, CHANGES.key(), WRITE, false))
|
||||
.setReadChanges(cfg.getBoolean(SECTION_NOTE_DB, CHANGES.key(), READ, false))
|
||||
.setReadChangeSequence(cfg.getBoolean(SECTION_NOTE_DB, CHANGES.key(), SEQUENCE, false))
|
||||
.setChangePrimaryStorage(
|
||||
cfg.getEnum(
|
||||
SECTION_NOTE_DB, CHANGES.key(), PRIMARY_STORAGE, PrimaryStorage.REVIEW_DB))
|
||||
.setDisableChangeReviewDb(
|
||||
cfg.getBoolean(SECTION_NOTE_DB, CHANGES.key(), DISABLE_REVIEW_DB, false))
|
||||
.setFuseUpdates(cfg.getBoolean(SECTION_NOTE_DB, CHANGES.key(), FUSE_UPDATES, false))
|
||||
.setFailOnLoadForTest(false) // Only set in tests, can't be set via config.
|
||||
.build();
|
||||
}
|
||||
|
||||
abstract boolean writeChanges();
|
||||
|
||||
abstract boolean readChanges();
|
||||
|
||||
abstract boolean readChangeSequence();
|
||||
|
||||
abstract PrimaryStorage changePrimaryStorage();
|
||||
|
||||
abstract boolean disableChangeReviewDb();
|
||||
|
||||
abstract boolean fuseUpdates();
|
||||
|
||||
abstract boolean failOnLoadForTest();
|
||||
|
||||
abstract Builder toBuilder();
|
||||
|
||||
void setConfigValues(Config cfg) {
|
||||
cfg.setBoolean(SECTION_NOTE_DB, CHANGES.key(), WRITE, writeChanges());
|
||||
cfg.setBoolean(SECTION_NOTE_DB, CHANGES.key(), READ, readChanges());
|
||||
cfg.setBoolean(SECTION_NOTE_DB, CHANGES.key(), SEQUENCE, readChangeSequence());
|
||||
cfg.setEnum(SECTION_NOTE_DB, CHANGES.key(), PRIMARY_STORAGE, changePrimaryStorage());
|
||||
cfg.setBoolean(SECTION_NOTE_DB, CHANGES.key(), DISABLE_REVIEW_DB, disableChangeReviewDb());
|
||||
cfg.setBoolean(SECTION_NOTE_DB, CHANGES.key(), FUSE_UPDATES, fuseUpdates());
|
||||
}
|
||||
|
||||
@AutoValue.Builder
|
||||
abstract static class Builder {
|
||||
abstract Builder setWriteChanges(boolean writeChanges);
|
||||
|
||||
abstract Builder setReadChanges(boolean readChanges);
|
||||
|
||||
abstract Builder setReadChangeSequence(boolean readChangeSequence);
|
||||
|
||||
abstract Builder setChangePrimaryStorage(PrimaryStorage changePrimaryStorage);
|
||||
|
||||
abstract Builder setDisableChangeReviewDb(boolean disableChangeReviewDb);
|
||||
|
||||
abstract Builder setFuseUpdates(boolean fuseUpdates);
|
||||
|
||||
abstract Builder setFailOnLoadForTest(boolean failOnLoadForTest);
|
||||
|
||||
abstract Snapshot autoBuild();
|
||||
|
||||
Snapshot build() {
|
||||
Snapshot s = autoBuild();
|
||||
checkArgument(
|
||||
!(s.disableChangeReviewDb() && s.changePrimaryStorage() != PrimaryStorage.NOTE_DB),
|
||||
"cannot disable ReviewDb for changes if default change primary storage is ReviewDb");
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected final AtomicReference<Snapshot> snapshot;
|
||||
|
||||
/**
|
||||
* Read changes from NoteDb.
|
||||
*
|
||||
@ -57,7 +157,9 @@ public abstract class NotesMigration {
|
||||
* <p>If true and {@code writeChanges() = false}, changes can still be read from NoteDb, but any
|
||||
* attempts to write will generate an error.
|
||||
*/
|
||||
public abstract boolean readChanges();
|
||||
public final boolean readChanges() {
|
||||
return snapshot.get().readChanges();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write changes to NoteDb.
|
||||
@ -73,7 +175,9 @@ public abstract class NotesMigration {
|
||||
* readChanges() = false}, writes to NoteDb are simply ignored; if {@code true}, any attempts to
|
||||
* write will generate an error.
|
||||
*/
|
||||
public abstract boolean rawWriteChangesSetting();
|
||||
public final boolean rawWriteChangesSetting() {
|
||||
return snapshot.get().writeChanges();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read sequential change ID numbers from NoteDb.
|
||||
@ -81,10 +185,14 @@ public abstract class NotesMigration {
|
||||
* <p>If true, change IDs are read from {@code refs/sequences/changes} in All-Projects. If false,
|
||||
* change IDs are read from ReviewDb's native sequences.
|
||||
*/
|
||||
public abstract boolean readChangeSequence();
|
||||
public final boolean readChangeSequence() {
|
||||
return snapshot.get().readChangeSequence();
|
||||
}
|
||||
|
||||
/** @return default primary storage for new changes. */
|
||||
public abstract PrimaryStorage changePrimaryStorage();
|
||||
public final PrimaryStorage changePrimaryStorage() {
|
||||
return snapshot.get().changePrimaryStorage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable ReviewDb access for changes.
|
||||
@ -93,7 +201,9 @@ public abstract class NotesMigration {
|
||||
* results; updates do nothing, as does opening, committing, or rolling back a transaction on the
|
||||
* Changes table.
|
||||
*/
|
||||
public abstract boolean disableChangeReviewDb();
|
||||
public final boolean disableChangeReviewDb() {
|
||||
return snapshot.get().disableChangeReviewDb();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fuse meta ref updates in the same batch as code updates.
|
||||
@ -106,18 +216,8 @@ public abstract class NotesMigration {
|
||||
*
|
||||
* <p>Has no effect if {@link #disableChangeReviewDb()} is false.
|
||||
*/
|
||||
public abstract boolean fuseUpdates();
|
||||
|
||||
/**
|
||||
* Set the values returned by this instance to match another instance.
|
||||
*
|
||||
* <p>Optional operation: not all implementations support setting values after initialization.
|
||||
*
|
||||
* @param other other instance to copy values from.
|
||||
* @return this.
|
||||
*/
|
||||
public NotesMigration setFrom(NotesMigration other) {
|
||||
throw new UnsupportedOperationException(getClass().getSimpleName() + " is read-only");
|
||||
public final boolean fuseUpdates() {
|
||||
return snapshot.get().fuseUpdates();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -125,8 +225,8 @@ public abstract class NotesMigration {
|
||||
*
|
||||
* <p>Used in conjunction with {@link #readChanges()} for tests.
|
||||
*/
|
||||
public boolean failOnLoad() {
|
||||
return false;
|
||||
public boolean failOnLoadForTest() {
|
||||
return snapshot.get().failOnLoadForTest();
|
||||
}
|
||||
|
||||
public final boolean commitChangeWrites() {
|
||||
@ -151,30 +251,26 @@ public abstract class NotesMigration {
|
||||
return rawWriteChangesSetting() || readChanges();
|
||||
}
|
||||
|
||||
public final void setConfigValues(Config cfg) {
|
||||
snapshot.get().setConfigValues(cfg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object o) {
|
||||
if (!(o instanceof NotesMigration)) {
|
||||
return false;
|
||||
}
|
||||
NotesMigration m = (NotesMigration) o;
|
||||
return readChanges() == m.readChanges()
|
||||
&& rawWriteChangesSetting() == m.rawWriteChangesSetting()
|
||||
&& readChangeSequence() == m.readChangeSequence()
|
||||
&& changePrimaryStorage() == m.changePrimaryStorage()
|
||||
&& disableChangeReviewDb() == m.disableChangeReviewDb()
|
||||
&& fuseUpdates() == m.fuseUpdates()
|
||||
&& failOnLoad() == m.failOnLoad();
|
||||
return o instanceof NotesMigration
|
||||
&& snapshot.get().equals(((NotesMigration) o).snapshot.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return Objects.hash(
|
||||
readChanges(),
|
||||
rawWriteChangesSetting(),
|
||||
readChangeSequence(),
|
||||
changePrimaryStorage(),
|
||||
disableChangeReviewDb(),
|
||||
fuseUpdates(),
|
||||
failOnLoad());
|
||||
return snapshot.get().hashCode();
|
||||
}
|
||||
|
||||
protected NotesMigration(Snapshot snapshot) {
|
||||
this.snapshot = new AtomicReference<>(snapshot);
|
||||
}
|
||||
|
||||
final Snapshot snapshot() {
|
||||
return snapshot.get();
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,10 @@
|
||||
package com.google.gerrit.server.notedb;
|
||||
|
||||
import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage;
|
||||
import com.google.gerrit.server.notedb.NotesMigration.Snapshot;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
|
||||
/**
|
||||
* Possible high-level states of the NoteDb migration for changes.
|
||||
@ -47,11 +49,22 @@ public enum NotesMigrationState {
|
||||
|
||||
NOTE_DB(true, true, true, PrimaryStorage.NOTE_DB, true, true);
|
||||
|
||||
public static Optional<NotesMigrationState> forNotesMigration(NotesMigration migration) {
|
||||
return Stream.of(values()).filter(s -> s.migration().equals(migration)).findFirst();
|
||||
// TODO(dborowitz): Replace with NOTE_DB when FileRepository fuses BatchRefUpdates.
|
||||
public static final NotesMigrationState FINAL = NOTE_DB_UNFUSED;
|
||||
|
||||
public static Optional<NotesMigrationState> forConfig(Config cfg) {
|
||||
return forSnapshot(Snapshot.create(cfg));
|
||||
}
|
||||
|
||||
private final NotesMigration migration;
|
||||
public static Optional<NotesMigrationState> forNotesMigration(NotesMigration migration) {
|
||||
return forSnapshot(migration.snapshot());
|
||||
}
|
||||
|
||||
private static Optional<NotesMigrationState> forSnapshot(Snapshot s) {
|
||||
return Stream.of(values()).filter(v -> v.snapshot.equals(s)).findFirst();
|
||||
}
|
||||
|
||||
private final Snapshot snapshot;
|
||||
|
||||
NotesMigrationState(
|
||||
// Arguments match abstract methods in NotesMigration.
|
||||
@ -61,45 +74,28 @@ public enum NotesMigrationState {
|
||||
PrimaryStorage changePrimaryStorage,
|
||||
boolean disableChangeReviewDb,
|
||||
boolean fuseUpdates) {
|
||||
this.migration =
|
||||
new NotesMigration() {
|
||||
@Override
|
||||
public boolean readChanges() {
|
||||
return readChanges;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean rawWriteChangesSetting() {
|
||||
return rawWriteChangesSetting;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readChangeSequence() {
|
||||
return readChangeSequence;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrimaryStorage changePrimaryStorage() {
|
||||
return changePrimaryStorage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean disableChangeReviewDb() {
|
||||
return disableChangeReviewDb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fuseUpdates() {
|
||||
return fuseUpdates;
|
||||
}
|
||||
};
|
||||
this.snapshot =
|
||||
Snapshot.builder()
|
||||
.setReadChanges(readChanges)
|
||||
.setWriteChanges(rawWriteChangesSetting)
|
||||
.setReadChangeSequence(readChangeSequence)
|
||||
.setChangePrimaryStorage(changePrimaryStorage)
|
||||
.setDisableChangeReviewDb(disableChangeReviewDb)
|
||||
.setFuseUpdates(fuseUpdates)
|
||||
.build();
|
||||
}
|
||||
|
||||
public NotesMigration migration() {
|
||||
return migration;
|
||||
public void setConfigValues(Config cfg) {
|
||||
snapshot.setConfigValues(cfg);
|
||||
}
|
||||
|
||||
public String toText() {
|
||||
return ConfigNotesMigration.toText(migration);
|
||||
Config cfg = new Config();
|
||||
setConfigValues(cfg);
|
||||
return cfg.toText();
|
||||
}
|
||||
|
||||
Snapshot snapshot() {
|
||||
return snapshot;
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.gerrit.reviewdb.server.ReviewDbUtil.unwrapDb;
|
||||
import static com.google.gerrit.server.notedb.ConfigNotesMigration.SECTION_NOTE_DB;
|
||||
import static com.google.gerrit.server.notedb.NotesMigration.SECTION_NOTE_DB;
|
||||
import static com.google.gerrit.server.notedb.NotesMigrationState.NOTE_DB_UNFUSED;
|
||||
import static com.google.gerrit.server.notedb.NotesMigrationState.READ_WRITE_NO_SEQUENCE;
|
||||
import static com.google.gerrit.server.notedb.NotesMigrationState.READ_WRITE_WITH_SEQUENCE_NOTE_DB_PRIMARY;
|
||||
@ -54,9 +54,8 @@ import com.google.gerrit.server.config.SitePaths;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.git.LockFailureException;
|
||||
import com.google.gerrit.server.git.WorkQueue;
|
||||
import com.google.gerrit.server.notedb.ConfigNotesMigration;
|
||||
import com.google.gerrit.server.notedb.MutableNotesMigration;
|
||||
import com.google.gerrit.server.notedb.NoteDbTable;
|
||||
import com.google.gerrit.server.notedb.NotesMigration;
|
||||
import com.google.gerrit.server.notedb.NotesMigrationState;
|
||||
import com.google.gerrit.server.notedb.PrimaryStorageMigrator;
|
||||
import com.google.gerrit.server.notedb.RepoSequence;
|
||||
@ -114,7 +113,7 @@ public class NoteDbMigrator implements AutoCloseable {
|
||||
private final ThreadLocalRequestContext requestContext;
|
||||
private final ChangeRebuilder rebuilder;
|
||||
private final WorkQueue workQueue;
|
||||
private final NotesMigration globalNotesMigration;
|
||||
private final MutableNotesMigration globalNotesMigration;
|
||||
private final PrimaryStorageMigrator primaryStorageMigrator;
|
||||
|
||||
private int threads;
|
||||
@ -138,7 +137,7 @@ public class NoteDbMigrator implements AutoCloseable {
|
||||
InternalUser.Factory userFactory,
|
||||
ChangeRebuilder rebuilder,
|
||||
WorkQueue workQueue,
|
||||
NotesMigration globalNotesMigration,
|
||||
MutableNotesMigration globalNotesMigration,
|
||||
PrimaryStorageMigrator primaryStorageMigrator) {
|
||||
this.cfg = cfg;
|
||||
this.sitePaths = sitePaths;
|
||||
@ -327,7 +326,7 @@ public class NoteDbMigrator implements AutoCloseable {
|
||||
private final ThreadLocalRequestContext requestContext;
|
||||
private final InternalUser.Factory userFactory;
|
||||
private final ChangeRebuilder rebuilder;
|
||||
private final NotesMigration globalNotesMigration;
|
||||
private final MutableNotesMigration globalNotesMigration;
|
||||
private final PrimaryStorageMigrator primaryStorageMigrator;
|
||||
|
||||
private final ListeningExecutorService executor;
|
||||
@ -348,7 +347,7 @@ public class NoteDbMigrator implements AutoCloseable {
|
||||
ThreadLocalRequestContext requestContext,
|
||||
InternalUser.Factory userFactory,
|
||||
ChangeRebuilder rebuilder,
|
||||
NotesMigration globalNotesMigration,
|
||||
MutableNotesMigration globalNotesMigration,
|
||||
PrimaryStorageMigrator primaryStorageMigrator,
|
||||
ListeningExecutorService executor,
|
||||
ImmutableList<Project.NameKey> projects,
|
||||
@ -568,7 +567,7 @@ public class NoteDbMigrator implements AutoCloseable {
|
||||
private Optional<NotesMigrationState> loadState() throws IOException {
|
||||
try {
|
||||
gerritConfig.load();
|
||||
return NotesMigrationState.forNotesMigration(new ConfigNotesMigration(gerritConfig));
|
||||
return NotesMigrationState.forConfig(gerritConfig);
|
||||
} catch (ConfigInvalidException | IllegalArgumentException e) {
|
||||
log.warn("error reading NoteDb migration options from " + gerritConfig.getFile(), e);
|
||||
return Optional.empty();
|
||||
@ -601,12 +600,12 @@ public class NoteDbMigrator implements AutoCloseable {
|
||||
? "But found this state:\n" + actualOldState.get().toText()
|
||||
: "But could not parse the current state"));
|
||||
}
|
||||
ConfigNotesMigration.setConfigValues(gerritConfig, newState.migration());
|
||||
newState.setConfigValues(gerritConfig);
|
||||
additionalUpdates.accept(gerritConfig);
|
||||
gerritConfig.save();
|
||||
|
||||
// Only set in-memory state once it's been persisted to storage.
|
||||
globalNotesMigration.setFrom(newState.migration());
|
||||
globalNotesMigration.setFrom(newState);
|
||||
|
||||
return newState;
|
||||
}
|
||||
@ -744,6 +743,7 @@ public class NoteDbMigrator implements AutoCloseable {
|
||||
private class ContextHelper implements AutoCloseable {
|
||||
private final Thread callingThread;
|
||||
private ReviewDb db;
|
||||
private Runnable closeDb;
|
||||
|
||||
ContextHelper() {
|
||||
callingThread = Thread.currentThread();
|
||||
@ -760,8 +760,10 @@ public class NoteDbMigrator implements AutoCloseable {
|
||||
|
||||
synchronized ReviewDb getReviewDb() throws OrmException {
|
||||
if (db == null) {
|
||||
ReviewDb actual = schemaFactory.open();
|
||||
closeDb = actual::close;
|
||||
db =
|
||||
new ReviewDbWrapper(unwrapDb(schemaFactory.open())) {
|
||||
new ReviewDbWrapper(unwrapDb(actual)) {
|
||||
@Override
|
||||
public void close() {
|
||||
// Closed by ContextHelper#close.
|
||||
@ -774,7 +776,9 @@ public class NoteDbMigrator implements AutoCloseable {
|
||||
@Override
|
||||
public synchronized void close() {
|
||||
if (db != null) {
|
||||
db.close();
|
||||
closeDb.run();
|
||||
db = null;
|
||||
closeDb = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,6 @@ import com.google.gerrit.testutil.FakeAccountCache;
|
||||
import com.google.gerrit.testutil.GerritBaseTests;
|
||||
import com.google.gerrit.testutil.InMemoryRepositoryManager;
|
||||
import com.google.gerrit.testutil.TestChanges;
|
||||
import com.google.gerrit.testutil.TestNotesMigration;
|
||||
import com.google.gerrit.testutil.TestTimeUtil;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.gwtorm.server.SchemaFactory;
|
||||
@ -98,8 +97,6 @@ public abstract class AbstractChangeNotesTest extends GerritBaseTests {
|
||||
|
||||
private static final TimeZone TZ = TimeZone.getTimeZone("America/Los_Angeles");
|
||||
|
||||
private static final NotesMigration MIGRATION = new TestNotesMigration().setAllEnabled(true);
|
||||
|
||||
protected Account.Id otherUserId;
|
||||
protected FakeAccountCache accountCache;
|
||||
protected IdentifiedUser changeOwner;
|
||||
@ -154,7 +151,6 @@ public abstract class AbstractChangeNotesTest extends GerritBaseTests {
|
||||
install(NoteDbModule.forTest(testConfig));
|
||||
bind(AllUsersName.class).toProvider(AllUsersNameProvider.class);
|
||||
bind(String.class).annotatedWith(GerritServerId.class).toInstance("gerrit");
|
||||
bind(NotesMigration.class).toInstance(MIGRATION);
|
||||
bind(GitRepositoryManager.class).toInstance(repoManager);
|
||||
bind(ProjectCache.class).toProvider(Providers.<ProjectCache>of(null));
|
||||
bind(Config.class).annotatedWith(GerritServerConfig.class).toInstance(testConfig);
|
||||
@ -177,6 +173,11 @@ public abstract class AbstractChangeNotesTest extends GerritBaseTests {
|
||||
bind(MetricMaker.class).to(DisabledMetricMaker.class);
|
||||
bind(ReviewDb.class).toProvider(Providers.<ReviewDb>of(null));
|
||||
|
||||
MutableNotesMigration migration = MutableNotesMigration.newDisabled();
|
||||
migration.setFrom(NotesMigrationState.FINAL);
|
||||
bind(MutableNotesMigration.class).toInstance(migration);
|
||||
bind(NotesMigration.class).to(MutableNotesMigration.class);
|
||||
|
||||
// Tests don't support ReviewDb at all, but bindings are required via NoteDbModule.
|
||||
bind(new TypeLiteral<SchemaFactory<ReviewDb>>() {})
|
||||
.toInstance(
|
||||
|
@ -30,7 +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.server.notedb.NotesMigration;
|
||||
import com.google.gerrit.testutil.InMemoryDatabase;
|
||||
import com.google.gerrit.testutil.InMemoryH2Type;
|
||||
import com.google.gerrit.testutil.InMemoryRepositoryManager;
|
||||
@ -113,7 +113,7 @@ public class SchemaUpdaterTest {
|
||||
bind(DataSourceType.class).to(InMemoryH2Type.class);
|
||||
|
||||
bind(SystemGroupBackend.class);
|
||||
install(new ConfigNotesMigration.Module());
|
||||
install(new NotesMigration.Module());
|
||||
}
|
||||
})
|
||||
.getInstance(SchemaUpdater.class);
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
package com.google.gerrit.testutil;
|
||||
|
||||
import com.google.gerrit.server.notedb.MutableNotesMigration;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.TestRule;
|
||||
@ -27,7 +28,7 @@ public class GerritServerTests extends GerritBaseTests {
|
||||
|
||||
@ConfigSuite.Name private String configName;
|
||||
|
||||
protected TestNotesMigration notesMigration;
|
||||
protected MutableNotesMigration notesMigration;
|
||||
|
||||
@Rule
|
||||
public TestRule testRunner =
|
||||
@ -49,10 +50,10 @@ public class GerritServerTests extends GerritBaseTests {
|
||||
};
|
||||
|
||||
public void beforeTest() throws Exception {
|
||||
notesMigration = new TestNotesMigration();
|
||||
notesMigration = NoteDbMode.newNotesMigrationFromEnv();
|
||||
}
|
||||
|
||||
public void afterTest() {
|
||||
notesMigration.resetFromEnv();
|
||||
NoteDbMode.resetFromEnv(notesMigration);
|
||||
}
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ import com.google.gerrit.server.index.group.GroupSchemaDefinitions;
|
||||
import com.google.gerrit.server.mail.SignedTokenEmailTokenVerifier;
|
||||
import com.google.gerrit.server.notedb.ChangeBundleReader;
|
||||
import com.google.gerrit.server.notedb.GwtormChangeBundleReader;
|
||||
import com.google.gerrit.server.notedb.MutableNotesMigration;
|
||||
import com.google.gerrit.server.notedb.NotesMigration;
|
||||
import com.google.gerrit.server.patch.DiffExecutor;
|
||||
import com.google.gerrit.server.project.DefaultPermissionBackendModule;
|
||||
@ -118,13 +119,13 @@ public class InMemoryModule extends FactoryModule {
|
||||
}
|
||||
|
||||
private final Config cfg;
|
||||
private final TestNotesMigration notesMigration;
|
||||
private final MutableNotesMigration notesMigration;
|
||||
|
||||
public InMemoryModule() {
|
||||
this(newDefaultConfig(), new TestNotesMigration());
|
||||
this(newDefaultConfig(), NoteDbMode.newNotesMigrationFromEnv());
|
||||
}
|
||||
|
||||
public InMemoryModule(Config cfg, TestNotesMigration notesMigration) {
|
||||
public InMemoryModule(Config cfg, MutableNotesMigration notesMigration) {
|
||||
this.cfg = cfg;
|
||||
this.notesMigration = notesMigration;
|
||||
}
|
||||
@ -176,7 +177,8 @@ public class InMemoryModule extends FactoryModule {
|
||||
bind(GitRepositoryManager.class).to(InMemoryRepositoryManager.class);
|
||||
bind(InMemoryRepositoryManager.class).in(SINGLETON);
|
||||
bind(TrackingFooters.class).toProvider(TrackingFootersProvider.class).in(SINGLETON);
|
||||
bind(NotesMigration.class).toInstance(notesMigration);
|
||||
bind(MutableNotesMigration.class).toInstance(notesMigration);
|
||||
bind(NotesMigration.class).to(MutableNotesMigration.class);
|
||||
bind(ListeningExecutorService.class)
|
||||
.annotatedWith(ChangeUpdateExecutor.class)
|
||||
.toInstance(MoreExecutors.newDirectExecutorService());
|
||||
|
@ -32,7 +32,7 @@ import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
|
||||
/** Repository manager that uses in-memory repositories. */
|
||||
public class InMemoryRepositoryManager implements GitRepositoryManager {
|
||||
public static InMemoryRepository newRepository(Project.NameKey name) {
|
||||
return new Repo(new TestNotesMigration(), name);
|
||||
return new Repo(NoteDbMode.newNotesMigrationFromEnv(), name);
|
||||
}
|
||||
|
||||
public static class Description extends DfsRepositoryDescription {
|
||||
@ -82,7 +82,7 @@ public class InMemoryRepositoryManager implements GitRepositoryManager {
|
||||
private final Map<String, Repo> repos;
|
||||
|
||||
public InMemoryRepositoryManager() {
|
||||
this(new TestNotesMigration());
|
||||
this(NoteDbMode.newNotesMigrationFromEnv());
|
||||
}
|
||||
|
||||
@Inject
|
||||
|
@ -29,6 +29,7 @@ import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.notedb.ChangeBundle;
|
||||
import com.google.gerrit.server.notedb.ChangeBundleReader;
|
||||
import com.google.gerrit.server.notedb.ChangeNotes;
|
||||
import com.google.gerrit.server.notedb.MutableNotesMigration;
|
||||
import com.google.gerrit.server.notedb.rebuild.ChangeRebuilder;
|
||||
import com.google.gwtorm.client.IntKey;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
@ -52,7 +53,7 @@ public class NoteDbChecker {
|
||||
|
||||
private final Provider<ReviewDb> dbProvider;
|
||||
private final GitRepositoryManager repoManager;
|
||||
private final TestNotesMigration notesMigration;
|
||||
private final MutableNotesMigration notesMigration;
|
||||
private final ChangeBundleReader bundleReader;
|
||||
private final ChangeNotes.Factory notesFactory;
|
||||
private final ChangeRebuilder changeRebuilder;
|
||||
@ -62,7 +63,7 @@ public class NoteDbChecker {
|
||||
NoteDbChecker(
|
||||
Provider<ReviewDb> dbProvider,
|
||||
GitRepositoryManager repoManager,
|
||||
TestNotesMigration notesMigration,
|
||||
MutableNotesMigration notesMigration,
|
||||
ChangeBundleReader bundleReader,
|
||||
ChangeNotes.Factory notesFactory,
|
||||
ChangeRebuilder changeRebuilder,
|
||||
|
@ -18,7 +18,7 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import com.google.common.base.Enums;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.gerrit.server.notedb.NotesMigration;
|
||||
import com.google.gerrit.server.notedb.MutableNotesMigration;
|
||||
import com.google.gerrit.server.notedb.NotesMigrationState;
|
||||
|
||||
public enum NoteDbMode {
|
||||
@ -72,14 +72,19 @@ public enum NoteDbMode {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public static boolean readWrite() {
|
||||
NotesMigration migration = get().migration;
|
||||
return migration.rawWriteChangesSetting() && migration.readChanges();
|
||||
public static MutableNotesMigration newNotesMigrationFromEnv() {
|
||||
MutableNotesMigration m = MutableNotesMigration.newDisabled();
|
||||
resetFromEnv(m);
|
||||
return m;
|
||||
}
|
||||
|
||||
final NotesMigration migration;
|
||||
public static void resetFromEnv(MutableNotesMigration migration) {
|
||||
migration.setFrom(get().state);
|
||||
}
|
||||
|
||||
private final NotesMigrationState state;
|
||||
|
||||
private NoteDbMode(NotesMigrationState state) {
|
||||
migration = state.migration();
|
||||
this.state = state;
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ public class TempFileUtil {
|
||||
allDirsCreated.clear();
|
||||
}
|
||||
|
||||
private static void recursivelyDelete(File dir) throws IOException {
|
||||
public static void recursivelyDelete(File dir) throws IOException {
|
||||
if (!dir.getPath().equals(dir.getCanonicalPath())) {
|
||||
// Directory symlink reaching outside of temporary space.
|
||||
return;
|
||||
|
@ -1,128 +0,0 @@
|
||||
// Copyright (C) 2016 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.testutil;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage;
|
||||
import com.google.gerrit.server.notedb.NotesMigration;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
/** {@link NotesMigration} with bits that can be flipped live for testing. */
|
||||
@Singleton
|
||||
public class TestNotesMigration extends NotesMigration {
|
||||
private volatile boolean readChanges;
|
||||
private volatile boolean writeChanges;
|
||||
private volatile boolean readChangeSequence;
|
||||
private volatile PrimaryStorage changePrimaryStorage = PrimaryStorage.REVIEW_DB;
|
||||
private volatile boolean disableChangeReviewDb;
|
||||
private volatile boolean fuseUpdates;
|
||||
private volatile boolean failOnLoad;
|
||||
|
||||
public TestNotesMigration() {
|
||||
resetFromEnv();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readChanges() {
|
||||
return readChanges;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readChangeSequence() {
|
||||
return readChangeSequence;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrimaryStorage changePrimaryStorage() {
|
||||
return changePrimaryStorage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean disableChangeReviewDb() {
|
||||
return disableChangeReviewDb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fuseUpdates() {
|
||||
return fuseUpdates;
|
||||
}
|
||||
|
||||
// Increase visbility from superclass, as tests may want to check whether
|
||||
// NoteDb data is written in specific migration scenarios.
|
||||
@Override
|
||||
public boolean rawWriteChangesSetting() {
|
||||
return writeChanges;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean failOnLoad() {
|
||||
return failOnLoad;
|
||||
}
|
||||
|
||||
public TestNotesMigration setReadChanges(boolean readChanges) {
|
||||
this.readChanges = readChanges;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TestNotesMigration setWriteChanges(boolean writeChanges) {
|
||||
this.writeChanges = writeChanges;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TestNotesMigration setReadChangeSequence(boolean readChangeSequence) {
|
||||
this.readChangeSequence = readChangeSequence;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TestNotesMigration setChangePrimaryStorage(PrimaryStorage changePrimaryStorage) {
|
||||
this.changePrimaryStorage = checkNotNull(changePrimaryStorage);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TestNotesMigration setDisableChangeReviewDb(boolean disableChangeReviewDb) {
|
||||
this.disableChangeReviewDb = disableChangeReviewDb;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TestNotesMigration setFuseUpdates(boolean fuseUpdates) {
|
||||
this.fuseUpdates = fuseUpdates;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TestNotesMigration setFailOnLoad(boolean failOnLoad) {
|
||||
this.failOnLoad = failOnLoad;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TestNotesMigration setAllEnabled(boolean enabled) {
|
||||
return setReadChanges(enabled).setWriteChanges(enabled);
|
||||
}
|
||||
|
||||
public TestNotesMigration resetFromEnv() {
|
||||
return setFrom(NoteDbMode.get().migration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestNotesMigration setFrom(NotesMigration other) {
|
||||
setWriteChanges(other.rawWriteChangesSetting());
|
||||
setReadChanges(other.readChanges());
|
||||
setReadChangeSequence(other.readChangeSequence());
|
||||
setChangePrimaryStorage(other.changePrimaryStorage());
|
||||
setDisableChangeReviewDb(other.disableChangeReviewDb());
|
||||
setFuseUpdates(other.fuseUpdates());
|
||||
return this;
|
||||
}
|
||||
}
|
@ -58,7 +58,7 @@ import com.google.gerrit.server.mail.SignedTokenEmailTokenVerifier;
|
||||
import com.google.gerrit.server.mail.receive.MailReceiver;
|
||||
import com.google.gerrit.server.mail.send.SmtpEmailSender;
|
||||
import com.google.gerrit.server.mime.MimeUtil2Module;
|
||||
import com.google.gerrit.server.notedb.ConfigNotesMigration;
|
||||
import com.google.gerrit.server.notedb.NotesMigration;
|
||||
import com.google.gerrit.server.patch.DiffExecutorModule;
|
||||
import com.google.gerrit.server.plugins.PluginGuiceEnvironment;
|
||||
import com.google.gerrit.server.plugins.PluginModule;
|
||||
@ -292,7 +292,7 @@ public class WebAppInitializer extends GuiceServletContextListener implements Fi
|
||||
modules.add(new GerritServerConfigModule());
|
||||
}
|
||||
modules.add(new DatabaseModule());
|
||||
modules.add(new ConfigNotesMigration.Module());
|
||||
modules.add(new NotesMigration.Module());
|
||||
modules.add(new DropWizardMetricMaker.ApiModule());
|
||||
return Guice.createInjector(PRODUCTION, modules);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user