summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--.settings/org.eclipse.jdt.core.prefs6
-rw-r--r--BUCK40
-rw-r--r--BUILD46
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadConfigDecorator.java62
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadSecureCredentialsFactoryDecorator.java38
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/CredentialsFactory.java1
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java283
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/DestinationConfiguration.java44
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/DestinationFactory.java70
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/Init.java70
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/ListCommand.java47
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/OnStartStop.java9
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/PushAll.java8
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java194
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/PushResultProcessing.java39
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/RefReplicatedEvent.java10
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/RemoteSiteUser.java4
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationConfig.java2
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationFileBasedConfig.java130
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationFilter.java10
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationLogFile.java9
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationMetrics.java42
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationModule.java34
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java171
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationScheduledEvent.java44
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationSshSessionFactoryProvider.java1
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationState.java37
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationStateListener.java16
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationStateLogger.java9
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/SecureCredentialsFactory.java21
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/SecureCredentialsProvider.java3
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/replication/StartCommand.java24
-rw-r--r--src/main/resources/Documentation/cmd-list.md2
-rw-r--r--src/main/resources/Documentation/cmd-start.md2
-rw-r--r--src/main/resources/Documentation/config.md15
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/replication/GitUpdateProcessingTest.java62
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/replication/PushReplicationTest.java5
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/replication/RefReplicatedEventEquals.java2
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/replication/RefReplicationDoneEventEquals.java2
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/replication/ReplicationStateTest.java129
41 files changed, 930 insertions, 817 deletions
diff --git a/.gitignore b/.gitignore
index 9c143f3..1e8377d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,4 @@
/.settings/org.eclipse.m2e.core.prefs
/.idea
replication.iml
-/.buckd
-/buck-cache
-/buck-out
+*.iml
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
index 17904c0..1792fcc 100644
--- a/.settings/org.eclipse.jdt.core.prefs
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -1,9 +1,9 @@
#Fri Jul 16 23:39:13 PDT 2010
eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.source=1.8
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
diff --git a/BUCK b/BUCK
deleted file mode 100644
index d658b92..0000000
--- a/BUCK
+++ /dev/null
@@ -1,40 +0,0 @@
-include_defs('//lib/maven.defs')
-
-gerrit_plugin(
- name = 'replication',
- srcs = glob(['src/main/java/**/*.java']),
- resources = glob(['src/main/resources/**/*']),
- manifest_entries = [
- 'Implementation-Title: Replication plugin',
- 'Implementation-URL: https://gerrit-review.googlesource.com/#/admin/projects/plugins/replication',
- 'Gerrit-PluginName: replication',
- 'Gerrit-Module: com.googlesource.gerrit.plugins.replication.ReplicationModule',
- 'Gerrit-SshModule: com.googlesource.gerrit.plugins.replication.SshModule'
- ],
- deps = [
- ':commons-io',
- ],
- provided_deps = [
- '//lib:gson',
- '//lib/log:log4j'
- ],
-)
-
-maven_jar(
- name = 'commons-io',
- id = 'commons-io:commons-io:1.4',
- sha1 = 'a8762d07e76cfde2395257a5da47ba7c1dbd3dce',
- license = 'Apache2.0',
-)
-
-java_test(
- name = 'replication_tests',
- srcs = glob(['src/test/java/**/*.java']),
- labels = ['replication'],
- source_under_test = [':replication__plugin'],
- deps = [
- ':replication__plugin',
- '//gerrit-acceptance-framework:lib',
- '//gerrit-plugin-api:lib',
- ],
-)
diff --git a/BUILD b/BUILD
new file mode 100644
index 0000000..1cad80c
--- /dev/null
+++ b/BUILD
@@ -0,0 +1,46 @@
+load("//tools/bzl:junit.bzl", "junit_tests")
+load("//tools/bzl:plugin.bzl", "gerrit_plugin")
+
+gerrit_plugin(
+ name = "replication",
+ srcs = glob(["src/main/java/**/*.java"]),
+ manifest_entries = [
+ "Implementation-Title: Replication plugin",
+ "Implementation-URL: https://gerrit-review.googlesource.com/#/admin/projects/plugins/replication",
+ "Gerrit-PluginName: replication",
+ "Gerrit-InitStep: com.googlesource.gerrit.plugins.replication.Init",
+ "Gerrit-Module: com.googlesource.gerrit.plugins.replication.ReplicationModule",
+ "Gerrit-SshModule: com.googlesource.gerrit.plugins.replication.SshModule",
+ ],
+ resources = glob(["src/main/resources/**/*"]),
+ deps = [
+ "//lib:commons-io",
+ ],
+)
+
+junit_tests(
+ name = "replication_tests",
+ srcs = glob(["src/test/java/**/*Test.java"]),
+ tags = ["replication"],
+ visibility = ["//visibility:public"],
+ deps = [
+ ":replication__plugin",
+ ":replication_util",
+ "//gerrit-acceptance-framework:lib",
+ "//gerrit-plugin-api:lib",
+ ],
+)
+
+java_library(
+ name = "replication_util",
+ testonly = 1,
+ srcs = glob(
+ ["src/test/java/**/*.java"],
+ exclude = ["src/test/java/**/*Test.java"],
+ ),
+ deps = [
+ ":replication__plugin",
+ "//gerrit-acceptance-framework:lib",
+ "//gerrit-plugin-api:lib",
+ ],
+)
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadConfigDecorator.java b/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadConfigDecorator.java
index 22b29b1..55c7072 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadConfigDecorator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadConfigDecorator.java
@@ -14,73 +14,43 @@
package com.googlesource.gerrit.plugins.replication;
import com.google.gerrit.common.FileUtil;
-import com.google.gerrit.server.PluginUser;
-import com.google.gerrit.server.account.GroupBackend;
-import com.google.gerrit.server.account.GroupIncludeCache;
import com.google.gerrit.server.config.SitePaths;
-import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.WorkQueue;
import com.google.inject.Inject;
-import com.google.inject.Injector;
import com.google.inject.Singleton;
-
+import java.io.IOException;
+import java.util.List;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.util.List;
-
@Singleton
public class AutoReloadConfigDecorator implements ReplicationConfig {
- private static final Logger log = LoggerFactory
- .getLogger(AutoReloadConfigDecorator.class);
+ private static final Logger log = LoggerFactory.getLogger(AutoReloadConfigDecorator.class);
private ReplicationFileBasedConfig currentConfig;
private long currentConfigTs;
- private final Injector injector;
private final SitePaths site;
- private final RemoteSiteUser.Factory remoteSiteUserFactory;
- private final PluginUser pluginUser;
- private final GitRepositoryManager gitRepositoryManager;
- private final GroupBackend groupBackend;
private final WorkQueue workQueue;
- private final ReplicationStateListener stateLog;
- private final GroupIncludeCache groupIncludeCache;
+ private final DestinationFactory destinationFactory;
@Inject
- public AutoReloadConfigDecorator(Injector injector,
- SitePaths site,
- RemoteSiteUser.Factory ruf,
- PluginUser pu,
- GitRepositoryManager grm,
- GroupBackend gb,
- WorkQueue workQueue,
- ReplicationStateListener stateLog,
- GroupIncludeCache groupIncludeCache)
+ public AutoReloadConfigDecorator(
+ SitePaths site, WorkQueue workQueue, DestinationFactory destinationFactory)
throws ConfigInvalidException, IOException {
- this.injector = injector;
this.site = site;
- this.remoteSiteUserFactory = ruf;
- this.pluginUser = pu;
- this.gitRepositoryManager = grm;
- this.groupBackend = gb;
- this.groupIncludeCache = groupIncludeCache;
+ this.destinationFactory = destinationFactory;
this.currentConfig = loadConfig();
this.currentConfigTs = getLastModified(currentConfig);
this.workQueue = workQueue;
- this.stateLog = stateLog;
}
private static long getLastModified(ReplicationFileBasedConfig cfg) {
return FileUtil.lastModified(cfg.getCfgPath());
}
- private ReplicationFileBasedConfig loadConfig()
- throws ConfigInvalidException, IOException {
- return new ReplicationFileBasedConfig(injector, site, remoteSiteUserFactory,
- pluginUser, gitRepositoryManager, groupBackend, stateLog,
- groupIncludeCache);
+ private ReplicationFileBasedConfig loadConfig() throws ConfigInvalidException, IOException {
+ return new ReplicationFileBasedConfig(site, destinationFactory);
}
private synchronized boolean isAutoReload() {
@@ -104,16 +74,16 @@ public class AutoReloadConfigDecorator implements ReplicationConfig {
this.currentConfig = newConfig;
this.currentConfigTs = lastModified;
- log.info("Configuration reloaded: "
- + currentConfig.getDestinations(FilterType.ALL).size() + " destinations, "
- + discarded + " replication events discarded");
-
+ log.info(
+ "Configuration reloaded: "
+ + currentConfig.getDestinations(FilterType.ALL).size()
+ + " destinations, "
+ + discarded
+ + " replication events discarded");
}
}
} catch (Exception e) {
- log.error(
- "Cannot reload replication configuration: keeping existing settings",
- e);
+ log.error("Cannot reload replication configuration: keeping existing settings", e);
return;
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadSecureCredentialsFactoryDecorator.java b/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadSecureCredentialsFactoryDecorator.java
index 3a0cc3f..f8737b6 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadSecureCredentialsFactoryDecorator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadSecureCredentialsFactoryDecorator.java
@@ -18,19 +18,16 @@ import static com.google.gerrit.common.FileUtil.lastModified;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.Inject;
-
-import org.eclipse.jgit.errors.ConfigInvalidException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.io.IOException;
import java.nio.file.Files;
import java.util.concurrent.atomic.AtomicReference;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
-public class AutoReloadSecureCredentialsFactoryDecorator implements
- CredentialsFactory {
- private static final Logger log = LoggerFactory
- .getLogger(AutoReloadSecureCredentialsFactoryDecorator.class);
+public class AutoReloadSecureCredentialsFactoryDecorator implements CredentialsFactory {
+ private static final Logger log =
+ LoggerFactory.getLogger(AutoReloadSecureCredentialsFactoryDecorator.class);
private final AtomicReference<SecureCredentialsFactory> secureCredentialsFactory;
private volatile long secureCredentialsFactoryLoadTs;
@@ -38,13 +35,12 @@ public class AutoReloadSecureCredentialsFactoryDecorator implements
private ReplicationFileBasedConfig config;
@Inject
- public AutoReloadSecureCredentialsFactoryDecorator(SitePaths site,
- ReplicationFileBasedConfig config) throws ConfigInvalidException,
- IOException {
+ public AutoReloadSecureCredentialsFactoryDecorator(
+ SitePaths site, ReplicationFileBasedConfig config)
+ throws ConfigInvalidException, IOException {
this.site = site;
this.config = config;
- this.secureCredentialsFactory =
- new AtomicReference<>(new SecureCredentialsFactory(site));
+ this.secureCredentialsFactory = new AtomicReference<>(new SecureCredentialsFactory(site));
this.secureCredentialsFactoryLoadTs = getSecureConfigLastEditTs();
}
@@ -59,21 +55,23 @@ public class AutoReloadSecureCredentialsFactoryDecorator implements
public SecureCredentialsProvider create(String remoteName) {
try {
if (needsReload()) {
- secureCredentialsFactory.compareAndSet(secureCredentialsFactory.get(),
- new SecureCredentialsFactory(site));
+ secureCredentialsFactory.compareAndSet(
+ secureCredentialsFactory.get(), new SecureCredentialsFactory(site));
secureCredentialsFactoryLoadTs = getSecureConfigLastEditTs();
log.info("secure.config reloaded as it was updated on the file system");
}
} catch (Exception e) {
- log.error("Unexpected error while trying to reload "
- + "secure.config: keeping existing credentials", e);
+ log.error(
+ "Unexpected error while trying to reload "
+ + "secure.config: keeping existing credentials",
+ e);
}
return secureCredentialsFactory.get().create(remoteName);
}
private boolean needsReload() {
- return config.getConfig().getBoolean("gerrit", "autoReload", false) &&
- getSecureConfigLastEditTs() != secureCredentialsFactoryLoadTs;
+ return config.getConfig().getBoolean("gerrit", "autoReload", false)
+ && getSecureConfigLastEditTs() != secureCredentialsFactoryLoadTs;
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/CredentialsFactory.java b/src/main/java/com/googlesource/gerrit/plugins/replication/CredentialsFactory.java
index e960533..10719c1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/CredentialsFactory.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/CredentialsFactory.java
@@ -16,5 +16,4 @@ package com.googlesource.gerrit.plugins.replication;
public interface CredentialsFactory {
SecureCredentialsProvider create(String remoteName);
-
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java b/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java
index ed361a9..f8e2d7b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java
@@ -14,15 +14,20 @@
package com.googlesource.gerrit.plugins.replication;
+import static com.googlesource.gerrit.plugins.replication.PushResultProcessing.resolveNodeName;
+
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.collect.Lists;
+import com.google.gerrit.common.EventDispatcher;
import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.extensions.config.FactoryModule;
+import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.reviewdb.server.ReviewDb;
@@ -45,16 +50,6 @@ import com.google.inject.Provider;
import com.google.inject.Provides;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import com.google.inject.servlet.RequestScoped;
-
-import org.apache.commons.io.FilenameUtils;
-import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.transport.RefSpec;
-import org.eclipse.jgit.transport.RemoteConfig;
-import org.eclipse.jgit.transport.URIish;
-import org.slf4j.Logger;
-
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
@@ -63,6 +58,14 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
+import org.apache.commons.io.FilenameUtils;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.RefSpec;
+import org.eclipse.jgit.transport.RemoteConfig;
+import org.eclipse.jgit.transport.URIish;
+import org.slf4j.Logger;
public class Destination {
private static final Logger repLog = ReplicationQueue.repLog;
@@ -76,31 +79,36 @@ public class Destination {
private volatile WorkQueue.Executor pool;
private final PerThreadRequestScope.Scoper threadScoper;
private final DestinationConfiguration config;
+ private final DynamicItem<EventDispatcher> eventDispatcher;
protected enum RetryReason {
- TRANSPORT_ERROR, COLLISION, REPOSITORY_MISSING;
+ TRANSPORT_ERROR,
+ COLLISION,
+ REPOSITORY_MISSING;
}
public static class QueueInfo {
public final Map<URIish, PushOne> pending;
public final Map<URIish, PushOne> inFlight;
- public QueueInfo(Map<URIish, PushOne> pending,
- Map<URIish, PushOne> inFlight) {
+ public QueueInfo(Map<URIish, PushOne> pending, Map<URIish, PushOne> inFlight) {
this.pending = ImmutableMap.copyOf(pending);
this.inFlight = ImmutableMap.copyOf(inFlight);
}
}
- protected Destination(Injector injector,
+ protected Destination(
+ Injector injector,
DestinationConfiguration cfg,
RemoteSiteUser.Factory replicationUserFactory,
PluginUser pluginUser,
GitRepositoryManager gitRepositoryManager,
GroupBackend groupBackend,
ReplicationStateListener stateLog,
- GroupIncludeCache groupIncludeCache) {
+ GroupIncludeCache groupIncludeCache,
+ DynamicItem<EventDispatcher> eventDispatcher) {
config = cfg;
+ this.eventDispatcher = eventDispatcher;
gitManager = gitRepositoryManager;
this.stateLog = stateLog;
@@ -113,59 +121,62 @@ public class Destination {
builder.add(g.getUUID());
addRecursiveParents(g.getUUID(), builder, groupIncludeCache);
} else {
- repLog.warn(String.format(
- "Group \"%s\" not recognized, removing from authGroup", name));
+ repLog.warn(String.format("Group \"%s\" not recognized, removing from authGroup", name));
}
}
- remoteUser = replicationUserFactory.create(
- new ListGroupMembership(builder.build()));
+ remoteUser = replicationUserFactory.create(new ListGroupMembership(builder.build()));
} else {
remoteUser = pluginUser;
}
- Injector child = injector.createChildInjector(new FactoryModule() {
- @Override
- protected void configure() {
- bindScope(RequestScoped.class, PerThreadRequestScope.REQUEST);
- bind(PerThreadRequestScope.Propagator.class);
- bind(PerRequestProjectControlCache.class).in(RequestScoped.class);
-
- bind(Destination.class).toInstance(Destination.this);
- bind(RemoteConfig.class).toInstance(config.getRemoteConfig());
- install(new FactoryModuleBuilder().build(PushOne.Factory.class));
- }
-
- @Provides
- public PerThreadRequestScope.Scoper provideScoper(
- final PerThreadRequestScope.Propagator propagator,
- final Provider<RequestScopedReviewDbProvider> dbProvider) {
- final RequestContext requestContext = new RequestContext() {
- @Override
- public CurrentUser getUser() {
- return remoteUser;
- }
-
- @Override
- public Provider<ReviewDb> getReviewDbProvider() {
- return dbProvider.get();
- }
- };
- return new PerThreadRequestScope.Scoper() {
- @Override
- public <T> Callable<T> scope(Callable<T> callable) {
- return propagator.scope(requestContext, callable);
- }
- };
- }
- });
+ Injector child =
+ injector.createChildInjector(
+ new FactoryModule() {
+ @Override
+ protected void configure() {
+ bindScope(RequestScoped.class, PerThreadRequestScope.REQUEST);
+ bind(PerThreadRequestScope.Propagator.class);
+ bind(PerRequestProjectControlCache.class).in(RequestScoped.class);
+
+ bind(Destination.class).toInstance(Destination.this);
+ bind(RemoteConfig.class).toInstance(config.getRemoteConfig());
+ install(new FactoryModuleBuilder().build(PushOne.Factory.class));
+ }
+
+ @Provides
+ public PerThreadRequestScope.Scoper provideScoper(
+ final PerThreadRequestScope.Propagator propagator,
+ final Provider<RequestScopedReviewDbProvider> dbProvider) {
+ final RequestContext requestContext =
+ new RequestContext() {
+ @Override
+ public CurrentUser getUser() {
+ return remoteUser;
+ }
+
+ @Override
+ public Provider<ReviewDb> getReviewDbProvider() {
+ return dbProvider.get();
+ }
+ };
+ return new PerThreadRequestScope.Scoper() {
+ @Override
+ public <T> Callable<T> scope(Callable<T> callable) {
+ return propagator.scope(requestContext, callable);
+ }
+ };
+ }
+ });
projectControlFactory = child.getInstance(ProjectControl.Factory.class);
opFactory = child.getInstance(PushOne.Factory.class);
threadScoper = child.getInstance(PerThreadRequestScope.Scoper.class);
}
- private void addRecursiveParents(AccountGroup.UUID g,
- Builder<AccountGroup.UUID> builder, GroupIncludeCache groupIncludeCache) {
+ private void addRecursiveParents(
+ AccountGroup.UUID g,
+ Builder<AccountGroup.UUID> builder,
+ GroupIncludeCache groupIncludeCache) {
for (AccountGroup.UUID p : groupIncludeCache.parentGroupsOf(g)) {
if (builder.build().contains(p)) {
continue;
@@ -200,52 +211,55 @@ public class Destination {
}
private boolean shouldReplicate(ProjectControl projectControl) {
- return projectControl.isReadable() && (!projectControl.isHidden()
- || config.replicateHiddenProjects());
+ return projectControl.isReadable()
+ && (!projectControl.isHidden() || config.replicateHiddenProjects());
}
- private boolean shouldReplicate(final Project.NameKey project, final String ref,
- ReplicationState... states) {
+ private boolean shouldReplicate(
+ final Project.NameKey project, final String ref, ReplicationState... states) {
try {
- return threadScoper.scope(new Callable<Boolean>() {
- @Override
- public Boolean call() throws NoSuchProjectException {
- ProjectControl projectControl = controlFor(project);
- return shouldReplicate(projectControl)
- && (PushOne.ALL_REFS.equals(ref)
- || projectControl.controlForRef(ref).isVisible());
- }
- }).call();
+ return threadScoper
+ .scope(
+ new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws NoSuchProjectException {
+ ProjectControl projectControl = controlFor(project);
+ return shouldReplicate(projectControl)
+ && (PushOne.ALL_REFS.equals(ref)
+ || projectControl.controlForRef(ref).isVisible());
+ }
+ })
+ .call();
} catch (NoSuchProjectException err) {
- stateLog.error(String.format("source project %s not available", project),
- err, states);
+ stateLog.error(String.format("source project %s not available", project), err, states);
} catch (Exception e) {
- throw Throwables.propagate(e);
+ Throwables.throwIfUnchecked(e);
+ throw new RuntimeException(e);
}
return false;
}
- private boolean shouldReplicate(final Project.NameKey project,
- ReplicationState... states) {
+ private boolean shouldReplicate(final Project.NameKey project, ReplicationState... states) {
try {
- return threadScoper.scope(new Callable<Boolean>() {
- @Override
- public Boolean call() throws NoSuchProjectException {
- return shouldReplicate(controlFor(project));
- }
- }).call();
+ return threadScoper
+ .scope(
+ new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws NoSuchProjectException {
+ return shouldReplicate(controlFor(project));
+ }
+ })
+ .call();
} catch (NoSuchProjectException err) {
- stateLog.error(String.format("source project %s not available", project),
- err, states);
+ stateLog.error(String.format("source project %s not available", project), err, states);
} catch (Exception e) {
- Throwables.propagateIfPossible(e);
+ Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
}
return false;
}
- void schedule(Project.NameKey project, String ref, URIish uri,
- ReplicationState state) {
+ void schedule(Project.NameKey project, String ref, URIish uri, ReplicationState state) {
repLog.info("scheduling replication {}:{} => {}", project, ref, uri);
if (!shouldReplicate(project, ref, state)) {
return;
@@ -266,13 +280,11 @@ public class Destination {
return;
}
} catch (IOException err) {
- stateLog.error(String.format(
- "cannot check type of project %s", project), err, state);
+ stateLog.error(String.format("cannot check type of project %s", project), err, state);
return;
}
} catch (IOException err) {
- stateLog.error(String.format(
- "source project %s not available", project), err, state);
+ stateLog.error(String.format("source project %s not available", project), err, state);
return;
}
}
@@ -282,14 +294,16 @@ public class Destination {
PushOne e = pending.get(uri);
if (e == null) {
e = opFactory.create(project, uri);
+ addRef(e, ref);
+ e.addState(ref, state);
pool.schedule(e, config.getDelay(), TimeUnit.SECONDS);
pending.put(uri, e);
+ } else if (!e.getRefs().contains(ref)) {
+ addRef(e, ref);
+ e.addState(ref, state);
}
- e.addRef(ref);
state.increasePushTaskCount(project.get(), ref);
- e.addState(ref, state);
- repLog.info("scheduled {}:{} => {} to run after {}s", project, ref,
- e, config.getDelay());
+ repLog.info("scheduled {}:{} => {} to run after {}s", project, ref, e, config.getDelay());
}
}
@@ -300,32 +314,29 @@ public class Destination {
}
}
+ private void addRef(PushOne e, String ref) {
+ e.addRef(ref);
+ postEvent(e, ref);
+ }
+
/**
* It schedules again a PushOp instance.
- * <p>
- * If the reason for rescheduling is to avoid a collision
- * with an in-flight push to the same URI, we don't
- * mark the operation as "retrying," and we schedule
- * using the replication delay, rather than the retry
- * delay. Otherwise, the operation is marked as
- * "retrying" and scheduled to run following the
- * minutes count determined by class attribute retryDelay.
- * <p>
- * In case the PushOp instance to be scheduled has same
- * URI than one marked as "retrying," it adds to the one
- * pending the refs list of the parameter instance.
- * <p>
- * In case the PushOp instance to be scheduled has the
- * same URI as one pending, but not marked "retrying," it
- * indicates the one pending should be canceled when it
- * starts executing, removes it from pending list, and
- * adds its refs to the parameter instance. The parameter
- * instance is scheduled for retry.
- * <p>
- * Notice all operations to indicate a PushOp should be
- * canceled, or it is retrying, or remove/add it from/to
- * pending Map should be protected by synchronizing on the
- * stateLock object.
+ *
+ * <p>If the reason for rescheduling is to avoid a collision with an in-flight push to the same
+ * URI, we don't mark the operation as "retrying," and we schedule using the replication delay,
+ * rather than the retry delay. Otherwise, the operation is marked as "retrying" and scheduled to
+ * run following the minutes count determined by class attribute retryDelay.
+ *
+ * <p>In case the PushOp instance to be scheduled has same URI than one marked as "retrying," it
+ * adds to the one pending the refs list of the parameter instance.
+ *
+ * <p>In case the PushOp instance to be scheduled has the same URI as one pending, but not marked
+ * "retrying," it indicates the one pending should be canceled when it starts executing, removes
+ * it from pending list, and adds its refs to the parameter instance. The parameter instance is
+ * scheduled for retry.
+ *
+ * <p>Notice all operations to indicate a PushOp should be canceled, or it is retrying, or
+ * remove/add it from/to pending Map should be protected by synchronizing on the stateLock object.
*
* @param pushOp The PushOp instance to be scheduled.
*/
@@ -378,13 +389,19 @@ public class Destination {
pending.put(uri, pushOp);
switch (reason) {
case COLLISION:
- pool.schedule(pushOp, config.getDelay(), TimeUnit.SECONDS);
+ pool.schedule(pushOp, config.getRescheduleDelay(), TimeUnit.SECONDS);
break;
case TRANSPORT_ERROR:
case REPOSITORY_MISSING:
default:
if (pushOp.setToRetry()) {
pool.schedule(pushOp, config.getRetryDelay(), TimeUnit.MINUTES);
+ } else {
+ pushOp.canceledByReplication();
+ pending.remove(uri);
+ stateLog.error(
+ "Push to " + pushOp.getURI() + " cancelled after maximum number of retries",
+ pushOp.getStatesAsArray());
}
break;
}
@@ -392,8 +409,7 @@ public class Destination {
}
}
- ProjectControl controlFor(Project.NameKey project)
- throws NoSuchProjectException {
+ ProjectControl controlFor(Project.NameKey project) throws NoSuchProjectException {
return projectControlFactory.controlFor(project);
}
@@ -474,8 +490,7 @@ public class Destination {
}
List<URIish> getURIs(Project.NameKey project, String urlMatch) {
- List<URIish> r = Lists.newArrayListWithCapacity(
- config.getRemoteConfig().getURIs().size());
+ List<URIish> r = Lists.newArrayListWithCapacity(config.getRemoteConfig().getURIs().size());
for (URIish uri : config.getRemoteConfig().getURIs()) {
if (matches(uri, urlMatch)) {
String name = project.get();
@@ -490,12 +505,11 @@ public class Destination {
} else if (remoteNameStyle.equals("basenameOnly")) {
name = FilenameUtils.getBaseName(name);
} else if (!remoteNameStyle.equals("slash")) {
- repLog.debug(String.format(
- "Unknown remoteNameStyle: %s, falling back to slash",
- remoteNameStyle));
+ repLog.debug(
+ String.format("Unknown remoteNameStyle: %s, falling back to slash", remoteNameStyle));
}
- String replacedPath = ReplicationQueue.replaceName(uri.getPath(), name,
- isSingleProjectMatch());
+ String replacedPath =
+ ReplicationQueue.replaceName(uri.getPath(), name, isSingleProjectMatch());
if (replacedPath != null) {
uri = uri.setPath(replacedPath);
r.add(uri);
@@ -507,8 +521,8 @@ public class Destination {
static boolean needsUrlEncoding(URIish uri) {
return "http".equalsIgnoreCase(uri.getScheme())
- || "https".equalsIgnoreCase(uri.getScheme())
- || "amazon-s3".equalsIgnoreCase(uri.getScheme());
+ || "https".equalsIgnoreCase(uri.getScheme())
+ || "amazon-s3".equalsIgnoreCase(uri.getScheme());
}
static String encode(String str) {
@@ -518,9 +532,7 @@ public class Destination {
// path used to the repository. Space is incorrectly encoded as '+' for this
// context. In the path part of a URI space should be %20, but in form data
// space is '+'. Our cleanup replace fixes these two issues.
- return URLEncoder.encode(str, "UTF-8")
- .replaceAll("%2[fF]", "/")
- .replace("+", "%20");
+ return URLEncoder.encode(str, "UTF-8").replaceAll("%2[fF]", "/").replace("+", "%20");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
@@ -560,4 +572,11 @@ public class Destination {
}
return uri.toString().contains(urlMatch);
}
+
+ private void postEvent(PushOne pushOp, String ref) {
+ Project.NameKey project = pushOp.getProjectNameKey();
+ String targetNode = resolveNodeName(pushOp.getURI());
+ ReplicationScheduledEvent event = new ReplicationScheduledEvent(project.get(), ref, targetNode);
+ eventDispatcher.get().postEvent(new Branch.NameKey(project, ref), event);
+ }
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationConfiguration.java b/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationConfiguration.java
index f79f616..856ffb1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationConfiguration.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationConfiguration.java
@@ -16,12 +16,15 @@ package com.googlesource.gerrit.plugins.replication;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
-
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.transport.RemoteConfig;
class DestinationConfiguration {
+ static final int DEFAULT_REPLICATION_DELAY = 15;
+ static final int DEFAULT_RESCHEDULE_DELAY = 3;
+
private final int delay;
+ private final int rescheduleDelay;
private final int retryDelay;
private final int lockErrorMaxRetries;
private final ImmutableList<String> adminUrls;
@@ -40,29 +43,23 @@ class DestinationConfiguration {
DestinationConfiguration(RemoteConfig remoteConfig, Config cfg) {
this.remoteConfig = remoteConfig;
String name = remoteConfig.getName();
- urls = ImmutableList.copyOf(
- cfg.getStringList("remote", name, "url"));
- delay = Math.max(0, getInt(remoteConfig, cfg, "replicationdelay", 15));
- projects = ImmutableList.copyOf(
- cfg.getStringList("remote", name, "projects"));
- adminUrls = ImmutableList.copyOf(
- cfg.getStringList("remote", name, "adminUrl"));
+ urls = ImmutableList.copyOf(cfg.getStringList("remote", name, "url"));
+ delay = Math.max(0, getInt(remoteConfig, cfg, "replicationdelay", DEFAULT_REPLICATION_DELAY));
+ rescheduleDelay =
+ Math.max(3, getInt(remoteConfig, cfg, "rescheduledelay", DEFAULT_RESCHEDULE_DELAY));
+ projects = ImmutableList.copyOf(cfg.getStringList("remote", name, "projects"));
+ adminUrls = ImmutableList.copyOf(cfg.getStringList("remote", name, "adminUrl"));
retryDelay = Math.max(0, getInt(remoteConfig, cfg, "replicationretry", 1));
poolThreads = Math.max(0, getInt(remoteConfig, cfg, "threads", 1));
- authGroupNames = ImmutableList.copyOf(
- cfg.getStringList("remote", name, "authGroup"));
+ authGroupNames = ImmutableList.copyOf(cfg.getStringList("remote", name, "authGroup"));
lockErrorMaxRetries = cfg.getInt("replication", "lockErrorMaxRetries", 0);
- createMissingRepos =
- cfg.getBoolean("remote", name, "createMissingRepositories", true);
- replicatePermissions =
- cfg.getBoolean("remote", name, "replicatePermissions", true);
- replicateProjectDeletions =
- cfg.getBoolean("remote", name, "replicateProjectDeletions", false);
- replicateHiddenProjects =
- cfg.getBoolean("remote", name, "replicateHiddenProjects", false);
- remoteNameStyle = MoreObjects.firstNonNull(
- cfg.getString("remote", name, "remoteNameStyle"), "slash");
+ createMissingRepos = cfg.getBoolean("remote", name, "createMissingRepositories", true);
+ replicatePermissions = cfg.getBoolean("remote", name, "replicatePermissions", true);
+ replicateProjectDeletions = cfg.getBoolean("remote", name, "replicateProjectDeletions", false);
+ replicateHiddenProjects = cfg.getBoolean("remote", name, "replicateHiddenProjects", false);
+ remoteNameStyle =
+ MoreObjects.firstNonNull(cfg.getString("remote", name, "remoteNameStyle"), "slash");
maxRetries =
getInt(
remoteConfig, cfg, "replicationMaxRetries", cfg.getInt("replication", "maxRetries", 0));
@@ -72,6 +69,10 @@ class DestinationConfiguration {
return delay;
}
+ public int getRescheduleDelay() {
+ return rescheduleDelay;
+ }
+
public int getRetryDelay() {
return retryDelay;
}
@@ -128,8 +129,7 @@ class DestinationConfiguration {
return maxRetries;
}
- private static int getInt(
- RemoteConfig rc, Config cfg, String name, int defValue) {
+ private static int getInt(RemoteConfig rc, Config cfg, String name, int defValue) {
return cfg.getInt("remote", rc.getName(), name, defValue);
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationFactory.java b/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationFactory.java
new file mode 100644
index 0000000..df886cb
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationFactory.java
@@ -0,0 +1,70 @@
+// 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.googlesource.gerrit.plugins.replication;
+
+import com.google.gerrit.common.EventDispatcher;
+import com.google.gerrit.extensions.registration.DynamicItem;
+import com.google.gerrit.server.PluginUser;
+import com.google.gerrit.server.account.GroupBackend;
+import com.google.gerrit.server.account.GroupIncludeCache;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.Singleton;
+
+@Singleton
+public class DestinationFactory {
+ private final Injector injector;
+ private final RemoteSiteUser.Factory replicationUserFactory;
+ private final PluginUser pluginUser;
+ private final GitRepositoryManager gitRepositoryManager;
+ private final GroupBackend groupBackend;
+ private final ReplicationStateListener stateLog;
+ private final GroupIncludeCache groupIncludeCache;
+ private final DynamicItem<EventDispatcher> eventDispatcher;
+
+ @Inject
+ public DestinationFactory(
+ Injector injector,
+ RemoteSiteUser.Factory replicationUserFactory,
+ PluginUser pluginUser,
+ GitRepositoryManager gitRepositoryManager,
+ GroupBackend groupBackend,
+ ReplicationStateListener stateLog,
+ GroupIncludeCache groupIncludeCache,
+ DynamicItem<EventDispatcher> eventDispatcher) {
+ this.injector = injector;
+ this.replicationUserFactory = replicationUserFactory;
+ this.pluginUser = pluginUser;
+ this.gitRepositoryManager = gitRepositoryManager;
+ this.groupBackend = groupBackend;
+ this.stateLog = stateLog;
+ this.groupIncludeCache = groupIncludeCache;
+ this.eventDispatcher = eventDispatcher;
+ }
+
+ Destination create(DestinationConfiguration config) {
+ return new Destination(
+ injector,
+ config,
+ replicationUserFactory,
+ pluginUser,
+ gitRepositoryManager,
+ groupBackend,
+ stateLog,
+ groupIncludeCache,
+ eventDispatcher);
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/Init.java b/src/main/java/com/googlesource/gerrit/plugins/replication/Init.java
new file mode 100644
index 0000000..a9fdb4f
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/Init.java
@@ -0,0 +1,70 @@
+// 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.googlesource.gerrit.plugins.replication;
+
+import static com.googlesource.gerrit.plugins.replication.DestinationConfiguration.DEFAULT_REPLICATION_DELAY;
+import static com.googlesource.gerrit.plugins.replication.DestinationConfiguration.DEFAULT_RESCHEDULE_DELAY;
+
+import com.google.common.base.Strings;
+import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.pgm.init.api.ConsoleUI;
+import com.google.gerrit.pgm.init.api.InitStep;
+import com.google.gerrit.server.config.SitePaths;
+import com.google.inject.Inject;
+import java.io.File;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
+
+public class Init implements InitStep {
+ private final String pluginName;
+ private final SitePaths site;
+ private final ConsoleUI ui;
+
+ @Inject
+ Init(@PluginName String pluginName, SitePaths site, ConsoleUI ui) {
+ this.pluginName = pluginName;
+ this.site = site;
+ this.ui = ui;
+ }
+
+ @Override
+ public void run() throws Exception {
+ File configFile = site.etc_dir.resolve(pluginName + ".config").toFile();
+ if (!configFile.exists()) {
+ return;
+ }
+
+ FileBasedConfig config = new FileBasedConfig(configFile, FS.DETECTED);
+ config.load();
+ for (String name : config.getSubsections("remote")) {
+ if (!Strings.isNullOrEmpty(config.getString("remote", name, "rescheduleDelay"))) {
+ continue;
+ }
+
+ int replicationDelay =
+ config.getInt("remote", name, "replicationDelay", DEFAULT_REPLICATION_DELAY);
+ if (replicationDelay > 0) {
+ int delay = Math.max(replicationDelay, DEFAULT_RESCHEDULE_DELAY);
+ ui.message("Setting remote.%s.rescheduleDelay = %d\n", name, delay);
+ config.setInt("remote", name, "rescheduleDelay", delay);
+ } else {
+ ui.message(
+ "INFO: Assuming default (%d s) for remote.%s.rescheduleDelay\n",
+ DEFAULT_RESCHEDULE_DELAY, name);
+ }
+ }
+ config.save();
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ListCommand.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ListCommand.java
index 247ebf7..fa17dce 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/ListCommand.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ListCommand.java
@@ -23,13 +23,10 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.inject.Inject;
-
import com.googlesource.gerrit.plugins.replication.ReplicationConfig.FilterType;
-
-import org.kohsuke.args4j.Option;
-
import java.util.Collection;
import java.util.List;
+import org.kohsuke.args4j.Option;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
@CommandMetaData(name = "list", description = "List remote destination information")
@@ -43,8 +40,7 @@ final class ListCommand extends SshCommand {
@Option(name = "--json", usage = "output in json format")
private boolean json;
- @Inject
- private ReplicationConfig config;
+ @Inject private ReplicationConfig config;
@Override
protected void run() {
@@ -56,9 +52,7 @@ final class ListCommand extends SshCommand {
}
private boolean matches(String name) {
- return (Strings.isNullOrEmpty(remote)
- || name.contains(remote)
- || name.matches(remote));
+ return (Strings.isNullOrEmpty(remote) || name.contains(remote) || name.matches(remote));
}
private void addProperty(JsonObject obj, String key, List<String> values) {
@@ -73,14 +67,11 @@ final class ListCommand extends SshCommand {
private void addQueueDetails(StringBuilder out, Collection<PushOne> values) {
for (PushOne p : values) {
- out.append(" ")
- .append(p.toString())
- .append("\n");
+ out.append(" ").append(p.toString()).append("\n");
}
}
- private void addQueueDetails(JsonObject obj, String key,
- Collection<PushOne> values) {
+ private void addQueueDetails(JsonObject obj, String key, Collection<PushOne> values) {
if (values.size() > 0) {
JsonArray list = new JsonArray();
for (PushOne p : values) {
@@ -106,42 +97,28 @@ final class ListCommand extends SshCommand {
stdout.print(obj.toString() + "\n");
} else {
StringBuilder out = new StringBuilder();
- out.append("Remote: ")
- .append(d.getRemoteConfigName())
- .append("\n");
+ out.append("Remote: ").append(d.getRemoteConfigName()).append("\n");
for (String url : d.getUrls()) {
- out.append("Url: ")
- .append(url)
- .append("\n");
+ out.append("Url: ").append(url).append("\n");
}
if (detail) {
for (String adminUrl : d.getAdminUrls()) {
- out.append("AdminUrl: ")
- .append(adminUrl)
- .append("\n");
+ out.append("AdminUrl: ").append(adminUrl).append("\n");
}
for (String authGroup : d.getAuthGroupNames()) {
- out.append("AuthGroup: ")
- .append(authGroup)
- .append("\n");
+ out.append("AuthGroup: ").append(authGroup).append("\n");
}
for (String project : d.getProjects()) {
- out.append("Project: ")
- .append(project)
- .append("\n");
+ out.append("Project: ").append(project).append("\n");
}
Destination.QueueInfo q = d.getQueueInfo();
- out.append("In Flight: ")
- .append(q.inFlight.size())
- .append("\n");
+ out.append("In Flight: ").append(q.inFlight.size()).append("\n");
addQueueDetails(out, q.inFlight.values());
- out.append("Pending: ")
- .append(q.pending.size())
- .append("\n");
+ out.append("Pending: ").append(q.pending.size()).append("\n");
addQueueDetails(out, q.pending.values());
}
stdout.print(out.toString() + "\n");
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/OnStartStop.java b/src/main/java/com/googlesource/gerrit/plugins/replication/OnStartStop.java
index cad7bdd..a6b38c1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/OnStartStop.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/OnStartStop.java
@@ -20,9 +20,7 @@ import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.systemstatus.ServerInformation;
import com.google.inject.Inject;
-
import com.googlesource.gerrit.plugins.replication.PushResultProcessing.GitUpdateProcessing;
-
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
@@ -56,10 +54,9 @@ public class OnStartStop implements LifecycleListener {
if (srvInfo.getState() == ServerInformation.State.STARTUP
&& config.isReplicateAllOnPluginStart()) {
- ReplicationState state = new ReplicationState(
- new GitUpdateProcessing(eventDispatcher.get()));
- pushAllFuture.set(pushAll.create(
- null, ReplicationFilter.all(), state).schedule(30, TimeUnit.SECONDS));
+ ReplicationState state = new ReplicationState(new GitUpdateProcessing(eventDispatcher.get()));
+ pushAllFuture.set(
+ pushAll.create(null, ReplicationFilter.all(), state).schedule(30, TimeUnit.SECONDS));
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/PushAll.java b/src/main/java/com/googlesource/gerrit/plugins/replication/PushAll.java
index 16e1678..da32ecd 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/PushAll.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/PushAll.java
@@ -20,7 +20,6 @@ import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.project.ProjectCache;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
-
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
@@ -28,9 +27,7 @@ public class PushAll implements Runnable {
private final ReplicationStateListener stateLog;
public interface Factory {
- PushAll create(String urlMatch,
- ReplicationFilter filter,
- ReplicationState state);
+ PushAll create(String urlMatch, ReplicationFilter filter, ReplicationState state);
}
private final WorkQueue workQueue;
@@ -41,7 +38,8 @@ public class PushAll implements Runnable {
private final ReplicationState state;
@Inject
- protected PushAll(WorkQueue wq,
+ protected PushAll(
+ WorkQueue wq,
ProjectCache projectCache,
ReplicationQueue rq,
ReplicationStateListener stateLog,
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java b/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java
index 46a87a4..525c990 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java
@@ -19,7 +19,7 @@ import static java.util.concurrent.TimeUnit.NANOSECONDS;
import com.google.common.base.Throwables;
import com.google.common.collect.LinkedListMultimap;
-import com.google.common.collect.Multimap;
+import com.google.common.collect.ListMultimap;
import com.google.common.collect.Sets;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
@@ -42,10 +42,19 @@ import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.SchemaFactory;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
-
import com.googlesource.gerrit.plugins.replication.ReplicationState.RefPushResult;
import com.jcraft.jsch.JSchException;
-
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.jgit.errors.NoRemoteRepositoryException;
import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.RemoteRepositoryException;
@@ -65,23 +74,11 @@ import org.eclipse.jgit.transport.Transport;
import org.eclipse.jgit.transport.URIish;
import org.slf4j.MDC;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.atomic.AtomicBoolean;
-
/**
* A push to remote operation started by {@link GitReferenceUpdatedListener}.
- * <p>
- * Instance members are protected by the lock within PushQueue. Callers must
- * take that lock to ensure they are working with a current view of the object.
+ *
+ * <p>Instance members are protected by the lock within PushQueue. Callers must take that lock to
+ * ensure they are working with a current view of the object.
*/
class PushOne implements ProjectRunnable, CanceledWhileRunning {
private final ReplicationStateListener stateLog;
@@ -112,8 +109,7 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
private int retryCount;
private final int maxRetries;
private boolean canceled;
- private final Multimap<String,ReplicationState> stateMap =
- LinkedListMultimap.create();
+ private final ListMultimap<String, ReplicationState> stateMap = LinkedListMultimap.create();
private final int maxLockRetries;
private int lockRetryCount;
private final int id;
@@ -122,7 +118,8 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
private final AtomicBoolean canceledWhileRunning;
@Inject
- PushOne(GitRepositoryManager grm,
+ PushOne(
+ GitRepositoryManager grm,
SchemaFactory<ReviewDb> s,
Destination p,
RemoteConfig c,
@@ -246,7 +243,7 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
stateMap.put(ref, state);
}
- Multimap<String,ReplicationState> getStates() {
+ ListMultimap<String, ReplicationState> getStates() {
return stateMap;
}
@@ -261,7 +258,7 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
return states.toArray(new ReplicationState[states.size()]);
}
- void addStates(Multimap<String,ReplicationState> states) {
+ void addStates(ListMultimap<String, ReplicationState> states) {
stateMap.putAll(states);
}
@@ -271,9 +268,11 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
private void statesCleanUp() {
if (!stateMap.isEmpty() && !isRetrying()) {
- for (Map.Entry<String,ReplicationState> entry : stateMap.entries()) {
- entry.getValue().notifyRefReplicated(projectName.get(), entry.getKey(), uri,
- RefPushResult.FAILED, null);
+ for (Map.Entry<String, ReplicationState> entry : stateMap.entries()) {
+ entry
+ .getValue()
+ .notifyRefReplicated(
+ projectName.get(), entry.getKey(), uri, RefPushResult.FAILED, null);
}
}
}
@@ -281,15 +280,18 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
@Override
public void run() {
try {
- threadScoper.scope(new Callable<Void>() {
- @Override
- public Void call() {
- runPushOperation();
- return null;
- }
- }).call();
+ threadScoper
+ .scope(
+ new Callable<Void>() {
+ @Override
+ public Void call() {
+ runPushOperation();
+ return null;
+ }
+ })
+ .call();
} catch (Exception e) {
- Throwables.propagateIfPossible(e);
+ Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
} finally {
statesCleanUp();
@@ -304,8 +306,8 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
MDC.put(ID_MDC_KEY, IdGenerator.format(id));
if (!pool.requestRunway(this)) {
if (!canceled) {
- repLog.info("Rescheduling replication to " + uri
- + " to avoid collision with an in-flight push.");
+ repLog.info(
+ "Rescheduling replication to " + uri + " to avoid collision with an in-flight push.");
pool.reschedule(this, Destination.RetryReason.COLLISION);
}
return;
@@ -320,13 +322,20 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
git = gitManager.openRepository(projectName);
runImpl();
long elapsed = NANOSECONDS.toMillis(context.stop());
- repLog.info("Replication to " + uri + " completed in "
- + (elapsed) + "ms, "
- + (delay) + "ms delay, " + retryCount + " retries");
+ repLog.info(
+ "Replication to "
+ + uri
+ + " completed in "
+ + (elapsed)
+ + "ms, "
+ + (delay)
+ + "ms delay, "
+ + retryCount
+ + " retries");
} catch (RepositoryNotFoundException e) {
- stateLog.error("Cannot replicate " + projectName
- + "; Local repository error: "
- + e.getMessage(), getStatesAsArray());
+ stateLog.error(
+ "Cannot replicate " + projectName + "; Local repository error: " + e.getMessage(),
+ getStatesAsArray());
} catch (RemoteRepositoryException e) {
// Tried to replicate to a remote via anonymous git:// but the repository
@@ -336,8 +345,7 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
if (msg.contains("access denied") || msg.contains("no such repository")) {
createRepository();
} else {
- repLog.error("Cannot replicate " + projectName
- + "; Remote repository error: " + msg);
+ repLog.error("Cannot replicate " + projectName + "; Remote repository error: " + msg);
}
} catch (NoRemoteRepositoryException e) {
@@ -346,8 +354,7 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
stateLog.error("Cannot replicate to " + uri, e, getStatesAsArray());
} catch (TransportException e) {
Throwable cause = e.getCause();
- if (cause instanceof JSchException
- && cause.getMessage().startsWith("UnknownHostKey:")) {
+ if (cause instanceof JSchException && cause.getMessage().startsWith("UnknownHostKey:")) {
repLog.error("Cannot replicate to " + uri + ": " + cause.getMessage());
} else if (e instanceof LockFailureException) {
lockRetryCount++;
@@ -363,8 +370,11 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
pool.reschedule(this, Destination.RetryReason.TRANSPORT_ERROR);
}
} else {
- repLog.error("Giving up after " + lockRetryCount
- + " of this error during replication to " + e.getMessage());
+ repLog.error(
+ "Giving up after "
+ + lockRetryCount
+ + " of this error during replication to "
+ + e.getMessage());
}
} else {
if (canceledWhileRunning.get()) {
@@ -388,8 +398,7 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
}
private void logCanceledWhileRunningException(TransportException e) {
- repLog.info("Cannot replicate to " + uri + "."
- + " It was canceled while running", e);
+ repLog.info("Cannot replicate to " + uri + "." + " It was canceled while running", e);
}
private void createRepository() {
@@ -400,13 +409,17 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
repLog.warn("Missing repository created; retry replication to " + uri);
pool.reschedule(this, Destination.RetryReason.REPOSITORY_MISSING);
} else {
- repLog.warn("Missing repository could not be created when replicating " + uri +
- ". You can only create missing repositories locally, over SSH or when " +
- "using adminUrl in replication.config. See documentation for more information.");
+ repLog.warn(
+ "Missing repository could not be created when replicating "
+ + uri
+ + ". You can only create missing repositories locally, over SSH or when "
+ + "using adminUrl in replication.config. See documentation for more information.");
}
} catch (IOException ioe) {
- stateLog.error("Cannot replicate to " + uri + "; failed to create missing repository",
- ioe, getStatesAsArray());
+ stateLog.error(
+ "Cannot replicate to " + uri + "; failed to create missing repository",
+ ioe,
+ getStatesAsArray());
}
} else {
stateLog.error("Cannot replicate to " + uri + "; repository not found", getStatesAsArray());
@@ -440,8 +453,7 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
return tn.push(NullProgressMonitor.INSTANCE, todo);
}
- private List<RemoteRefUpdate> generateUpdates(Transport tn)
- throws IOException {
+ private List<RemoteRefUpdate> generateUpdates(Transport tn) throws IOException {
ProjectControl pc;
try {
pc = pool.controlFor(projectName);
@@ -466,11 +478,12 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
}
try (ReviewDb db = schema.open()) {
- local = new VisibleRefFilter(
- tagCache, changeNotesFactory, changeCache, git, pc, db, true)
- .filter(local, true);
+ local =
+ new VisibleRefFilter(tagCache, changeNotesFactory, changeCache, git, pc, db, true)
+ .filter(local, true);
} catch (OrmException e) {
- stateLog.error("Cannot read database to replicate to " + projectName, e, getStatesAsArray());
+ stateLog.error(
+ "Cannot read database to replicate to " + projectName, e, getStatesAsArray());
return Collections.emptyList();
}
}
@@ -512,8 +525,7 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
return cmds;
}
- private List<RemoteRefUpdate> doPushDelta(Map<String, Ref> local)
- throws IOException {
+ private List<RemoteRefUpdate> doPushDelta(Map<String, Ref> local) throws IOException {
List<RemoteRefUpdate> cmds = new ArrayList<>();
boolean noPerms = !pool.isReplicatePermissions();
for (String src : delta) {
@@ -538,8 +550,8 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
}
private boolean canPushRef(String ref, boolean noPerms) {
- return !(noPerms && RefNames.REFS_CONFIG.equals(ref)) &&
- !ref.startsWith(RefNames.REFS_CACHE_AUTOMERGE);
+ return !(noPerms && RefNames.REFS_CONFIG.equals(ref))
+ && !ref.startsWith(RefNames.REFS_CACHE_AUTOMERGE);
}
private Map<String, Ref> listRemote(Transport tn)
@@ -567,22 +579,19 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
return null;
}
- private void push(List<RemoteRefUpdate> cmds, RefSpec spec, Ref src)
- throws IOException {
+ private void push(List<RemoteRefUpdate> cmds, RefSpec spec, Ref src) throws IOException {
String dst = spec.getDestination();
boolean force = spec.isForceUpdate();
cmds.add(new RemoteRefUpdate(git, src, dst, force, null, null));
}
- private void delete(List<RemoteRefUpdate> cmds, RefSpec spec)
- throws IOException {
+ private void delete(List<RemoteRefUpdate> cmds, RefSpec spec) throws IOException {
String dst = spec.getDestination();
boolean force = spec.isForceUpdate();
cmds.add(new RemoteRefUpdate(git, (Ref) null, dst, force, null, null));
}
- private void updateStates(Collection<RemoteRefUpdate> refUpdates)
- throws LockFailureException {
+ private void updateStates(Collection<RemoteRefUpdate> refUpdates) throws LockFailureException {
Set<String> doneRefs = new HashSet<>();
boolean anyRefFailed = false;
RemoteRefUpdate.Status lastRefStatusError = RemoteRefUpdate.Status.OK;
@@ -607,8 +616,10 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
case REJECTED_NODELETE:
case REJECTED_NONFASTFORWARD:
case REJECTED_REMOTE_CHANGED:
- stateLog.error(String.format("Failed replicate of %s to %s: status %s",
- u.getRemoteName(), uri, u.getStatus()), logStatesArray);
+ stateLog.error(
+ String.format(
+ "Failed replicate of %s to %s: status %s", u.getRemoteName(), uri, u.getStatus()),
+ logStatesArray);
pushStatus = RefPushResult.FAILED;
anyRefFailed = true;
lastRefStatusError = u.getStatus();
@@ -616,16 +627,22 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
case REJECTED_OTHER_REASON:
if ("non-fast-forward".equals(u.getMessage())) {
- stateLog.error(String.format("Failed replicate of %s to %s"
- + ", remote rejected non-fast-forward push."
- + " Check receive.denyNonFastForwards variable in config file"
- + " of destination repository.", u.getRemoteName(), uri), logStatesArray);
+ stateLog.error(
+ String.format(
+ "Failed replicate of %s to %s"
+ + ", remote rejected non-fast-forward push."
+ + " Check receive.denyNonFastForwards variable in config file"
+ + " of destination repository.",
+ u.getRemoteName(), uri),
+ logStatesArray);
} else if ("failed to lock".equals(u.getMessage())) {
throw new LockFailureException(uri, u.getMessage());
} else {
- stateLog.error(String.format(
- "Failed replicate of %s to %s, reason: %s",
- u.getRemoteName(), uri, u.getMessage()), logStatesArray);
+ stateLog.error(
+ String.format(
+ "Failed replicate of %s to %s, reason: %s",
+ u.getRemoteName(), uri, u.getMessage()),
+ logStatesArray);
}
pushStatus = RefPushResult.FAILED;
anyRefFailed = true;
@@ -634,20 +651,25 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning {
}
for (ReplicationState rs : getStatesByRef(u.getSrcRef())) {
- rs.notifyRefReplicated(projectName.get(), u.getSrcRef(),
- uri, pushStatus, u.getStatus());
+ rs.notifyRefReplicated(projectName.get(), u.getSrcRef(), uri, pushStatus, u.getStatus());
}
}
doneRefs.add(ALL_REFS);
for (ReplicationState rs : getStatesByRef(ALL_REFS)) {
- rs.notifyRefReplicated(projectName.get(), ALL_REFS, uri, anyRefFailed
- ? RefPushResult.FAILED : RefPushResult.SUCCEEDED, lastRefStatusError);
+ rs.notifyRefReplicated(
+ projectName.get(),
+ ALL_REFS,
+ uri,
+ anyRefFailed ? RefPushResult.FAILED : RefPushResult.SUCCEEDED,
+ lastRefStatusError);
}
for (Map.Entry<String, ReplicationState> entry : stateMap.entries()) {
if (!doneRefs.contains(entry.getKey())) {
- entry.getValue().notifyRefReplicated(projectName.get(), entry.getKey(),
- uri, RefPushResult.NOT_ATTEMPTED, null);
+ entry
+ .getValue()
+ .notifyRefReplicated(
+ projectName.get(), entry.getKey(), uri, RefPushResult.NOT_ATTEMPTED, null);
}
}
stateMap.clear();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/PushResultProcessing.java b/src/main/java/com/googlesource/gerrit/plugins/replication/PushResultProcessing.java
index 6717660..0c3e158 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/PushResultProcessing.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/PushResultProcessing.java
@@ -17,21 +17,22 @@ package com.googlesource.gerrit.plugins.replication;
import com.google.gerrit.common.EventDispatcher;
import com.google.gerrit.server.events.RefEvent;
import com.google.gwtorm.server.OrmException;
-
import com.googlesource.gerrit.plugins.replication.ReplicationState.RefPushResult;
-
+import java.lang.ref.WeakReference;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.jgit.transport.RemoteRefUpdate;
import org.eclipse.jgit.transport.URIish;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.lang.ref.WeakReference;
-import java.util.concurrent.atomic.AtomicBoolean;
-
public abstract class PushResultProcessing {
- abstract void onRefReplicatedToOneNode(String project, String ref,
- URIish uri, RefPushResult status, RemoteRefUpdate.Status refStatus);
+ abstract void onRefReplicatedToOneNode(
+ String project,
+ String ref,
+ URIish uri,
+ RefPushResult status,
+ RemoteRefUpdate.Status refStatus);
abstract void onRefReplicatedToAllNodes(String project, String ref, int nodesCount);
@@ -55,7 +56,7 @@ public abstract class PushResultProcessing {
// Default doing nothing
}
- private static String resolveNodeName(URIish uri) {
+ static String resolveNodeName(URIish uri) {
StringBuilder sb = new StringBuilder();
if (uri.isRemote()) {
sb.append(uri.getHost());
@@ -78,8 +79,12 @@ public abstract class PushResultProcessing {
}
@Override
- void onRefReplicatedToOneNode(String project, String ref, URIish uri,
- RefPushResult status, RemoteRefUpdate.Status refStatus) {
+ void onRefReplicatedToOneNode(
+ String project,
+ String ref,
+ URIish uri,
+ RefPushResult status,
+ RemoteRefUpdate.Status refStatus) {
StringBuilder sb = new StringBuilder();
sb.append("Replicate ");
sb.append(project);
@@ -162,10 +167,13 @@ public abstract class PushResultProcessing {
}
@Override
- void onRefReplicatedToOneNode(String project, String ref, URIish uri,
- RefPushResult status, RemoteRefUpdate.Status refStatus) {
- postEvent(new RefReplicatedEvent(project, ref, resolveNodeName(uri),
- status, refStatus));
+ void onRefReplicatedToOneNode(
+ String project,
+ String ref,
+ URIish uri,
+ RefPushResult status,
+ RemoteRefUpdate.Status refStatus) {
+ postEvent(new RefReplicatedEvent(project, ref, resolveNodeName(uri), status, refStatus));
}
@Override
@@ -174,8 +182,7 @@ public abstract class PushResultProcessing {
}
@Override
- void onAllRefsReplicatedToAllNodes(int totalPushTasksCount) {
- }
+ void onAllRefsReplicatedToAllNodes(int totalPushTasksCount) {}
private void postEvent(RefEvent event) {
try {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/RefReplicatedEvent.java b/src/main/java/com/googlesource/gerrit/plugins/replication/RefReplicatedEvent.java
index a1c5596..364f1b4 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/RefReplicatedEvent.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/RefReplicatedEvent.java
@@ -16,9 +16,7 @@ package com.googlesource.gerrit.plugins.replication;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.events.RefEvent;
-
import com.googlesource.gerrit.plugins.replication.ReplicationState.RefPushResult;
-
import org.eclipse.jgit.transport.RemoteRefUpdate;
import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
@@ -31,8 +29,12 @@ public class RefReplicatedEvent extends RefEvent {
final String status;
final Status refStatus;
- public RefReplicatedEvent(String project, String ref, String targetNode,
- RefPushResult status, RemoteRefUpdate.Status refStatus) {
+ public RefReplicatedEvent(
+ String project,
+ String ref,
+ String targetNode,
+ RefPushResult status,
+ RemoteRefUpdate.Status refStatus) {
super(TYPE);
this.project = project;
this.ref = ref;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/RemoteSiteUser.java b/src/main/java/com/googlesource/gerrit/plugins/replication/RemoteSiteUser.java
index 11253c6..f3dc04d 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/RemoteSiteUser.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/RemoteSiteUser.java
@@ -28,8 +28,8 @@ public class RemoteSiteUser extends CurrentUser {
private final GroupMembership effectiveGroups;
@Inject
- RemoteSiteUser(CapabilityControl.Factory capabilityControlFactory,
- @Assisted GroupMembership authGroups) {
+ RemoteSiteUser(
+ CapabilityControl.Factory capabilityControlFactory, @Assisted GroupMembership authGroups) {
super(capabilityControlFactory);
effectiveGroups = authGroups;
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationConfig.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationConfig.java
index 241c881..e94abbd 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationConfig.java
@@ -14,7 +14,6 @@
package com.googlesource.gerrit.plugins.replication;
import com.google.gerrit.server.git.WorkQueue;
-
import java.util.List;
public interface ReplicationConfig {
@@ -36,5 +35,4 @@ public interface ReplicationConfig {
int shutdown();
void startup(WorkQueue workQueue);
-
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationFileBasedConfig.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationFileBasedConfig.java
index 4b976bc..82e68ed 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationFileBasedConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationFileBasedConfig.java
@@ -13,20 +13,22 @@
// limitations under the License.
package com.googlesource.gerrit.plugins.replication;
-import com.google.common.base.Predicate;
-import com.google.common.collect.FluentIterable;
+import static java.util.stream.Collectors.toList;
+
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
-import com.google.gerrit.server.PluginUser;
-import com.google.gerrit.server.account.GroupBackend;
-import com.google.gerrit.server.account.GroupIncludeCache;
import com.google.gerrit.server.config.SitePaths;
-import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.WorkQueue;
import com.google.inject.Inject;
-import com.google.inject.Injector;
import com.google.inject.Singleton;
-
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Predicate;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.transport.RefSpec;
@@ -36,13 +38,6 @@ import org.eclipse.jgit.util.FS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.nio.file.Path;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
@Singleton
public class ReplicationFileBasedConfig implements ReplicationConfig {
static final Logger log = LoggerFactory.getLogger(ReplicationFileBasedConfig.class);
@@ -50,35 +45,14 @@ public class ReplicationFileBasedConfig implements ReplicationConfig {
private Path cfgPath;
private boolean replicateAllOnPluginStart;
private boolean defaultForceUpdate;
- private Injector injector;
- private final RemoteSiteUser.Factory replicationUserFactory;
- private final PluginUser pluginUser;
- private final GitRepositoryManager gitRepositoryManager;
- private final GroupBackend groupBackend;
private final FileBasedConfig config;
- private final ReplicationStateListener stateLog;
- private final GroupIncludeCache groupIncludeCache;
@Inject
- public ReplicationFileBasedConfig(Injector injector,
- SitePaths site,
- RemoteSiteUser.Factory ruf,
- PluginUser pu,
- GitRepositoryManager grm,
- GroupBackend gb,
- ReplicationStateListener stateLog,
- GroupIncludeCache groupIncludeCache)
+ public ReplicationFileBasedConfig(SitePaths site, DestinationFactory destinationFactory)
throws ConfigInvalidException, IOException {
this.cfgPath = site.etc_dir.resolve("replication.config");
- this.groupIncludeCache = groupIncludeCache;
- this.injector = injector;
- this.replicationUserFactory = ruf;
- this.pluginUser = pu;
- this.gitRepositoryManager = grm;
- this.groupBackend = gb;
this.config = new FileBasedConfig(cfgPath.toFile(), FS.DETECTED);
- this.destinations = allDestinations();
- this.stateLog = stateLog;
+ this.destinations = allDestinations(destinationFactory);
}
/*
@@ -89,40 +63,23 @@ public class ReplicationFileBasedConfig implements ReplicationConfig {
*/
@Override
public List<Destination> getDestinations(FilterType filterType) {
- Predicate<Destination> filter;
+ Predicate<? super Destination> filter;
switch (filterType) {
- case PROJECT_CREATION :
- filter = new Predicate<Destination>() {
-
- @Override
- public boolean apply(Destination dest) {
- if (dest == null || !dest.isCreateMissingRepos()) {
- return false;
- }
- return true;
- }
- };
+ case PROJECT_CREATION:
+ filter = dest -> dest.isCreateMissingRepos();
break;
- case PROJECT_DELETION :
- filter = new Predicate<Destination>() {
-
- @Override
- public boolean apply(Destination dest) {
- if (dest == null || !dest.isReplicateProjectDeletions()) {
- return false;
- }
- return true;
- }
- };
+ case PROJECT_DELETION:
+ filter = dest -> dest.isReplicateProjectDeletions();
+ break;
+ case ALL:
+ default:
+ filter = dest -> true;
break;
- case ALL :
- return destinations;
- default :
- return destinations;
}
- return FluentIterable.from(destinations).filter(filter).toList();
+ return destinations.stream().filter(Objects::nonNull).filter(filter).collect(toList());
}
- private List<Destination> allDestinations()
+
+ private List<Destination> allDestinations(DestinationFactory destinationFactory)
throws ConfigInvalidException, IOException {
if (!config.getFile().exists()) {
log.warn("Config file " + config.getFile() + " does not exist; not replicating");
@@ -136,18 +93,16 @@ public class ReplicationFileBasedConfig implements ReplicationConfig {
try {
config.load();
} catch (ConfigInvalidException e) {
- throw new ConfigInvalidException(String.format(
- "Config file %s is invalid: %s", config.getFile(), e.getMessage()), e);
+ throw new ConfigInvalidException(
+ String.format("Config file %s is invalid: %s", config.getFile(), e.getMessage()), e);
} catch (IOException e) {
- throw new IOException(String.format("Cannot read %s: %s", config.getFile(),
- e.getMessage()), e);
+ throw new IOException(
+ String.format("Cannot read %s: %s", config.getFile(), e.getMessage()), e);
}
- replicateAllOnPluginStart =
- config.getBoolean("gerrit", "replicateOnStartup", true);
+ replicateAllOnPluginStart = config.getBoolean("gerrit", "replicateOnStartup", true);
- defaultForceUpdate =
- config.getBoolean("gerrit", "defaultForceUpdate", false);
+ defaultForceUpdate = config.getBoolean("gerrit", "defaultForceUpdate", false);
ImmutableList.Builder<Destination> dest = ImmutableList.builder();
for (RemoteConfig c : allRemotes(config)) {
@@ -163,21 +118,21 @@ public class ReplicationFileBasedConfig implements ReplicationConfig {
}
if (c.getPushRefSpecs().isEmpty()) {
- c.addPushRefSpec(new RefSpec().setSourceDestination("refs/*", "refs/*")
- .setForceUpdate(defaultForceUpdate));
+ c.addPushRefSpec(
+ new RefSpec()
+ .setSourceDestination("refs/*", "refs/*")
+ .setForceUpdate(defaultForceUpdate));
}
- Destination destination =
- new Destination(injector, new DestinationConfiguration(c,
- config), replicationUserFactory, pluginUser,
- gitRepositoryManager, groupBackend, stateLog, groupIncludeCache);
+ Destination destination = destinationFactory.create(new DestinationConfiguration(c, config));
if (!destination.isSingleProjectMatch()) {
for (URIish u : c.getURIs()) {
if (u.getPath() == null || !u.getPath().contains("${name}")) {
- throw new ConfigInvalidException(String.format(
- "remote.%s.url \"%s\" lacks ${name} placeholder in %s",
- c.getName(), u, config.getFile()));
+ throw new ConfigInvalidException(
+ String.format(
+ "remote.%s.url \"%s\" lacks ${name} placeholder in %s",
+ c.getName(), u, config.getFile()));
}
}
}
@@ -203,16 +158,15 @@ public class ReplicationFileBasedConfig implements ReplicationConfig {
return defaultForceUpdate;
}
- private static List<RemoteConfig> allRemotes(FileBasedConfig cfg)
- throws ConfigInvalidException {
+ private static List<RemoteConfig> allRemotes(FileBasedConfig cfg) throws ConfigInvalidException {
Set<String> names = cfg.getSubsections("remote");
List<RemoteConfig> result = Lists.newArrayListWithCapacity(names.size());
for (String name : names) {
try {
result.add(new RemoteConfig(cfg, name));
} catch (URISyntaxException e) {
- throw new ConfigInvalidException(String.format(
- "remote %s has invalid URL in %s", name, cfg.getFile()));
+ throw new ConfigInvalidException(
+ String.format("remote %s has invalid URL in %s", name, cfg.getFile()));
}
}
return result;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationFilter.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationFilter.java
index 6b75d3e..7b3486b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationFilter.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationFilter.java
@@ -16,17 +16,18 @@ package com.googlesource.gerrit.plugins.replication;
import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.reviewdb.client.Project.NameKey;
-
import java.util.Collections;
import java.util.List;
public class ReplicationFilter {
public enum PatternType {
- REGEX, WILDCARD, EXACT_MATCH;
+ REGEX,
+ WILDCARD,
+ EXACT_MATCH;
}
public static ReplicationFilter all() {
- return new ReplicationFilter(Collections.<String> emptyList());
+ return new ReplicationFilter(Collections.<String>emptyList());
}
public static PatternType getPatternType(String pattern) {
@@ -66,8 +67,7 @@ public class ReplicationFilter {
match = projectName.matches(pattern);
break;
case WILDCARD:
- match =
- projectName.startsWith(pattern.substring(0, pattern.length() - 1));
+ match = projectName.startsWith(pattern.substring(0, pattern.length() - 1));
break;
case EXACT_MATCH:
match = projectName.equals(pattern);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationLogFile.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationLogFile.java
index fcc3437..fed09f9 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationLogFile.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationLogFile.java
@@ -18,15 +18,16 @@ import com.google.gerrit.extensions.systemstatus.ServerInformation;
import com.google.gerrit.server.util.PluginLogFile;
import com.google.gerrit.server.util.SystemLog;
import com.google.inject.Inject;
-
import org.apache.log4j.PatternLayout;
public class ReplicationLogFile extends PluginLogFile {
@Inject
- public ReplicationLogFile(SystemLog systemLog,
- ServerInformation serverInfo) {
- super(systemLog, serverInfo, ReplicationQueue.REPLICATION_LOG_NAME,
+ public ReplicationLogFile(SystemLog systemLog, ServerInformation serverInfo) {
+ super(
+ systemLog,
+ serverInfo,
+ ReplicationQueue.REPLICATION_LOG_NAME,
new PatternLayout("[%d] [%X{" + PushOne.ID_MDC_KEY + "}] %m%n"));
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationMetrics.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationMetrics.java
index a7b27a0..afc7926 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationMetrics.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationMetrics.java
@@ -32,30 +32,34 @@ public class ReplicationMetrics {
ReplicationMetrics(MetricMaker metricMaker) {
Field<String> DEST_FIELD = Field.ofString("destination");
- executionTime = metricMaker.newTimer(
- "replication_latency",
- new Description("Time spent pushing to remote destination.")
- .setCumulative()
- .setUnit(Description.Units.MILLISECONDS),
- DEST_FIELD);
+ executionTime =
+ metricMaker.newTimer(
+ "replication_latency",
+ new Description("Time spent pushing to remote destination.")
+ .setCumulative()
+ .setUnit(Description.Units.MILLISECONDS),
+ DEST_FIELD);
- executionDelay = metricMaker.newHistogram(
- "replication_delay",
- new Description("Time spent waiting before pushing to remote destination")
- .setCumulative()
- .setUnit(Description.Units.MILLISECONDS),
- DEST_FIELD);
+ executionDelay =
+ metricMaker.newHistogram(
+ "replication_delay",
+ new Description("Time spent waiting before pushing to remote destination")
+ .setCumulative()
+ .setUnit(Description.Units.MILLISECONDS),
+ DEST_FIELD);
- executionRetries = metricMaker.newHistogram(
- "replication_retries",
- new Description("Number of retries when pushing to remote destination")
- .setCumulative()
- .setUnit("retries"),
- DEST_FIELD);
+ executionRetries =
+ metricMaker.newHistogram(
+ "replication_retries",
+ new Description("Number of retries when pushing to remote destination")
+ .setCumulative()
+ .setUnit("retries"),
+ DEST_FIELD);
}
/**
* Start the replication latency timer for a destination.
+ *
* @param name the destination name.
* @return the timer context.
*/
@@ -65,6 +69,7 @@ public class ReplicationMetrics {
/**
* Record the replication delay and retry metrics for a destination.
+ *
* @param name the destination name.
* @param delay replication delay in milliseconds.
* @param retries number of retries.
@@ -73,5 +78,4 @@ public class ReplicationMetrics {
executionDelay.record(name, delay);
executionRetries.record(name, retries);
}
-
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationModule.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationModule.java
index 5a5f3b4..f30e13d 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationModule.java
@@ -29,34 +29,30 @@ import com.google.inject.AbstractModule;
import com.google.inject.Scopes;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import com.google.inject.internal.UniqueAnnotations;
-
import org.eclipse.jgit.transport.SshSessionFactory;
class ReplicationModule extends AbstractModule {
@Override
protected void configure() {
+ bind(DestinationFactory.class).in(Scopes.SINGLETON);
bind(ReplicationQueue.class).in(Scopes.SINGLETON);
- DynamicSet.bind(binder(), GitReferenceUpdatedListener.class)
- .to(ReplicationQueue.class);
- DynamicSet.bind(binder(), NewProjectCreatedListener.class)
- .to(ReplicationQueue.class);
- DynamicSet.bind(binder(), ProjectDeletedListener.class)
- .to(ReplicationQueue.class);
- DynamicSet.bind(binder(), HeadUpdatedListener.class)
- .to(ReplicationQueue.class);
+ DynamicSet.bind(binder(), GitReferenceUpdatedListener.class).to(ReplicationQueue.class);
+ DynamicSet.bind(binder(), NewProjectCreatedListener.class).to(ReplicationQueue.class);
+ DynamicSet.bind(binder(), ProjectDeletedListener.class).to(ReplicationQueue.class);
+ DynamicSet.bind(binder(), HeadUpdatedListener.class).to(ReplicationQueue.class);
bind(OnStartStop.class).in(Scopes.SINGLETON);
+ bind(LifecycleListener.class).annotatedWith(UniqueAnnotations.create()).to(OnStartStop.class);
bind(LifecycleListener.class)
- .annotatedWith(UniqueAnnotations.create())
- .to(OnStartStop.class);
- bind(LifecycleListener.class).annotatedWith(UniqueAnnotations.create()).to(
- ReplicationLogFile.class);
- bind(CredentialsFactory.class).to(
- AutoReloadSecureCredentialsFactoryDecorator.class).in(Scopes.SINGLETON);
+ .annotatedWith(UniqueAnnotations.create())
+ .to(ReplicationLogFile.class);
+ bind(CredentialsFactory.class)
+ .to(AutoReloadSecureCredentialsFactoryDecorator.class)
+ .in(Scopes.SINGLETON);
bind(CapabilityDefinition.class)
- .annotatedWith(Exports.named(START_REPLICATION))
- .to(StartReplicationCapability.class);
+ .annotatedWith(Exports.named(START_REPLICATION))
+ .to(StartReplicationCapability.class);
install(new FactoryModuleBuilder().build(PushAll.Factory.class));
install(new FactoryModuleBuilder().build(RemoteSiteUser.Factory.class));
@@ -66,7 +62,7 @@ class ReplicationModule extends AbstractModule {
EventTypes.register(RefReplicatedEvent.TYPE, RefReplicatedEvent.class);
EventTypes.register(RefReplicationDoneEvent.TYPE, RefReplicationDoneEvent.class);
- bind(SshSessionFactory.class).toProvider(
- ReplicationSshSessionFactoryProvider.class);
+ EventTypes.register(ReplicationScheduledEvent.TYPE, ReplicationScheduledEvent.class);
+ bind(SshSessionFactory.class).toProvider(ReplicationSshSessionFactoryProvider.class);
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java
index ba8e9cc..9a68d32 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java
@@ -26,10 +26,15 @@ import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.git.WorkQueue;
import com.google.inject.Inject;
import com.google.inject.Provider;
-
import com.googlesource.gerrit.plugins.replication.PushResultProcessing.GitUpdateProcessing;
import com.googlesource.gerrit.plugins.replication.ReplicationConfig.FilterType;
-
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.lib.Constants;
@@ -44,21 +49,13 @@ import org.eclipse.jgit.util.io.StreamCopyThread;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.net.URISyntaxException;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
/** Manages automatic replication to remote repositories. */
-public class ReplicationQueue implements
- LifecycleListener,
- GitReferenceUpdatedListener,
- NewProjectCreatedListener,
- ProjectDeletedListener,
- HeadUpdatedListener {
+public class ReplicationQueue
+ implements LifecycleListener,
+ GitReferenceUpdatedListener,
+ NewProjectCreatedListener,
+ ProjectDeletedListener,
+ HeadUpdatedListener {
static final String REPLICATION_LOG_NAME = "replication_log";
static final Logger repLog = LoggerFactory.getLogger(REPLICATION_LOG_NAME);
private static final int SSH_REMOTE_TIMEOUT = 120 * 1000;
@@ -84,7 +81,8 @@ public class ReplicationQueue implements
private volatile boolean running;
@Inject
- ReplicationQueue(WorkQueue wq,
+ ReplicationQueue(
+ WorkQueue wq,
ReplicationConfig rc,
DynamicItem<EventDispatcher> dis,
ReplicationStateListener sl,
@@ -107,16 +105,14 @@ public class ReplicationQueue implements
running = false;
int discarded = config.shutdown();
if (discarded > 0) {
- repLog.warn(String.format(
- "Canceled %d replication events during shutdown", discarded));
+ repLog.warn(String.format("Canceled %d replication events during shutdown", discarded));
}
}
- void scheduleFullSync(final Project.NameKey project, final String urlMatch,
- ReplicationState state) {
+ void scheduleFullSync(
+ final Project.NameKey project, final String urlMatch, ReplicationState state) {
if (!running) {
- stateLog.warn("Replication plugin did not finish startup before event",
- state);
+ stateLog.warn("Replication plugin did not finish startup before event", state);
return;
}
@@ -131,8 +127,7 @@ public class ReplicationQueue implements
@Override
public void onGitReferenceUpdated(GitReferenceUpdatedListener.Event event) {
- ReplicationState state =
- new ReplicationState(new GitUpdateProcessing(dispatcher.get()));
+ ReplicationState state = new ReplicationState(new GitUpdateProcessing(dispatcher.get()));
if (!running) {
stateLog.warn("Replication plugin did not finish startup before event", state);
return;
@@ -151,30 +146,28 @@ public class ReplicationQueue implements
@Override
public void onNewProjectCreated(NewProjectCreatedListener.Event event) {
- for (URIish uri : getURIs(new Project.NameKey(event.getProjectName()),
- FilterType.PROJECT_CREATION)) {
+ for (URIish uri :
+ getURIs(new Project.NameKey(event.getProjectName()), FilterType.PROJECT_CREATION)) {
createProject(uri, event.getHeadName());
}
}
@Override
public void onProjectDeleted(ProjectDeletedListener.Event event) {
- for (URIish uri : getURIs(new Project.NameKey(event.getProjectName()),
- FilterType.PROJECT_DELETION)) {
+ for (URIish uri :
+ getURIs(new Project.NameKey(event.getProjectName()), FilterType.PROJECT_DELETION)) {
deleteProject(uri);
}
}
@Override
public void onHeadUpdated(HeadUpdatedListener.Event event) {
- for (URIish uri : getURIs(new Project.NameKey(event.getProjectName()),
- FilterType.ALL)) {
+ for (URIish uri : getURIs(new Project.NameKey(event.getProjectName()), FilterType.ALL)) {
updateHead(uri, event.getNewHeadName());
}
}
- private Set<URIish> getURIs(Project.NameKey projectName,
- FilterType filterType) {
+ private Set<URIish> getURIs(Project.NameKey projectName, FilterType filterType) {
if (config.getDestinations(filterType).isEmpty()) {
return Collections.emptySet();
}
@@ -200,23 +193,19 @@ public class ReplicationQueue implements
try {
uri = new URIish(url);
} catch (URISyntaxException e) {
- repLog.warn(String.format("adminURL '%s' is invalid: %s", url,
- e.getMessage()));
+ repLog.warn(String.format("adminURL '%s' is invalid: %s", url, e.getMessage()));
continue;
}
- String path = replaceName(uri.getPath(), projectName.get(),
- config.isSingleProjectMatch());
+ String path = replaceName(uri.getPath(), projectName.get(), config.isSingleProjectMatch());
if (path == null) {
- repLog.warn(String
- .format("adminURL %s does not contain ${name}", uri));
+ repLog.warn(String.format("adminURL %s does not contain ${name}", uri));
continue;
}
uri = uri.setPath(path);
if (!isSSH(uri)) {
- repLog.warn(String.format(
- "adminURL '%s' is invalid: only SSH is supported", uri));
+ repLog.warn(String.format("adminURL '%s' is invalid: only SSH is supported", uri));
continue;
}
@@ -249,9 +238,12 @@ public class ReplicationQueue implements
createRemoteSsh(replicateURI, head);
repLog.info("Created remote repository: " + replicateURI);
} else {
- repLog.warn(String.format("Cannot create new project on remote site %s."
- + " Only local paths and SSH URLs are supported"
- + " for remote repository creation", replicateURI));
+ repLog.warn(
+ String.format(
+ "Cannot create new project on remote site %s."
+ + " Only local paths and SSH URLs are supported"
+ + " for remote repository creation",
+ replicateURI));
return false;
}
return true;
@@ -267,16 +259,13 @@ public class ReplicationQueue implements
u.link(head);
}
} catch (IOException e) {
- repLog.error(String.format(
- "Error creating local repository %s:\n", uri.getPath()), e);
+ repLog.error(String.format("Error creating local repository %s:\n", uri.getPath()), e);
}
}
private void createRemoteSsh(URIish uri, String head) {
String quotedPath = QuotedString.BOURNE.quote(uri.getPath());
- String cmd = "mkdir -p " + quotedPath
- + " && cd " + quotedPath
- + " && git init --bare";
+ String cmd = "mkdir -p " + quotedPath + " && cd " + quotedPath + " && git init --bare";
if (head != null) {
cmd = cmd + " && git symbolic-ref HEAD " + QuotedString.BOURNE.quote(head);
}
@@ -284,12 +273,14 @@ public class ReplicationQueue implements
try {
executeRemoteSsh(uri, cmd, errStream);
} catch (IOException e) {
- repLog.error(String.format(
- "Error creating remote repository at %s:\n"
- + " Exception: %s\n"
- + " Command: %s\n"
- + " Output: %s",
- uri, e, cmd, errStream), e);
+ repLog.error(
+ String.format(
+ "Error creating remote repository at %s:\n"
+ + " Exception: %s\n"
+ + " Command: %s\n"
+ + " Output: %s",
+ uri, e, cmd, errStream),
+ e);
}
}
@@ -301,9 +292,12 @@ public class ReplicationQueue implements
deleteRemoteSsh(replicateURI);
repLog.info("Deleted remote repository: " + replicateURI);
} else {
- repLog.warn(String.format("Cannot delete project on remote site %s."
- + " Only local paths and SSH URLs are supported"
- + " for remote repository deletion", replicateURI));
+ repLog.warn(
+ String.format(
+ "Cannot delete project on remote site %s."
+ + " Only local paths and SSH URLs are supported"
+ + " for remote repository deletion",
+ replicateURI));
}
}
@@ -311,9 +305,7 @@ public class ReplicationQueue implements
try {
recursivelyDelete(new File(uri.getPath()));
} catch (IOException e) {
- repLog.error(String.format(
- "Error deleting local repository %s:\n",
- uri.getPath()), e);
+ repLog.error(String.format("Error deleting local repository %s:\n", uri.getPath()), e);
}
}
@@ -342,12 +334,14 @@ public class ReplicationQueue implements
try {
executeRemoteSsh(uri, cmd, errStream);
} catch (IOException e) {
- repLog.error(String.format(
- "Error deleting remote repository at %s:\n"
- + " Exception: %s\n"
- + " Command: %s\n"
- + " Output: %s",
- uri, e, cmd, errStream), e);
+ repLog.error(
+ String.format(
+ "Error deleting remote repository at %s:\n"
+ + " Exception: %s\n"
+ + " Command: %s\n"
+ + " Output: %s",
+ uri, e, cmd, errStream),
+ e);
}
}
@@ -357,27 +351,31 @@ public class ReplicationQueue implements
} else if (isSSH(replicateURI)) {
updateHeadRemoteSsh(replicateURI, newHead);
} else {
- repLog.warn(String.format(
- "Cannot update HEAD of project on remote site %s."
- + " Only local paths and SSH URLs are supported"
- + " for remote HEAD update.", replicateURI));
+ repLog.warn(
+ String.format(
+ "Cannot update HEAD of project on remote site %s."
+ + " Only local paths and SSH URLs are supported"
+ + " for remote HEAD update.",
+ replicateURI));
}
}
private void updateHeadRemoteSsh(URIish uri, String newHead) {
String quotedPath = QuotedString.BOURNE.quote(uri.getPath());
- String cmd = "cd " + quotedPath
- + " && git symbolic-ref HEAD " + QuotedString.BOURNE.quote(newHead);
+ String cmd =
+ "cd " + quotedPath + " && git symbolic-ref HEAD " + QuotedString.BOURNE.quote(newHead);
OutputStream errStream = newErrorBufferStream();
try {
executeRemoteSsh(uri, cmd, errStream);
} catch (IOException e) {
- repLog.error(String.format(
- "Error updating HEAD of remote repository at %s to %s:\n"
- + " Exception: %s\n"
- + " Command: %s\n"
- + " Output: %s",
- uri, newHead, e, cmd, errStream), e);
+ repLog.error(
+ String.format(
+ "Error updating HEAD of remote repository at %s to %s:\n"
+ + " Exception: %s\n"
+ + " Command: %s\n"
+ + " Output: %s",
+ uri, newHead, e, cmd, errStream),
+ e);
}
}
@@ -389,20 +387,16 @@ public class ReplicationQueue implements
}
} catch (IOException e) {
repLog.error(
- String.format("Failed to update HEAD of repository %s to %s",
- uri.getPath(), newHead), e);
+ String.format("Failed to update HEAD of repository %s to %s", uri.getPath(), newHead), e);
}
}
- private void executeRemoteSsh(URIish uri, String cmd,
- OutputStream errStream) throws IOException {
+ private void executeRemoteSsh(URIish uri, String cmd, OutputStream errStream) throws IOException {
RemoteSession ssh = connect(uri);
Process proc = ssh.exec(cmd, 0);
proc.getOutputStream().close();
- StreamCopyThread out =
- new StreamCopyThread(proc.getInputStream(), errStream);
- StreamCopyThread err =
- new StreamCopyThread(proc.getErrorStream(), errStream);
+ StreamCopyThread out = new StreamCopyThread(proc.getInputStream(), errStream);
+ StreamCopyThread err = new StreamCopyThread(proc.getErrorStream(), errStream);
out.start();
err.start();
try {
@@ -416,8 +410,7 @@ public class ReplicationQueue implements
}
private RemoteSession connect(URIish uri) throws TransportException {
- return sshSessionFactoryProvider.get().getSession(uri, null, FS.DETECTED,
- SSH_REMOTE_TIMEOUT);
+ return sshSessionFactoryProvider.get().getSession(uri, null, FS.DETECTED, SSH_REMOTE_TIMEOUT);
}
private static OutputStream newErrorBufferStream() {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationScheduledEvent.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationScheduledEvent.java
new file mode 100644
index 0000000..7268709
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationScheduledEvent.java
@@ -0,0 +1,44 @@
+// 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.googlesource.gerrit.plugins.replication;
+
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.Project.NameKey;
+import com.google.gerrit.server.events.RefEvent;
+
+public class ReplicationScheduledEvent extends RefEvent {
+ static final String TYPE = "ref-replication-scheduled";
+
+ final String project;
+ final String ref;
+ final String targetNode;
+
+ public ReplicationScheduledEvent(String project, String ref, String targetNode) {
+ super(TYPE);
+ this.project = project;
+ this.ref = ref;
+ this.targetNode = targetNode;
+ }
+
+ @Override
+ public String getRefName() {
+ return ref;
+ }
+
+ @Override
+ public NameKey getProjectNameKey() {
+ return new Project.NameKey(project);
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationSshSessionFactoryProvider.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationSshSessionFactoryProvider.java
index 42bc284..0d1aa06 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationSshSessionFactoryProvider.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationSshSessionFactoryProvider.java
@@ -15,7 +15,6 @@
package com.googlesource.gerrit.plugins.replication;
import com.google.inject.Provider;
-
import org.eclipse.jgit.transport.SshSessionFactory;
class ReplicationSshSessionFactoryProvider implements Provider<SshSessionFactory> {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationState.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationState.java
index 27fe841..9a68c83 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationState.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationState.java
@@ -16,13 +16,11 @@ package com.googlesource.gerrit.plugins.replication;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
-
-import org.eclipse.jgit.transport.RemoteRefUpdate;
-import org.eclipse.jgit.transport.URIish;
-
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
+import org.eclipse.jgit.transport.RemoteRefUpdate;
+import org.eclipse.jgit.transport.URIish;
public class ReplicationState {
private boolean allScheduled;
@@ -46,6 +44,7 @@ public class ReplicationState {
return replicatedNodesCount == nodesToReplicateCount;
}
}
+
private final Table<String, String, RefReplicationStatus> statusByProjectRef;
private int totalPushTasksCount;
private int finishedPushTasksCount;
@@ -69,10 +68,13 @@ public class ReplicationState {
return totalPushTasksCount != 0;
}
- public void notifyRefReplicated(String project, String ref, URIish uri,
- RefPushResult status, RemoteRefUpdate.Status refUpdateStatus) {
- pushResultProcessing.onRefReplicatedToOneNode(project, ref, uri, status,
- refUpdateStatus);
+ public void notifyRefReplicated(
+ String project,
+ String ref,
+ URIish uri,
+ RefPushResult status,
+ RemoteRefUpdate.Status refUpdateStatus) {
+ pushResultProcessing.onRefReplicatedToOneNode(project, ref, uri, status, refUpdateStatus);
RefReplicationStatus completedRefStatus = null;
boolean allPushTaksCompleted = false;
@@ -122,8 +124,7 @@ public class ReplicationState {
}
/**
- * Some could be remaining if replication of a ref is completed before all
- * tasks are scheduled.
+ * Some could be remaining if replication of a ref is completed before all tasks are scheduled.
*/
private void fireRemainingOnRefReplicatedToAllNodes() {
for (RefReplicationStatus refStatus : statusByProjectRef.values()) {
@@ -132,8 +133,8 @@ public class ReplicationState {
}
private void doRefPushTasksCompleted(RefReplicationStatus refStatus) {
- pushResultProcessing.onRefReplicatedToAllNodes(refStatus.project,
- refStatus.ref, refStatus.nodesToReplicateCount);
+ pushResultProcessing.onRefReplicatedToAllNodes(
+ refStatus.project, refStatus.ref, refStatus.nodesToReplicateCount);
}
private RefReplicationStatus getRefStatus(String project, String ref) {
@@ -158,19 +159,13 @@ public class ReplicationState {
}
public enum RefPushResult {
- /**
- * The ref was not successfully replicated.
- */
+ /** The ref was not successfully replicated. */
FAILED,
- /**
- * The ref is not configured to be replicated.
- */
+ /** The ref is not configured to be replicated. */
NOT_ATTEMPTED,
- /**
- * The ref was successfully replicated.
- */
+ /** The ref was successfully replicated. */
SUCCEEDED;
@Override
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationStateListener.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationStateListener.java
index 4dcf5a1..8e26906 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationStateListener.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationStateListener.java
@@ -14,16 +14,13 @@
package com.googlesource.gerrit.plugins.replication;
-/**
- * Interface for notifying replication status updates.
- */
+/** Interface for notifying replication status updates. */
public interface ReplicationStateListener {
/**
* Notify a non-fatal replication error.
*
- * Replication states received a non-fatal error with an associated
- * warning message.
+ * <p>Replication states received a non-fatal error with an associated warning message.
*
* @param msg message description of the error
* @param states replication states impacted
@@ -33,8 +30,7 @@ public interface ReplicationStateListener {
/**
* Notify a fatal replication error.
*
- * Replication states have received a fatal error and replication has
- * failed.
+ * <p>Replication states have received a fatal error and replication has failed.
*
* @param msg message description of the error
* @param states replication states impacted
@@ -44,13 +40,11 @@ public interface ReplicationStateListener {
/**
* Notify a fatal replication error with the associated exception.
*
- * Replication states have received a fatal exception and replication has failed.
+ * <p>Replication states have received a fatal exception and replication has failed.
*
* @param msg message description of the error
* @param t exception that caused the replication to fail
* @param states replication states impacted
*/
- void error(String msg, Throwable t,
- ReplicationState... states);
-
+ void error(String msg, Throwable t, ReplicationState... states);
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationStateLogger.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationStateLogger.java
index 0a59ad3..cfa95dd 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationStateLogger.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationStateLogger.java
@@ -20,11 +20,10 @@ import com.google.inject.Singleton;
/**
* Wrapper around a Logger that also logs out the replication state.
- * <p>
- * When logging replication errors it is useful to know the current
- * replication state. This utility class wraps the methods from Logger
- * and logs additional information about the replication state to the
- * stderr console.
+ *
+ * <p>When logging replication errors it is useful to know the current replication state. This
+ * utility class wraps the methods from Logger and logs additional information about the replication
+ * state to the stderr console.
*/
@Singleton
class ReplicationStateLogger implements ReplicationStateListener {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/SecureCredentialsFactory.java b/src/main/java/com/googlesource/gerrit/plugins/replication/SecureCredentialsFactory.java
index a10f62f..2b0c16b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/SecureCredentialsFactory.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/SecureCredentialsFactory.java
@@ -16,37 +16,32 @@ package com.googlesource.gerrit.plugins.replication;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.Inject;
-
+import java.io.IOException;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.util.FS;
-import java.io.IOException;
-
/** Looks up a remote's password in secure.config. */
class SecureCredentialsFactory implements CredentialsFactory {
private final Config config;
@Inject
- SecureCredentialsFactory(SitePaths site)
- throws ConfigInvalidException, IOException {
+ SecureCredentialsFactory(SitePaths site) throws ConfigInvalidException, IOException {
config = load(site);
}
- private static Config load(SitePaths site)
- throws ConfigInvalidException, IOException {
- FileBasedConfig cfg =
- new FileBasedConfig(site.secure_config.toFile(), FS.DETECTED);
+ private static Config load(SitePaths site) throws ConfigInvalidException, IOException {
+ FileBasedConfig cfg = new FileBasedConfig(site.secure_config.toFile(), FS.DETECTED);
if (cfg.getFile().exists() && cfg.getFile().length() > 0) {
try {
cfg.load();
} catch (ConfigInvalidException e) {
- throw new ConfigInvalidException(String.format(
- "Config file %s is invalid: %s", cfg.getFile(), e.getMessage()), e);
+ throw new ConfigInvalidException(
+ String.format("Config file %s is invalid: %s", cfg.getFile(), e.getMessage()), e);
} catch (IOException e) {
- throw new IOException(String.format(
- "Cannot read %s: %s", cfg.getFile(), e.getMessage()), e);
+ throw new IOException(
+ String.format("Cannot read %s: %s", cfg.getFile(), e.getMessage()), e);
}
}
return cfg;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/SecureCredentialsProvider.java b/src/main/java/com/googlesource/gerrit/plugins/replication/SecureCredentialsProvider.java
index a878ed9..c4294a9 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/SecureCredentialsProvider.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/SecureCredentialsProvider.java
@@ -49,8 +49,7 @@ class SecureCredentialsProvider extends CredentialsProvider {
}
@Override
- public boolean get(URIish uri, CredentialItem... items)
- throws UnsupportedCredentialItem {
+ public boolean get(URIish uri, CredentialItem... items) throws UnsupportedCredentialItem {
String username = uri.getUser();
if (username == null) {
username = cfgUser;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/StartCommand.java b/src/main/java/com/googlesource/gerrit/plugins/replication/StartCommand.java
index be5242e..c701c21 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/StartCommand.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/StartCommand.java
@@ -18,23 +18,22 @@ import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;
-
import com.googlesource.gerrit.plugins.replication.PushResultProcessing.CommandProcessing;
-
-import org.kohsuke.args4j.Argument;
-import org.kohsuke.args4j.Option;
-
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
@RequiresCapability(StartReplicationCapability.START_REPLICATION)
-@CommandMetaData(name = "start", description = "Start replication for specific project or all projects")
+@CommandMetaData(
+ name = "start",
+ description = "Start replication for specific project or all projects"
+)
final class StartCommand extends SshCommand {
- @Inject
- private ReplicationStateLogger stateLog;
+ @Inject private ReplicationStateLogger stateLog;
@Option(name = "--all", usage = "push all known projects")
private boolean all;
@@ -42,15 +41,13 @@ final class StartCommand extends SshCommand {
@Option(name = "--url", metaVar = "PATTERN", usage = "pattern to match URL on")
private String urlMatch;
- @Option(name = "--wait",
- usage = "wait for replication to finish before exiting")
+ @Option(name = "--wait", usage = "wait for replication to finish before exiting")
private boolean wait;
@Argument(index = 0, multiValued = true, metaVar = "PATTERN", usage = "project name pattern")
private List<String> projectPatterns = new ArrayList<>(2);
- @Inject
- private PushAll.Factory pushFactory;
+ @Inject private PushAll.Factory pushFactory;
@Override
protected void run() throws Failure {
@@ -76,7 +73,8 @@ final class StartCommand extends SshCommand {
try {
future.get();
} catch (InterruptedException e) {
- stateLog.error("Thread was interrupted while waiting for PushAll operation to finish", e, state);
+ stateLog.error(
+ "Thread was interrupted while waiting for PushAll operation to finish", e, state);
return;
} catch (ExecutionException e) {
stateLog.error("An exception was thrown in PushAll operation", e, state);
diff --git a/src/main/resources/Documentation/cmd-list.md b/src/main/resources/Documentation/cmd-list.md
index 3c6b78f..b6688e0 100644
--- a/src/main/resources/Documentation/cmd-list.md
+++ b/src/main/resources/Documentation/cmd-list.md
@@ -70,5 +70,5 @@ List destinations whose name contains mirror:
SEE ALSO
--------
-* [Replication Configuration](config.html)
+* [Replication Configuration](config.md)
* [Access Control](../../../Documentation/access-control.html)
diff --git a/src/main/resources/Documentation/cmd-start.md b/src/main/resources/Documentation/cmd-start.md
index 19b33ec..59c3d1d 100644
--- a/src/main/resources/Documentation/cmd-start.md
+++ b/src/main/resources/Documentation/cmd-start.md
@@ -134,5 +134,5 @@ Replicate projects whose path includes a folder named `vendor` to host slave1:
SEE ALSO
--------
-* [Replication Configuration](config.html)
+* [Replication Configuration](config.md)
* [Access Control](../../../Documentation/access-control.html)
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 0577ab1..b1058b5 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -4,7 +4,7 @@ Replication Configuration
Enabling Replication
--------------------
-If replicating over SSH (recommended), ensure the host key of the
+If replicating over SSH, ensure the host key of the
remote system(s) is already in the Gerrit user's `~/.ssh/known_hosts`
file. The easiest way to add the host key is to connect once by hand
with the command line:
@@ -39,7 +39,7 @@ Then reload the replication plugin to pick up the new configuration:
```
To manually trigger replication at runtime, see
-SSH command [start](cmd-start.html).
+SSH command [start](cmd-start.md).
File `replication.config`
-------------------------
@@ -216,6 +216,17 @@ remote.NAME.replicationDelay
By default, 15 seconds.
+remote.NAME.rescheduleDelay
+: Delay when rescheduling a push operation due to an in-flight push
+ running for the same project.
+
+ Cannot be set to a value lower than 3 seconds to avoid a tight loop
+ of schedule/run which could cause 1K+ retries per second.
+
+ A configured value lower than 3 seconds will be rounded to 3 seconds.
+
+ By default, 3 seconds.
+
remote.NAME.replicationRetry
: Time to wait before scheduling a remote push operation previously
failed due to an offline remote server.
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/GitUpdateProcessingTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/GitUpdateProcessingTest.java
index 4cbac3a..41829bc 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/GitUpdateProcessingTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/GitUpdateProcessingTest.java
@@ -28,19 +28,16 @@ import com.google.gwtorm.client.KeyUtil;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.SchemaFactory;
import com.google.gwtorm.server.StandardKeyEncoder;
-
import com.googlesource.gerrit.plugins.replication.PushResultProcessing.GitUpdateProcessing;
import com.googlesource.gerrit.plugins.replication.ReplicationState.RefPushResult;
-
-import junit.framework.TestCase;
-
+import java.net.URISyntaxException;
import org.eclipse.jgit.transport.RemoteRefUpdate;
import org.eclipse.jgit.transport.URIish;
-
-import java.net.URISyntaxException;
+import org.junit.Before;
+import org.junit.Test;
@SuppressWarnings("unchecked")
-public class GitUpdateProcessingTest extends TestCase {
+public class GitUpdateProcessingTest {
static {
KeyUtil.setEncoderImpl(new StandardKeyEncoder());
}
@@ -48,9 +45,8 @@ public class GitUpdateProcessingTest extends TestCase {
private EventDispatcher dispatcherMock;
private GitUpdateProcessing gitUpdateProcessing;
- @Override
- protected void setUp() throws Exception {
- super.setUp();
+ @Before
+ public void setUp() throws Exception {
dispatcherMock = createMock(EventDispatcher.class);
replay(dispatcherMock);
ReviewDb reviewDbMock = createNiceMock(ReviewDb.class);
@@ -61,42 +57,58 @@ public class GitUpdateProcessingTest extends TestCase {
gitUpdateProcessing = new GitUpdateProcessing(dispatcherMock);
}
- public void testHeadRefReplicated() throws URISyntaxException, OrmException {
+ @Test
+ public void headRefReplicated() throws URISyntaxException, OrmException {
reset(dispatcherMock);
RefReplicatedEvent expectedEvent =
- new RefReplicatedEvent("someProject", "refs/heads/master", "someHost",
- RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ new RefReplicatedEvent(
+ "someProject",
+ "refs/heads/master",
+ "someHost",
+ RefPushResult.SUCCEEDED,
+ RemoteRefUpdate.Status.OK);
dispatcherMock.postEvent(RefReplicatedEventEquals.eqEvent(expectedEvent));
expectLastCall().once();
replay(dispatcherMock);
- gitUpdateProcessing.onRefReplicatedToOneNode("someProject",
- "refs/heads/master", new URIish("git://someHost/someProject.git"),
- RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ gitUpdateProcessing.onRefReplicatedToOneNode(
+ "someProject",
+ "refs/heads/master",
+ new URIish("git://someHost/someProject.git"),
+ RefPushResult.SUCCEEDED,
+ RemoteRefUpdate.Status.OK);
verify(dispatcherMock);
}
- public void testChangeRefReplicated() throws URISyntaxException, OrmException {
+ @Test
+ public void changeRefReplicated() throws URISyntaxException, OrmException {
reset(dispatcherMock);
RefReplicatedEvent expectedEvent =
- new RefReplicatedEvent("someProject", "refs/changes/01/1/1", "someHost",
- RefPushResult.FAILED, RemoteRefUpdate.Status.REJECTED_NONFASTFORWARD);
+ new RefReplicatedEvent(
+ "someProject",
+ "refs/changes/01/1/1",
+ "someHost",
+ RefPushResult.FAILED,
+ RemoteRefUpdate.Status.REJECTED_NONFASTFORWARD);
dispatcherMock.postEvent(RefReplicatedEventEquals.eqEvent(expectedEvent));
expectLastCall().once();
replay(dispatcherMock);
- gitUpdateProcessing.onRefReplicatedToOneNode("someProject",
- "refs/changes/01/1/1", new URIish("git://someHost/someProject.git"),
- RefPushResult.FAILED, RemoteRefUpdate.Status.REJECTED_NONFASTFORWARD);
+ gitUpdateProcessing.onRefReplicatedToOneNode(
+ "someProject",
+ "refs/changes/01/1/1",
+ new URIish("git://someHost/someProject.git"),
+ RefPushResult.FAILED,
+ RemoteRefUpdate.Status.REJECTED_NONFASTFORWARD);
verify(dispatcherMock);
}
- public void testOnAllNodesReplicated() throws OrmException {
+ @Test
+ public void onAllNodesReplicated() throws OrmException {
reset(dispatcherMock);
RefReplicationDoneEvent expectedDoneEvent =
new RefReplicationDoneEvent("someProject", "refs/heads/master", 5);
- dispatcherMock.postEvent(
- RefReplicationDoneEventEquals.eqEvent(expectedDoneEvent));
+ dispatcherMock.postEvent(RefReplicationDoneEventEquals.eqEvent(expectedDoneEvent));
expectLastCall().once();
replay(dispatcherMock);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/PushReplicationTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/PushReplicationTest.java
index 71b6600..8480cbe 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/PushReplicationTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/PushReplicationTest.java
@@ -18,11 +18,10 @@ import static com.google.common.truth.Truth.assertThat;
import static com.googlesource.gerrit.plugins.replication.Destination.encode;
import static com.googlesource.gerrit.plugins.replication.Destination.needsUrlEncoding;
+import java.net.URISyntaxException;
import org.eclipse.jgit.transport.URIish;
import org.junit.Test;
-import java.net.URISyntaxException;
-
public class PushReplicationTest {
@Test
@@ -38,7 +37,7 @@ public class PushReplicationTest {
}
@Test
- public void testUrlEncoding() {
+ public void urlEncoding() {
assertThat(encode("foo/bar/thing")).isEqualTo("foo/bar/thing");
assertThat(encode("-- All Projects --")).isEqualTo("--%20All%20Projects%20--");
assertThat(encode("name/with a space")).isEqualTo("name/with%20a%20space");
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/RefReplicatedEventEquals.java b/src/test/java/com/googlesource/gerrit/plugins/replication/RefReplicatedEventEquals.java
index d614463..983e97f 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/RefReplicatedEventEquals.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/RefReplicatedEventEquals.java
@@ -35,7 +35,7 @@ public class RefReplicatedEventEquals implements IArgumentMatcher {
if (!(actual instanceof RefReplicatedEvent)) {
return false;
}
- RefReplicatedEvent actualRefReplicatedEvent = (RefReplicatedEvent)actual;
+ RefReplicatedEvent actualRefReplicatedEvent = (RefReplicatedEvent) actual;
if (!equals(expected.project, actualRefReplicatedEvent.project)) {
return false;
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/RefReplicationDoneEventEquals.java b/src/test/java/com/googlesource/gerrit/plugins/replication/RefReplicationDoneEventEquals.java
index 02f96fb..d1284e1 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/RefReplicationDoneEventEquals.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/RefReplicationDoneEventEquals.java
@@ -35,7 +35,7 @@ public class RefReplicationDoneEventEquals implements IArgumentMatcher {
if (!(actual instanceof RefReplicationDoneEvent)) {
return false;
}
- RefReplicationDoneEvent actualRefReplicatedDoneEvent = (RefReplicationDoneEvent)actual;
+ RefReplicationDoneEvent actualRefReplicatedDoneEvent = (RefReplicationDoneEvent) actual;
if (!equals(expected.project, actualRefReplicatedDoneEvent.project)) {
return false;
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/ReplicationStateTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/ReplicationStateTest.java
index 56096c2..65e2d64 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/ReplicationStateTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/ReplicationStateTest.java
@@ -22,14 +22,12 @@ import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
import com.googlesource.gerrit.plugins.replication.ReplicationState.RefPushResult;
-
+import java.net.URISyntaxException;
import org.eclipse.jgit.transport.RemoteRefUpdate;
import org.eclipse.jgit.transport.URIish;
import org.junit.Before;
import org.junit.Test;
-import java.net.URISyntaxException;
-
public class ReplicationStateTest {
private ReplicationState replicationState;
@@ -67,41 +65,37 @@ public class ReplicationStateTest {
}
@Test
- public void shouldFireEventsForReplicationOfOneRefToOneNode()
- throws URISyntaxException {
+ public void shouldFireEventsForReplicationOfOneRefToOneNode() throws URISyntaxException {
resetToDefault(pushResultProcessingMock);
URIish uri = new URIish("git://someHost/someRepo.git");
//expected events
- pushResultProcessingMock.onRefReplicatedToOneNode("someProject", "someRef",
- uri, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
- pushResultProcessingMock.onRefReplicatedToAllNodes("someProject",
- "someRef", 1);
+ pushResultProcessingMock.onRefReplicatedToOneNode(
+ "someProject", "someRef", uri, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ pushResultProcessingMock.onRefReplicatedToAllNodes("someProject", "someRef", 1);
pushResultProcessingMock.onAllRefsReplicatedToAllNodes(1);
replay(pushResultProcessingMock);
//actual test
replicationState.increasePushTaskCount("someProject", "someRef");
replicationState.markAllPushTasksScheduled();
- replicationState.notifyRefReplicated("someProject", "someRef", uri,
- RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ replicationState.notifyRefReplicated(
+ "someProject", "someRef", uri, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
verify(pushResultProcessingMock);
}
@Test
- public void shouldFireEventsForReplicationOfOneRefToMultipleNodes()
- throws URISyntaxException {
+ public void shouldFireEventsForReplicationOfOneRefToMultipleNodes() throws URISyntaxException {
resetToDefault(pushResultProcessingMock);
URIish uri1 = new URIish("git://someHost1/someRepo.git");
URIish uri2 = new URIish("git://someHost2/someRepo.git");
//expected events
- pushResultProcessingMock.onRefReplicatedToOneNode("someProject", "someRef",
- uri1, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
- pushResultProcessingMock.onRefReplicatedToOneNode("someProject", "someRef",
- uri2, RefPushResult.FAILED, RemoteRefUpdate.Status.NON_EXISTING);
- pushResultProcessingMock.onRefReplicatedToAllNodes("someProject",
- "someRef", 2);
+ pushResultProcessingMock.onRefReplicatedToOneNode(
+ "someProject", "someRef", uri1, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ pushResultProcessingMock.onRefReplicatedToOneNode(
+ "someProject", "someRef", uri2, RefPushResult.FAILED, RemoteRefUpdate.Status.NON_EXISTING);
+ pushResultProcessingMock.onRefReplicatedToAllNodes("someProject", "someRef", 2);
pushResultProcessingMock.onAllRefsReplicatedToAllNodes(2);
replay(pushResultProcessingMock);
@@ -109,10 +103,10 @@ public class ReplicationStateTest {
replicationState.increasePushTaskCount("someProject", "someRef");
replicationState.increasePushTaskCount("someProject", "someRef");
replicationState.markAllPushTasksScheduled();
- replicationState.notifyRefReplicated("someProject", "someRef", uri1,
- RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
- replicationState.notifyRefReplicated("someProject", "someRef", uri2,
- RefPushResult.FAILED, RemoteRefUpdate.Status.NON_EXISTING);
+ replicationState.notifyRefReplicated(
+ "someProject", "someRef", uri1, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ replicationState.notifyRefReplicated(
+ "someProject", "someRef", uri2, RefPushResult.FAILED, RemoteRefUpdate.Status.NON_EXISTING);
verify(pushResultProcessingMock);
}
@@ -125,20 +119,18 @@ public class ReplicationStateTest {
URIish uri3 = new URIish("git://host3/someRepo.git");
//expected events
- pushResultProcessingMock.onRefReplicatedToOneNode("someProject", "ref1",
- uri1, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
- pushResultProcessingMock.onRefReplicatedToOneNode("someProject", "ref1",
- uri2, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
- pushResultProcessingMock.onRefReplicatedToOneNode("someProject", "ref1",
- uri3, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
- pushResultProcessingMock.onRefReplicatedToOneNode("someProject", "ref2",
- uri1, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
- pushResultProcessingMock.onRefReplicatedToOneNode("someProject", "ref2",
- uri2, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
- pushResultProcessingMock
- .onRefReplicatedToAllNodes("someProject", "ref1", 3);
- pushResultProcessingMock
- .onRefReplicatedToAllNodes("someProject", "ref2", 2);
+ pushResultProcessingMock.onRefReplicatedToOneNode(
+ "someProject", "ref1", uri1, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ pushResultProcessingMock.onRefReplicatedToOneNode(
+ "someProject", "ref1", uri2, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ pushResultProcessingMock.onRefReplicatedToOneNode(
+ "someProject", "ref1", uri3, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ pushResultProcessingMock.onRefReplicatedToOneNode(
+ "someProject", "ref2", uri1, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ pushResultProcessingMock.onRefReplicatedToOneNode(
+ "someProject", "ref2", uri2, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ pushResultProcessingMock.onRefReplicatedToAllNodes("someProject", "ref1", 3);
+ pushResultProcessingMock.onRefReplicatedToAllNodes("someProject", "ref2", 2);
pushResultProcessingMock.onAllRefsReplicatedToAllNodes(5);
replay(pushResultProcessingMock);
@@ -149,30 +141,29 @@ public class ReplicationStateTest {
replicationState.increasePushTaskCount("someProject", "ref2");
replicationState.increasePushTaskCount("someProject", "ref2");
replicationState.markAllPushTasksScheduled();
- replicationState.notifyRefReplicated("someProject", "ref1", uri1,
- RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
- replicationState.notifyRefReplicated("someProject", "ref1", uri2,
- RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
- replicationState.notifyRefReplicated("someProject", "ref1", uri3,
- RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
- replicationState.notifyRefReplicated("someProject", "ref2", uri1,
- RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
- replicationState.notifyRefReplicated("someProject", "ref2", uri2,
- RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ replicationState.notifyRefReplicated(
+ "someProject", "ref1", uri1, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ replicationState.notifyRefReplicated(
+ "someProject", "ref1", uri2, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ replicationState.notifyRefReplicated(
+ "someProject", "ref1", uri3, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ replicationState.notifyRefReplicated(
+ "someProject", "ref2", uri1, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ replicationState.notifyRefReplicated(
+ "someProject", "ref2", uri2, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
verify(pushResultProcessingMock);
}
@Test
- public void shouldFireEventsForReplicationSameRefDifferentProjects()
- throws URISyntaxException {
+ public void shouldFireEventsForReplicationSameRefDifferentProjects() throws URISyntaxException {
resetToDefault(pushResultProcessingMock);
URIish uri = new URIish("git://host1/someRepo.git");
//expected events
- pushResultProcessingMock.onRefReplicatedToOneNode("project1", "ref1", uri,
- RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
- pushResultProcessingMock.onRefReplicatedToOneNode("project2", "ref2", uri,
- RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ pushResultProcessingMock.onRefReplicatedToOneNode(
+ "project1", "ref1", uri, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ pushResultProcessingMock.onRefReplicatedToOneNode(
+ "project2", "ref2", uri, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
pushResultProcessingMock.onRefReplicatedToAllNodes("project1", "ref1", 1);
pushResultProcessingMock.onRefReplicatedToAllNodes("project2", "ref2", 1);
pushResultProcessingMock.onAllRefsReplicatedToAllNodes(2);
@@ -182,10 +173,10 @@ public class ReplicationStateTest {
replicationState.increasePushTaskCount("project1", "ref1");
replicationState.increasePushTaskCount("project2", "ref2");
replicationState.markAllPushTasksScheduled();
- replicationState.notifyRefReplicated("project1", "ref1", uri,
- RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
- replicationState.notifyRefReplicated("project2", "ref2", uri,
- RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ replicationState.notifyRefReplicated(
+ "project1", "ref1", uri, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ replicationState.notifyRefReplicated(
+ "project2", "ref2", uri, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
verify(pushResultProcessingMock);
}
@@ -195,25 +186,23 @@ public class ReplicationStateTest {
resetToDefault(pushResultProcessingMock);
URIish uri1 = new URIish("git://host1/someRepo.git");
- //expected events
- pushResultProcessingMock.onRefReplicatedToOneNode("someProject", "ref1",
- uri1, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
- pushResultProcessingMock.onRefReplicatedToOneNode("someProject", "ref2",
- uri1, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
- pushResultProcessingMock
- .onRefReplicatedToAllNodes("someProject", "ref1", 1);
- pushResultProcessingMock
- .onRefReplicatedToAllNodes("someProject", "ref2", 1);
+ //expected events
+ pushResultProcessingMock.onRefReplicatedToOneNode(
+ "someProject", "ref1", uri1, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ pushResultProcessingMock.onRefReplicatedToOneNode(
+ "someProject", "ref2", uri1, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ pushResultProcessingMock.onRefReplicatedToAllNodes("someProject", "ref1", 1);
+ pushResultProcessingMock.onRefReplicatedToAllNodes("someProject", "ref2", 1);
pushResultProcessingMock.onAllRefsReplicatedToAllNodes(2);
replay(pushResultProcessingMock);
//actual test
replicationState.increasePushTaskCount("someProject", "ref1");
replicationState.increasePushTaskCount("someProject", "ref2");
- replicationState.notifyRefReplicated("someProject", "ref1", uri1,
- RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
- replicationState.notifyRefReplicated("someProject", "ref2", uri1,
- RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ replicationState.notifyRefReplicated(
+ "someProject", "ref1", uri1, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
+ replicationState.notifyRefReplicated(
+ "someProject", "ref2", uri1, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK);
replicationState.markAllPushTasksScheduled();
verify(pushResultProcessingMock);
}