Merge branch 'stable-2.15' into stable-2.16
* stable-2.15:
Upgrade wiremock to 2.20.0
FileBasedWebSessionCacheTest: Pass test upon invalid key
Make the index striped locks size configurable
Bazel: Include eclipse-out directory in .bazelignore
Add explanatory comment to empty BUILD file(s)
Update mockito to 2.23.4
Setup: Replace 'multiply' with 'repeat' in init step
Setup: Add jgroups skipInterface configuration step
Setup: Add jgroups protocolStack configuration step
Configuration: Remove unnecessary usage of 'this'
Setup: Remove duplication of default auto reindex value
Setup: Add healthCheck configuration init step
Setup: Add synchronize event configuration init step
Setup: Add synchronize configuration step to forwarding sections
Setup: Call proper method for null subsection cases
Setup: Remove unused subsection method parameter
Setup: Add cache pattern configuration init step
Setup: Rename the number-to-string conversion methods
Setup: Add autoReindex delay and pollInterval configuration steps
Setup: Make the http section method name consistent
Setup: Add init step for autoReindex configuration
Add missing init step declaration in manifest
Upgrade bazlets to latest stable-2.15 to build with 2.15.7 API
FileBasedWebSessionCacheTest: Fix IncompatibleArgumentType error
Upgrade bazlets to latest stable-2.14 to build with 2.14.17 API
Harmonize how REST API handlers get a JSON body
Upgrade bazlets to latest stable-2.15 to build with 2.15.6 API
Upgrade bazlets to latest stable-2.14 to build with 2.14.16 API
Align Eclipse compiler settings with core Gerrit's
WORKSPACE: Make header line space indent consistent
WORKSPACE: Replace custom local_path with template
Upgrade wiremock to 2.19.0
bazlets: Replace native.git_repository with skylark rule
Harmonize external dependency names to use hyphen
Upgrade mockito to 2.23.0
Upgrade bazlets to latest stable-2.15 to build with 2.15.5 API
Update bazlets to latest stable-2.14 to build with 2.14.15 API
Update bazlets to latest stable-2.15 to build with 2.15.4 API
Update bazlets to latest stable-2.14 to build with 2.14.14 API
Migrate `tools/bazel.rc` to `.bazelrc`
Update bazlets to latest stable-2.14 to build with 2.14.13 API
Update bazlets to latest stable-2.14 to use 2.14.12 API
RestForwarder: Avoid retrying non recoverable exceptions
Configuration: Fix logging arguments should not require evaluation
Configuration: Move constants to corresponding classes
Auto-reindex changes, groups and accounts during startup
Upgrade wiremock to 2.18.0
Upgrade mockito to 2.21.0
Update bazlets to latest stable-2.14 to use 2.14.11 API
Upgrade bazlets to latest stable-2.15 to use 2.15.3 API
Change-Id: I7c32a40046a443e2c1cd8473402219ae4e6bf0af
diff --git a/.bazelignore b/.bazelignore
new file mode 100644
index 0000000..30f1613
--- /dev/null
+++ b/.bazelignore
@@ -0,0 +1 @@
+eclipse-out
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
index c2a4ef5..40e022d 100644
--- a/.settings/org.eclipse.jdt.core.prefs
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -18,7 +18,7 @@
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.doc.comment.support=enabled
org.eclipse.jdt.core.compiler.problem.APILeak=warning
-org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=ignore
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
@@ -35,7 +35,7 @@
org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
-org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
@@ -46,9 +46,9 @@
org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled
org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled
org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private
-org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
-org.eclipse.jdt.core.compiler.problem.missingDefaultCase=warning
+org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=enabled
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning
@@ -77,15 +77,15 @@
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
-org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
-org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
-org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=warning
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
@@ -113,7 +113,7 @@
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
-org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
org.eclipse.jdt.core.compiler.problem.unusedParameter=warning
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
diff --git a/BUILD b/BUILD
index 7fec2ea..7d5fad8 100644
--- a/BUILD
+++ b/BUILD
@@ -13,6 +13,7 @@
"Gerrit-PluginName: high-availability",
"Gerrit-Module: com.ericsson.gerrit.plugins.highavailability.Module",
"Gerrit-HttpModule: com.ericsson.gerrit.plugins.highavailability.HttpModule",
+ "Gerrit-InitStep: com.ericsson.gerrit.plugins.highavailability.Setup",
"Implementation-Title: high-availability plugin",
"Implementation-URL: https://gerrit-review.googlesource.com/#/admin/projects/plugins/high-availability",
],
diff --git a/WORKSPACE b/WORKSPACE
index 67d04d8..73b01f5 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -4,7 +4,7 @@
load_bazlets(
commit = "09a18a88ebdada986d32c1f50581e8734a47939a",
- #local_path = "/home/ehugare/workspaces/bazlets",
+ #local_path = "/home/<user>/projects/bazlets",
)
# Snapshot Plugin API
diff --git a/bazlets.bzl b/bazlets.bzl
index f97b72c..f089af4 100644
--- a/bazlets.bzl
+++ b/bazlets.bzl
@@ -1,10 +1,12 @@
+load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
+
NAME = "com_googlesource_gerrit_bazlets"
def load_bazlets(
commit,
local_path = None):
if not local_path:
- native.git_repository(
+ git_repository(
name = NAME,
remote = "https://gerrit.googlesource.com/bazlets",
commit = commit,
diff --git a/external_plugin_deps.bzl b/external_plugin_deps.bzl
index f3249eb..bca2271 100644
--- a/external_plugin_deps.bzl
+++ b/external_plugin_deps.bzl
@@ -3,33 +3,33 @@
def external_plugin_deps():
maven_jar(
name = "wiremock",
- artifact = "com.github.tomakehurst:wiremock-standalone:2.8.0",
- sha1 = "b4d91aca283a86b447d3906deac6e1509c3a94c5",
+ artifact = "com.github.tomakehurst:wiremock-standalone:2.20.0",
+ sha1 = "26e5d42ca7af2a9d4b97129595edd0192ad9bd30",
)
maven_jar(
name = "mockito",
- artifact = "org.mockito:mockito-core:2.15.0",
- sha1 = "b84bfbbc29cd22c9529409627af6ea2897f4fa85",
+ artifact = "org.mockito:mockito-core:2.23.4",
+ sha1 = "a35b6f8ffcfa786771eac7d7d903429e790fdf3f",
deps = [
- "@byte_buddy//jar",
- "@byte_buddy_agent//jar",
+ "@byte-buddy//jar",
+ "@byte-buddy-agent//jar",
"@objenesis//jar",
],
)
- BYTE_BUDDY_VER = "1.7.9"
+ BYTE_BUDDY_VERSION = "1.9.3"
maven_jar(
- name = "byte_buddy",
- artifact = "net.bytebuddy:byte-buddy:" + BYTE_BUDDY_VER,
- sha1 = "51218a01a882c04d0aba8c028179cce488bbcb58",
+ name = "byte-buddy",
+ artifact = "net.bytebuddy:byte-buddy:" + BYTE_BUDDY_VERSION,
+ sha1 = "f32e510b239620852fc9a2387fac41fd053d6a4d",
)
maven_jar(
- name = "byte_buddy_agent",
- artifact = "net.bytebuddy:byte-buddy-agent:" + BYTE_BUDDY_VER,
- sha1 = "a6c65f9da7f467ee1f02ff2841ffd3155aee2fc9",
+ name = "byte-buddy-agent",
+ artifact = "net.bytebuddy:byte-buddy-agent:" + BYTE_BUDDY_VERSION,
+ sha1 = "f5b78c16cf4060664d80b6ca32d80dca4bd3d264",
)
maven_jar(
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
index 9313656..8f1963a 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
@@ -33,6 +33,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Optional;
+import java.util.concurrent.TimeUnit;
import org.eclipse.jgit.lib.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -41,72 +42,17 @@
public class Configuration {
private static final Logger log = LoggerFactory.getLogger(Configuration.class);
- // main section
- static final String MAIN_SECTION = "main";
- static final String SHARED_DIRECTORY_KEY = "sharedDirectory";
- static final String DEFAULT_SHARED_DIRECTORY = "shared";
-
- // peerInfo section
+ // common parameter to peerInfo section
static final String PEER_INFO_SECTION = "peerInfo";
- static final String STATIC_SUBSECTION = PeerInfoStrategy.STATIC.name().toLowerCase();
- static final String JGROUPS_SUBSECTION = PeerInfoStrategy.JGROUPS.name().toLowerCase();
- static final String URL_KEY = "url";
- static final String STRATEGY_KEY = "strategy";
- static final String MY_URL_KEY = "myUrl";
-
- // jgroups section
- static final String JGROUPS_SECTION = "jgroups";
- static final String SKIP_INTERFACE_KEY = "skipInterface";
- static final String CLUSTER_NAME_KEY = "clusterName";
- static final String PROTOCOL_STACK_KEY = "protocolStack";
-
- // http section
- static final String HTTP_SECTION = "http";
- static final String USER_KEY = "user";
- static final String PASSWORD_KEY = "password";
- static final String CONNECTION_TIMEOUT_KEY = "connectionTimeout";
- static final String SOCKET_TIMEOUT_KEY = "socketTimeout";
- static final String MAX_TRIES_KEY = "maxTries";
- static final String RETRY_INTERVAL_KEY = "retryInterval";
-
- // cache section
- static final String CACHE_SECTION = "cache";
- static final String PATTERN_KEY = "pattern";
-
- // event section
- static final String EVENT_SECTION = "event";
-
- // index section
- static final String INDEX_SECTION = "index";
// common parameters to cache and index sections
static final String THREAD_POOL_SIZE_KEY = "threadPoolSize";
-
- // common parameters to cache, event index and websession sections
- static final String SYNCHRONIZE_KEY = "synchronize";
-
- // health check section
- static final String HEALTH_CHECK_SECTION = "healthCheck";
- static final String ENABLE_KEY = "enable";
- static final boolean DEFAULT_HEALTH_CHECK_ENABLED = true;
-
- // websession section
- static final String WEBSESSION_SECTION = "websession";
- static final String CLEANUP_INTERVAL_KEY = "cleanupInterval";
-
- static final int DEFAULT_TIMEOUT_MS = 5000;
- static final int DEFAULT_MAX_TRIES = 360;
- static final int DEFAULT_RETRY_INTERVAL = 10000;
static final int DEFAULT_THREAD_POOL_SIZE = 4;
- static final String DEFAULT_CLEANUP_INTERVAL = "24 hours";
- static final long DEFAULT_CLEANUP_INTERVAL_MS = HOURS.toMillis(24);
- static final boolean DEFAULT_SYNCHRONIZE = true;
- static final PeerInfoStrategy DEFAULT_PEER_INFO_STRATEGY = PeerInfoStrategy.STATIC;
- static final ImmutableList<String> DEFAULT_SKIP_INTERFACE_LIST =
- ImmutableList.of("lo*", "utun*", "awdl*");
- static final String DEFAULT_CLUSTER_NAME = "GerritHA";
+ static final String NUM_STRIPED_LOCKS = "numStripedLocks";
+ static final int DEFAULT_NUM_STRIPED_LOCKS = 10;
private final Main main;
+ private final AutoReindex autoReindex;
private final PeerInfo peerInfo;
private final JGroups jgroups;
private final Http http;
@@ -128,6 +74,7 @@
PluginConfigFactory pluginConfigFactory, @PluginName String pluginName, SitePaths site) {
Config cfg = pluginConfigFactory.getGlobalPluginConfig(pluginName);
main = new Main(site, cfg);
+ autoReindex = new AutoReindex(cfg);
peerInfo = new PeerInfo(cfg);
switch (peerInfo.strategy()) {
case STATIC:
@@ -152,6 +99,10 @@
return main;
}
+ public AutoReindex autoReindex() {
+ return autoReindex;
+ }
+
public PeerInfo peerInfo() {
return peerInfo;
}
@@ -208,6 +159,10 @@
}
public static class Main {
+ static final String MAIN_SECTION = "main";
+ static final String SHARED_DIRECTORY_KEY = "sharedDirectory";
+ static final String DEFAULT_SHARED_DIRECTORY = "shared";
+
private final Path sharedDirectory;
private Main(SitePaths site, Config cfg) {
@@ -228,12 +183,59 @@
}
}
+ public static class AutoReindex {
+
+ static final String AUTO_REINDEX_SECTION = "autoReindex";
+ static final String ENABLED = "enabled";
+ static final String DELAY = "delay";
+ static final String POLL_INTERVAL = "pollInterval";
+ static final boolean DEFAULT_AUTO_REINDEX = false;
+ static final long DEFAULT_DELAY = 10L;
+ static final long DEFAULT_POLL_INTERVAL = 0L;
+
+ private final boolean enabled;
+ private final long delaySec;
+ private final long pollSec;
+
+ public AutoReindex(Config cfg) {
+ enabled = cfg.getBoolean(AUTO_REINDEX_SECTION, ENABLED, DEFAULT_AUTO_REINDEX);
+ delaySec =
+ ConfigUtil.getTimeUnit(
+ cfg, AUTO_REINDEX_SECTION, null, DELAY, DEFAULT_DELAY, TimeUnit.SECONDS);
+ pollSec =
+ ConfigUtil.getTimeUnit(
+ cfg,
+ AUTO_REINDEX_SECTION,
+ null,
+ POLL_INTERVAL,
+ DEFAULT_POLL_INTERVAL,
+ TimeUnit.SECONDS);
+ }
+
+ public boolean enabled() {
+ return enabled;
+ }
+
+ public long delaySec() {
+ return delaySec;
+ }
+
+ public long pollSec() {
+ return pollSec;
+ }
+ }
+
public static class PeerInfo {
+ static final PeerInfoStrategy DEFAULT_PEER_INFO_STRATEGY = PeerInfoStrategy.STATIC;
+ static final String STRATEGY_KEY = "strategy";
+
private final PeerInfoStrategy strategy;
private PeerInfo(Config cfg) {
strategy = cfg.getEnum(PEER_INFO_SECTION, null, STRATEGY_KEY, DEFAULT_PEER_INFO_STRATEGY);
- log.debug("Strategy: {}", strategy.name());
+ if (log.isDebugEnabled()) {
+ log.debug("Strategy: {}", strategy.name());
+ }
}
public PeerInfoStrategy strategy() {
@@ -241,7 +243,10 @@
}
}
- public class PeerInfoStatic {
+ public static class PeerInfoStatic {
+ static final String STATIC_SUBSECTION = PeerInfoStrategy.STATIC.name().toLowerCase();
+ static final String URL_KEY = "url";
+
private final String url;
private PeerInfoStatic(Config cfg) {
@@ -257,6 +262,9 @@
}
public static class PeerInfoJGroups {
+ static final String JGROUPS_SUBSECTION = PeerInfoStrategy.JGROUPS.name().toLowerCase();
+ static final String MY_URL_KEY = "myUrl";
+
private final String myUrl;
private PeerInfoJGroups(Config cfg) {
@@ -270,6 +278,14 @@
}
public static class JGroups {
+ static final String JGROUPS_SECTION = "jgroups";
+ static final String SKIP_INTERFACE_KEY = "skipInterface";
+ static final String CLUSTER_NAME_KEY = "clusterName";
+ static final String PROTOCOL_STACK_KEY = "protocolStack";
+ static final ImmutableList<String> DEFAULT_SKIP_INTERFACE_LIST =
+ ImmutableList.of("lo*", "utun*", "awdl*");
+ static final String DEFAULT_CLUSTER_NAME = "GerritHA";
+
private final ImmutableList<String> skipInterface;
private final String clusterName;
private final Optional<Path> protocolStack;
@@ -311,6 +327,18 @@
}
public static class Http {
+ static final String HTTP_SECTION = "http";
+ static final String USER_KEY = "user";
+ static final String PASSWORD_KEY = "password";
+ static final String CONNECTION_TIMEOUT_KEY = "connectionTimeout";
+ static final String SOCKET_TIMEOUT_KEY = "socketTimeout";
+ static final String MAX_TRIES_KEY = "maxTries";
+ static final String RETRY_INTERVAL_KEY = "retryInterval";
+
+ static final int DEFAULT_TIMEOUT_MS = 5000;
+ static final int DEFAULT_MAX_TRIES = 360;
+ static final int DEFAULT_RETRY_INTERVAL = 10000;
+
private final String user;
private final String password;
private final int connectionTimeout;
@@ -354,6 +382,9 @@
/** Common parameters to cache, event, index and websession */
public abstract static class Forwarding {
+ static final boolean DEFAULT_SYNCHRONIZE = true;
+ static final String SYNCHRONIZE_KEY = "synchronize";
+
private final boolean synchronize;
private Forwarding(Config cfg, String section) {
@@ -377,6 +408,9 @@
}
public static class Cache extends Forwarding {
+ static final String CACHE_SECTION = "cache";
+ static final String PATTERN_KEY = "pattern";
+
private final int threadPoolSize;
private final List<String> patterns;
@@ -396,30 +430,46 @@
}
public static class Event extends Forwarding {
+ static final String EVENT_SECTION = "event";
+
private Event(Config cfg) {
super(cfg, EVENT_SECTION);
}
}
public static class Index extends Forwarding {
+ static final String INDEX_SECTION = "index";
+
private final int threadPoolSize;
+ private final int numStripedLocks;
+
private Index(Config cfg) {
super(cfg, INDEX_SECTION);
threadPoolSize = getInt(cfg, INDEX_SECTION, THREAD_POOL_SIZE_KEY, DEFAULT_THREAD_POOL_SIZE);
+ numStripedLocks = getInt(cfg, INDEX_SECTION, NUM_STRIPED_LOCKS, DEFAULT_NUM_STRIPED_LOCKS);
}
public int threadPoolSize() {
return threadPoolSize;
}
+
+ public int numStripedLocks() {
+ return numStripedLocks;
+ }
}
public static class Websession extends Forwarding {
+ static final String WEBSESSION_SECTION = "websession";
+ static final String CLEANUP_INTERVAL_KEY = "cleanupInterval";
+ static final String DEFAULT_CLEANUP_INTERVAL = "24 hours";
+ static final long DEFAULT_CLEANUP_INTERVAL_MS = HOURS.toMillis(24);
+
private final long cleanupInterval;
private Websession(Config cfg) {
super(cfg, WEBSESSION_SECTION);
- this.cleanupInterval =
+ cleanupInterval =
ConfigUtil.getTimeUnit(
Strings.nullToEmpty(cfg.getString(WEBSESSION_SECTION, null, CLEANUP_INTERVAL_KEY)),
DEFAULT_CLEANUP_INTERVAL_MS,
@@ -432,6 +482,10 @@
}
public static class HealthCheck {
+ static final String HEALTH_CHECK_SECTION = "healthCheck";
+ static final String ENABLE_KEY = "enable";
+ static final boolean DEFAULT_HEALTH_CHECK_ENABLED = true;
+
private final boolean enabled;
private HealthCheck(Config cfg) {
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java
index f9155da..744fac9 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java
@@ -14,6 +14,7 @@
package com.ericsson.gerrit.plugins.highavailability;
+import com.ericsson.gerrit.plugins.highavailability.autoreindex.AutoReindexModule;
import com.ericsson.gerrit.plugins.highavailability.cache.CacheModule;
import com.ericsson.gerrit.plugins.highavailability.event.EventModule;
import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwarderModule;
@@ -50,6 +51,9 @@
if (config.index().synchronize()) {
install(new IndexModule());
}
+ if (config.autoReindex().enabled()) {
+ install(new AutoReindexModule());
+ }
install(new PeerInfoModule(config.peerInfo().strategy()));
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Setup.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Setup.java
index a8241cb..e58f62f 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Setup.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Setup.java
@@ -14,33 +14,49 @@
package com.ericsson.gerrit.plugins.highavailability;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.CACHE_SECTION;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.CLEANUP_INTERVAL_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.CLUSTER_NAME_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.CONNECTION_TIMEOUT_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_CLEANUP_INTERVAL;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_CLUSTER_NAME;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_MAX_TRIES;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_RETRY_INTERVAL;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_SHARED_DIRECTORY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.AutoReindex.AUTO_REINDEX_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.AutoReindex.DEFAULT_AUTO_REINDEX;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.AutoReindex.DEFAULT_DELAY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.AutoReindex.DEFAULT_POLL_INTERVAL;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.AutoReindex.DELAY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.AutoReindex.ENABLED;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.AutoReindex.POLL_INTERVAL;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Cache.CACHE_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Cache.PATTERN_KEY;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_THREAD_POOL_SIZE;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_TIMEOUT_MS;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.HTTP_SECTION;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.INDEX_SECTION;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.JGROUPS_SUBSECTION;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.MAIN_SECTION;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.MAX_TRIES_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.PASSWORD_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Event.EVENT_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Forwarding.DEFAULT_SYNCHRONIZE;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Forwarding.SYNCHRONIZE_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.HealthCheck.DEFAULT_HEALTH_CHECK_ENABLED;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.HealthCheck.ENABLE_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.HealthCheck.HEALTH_CHECK_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.CONNECTION_TIMEOUT_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.DEFAULT_MAX_TRIES;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.DEFAULT_RETRY_INTERVAL;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.DEFAULT_TIMEOUT_MS;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.HTTP_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.MAX_TRIES_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.PASSWORD_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.RETRY_INTERVAL_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.SOCKET_TIMEOUT_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.USER_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Index.INDEX_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.JGroups.CLUSTER_NAME_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.JGroups.DEFAULT_CLUSTER_NAME;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.JGroups.PROTOCOL_STACK_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.JGroups.SKIP_INTERFACE_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Main.DEFAULT_SHARED_DIRECTORY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Main.MAIN_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Main.SHARED_DIRECTORY_KEY;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.PEER_INFO_SECTION;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.RETRY_INTERVAL_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.SHARED_DIRECTORY_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.SOCKET_TIMEOUT_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.STATIC_SUBSECTION;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.STRATEGY_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.PeerInfo.STRATEGY_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.PeerInfoJGroups.JGROUPS_SUBSECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.PeerInfoStatic.STATIC_SUBSECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.PeerInfoStatic.URL_KEY;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.THREAD_POOL_SIZE_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.URL_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.USER_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.WEBSESSION_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Websession.CLEANUP_INTERVAL_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Websession.DEFAULT_CLEANUP_INTERVAL;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Websession.WEBSESSION_SECTION;
import com.ericsson.gerrit.plugins.highavailability.Configuration.PeerInfoStrategy;
import com.google.common.base.Strings;
@@ -94,10 +110,13 @@
Path pluginConfigFile = site.etc_dir.resolve(pluginName + ".config");
config = new FileBasedConfig(pluginConfigFile.toFile(), FS.DETECTED);
config.load();
- configureHttp();
+ configureAutoReindexSection();
+ configureHttpSection();
configureCacheSection();
+ configureEventSection();
configureIndexSection();
configureWebsessionsSection();
+ configureHealthCheckSection();
if (!createHAReplicaSite(config)) {
configureMainSection();
configurePeerInfoSection();
@@ -107,6 +126,25 @@
}
}
+ private void configureAutoReindexSection() {
+ ui.header("AutoReindex section");
+ Boolean autoReindex =
+ promptAndSetBoolean("Auto reindex", AUTO_REINDEX_SECTION, ENABLED, DEFAULT_AUTO_REINDEX);
+ config.setBoolean(AUTO_REINDEX_SECTION, null, ENABLED, autoReindex);
+
+ String delay =
+ promptAndSetString("Delay", AUTO_REINDEX_SECTION, DELAY, numberToString(DEFAULT_DELAY));
+ config.setLong(AUTO_REINDEX_SECTION, null, DELAY, Long.valueOf(delay));
+
+ String pollInterval =
+ promptAndSetString(
+ "Poll interval",
+ AUTO_REINDEX_SECTION,
+ POLL_INTERVAL,
+ numberToString(DEFAULT_POLL_INTERVAL));
+ config.setLong(AUTO_REINDEX_SECTION, null, POLL_INTERVAL, Long.valueOf(pollInterval));
+ }
+
private void configureMainSection() {
ui.header("Main section");
String sharedDirDefault = ui.isBatch() ? DEFAULT_SHARED_DIRECTORY : null;
@@ -134,10 +172,22 @@
JGROUPS_SUBSECTION,
CLUSTER_NAME_KEY,
DEFAULT_CLUSTER_NAME);
+ promptAndSetString(
+ "Protocol stack (optional)",
+ PEER_INFO_SECTION,
+ JGROUPS_SUBSECTION,
+ PROTOCOL_STACK_KEY,
+ null);
+ promptAndSetString(
+ titleForOptionalWithNote("Skip interface", "interfaces"),
+ PEER_INFO_SECTION,
+ JGROUPS_SUBSECTION,
+ SKIP_INTERFACE_KEY,
+ null);
}
}
- private void configureHttp() {
+ private void configureHttpSection() {
ui.header("Http section");
promptAndSetString("User", HTTP_SECTION, USER_KEY, null);
promptAndSetString("Password", HTTP_SECTION, PASSWORD_KEY, null);
@@ -145,39 +195,82 @@
"Max number of tries to forward to remote peer",
HTTP_SECTION,
MAX_TRIES_KEY,
- str(DEFAULT_MAX_TRIES));
+ numberToString(DEFAULT_MAX_TRIES));
promptAndSetString(
- "Retry interval [ms]", HTTP_SECTION, RETRY_INTERVAL_KEY, str(DEFAULT_RETRY_INTERVAL));
+ "Retry interval [ms]",
+ HTTP_SECTION,
+ RETRY_INTERVAL_KEY,
+ numberToString(DEFAULT_RETRY_INTERVAL));
promptAndSetString(
- "Connection timeout [ms]", HTTP_SECTION, CONNECTION_TIMEOUT_KEY, str(DEFAULT_TIMEOUT_MS));
+ "Connection timeout [ms]",
+ HTTP_SECTION,
+ CONNECTION_TIMEOUT_KEY,
+ numberToString(DEFAULT_TIMEOUT_MS));
promptAndSetString(
- "Socket timeout [ms]", HTTP_SECTION, SOCKET_TIMEOUT_KEY, str(DEFAULT_TIMEOUT_MS));
+ "Socket timeout [ms]",
+ HTTP_SECTION,
+ SOCKET_TIMEOUT_KEY,
+ numberToString(DEFAULT_TIMEOUT_MS));
}
private void configureCacheSection() {
ui.header("Cache section");
+ promptAndSetSynchronize("Cache", CACHE_SECTION);
promptAndSetString(
"Cache thread pool size",
CACHE_SECTION,
THREAD_POOL_SIZE_KEY,
- str(DEFAULT_THREAD_POOL_SIZE));
+ numberToString(DEFAULT_THREAD_POOL_SIZE));
+ promptAndSetString(
+ titleForOptionalWithNote("Cache pattern", "patterns"), CACHE_SECTION, PATTERN_KEY, null);
+ }
+
+ private void configureEventSection() {
+ ui.header("Event section");
+ promptAndSetSynchronize("Event", EVENT_SECTION);
}
private void configureIndexSection() {
ui.header("Index section");
+ promptAndSetSynchronize("Index", INDEX_SECTION);
promptAndSetString(
"Index thread pool size",
INDEX_SECTION,
THREAD_POOL_SIZE_KEY,
- str(DEFAULT_THREAD_POOL_SIZE));
+ numberToString(DEFAULT_THREAD_POOL_SIZE));
}
private void configureWebsessionsSection() {
ui.header("Websession section");
+ promptAndSetSynchronize("Websession", WEBSESSION_SECTION);
promptAndSetString(
"Cleanup interval", WEBSESSION_SECTION, CLEANUP_INTERVAL_KEY, DEFAULT_CLEANUP_INTERVAL);
}
+ private void configureHealthCheckSection() {
+ ui.header("HealthCheck section");
+ Boolean healthCheck =
+ promptAndSetBoolean(
+ "Health check", HEALTH_CHECK_SECTION, ENABLE_KEY, DEFAULT_HEALTH_CHECK_ENABLED);
+ config.setBoolean(HEALTH_CHECK_SECTION, null, ENABLE_KEY, healthCheck);
+ }
+
+ private void promptAndSetSynchronize(String sectionTitle, String section) {
+ String titleSuffix = ": synchronize?";
+ String title = sectionTitle + titleSuffix;
+ promptAndSetBoolean(title, section, SYNCHRONIZE_KEY, DEFAULT_SYNCHRONIZE);
+ }
+
+ private Boolean promptAndSetBoolean(
+ String title, String section, String name, Boolean defaultValue) {
+ Boolean oldValue = config.getBoolean(section, null, name, defaultValue);
+ Boolean newValue = Boolean.parseBoolean(ui.readString(String.valueOf(oldValue), title));
+ if (!Objects.equals(oldValue, newValue)) {
+ config.setBoolean(section, null, name, newValue);
+ }
+ return newValue;
+ }
+
private String promptAndSetString(
String title, String section, String name, String defaultValue) {
return promptAndSetString(title, section, null, name, defaultValue);
@@ -197,8 +290,16 @@
return newValue;
}
- private static String str(int n) {
- return Integer.toString(n);
+ private static String titleForOptionalWithNote(String prefix, String suffix) {
+ return prefix + " (optional); manually repeat this line to configure more " + suffix;
+ }
+
+ private static String numberToString(int number) {
+ return Integer.toString(number);
+ }
+
+ private static String numberToString(long number) {
+ return Long.toString(number);
}
private boolean createHAReplicaSite(FileBasedConfig pluginConfig)
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/SetupLocalHAReplica.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/SetupLocalHAReplica.java
index ddbd994..b5c9730 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/SetupLocalHAReplica.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/SetupLocalHAReplica.java
@@ -14,14 +14,14 @@
package com.ericsson.gerrit.plugins.highavailability;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.CLUSTER_NAME_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_CLUSTER_NAME;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_SHARED_DIRECTORY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.JGROUPS_SUBSECTION;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.MAIN_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.JGroups.CLUSTER_NAME_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.JGroups.DEFAULT_CLUSTER_NAME;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Main.DEFAULT_SHARED_DIRECTORY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Main.MAIN_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Main.SHARED_DIRECTORY_KEY;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.PEER_INFO_SECTION;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.SHARED_DIRECTORY_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.STRATEGY_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.PeerInfo.STRATEGY_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.PeerInfoJGroups.JGROUPS_SUBSECTION;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.common.FileUtil;
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AccountReindexRunnable.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AccountReindexRunnable.java
new file mode 100644
index 0000000..da52555
--- /dev/null
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AccountReindexRunnable.java
@@ -0,0 +1,71 @@
+// Copyright (C) 2018 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.ericsson.gerrit.plugins.highavailability.autoreindex;
+
+import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexAccountHandler;
+import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexingHandler.Operation;
+import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.AbstractIndexRestApiServlet;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.account.AccountState;
+import com.google.gerrit.server.account.Accounts;
+import com.google.gerrit.server.util.OneOffRequestContext;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import java.io.IOException;
+import java.sql.Timestamp;
+import java.util.Optional;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AccountReindexRunnable extends ReindexRunnable<AccountState> {
+ private static final Logger log = LoggerFactory.getLogger(AccountReindexRunnable.class);
+
+ private final ForwardedIndexAccountHandler accountIdx;
+
+ private final Accounts accounts;
+
+ @Inject
+ public AccountReindexRunnable(
+ ForwardedIndexAccountHandler accountIdx,
+ IndexTs indexTs,
+ OneOffRequestContext ctx,
+ Accounts accounts) {
+ super(AbstractIndexRestApiServlet.IndexName.ACCOUNT, indexTs, ctx);
+ this.accountIdx = accountIdx;
+ this.accounts = accounts;
+ }
+
+ @Override
+ protected Iterable<AccountState> fetchItems(ReviewDb db) throws Exception {
+ return accounts.all();
+ }
+
+ @Override
+ protected Optional<Timestamp> indexIfNeeded(ReviewDb db, AccountState as, Timestamp sinceTs) {
+ try {
+ Account a = as.getAccount();
+ Timestamp accountTs = a.getRegisteredOn();
+ if (accountTs.after(sinceTs)) {
+ log.info("Index {}/{}/{}/{}", a.getId(), a.getFullName(), a.getPreferredEmail(), accountTs);
+ accountIdx.index(a.getId(), Operation.INDEX, Optional.empty());
+ return Optional.of(accountTs);
+ }
+ } catch (IOException | OrmException e) {
+ log.error("Reindex failed", e);
+ }
+ return Optional.empty();
+ }
+}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AutoReindexModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AutoReindexModule.java
new file mode 100644
index 0000000..d4871a7
--- /dev/null
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AutoReindexModule.java
@@ -0,0 +1,33 @@
+// Copyright (C) 2018 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.ericsson.gerrit.plugins.highavailability.autoreindex;
+
+import com.google.gerrit.extensions.events.AccountIndexedListener;
+import com.google.gerrit.extensions.events.ChangeIndexedListener;
+import com.google.gerrit.extensions.events.GroupIndexedListener;
+import com.google.gerrit.extensions.events.LifecycleListener;
+import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.inject.AbstractModule;
+
+public class AutoReindexModule extends AbstractModule {
+
+ @Override
+ protected void configure() {
+ DynamicSet.bind(binder(), LifecycleListener.class).to(AutoReindexScheduler.class);
+ DynamicSet.bind(binder(), ChangeIndexedListener.class).to(IndexTs.class);
+ DynamicSet.bind(binder(), AccountIndexedListener.class).to(IndexTs.class);
+ DynamicSet.bind(binder(), GroupIndexedListener.class).to(IndexTs.class);
+ }
+}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AutoReindexScheduler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AutoReindexScheduler.java
new file mode 100644
index 0000000..c0d90d1
--- /dev/null
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AutoReindexScheduler.java
@@ -0,0 +1,80 @@
+// Copyright (C) 2018 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.ericsson.gerrit.plugins.highavailability.autoreindex;
+
+import com.ericsson.gerrit.plugins.highavailability.Configuration;
+import com.google.gerrit.extensions.events.LifecycleListener;
+import com.google.gerrit.server.git.WorkQueue;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class AutoReindexScheduler implements LifecycleListener {
+ private static final Logger log = LoggerFactory.getLogger(AutoReindexScheduler.class);
+ private final Configuration.AutoReindex cfg;
+ private final ChangeReindexRunnable changeReindex;
+ private final AccountReindexRunnable accountReindex;
+ private final GroupReindexRunnable groupReindex;
+ private final ScheduledExecutorService executor;
+ private final List<Future<?>> futureTasks = new ArrayList<>();
+
+ @Inject
+ public AutoReindexScheduler(
+ Configuration cfg,
+ WorkQueue workQueue,
+ ChangeReindexRunnable changeReindex,
+ AccountReindexRunnable accountReindex,
+ GroupReindexRunnable groupReindex) {
+ this.cfg = cfg.autoReindex();
+ this.changeReindex = changeReindex;
+ this.accountReindex = accountReindex;
+ this.groupReindex = groupReindex;
+ this.executor = workQueue.createQueue(1, "HighAvailability-AutoReindex");
+ }
+
+ @Override
+ public void start() {
+ if (cfg.pollSec() > 0) {
+ log.info("Scheduling auto-reindex after {}s and every {}s", cfg.delaySec(), cfg.pollSec());
+ futureTasks.add(
+ executor.scheduleAtFixedRate(
+ changeReindex, cfg.delaySec(), cfg.pollSec(), TimeUnit.SECONDS));
+ futureTasks.add(
+ executor.scheduleAtFixedRate(
+ accountReindex, cfg.delaySec(), cfg.pollSec(), TimeUnit.SECONDS));
+ futureTasks.add(
+ executor.scheduleAtFixedRate(
+ groupReindex, cfg.delaySec(), cfg.pollSec(), TimeUnit.SECONDS));
+ } else {
+ log.info("Scheduling auto-reindex after {}s", cfg.delaySec());
+ futureTasks.add(executor.schedule(changeReindex, cfg.delaySec(), TimeUnit.SECONDS));
+ futureTasks.add(executor.schedule(accountReindex, cfg.delaySec(), TimeUnit.SECONDS));
+ futureTasks.add(executor.schedule(groupReindex, cfg.delaySec(), TimeUnit.SECONDS));
+ }
+ }
+
+ @Override
+ public void stop() {
+ futureTasks.forEach(t -> t.cancel(true));
+ executor.shutdown();
+ }
+}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ChangeReindexRunnable.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ChangeReindexRunnable.java
new file mode 100644
index 0000000..62a9792
--- /dev/null
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ChangeReindexRunnable.java
@@ -0,0 +1,114 @@
+// Copyright (C) 2018 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.ericsson.gerrit.plugins.highavailability.autoreindex;
+
+import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexChangeHandler;
+import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexingHandler.Operation;
+import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.AbstractIndexRestApiServlet;
+import com.google.common.collect.Streams;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gerrit.server.notedb.ChangeNotes.Factory.ChangeNotesResult;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.util.OneOffRequestContext;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import java.io.IOException;
+import java.sql.Timestamp;
+import java.util.Iterator;
+import java.util.Optional;
+import java.util.stream.Stream;
+import org.eclipse.jgit.lib.Repository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ChangeReindexRunnable extends ReindexRunnable<Change> {
+ private static final Logger log = LoggerFactory.getLogger(ChangeReindexRunnable.class);
+
+ private final ForwardedIndexChangeHandler changeIdx;
+
+ private final ProjectCache projectCache;
+
+ private final GitRepositoryManager repoManager;
+
+ private final ChangeNotes.Factory notesFactory;
+
+ private static class StreamIterable implements Iterable<Change> {
+
+ private final Stream<Change> stream;
+
+ public StreamIterable(Stream<Change> stream) {
+ this.stream = stream;
+ }
+
+ @Override
+ public Iterator<Change> iterator() {
+ return stream.iterator();
+ }
+ }
+
+ @Inject
+ public ChangeReindexRunnable(
+ ForwardedIndexChangeHandler changeIdx,
+ IndexTs indexTs,
+ OneOffRequestContext ctx,
+ ProjectCache projectCache,
+ GitRepositoryManager repoManager,
+ ChangeNotes.Factory notesFactory) {
+ super(AbstractIndexRestApiServlet.IndexName.CHANGE, indexTs, ctx);
+ this.changeIdx = changeIdx;
+ this.projectCache = projectCache;
+ this.repoManager = repoManager;
+ this.notesFactory = notesFactory;
+ }
+
+ @Override
+ protected Iterable<Change> fetchItems(ReviewDb db) throws Exception {
+ Stream<Change> allChangesStream = Stream.empty();
+ Iterable<Project.NameKey> projects = projectCache.all();
+ for (Project.NameKey projectName : projects) {
+ try (Repository repo = repoManager.openRepository(projectName)) {
+ Stream<Change> projectChangesStream =
+ notesFactory
+ .scan(repo, db, projectName)
+ .map(
+ (ChangeNotesResult changeNotes) -> {
+ return changeNotes.notes().getChange();
+ });
+ allChangesStream = Streams.concat(allChangesStream, projectChangesStream);
+ }
+ }
+ return new StreamIterable(allChangesStream);
+ }
+
+ @Override
+ protected Optional<Timestamp> indexIfNeeded(ReviewDb db, Change c, Timestamp sinceTs) {
+ try {
+ Timestamp changeTs = c.getLastUpdatedOn();
+ if (changeTs.after(sinceTs)) {
+ log.info(
+ "Index {}/{}/{} was updated after {}", c.getProject(), c.getId(), changeTs, sinceTs);
+ changeIdx.index(c.getProject() + "~" + c.getId(), Operation.INDEX, Optional.empty());
+ return Optional.of(changeTs);
+ }
+ } catch (OrmException | IOException e) {
+ log.error("Reindex failed", e);
+ }
+ return Optional.empty();
+ }
+}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnable.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnable.java
new file mode 100644
index 0000000..71a0280
--- /dev/null
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnable.java
@@ -0,0 +1,45 @@
+// Copyright (C) 2018 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.ericsson.gerrit.plugins.highavailability.autoreindex;
+
+import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.AbstractIndexRestApiServlet;
+import com.google.gerrit.common.data.GroupReference;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.group.db.Groups;
+import com.google.gerrit.server.util.OneOffRequestContext;
+import com.google.inject.Inject;
+import java.sql.Timestamp;
+import java.util.Optional;
+
+public class GroupReindexRunnable extends ReindexRunnable<GroupReference> {
+
+ private final Groups groups;
+
+ @Inject
+ public GroupReindexRunnable(IndexTs indexTs, OneOffRequestContext ctx, Groups groups) {
+ super(AbstractIndexRestApiServlet.IndexName.GROUP, indexTs, ctx);
+ this.groups = groups;
+ }
+
+ @Override
+ protected Iterable<GroupReference> fetchItems(ReviewDb db) throws Exception {
+ return groups.getAllGroupReferences()::iterator;
+ }
+
+ @Override
+ protected Optional<Timestamp> indexIfNeeded(ReviewDb db, GroupReference g, Timestamp sinceTs) {
+ return Optional.empty();
+ }
+}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/IndexTs.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/IndexTs.java
new file mode 100644
index 0000000..40b4117
--- /dev/null
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/IndexTs.java
@@ -0,0 +1,155 @@
+// Copyright (C) 2018 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.ericsson.gerrit.plugins.highavailability.autoreindex;
+
+import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.AbstractIndexRestApiServlet;
+import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.AbstractIndexRestApiServlet.IndexName;
+import com.google.gerrit.extensions.annotations.PluginData;
+import com.google.gerrit.extensions.events.AccountIndexedListener;
+import com.google.gerrit.extensions.events.ChangeIndexedListener;
+import com.google.gerrit.extensions.events.GroupIndexedListener;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.change.ChangeFinder;
+import com.google.gerrit.server.git.WorkQueue;
+import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ScheduledExecutorService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class IndexTs
+ implements ChangeIndexedListener, AccountIndexedListener, GroupIndexedListener {
+ private static final Logger log = LoggerFactory.getLogger(IndexTs.class);
+ private static final DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
+
+ private final Path dataDir;
+ private final ScheduledExecutorService exec;
+ private final FlusherRunner flusher;
+ private final SchemaFactory<ReviewDb> schemaFactory;
+ private final ChangeFinder changeFinder;
+
+ private volatile LocalDateTime changeTs;
+ private volatile LocalDateTime accountTs;
+ private volatile LocalDateTime groupTs;
+
+ class FlusherRunner implements Runnable {
+ private Map<AbstractIndexRestApiServlet.IndexName, LocalDateTime> storedTs = new HashMap<>();
+
+ @Override
+ public void run() {
+ store(AbstractIndexRestApiServlet.IndexName.CHANGE, changeTs);
+ store(AbstractIndexRestApiServlet.IndexName.ACCOUNT, accountTs);
+ store(AbstractIndexRestApiServlet.IndexName.GROUP, groupTs);
+ }
+
+ private void store(AbstractIndexRestApiServlet.IndexName index, LocalDateTime latestTs) {
+ LocalDateTime currTs = storedTs.get(index);
+ if (currTs == null || latestTs.isAfter(currTs)) {
+ Path indexTsFile = dataDir.resolve(index.name().toLowerCase());
+ try {
+ Files.write(indexTsFile, latestTs.format(formatter).getBytes(StandardCharsets.UTF_8));
+ storedTs.put(index, currTs);
+ } catch (IOException e) {
+ log.error("Unable to update last timestamp for index " + index, e);
+ }
+ }
+ }
+ }
+
+ @Inject
+ public IndexTs(
+ @PluginData Path dataDir,
+ WorkQueue queue,
+ SchemaFactory<ReviewDb> schemaFactory,
+ ChangeFinder changeFinder) {
+ this.dataDir = dataDir;
+ this.exec = queue.getDefaultQueue();
+ this.flusher = new FlusherRunner();
+ this.schemaFactory = schemaFactory;
+ this.changeFinder = changeFinder;
+ }
+
+ @Override
+ public void onGroupIndexed(String uuid) {
+ update(IndexName.GROUP, LocalDateTime.now());
+ }
+
+ @Override
+ public void onAccountIndexed(int id) {
+ update(IndexName.ACCOUNT, LocalDateTime.now());
+ }
+
+ @Override
+ public void onChangeIndexed(String projectName, int id) {
+ try (ReviewDb db = schemaFactory.open()) {
+ ChangeNotes changeNotes = changeFinder.findOne(projectName + "~" + id);
+ update(
+ IndexName.CHANGE,
+ changeNotes == null
+ ? LocalDateTime.now()
+ : changeNotes.getChange().getLastUpdatedOn().toLocalDateTime());
+ } catch (OrmException e) {
+ log.warn("Unable to update the latest TS for change {}", e);
+ }
+ }
+
+ @Override
+ public void onChangeDeleted(int id) {
+ update(IndexName.CHANGE, LocalDateTime.now());
+ }
+
+ public Optional<LocalDateTime> getUpdateTs(AbstractIndexRestApiServlet.IndexName index) {
+ try {
+ Path indexTsFile = dataDir.resolve(index.name().toLowerCase());
+ if (indexTsFile.toFile().exists()) {
+ String tsString = Files.readAllLines(indexTsFile).get(0);
+ return Optional.of(LocalDateTime.parse(tsString, formatter));
+ }
+ } catch (Exception e) {
+ log.warn("Unable to read last timestamp for index {}", index, e);
+ }
+ return Optional.empty();
+ }
+
+ void update(AbstractIndexRestApiServlet.IndexName index, LocalDateTime dateTime) {
+ switch (index) {
+ case CHANGE:
+ changeTs = dateTime;
+ break;
+ case ACCOUNT:
+ accountTs = dateTime;
+ break;
+ case GROUP:
+ groupTs = dateTime;
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported index " + index);
+ }
+ exec.execute(flusher);
+ }
+}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ReindexRunnable.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ReindexRunnable.java
new file mode 100644
index 0000000..7891bbf
--- /dev/null
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ReindexRunnable.java
@@ -0,0 +1,96 @@
+// Copyright (C) 2018 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.ericsson.gerrit.plugins.highavailability.autoreindex;
+
+import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.AbstractIndexRestApiServlet;
+import com.google.common.base.Stopwatch;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.util.ManualRequestContext;
+import com.google.gerrit.server.util.OneOffRequestContext;
+import com.google.inject.Inject;
+import java.sql.Timestamp;
+import java.time.LocalDateTime;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+abstract class ReindexRunnable<T> implements Runnable {
+ private static final Logger log = LoggerFactory.getLogger(ReindexRunnable.class);
+
+ private final AbstractIndexRestApiServlet.IndexName itemName;
+ private final OneOffRequestContext ctx;
+ private final IndexTs indexTs;
+
+ @Inject
+ public ReindexRunnable(
+ AbstractIndexRestApiServlet.IndexName itemName, IndexTs indexTs, OneOffRequestContext ctx) {
+ this.itemName = itemName;
+ this.ctx = ctx;
+ this.indexTs = indexTs;
+ }
+
+ @Override
+ public void run() {
+ Optional<LocalDateTime> maybeIndexTs = indexTs.getUpdateTs(itemName);
+ String itemNameString = itemName.name().toLowerCase();
+ if (maybeIndexTs.isPresent()) {
+ Timestamp lastIndexTs = Timestamp.valueOf(maybeIndexTs.get());
+ Timestamp newLastIndexTs = lastIndexTs;
+ log.debug("Scanning for all the {}s after {}", itemNameString, lastIndexTs);
+ try (ManualRequestContext mctx = ctx.open();
+ ReviewDb db = mctx.getReviewDbProvider().get()) {
+ int count = 0;
+ int errors = 0;
+ Stopwatch stopwatch = Stopwatch.createStarted();
+ for (T c : fetchItems(db)) {
+ try {
+ Optional<Timestamp> itemTs = indexIfNeeded(db, c, lastIndexTs);
+ if (itemTs.isPresent()) {
+ count++;
+ if (itemTs.get().after(newLastIndexTs)) {
+ newLastIndexTs = itemTs.get();
+ }
+ }
+ } catch (Exception e) {
+ log.error("Unable to reindex {} {}", itemNameString, c, e);
+ errors++;
+ }
+ }
+ long elapsedNanos = stopwatch.stop().elapsed(TimeUnit.NANOSECONDS);
+ if (count > 0) {
+ log.info(
+ "{} {}s reindexed in {} msec ({}/sec), {} failed",
+ count,
+ itemNameString,
+ elapsedNanos / 1000000L,
+ (count * 1000L) / (elapsedNanos / 1000000L),
+ errors);
+ } else if (errors > 0) {
+ log.info("{} {}s failed to reindex", errors, itemNameString);
+ } else {
+ log.debug("Scanning finished");
+ }
+ indexTs.update(itemName, newLastIndexTs.toLocalDateTime());
+ } catch (Exception e) {
+ log.error("Unable to scan " + itemNameString + "s", e);
+ }
+ }
+ }
+
+ protected abstract Iterable<T> fetchItems(ReviewDb db) throws Exception;
+
+ protected abstract Optional<Timestamp> indexIfNeeded(ReviewDb db, T item, Timestamp sinceTs);
+}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexAccountHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexAccountHandler.java
index 42d2123..1d68e72 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexAccountHandler.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexAccountHandler.java
@@ -14,12 +14,14 @@
package com.ericsson.gerrit.plugins.highavailability.forwarder;
+import com.ericsson.gerrit.plugins.highavailability.Configuration;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.server.index.account.AccountIndexer;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
+import java.util.Optional;
/**
* Index an account using {@link AccountIndexer}. This class is meant to be used on the receiving
@@ -32,18 +34,20 @@
private final AccountIndexer indexer;
@Inject
- ForwardedIndexAccountHandler(AccountIndexer indexer) {
+ ForwardedIndexAccountHandler(AccountIndexer indexer, Configuration config) {
+ super(config.index());
this.indexer = indexer;
}
@Override
- protected void doIndex(Account.Id id) throws IOException, OrmException {
+ protected void doIndex(Account.Id id, Optional<IndexEvent> indexEvent)
+ throws IOException, OrmException {
indexer.index(id);
log.debug("Account {} successfully indexed", id);
}
@Override
- protected void doDelete(Account.Id id) {
+ protected void doDelete(Account.Id id, Optional<IndexEvent> indexEvent) {
throw new UnsupportedOperationException("Delete from account index not supported");
}
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandler.java
index f31ef81..eb738d9 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandler.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandler.java
@@ -14,6 +14,7 @@
package com.ericsson.gerrit.plugins.highavailability.forwarder;
+import com.ericsson.gerrit.plugins.highavailability.Configuration;
import com.google.common.base.Splitter;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.server.ReviewDb;
@@ -26,6 +27,7 @@
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
+import java.util.Optional;
/**
* Index a change using {@link ChangeIndexer}. This class is meant to be used on the receiving side
@@ -41,14 +43,19 @@
@Inject
ForwardedIndexChangeHandler(
- ChangeIndexer indexer, SchemaFactory<ReviewDb> schemaFactory, ChangeFinder changeFinder) {
+ ChangeIndexer indexer,
+ SchemaFactory<ReviewDb> schemaFactory,
+ ChangeFinder changeFinder,
+ Configuration config) {
+ super(config.index());
this.indexer = indexer;
this.schemaFactory = schemaFactory;
this.changeFinder = changeFinder;
}
@Override
- protected void doIndex(String id) throws IOException, OrmException {
+ protected void doIndex(String id, Optional<IndexEvent> indexEvent)
+ throws IOException, OrmException {
ChangeNotes change = null;
try (ReviewDb db = schemaFactory.open()) {
change = changeFinder.findOne(id);
@@ -70,7 +77,7 @@
}
@Override
- protected void doDelete(String id) throws IOException {
+ protected void doDelete(String id, Optional<IndexEvent> indexEvent) throws IOException {
indexer.delete(parseChangeId(id));
log.debug("Change {} successfully deleted from index", id);
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexGroupHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexGroupHandler.java
index c518484..cbb748b 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexGroupHandler.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexGroupHandler.java
@@ -14,12 +14,14 @@
package com.ericsson.gerrit.plugins.highavailability.forwarder;
+import com.ericsson.gerrit.plugins.highavailability.Configuration;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.index.group.GroupIndexer;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
+import java.util.Optional;
/**
* Index a group using {@link GroupIndexer}. This class is meant to be used on the receiving side of
@@ -32,18 +34,20 @@
private final GroupIndexer indexer;
@Inject
- ForwardedIndexGroupHandler(GroupIndexer indexer) {
+ ForwardedIndexGroupHandler(GroupIndexer indexer, Configuration config) {
+ super(config.index());
this.indexer = indexer;
}
@Override
- protected void doIndex(AccountGroup.UUID uuid) throws IOException, OrmException {
+ protected void doIndex(AccountGroup.UUID uuid, Optional<IndexEvent> indexEvent)
+ throws IOException, OrmException {
indexer.index(uuid);
log.debug("Group {} successfully indexed", uuid);
}
@Override
- protected void doDelete(AccountGroup.UUID uuid) {
+ protected void doDelete(AccountGroup.UUID uuid, Optional<IndexEvent> indexEvent) {
throw new UnsupportedOperationException("Delete from group index not supported");
}
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexingHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexingHandler.java
index e64d97b..bfedf3f 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexingHandler.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexingHandler.java
@@ -14,9 +14,11 @@
package com.ericsson.gerrit.plugins.highavailability.forwarder;
+import com.ericsson.gerrit.plugins.highavailability.Configuration;
import com.google.common.util.concurrent.Striped;
import com.google.gwtorm.server.OrmException;
import java.io.IOException;
+import java.util.Optional;
import java.util.concurrent.locks.Lock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,22 +42,29 @@
}
}
- private final Striped<Lock> idLocks = Striped.lock(10);
+ private final Striped<Lock> idLocks;
- protected abstract void doIndex(T id) throws IOException, OrmException;
+ protected abstract void doIndex(T id, Optional<IndexEvent> indexEvent)
+ throws IOException, OrmException;
- protected abstract void doDelete(T id) throws IOException;
+ protected abstract void doDelete(T id, Optional<IndexEvent> indexEvent) throws IOException;
+
+ protected ForwardedIndexingHandler(Configuration.Index indexConfig) {
+ idLocks = Striped.lock(indexConfig.numStripedLocks());
+ }
/**
* Index an item in the local node, indexing will not be forwarded to the other node.
*
* @param id The id to index.
* @param operation The operation to do; index or delete
+ * @param indexEvent The index event details.
* @throws IOException If an error occur while indexing.
* @throws OrmException If an error occur while retrieving a change related to the item to index
*/
- public void index(T id, Operation operation) throws IOException, OrmException {
- log.debug("{} {}", operation, id);
+ public void index(T id, Operation operation, Optional<IndexEvent> indexEvent)
+ throws IOException, OrmException {
+ log.debug("{} {} {}", operation, id, indexEvent);
try {
Context.setForwardedEvent(true);
Lock idLock = idLocks.get(id);
@@ -63,10 +72,10 @@
try {
switch (operation) {
case INDEX:
- doIndex(id);
+ doIndex(id, indexEvent);
break;
case DELETE:
- doDelete(id);
+ doDelete(id, indexEvent);
break;
default:
log.error("unexpected operation: {}", operation);
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/Forwarder.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/Forwarder.java
index ab09b65..b156563 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/Forwarder.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/Forwarder.java
@@ -23,34 +23,38 @@
* Forward a account indexing event to the other master.
*
* @param accountId the account to index.
+ * @param indexEvent the details of the index event.
* @return true if successful, otherwise false.
*/
- boolean indexAccount(int accountId);
+ boolean indexAccount(int accountId, IndexEvent indexEvent);
/**
* Forward a change indexing event to the other master.
*
* @param projectName the project of the change to index.
* @param changeId the change to index.
+ * @param indexEvent the details of the index event.
* @return true if successful, otherwise false.
*/
- boolean indexChange(String projectName, int changeId);
+ boolean indexChange(String projectName, int changeId, IndexEvent indexEvent);
/**
* Forward a delete change from index event to the other master.
*
* @param changeId the change to remove from the index.
+ * @param indexEvent the details of the index event.
* @return rue if successful, otherwise false.
*/
- boolean deleteChangeFromIndex(int changeId);
+ boolean deleteChangeFromIndex(int changeId, IndexEvent indexEvent);
/**
* Forward a group indexing event to the other master.
*
* @param uuid the group to index.
+ * @param indexEvent the details of the index event.
* @return true if successful, otherwise false.
*/
- boolean indexGroup(String uuid);
+ boolean indexGroup(String uuid, IndexEvent indexEvent);
/**
* Forward a stream event to the other master.
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/IndexEvent.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/IndexEvent.java
new file mode 100644
index 0000000..f6f24a7
--- /dev/null
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/IndexEvent.java
@@ -0,0 +1,30 @@
+// Copyright (C) 2018 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.ericsson.gerrit.plugins.highavailability.forwarder;
+
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+
+public class IndexEvent {
+ public long eventCreatedOn = System.currentTimeMillis() / 1000;
+
+ @Override
+ public String toString() {
+ return "IndexEvent@"
+ + LocalDateTime.ofEpochSecond(eventCreatedOn, 0, ZoneOffset.UTC)
+ .format(DateTimeFormatter.ISO_DATE_TIME);
+ }
+}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractIndexRestApiServlet.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractIndexRestApiServlet.java
index 7349ca5..8c429de 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractIndexRestApiServlet.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractIndexRestApiServlet.java
@@ -21,13 +21,20 @@
import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexingHandler;
import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexingHandler.Operation;
+import com.ericsson.gerrit.plugins.highavailability.forwarder.IndexEvent;
+import com.google.common.base.Charsets;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
import com.google.gwtorm.server.OrmException;
import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public abstract class AbstractIndexRestApiServlet<T> extends AbstractRestApiServlet {
private static final long serialVersionUID = -1L;
+ private static final Gson gson = new GsonBuilder().create();
private final ForwardedIndexingHandler<T> forwardedIndexingHandler;
private final IndexName indexName;
@@ -80,7 +87,7 @@
String path = req.getRequestURI();
T id = parse(path.substring(path.lastIndexOf('/') + 1));
try {
- forwardedIndexingHandler.index(id, operation);
+ forwardedIndexingHandler.index(id, operation, parseBody(req));
rsp.setStatus(SC_NO_CONTENT);
} catch (IOException e) {
sendError(rsp, SC_CONFLICT, e.getMessage());
@@ -91,4 +98,14 @@
log.debug(msg, e);
}
}
+
+ protected Optional<IndexEvent> parseBody(HttpServletRequest req) throws IOException {
+ String contentType = req.getContentType();
+ if (contentType != null && contentType.contains("application/json")) {
+ return Optional.ofNullable(
+ gson.fromJson(
+ new InputStreamReader(req.getInputStream(), Charsets.UTF_8), IndexEvent.class));
+ }
+ return Optional.empty();
+ }
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpSession.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpSession.java
index d3fce97..253dca7 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpSession.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpSession.java
@@ -16,14 +16,19 @@
import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.HttpResponseHandler.HttpResult;
import com.ericsson.gerrit.plugins.highavailability.peers.PeerInfo;
-import com.google.common.base.Strings;
+import com.google.common.base.Supplier;
import com.google.common.net.MediaType;
+import com.google.gerrit.server.events.SupplierSerializer;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.io.IOException;
+import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
@@ -31,6 +36,8 @@
class HttpSession {
private final CloseableHttpClient httpClient;
private final Provider<Optional<PeerInfo>> peerInfo;
+ private final Gson gson =
+ new GsonBuilder().registerTypeAdapter(Supplier.class, new SupplierSerializer()).create();
@Inject
HttpSession(CloseableHttpClient httpClient, Provider<Optional<PeerInfo>> peerInfo) {
@@ -42,18 +49,14 @@
return post(endpoint, null);
}
- HttpResult post(String endpoint, String content) throws IOException {
+ HttpResult post(String endpoint, Object content) throws IOException {
HttpPost post = new HttpPost(getPeerInfo().getDirectUrl() + endpoint);
- if (!Strings.isNullOrEmpty(content)) {
- post.addHeader("Content-Type", MediaType.JSON_UTF_8.toString());
- post.setEntity(new StringEntity(content, StandardCharsets.UTF_8));
- }
+ setContent(post, content);
return httpClient.execute(post, new HttpResponseHandler());
}
HttpResult delete(String endpoint) throws IOException {
- return httpClient.execute(
- new HttpDelete(getPeerInfo().getDirectUrl() + endpoint), new HttpResponseHandler());
+ return delete(endpoint, null);
}
private PeerInfo getPeerInfo() throws PeerInfoNotAvailableException {
@@ -63,4 +66,35 @@
}
return info;
}
+
+ HttpResult delete(String endpoint, Object content) throws IOException {
+ HttpDeleteWithBody delete = new HttpDeleteWithBody(getPeerInfo().getDirectUrl() + endpoint);
+ setContent(delete, content);
+ return httpClient.execute(delete, new HttpResponseHandler());
+ }
+
+ private void setContent(HttpEntityEnclosingRequestBase request, Object content) {
+ if (content != null) {
+ request.addHeader("Content-Type", MediaType.JSON_UTF_8.toString());
+ request.setEntity(new StringEntity(jsonEncode(content), StandardCharsets.UTF_8));
+ }
+ }
+
+ private String jsonEncode(Object content) {
+ if (content instanceof String) {
+ return (String) content;
+ }
+ return gson.toJson(content);
+ }
+
+ private class HttpDeleteWithBody extends HttpEntityEnclosingRequestBase {
+ @Override
+ public String getMethod() {
+ return HttpDelete.METHOD_NAME;
+ }
+
+ private HttpDeleteWithBody(String uri) {
+ setURI(URI.create(uri));
+ }
+ }
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarder.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarder.java
index c2a0c6d..1e9e931 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarder.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarder.java
@@ -17,17 +17,17 @@
import com.ericsson.gerrit.plugins.highavailability.Configuration;
import com.ericsson.gerrit.plugins.highavailability.cache.Constants;
import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder;
+import com.ericsson.gerrit.plugins.highavailability.forwarder.IndexEvent;
import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.HttpResponseHandler.HttpResult;
import com.google.common.base.Joiner;
-import com.google.common.base.Supplier;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.server.events.Event;
-import com.google.gerrit.server.events.SupplierSerializer;
-import com.google.gson.GsonBuilder;
import com.google.inject.Inject;
import java.io.IOException;
import javax.net.ssl.SSLException;
+import org.apache.http.HttpException;
+import org.apache.http.client.ClientProtocolException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,42 +46,43 @@
}
@Override
- public boolean indexAccount(final int accountId) {
+ public boolean indexAccount(final int accountId, IndexEvent event) {
return new Request("index account", accountId) {
@Override
HttpResult send() throws IOException {
return httpSession.post(
- Joiner.on("/").join(pluginRelativePath, "index/account", accountId));
+ Joiner.on("/").join(pluginRelativePath, "index/account", accountId), event);
}
}.execute();
}
@Override
- public boolean indexChange(final String projectName, final int changeId) {
+ public boolean indexChange(String projectName, int changeId, IndexEvent event) {
return new Request("index change", changeId) {
@Override
HttpResult send() throws IOException {
- return httpSession.post(buildIndexEndpoint(projectName, changeId));
+ return httpSession.post(buildIndexEndpoint(projectName, changeId), event);
}
}.execute();
}
@Override
- public boolean deleteChangeFromIndex(final int changeId) {
+ public boolean deleteChangeFromIndex(final int changeId, IndexEvent event) {
return new Request("delete change", changeId) {
@Override
HttpResult send() throws IOException {
- return httpSession.delete(buildIndexEndpoint(changeId));
+ return httpSession.delete(buildIndexEndpoint(changeId), event);
}
}.execute();
}
@Override
- public boolean indexGroup(final String uuid) {
+ public boolean indexGroup(final String uuid, IndexEvent event) {
return new Request("index group", uuid) {
@Override
HttpResult send() throws IOException {
- return httpSession.post(Joiner.on("/").join(pluginRelativePath, "index/group", uuid));
+ return httpSession.post(
+ Joiner.on("/").join(pluginRelativePath, "index/group", uuid), event);
}
}.execute();
}
@@ -101,12 +102,7 @@
return new Request("send event", event.type) {
@Override
HttpResult send() throws IOException {
- String serializedEvent =
- new GsonBuilder()
- .registerTypeAdapter(Supplier.class, new SupplierSerializer())
- .create()
- .toJson(event);
- return httpSession.post(Joiner.on("/").join(pluginRelativePath, "event"), serializedEvent);
+ return httpSession.post(Joiner.on("/").join(pluginRelativePath, "event"), event);
}
}.execute();
}
@@ -204,7 +200,10 @@
abstract HttpResult send() throws IOException;
boolean isRecoverable(IOException e) {
- return !(e instanceof SSLException);
+ Throwable cause = e.getCause();
+ return !(e instanceof SSLException
+ || cause instanceof HttpException
+ || cause instanceof ClientProtocolException);
}
}
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandler.java
index 175eaaf..106422d 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandler.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandler.java
@@ -16,6 +16,7 @@
import com.ericsson.gerrit.plugins.highavailability.forwarder.Context;
import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder;
+import com.ericsson.gerrit.plugins.highavailability.forwarder.IndexEvent;
import com.google.common.base.Objects;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.events.AccountIndexedListener;
@@ -82,6 +83,12 @@
}
abstract class IndexTask implements Runnable {
+ protected final IndexEvent indexEvent;
+
+ IndexTask() {
+ indexEvent = new IndexEvent();
+ }
+
@Override
public void run() {
queuedTasks.remove(this);
@@ -105,9 +112,9 @@
@Override
public void execute() {
if (deleted) {
- forwarder.deleteChangeFromIndex(changeId);
+ forwarder.deleteChangeFromIndex(changeId, indexEvent);
} else {
- forwarder.indexChange(projectName, changeId);
+ forwarder.indexChange(projectName, changeId, indexEvent);
}
}
@@ -140,7 +147,7 @@
@Override
public void execute() {
- forwarder.indexAccount(accountId);
+ forwarder.indexAccount(accountId, indexEvent);
}
@Override
@@ -172,7 +179,7 @@
@Override
public void execute() {
- forwarder.indexGroup(groupUUID);
+ forwarder.indexGroup(groupUUID, indexEvent);
}
@Override
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 12b00b9..b59b1fc 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -12,6 +12,8 @@
```
[main]
sharedDirectory = /directory/accessible/from/both/instances
+[autoReindex]
+ enabled = false
[peerInfo]
strategy = static
[peerInfo "static"]
@@ -26,6 +28,8 @@
```
[main]
sharedDirectory = /directory/accessible/from/both/instances
+[autoReindex]
+ enabled = false
[peerInfo]
strategy = jgroups
[peerInfo "jgroups"]
@@ -50,6 +54,32 @@
directory is "/gerrit/root/shared/dir". When not specified, the default
is "shared".
+```autoReindex.enabled```
+: Enable the tracking of the latest change indexed under data/high-availability
+ for each of the indexes. At startup scans all the changes, accounts and groups
+ and reindex the ones that have been updated by other nodes while the server was down.
+ When not specified, the default is "false", that means no automatic tracking
+ and indexing at start.
+
+```autoReindex.delay```
+: When autoReindex is enabled, indicates the delay aftere the plugin startup,
+ before triggering the conditional reindexing of all changes, accounts and groups.
+ Delay is expressed in Gerrit time values as in [websession.cleanupInterval](#websessioncleanupInterval).
+ When not specified, the default is "10 seconds".
+
+```autoReindex.pollInterval```
+: When autoReindex is enabled, indicates the interval between the conditional
+ reindexing of all changes, accounts and groups.
+ Delay is expressed in Gerrit time values as in [websession.cleanupInterval](#websessioncleanupInterval).
+ When not specified, polling of conditional reindexing is disabled.
+
+```autoReindex.interval```
+: Enable the tracking of the latest change indexed under data/high-availability
+ for each of the indexes. At startup scans all the changes, accounts and groups
+ and reindex the ones that have been updated by other nodes while the server was down.
+ When not specified, the default is "false", that means no automatic tracking
+ and indexing at start.
+
```peerInfo.strategy```
: Strategy to find other peers. Supported strategies are `static` or `jgroups`.
Defaults to `static`.
@@ -150,6 +180,10 @@
: Whether to synchronize stream events.
Defaults to true.
+```index.numStripedLocks```
+: Number of striped locks to use during reindexing.
+ Defaults to 10.
+
```index.synchronize```
: Whether to synchronize secondary indexes.
Defaults to true.
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
index bb4c360..efb3b75 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
@@ -14,46 +14,48 @@
package com.ericsson.gerrit.plugins.highavailability;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.CACHE_SECTION;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.CLEANUP_INTERVAL_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.CLUSTER_NAME_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.CONNECTION_TIMEOUT_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_CLEANUP_INTERVAL_MS;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_CLUSTER_NAME;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_HEALTH_CHECK_ENABLED;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_MAX_TRIES;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_PEER_INFO_STRATEGY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_RETRY_INTERVAL;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_SHARED_DIRECTORY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_SKIP_INTERFACE_LIST;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_SYNCHRONIZE;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Cache.CACHE_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Cache.PATTERN_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_NUM_STRIPED_LOCKS;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_THREAD_POOL_SIZE;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_TIMEOUT_MS;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.ENABLE_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.EVENT_SECTION;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.HEALTH_CHECK_SECTION;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.HTTP_SECTION;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.INDEX_SECTION;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.JGROUPS_SECTION;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.JGROUPS_SUBSECTION;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.MAIN_SECTION;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.MAX_TRIES_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.MY_URL_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.PASSWORD_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.PATTERN_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Event.EVENT_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Forwarding.DEFAULT_SYNCHRONIZE;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Forwarding.SYNCHRONIZE_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.HealthCheck.DEFAULT_HEALTH_CHECK_ENABLED;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.HealthCheck.ENABLE_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.HealthCheck.HEALTH_CHECK_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.CONNECTION_TIMEOUT_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.DEFAULT_MAX_TRIES;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.DEFAULT_RETRY_INTERVAL;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.DEFAULT_TIMEOUT_MS;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.HTTP_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.MAX_TRIES_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.PASSWORD_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.RETRY_INTERVAL_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.SOCKET_TIMEOUT_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.USER_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Index.INDEX_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.JGroups.CLUSTER_NAME_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.JGroups.DEFAULT_CLUSTER_NAME;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.JGroups.DEFAULT_SKIP_INTERFACE_LIST;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.JGroups.JGROUPS_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.JGroups.PROTOCOL_STACK_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.JGroups.SKIP_INTERFACE_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Main.DEFAULT_SHARED_DIRECTORY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Main.MAIN_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Main.SHARED_DIRECTORY_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.NUM_STRIPED_LOCKS;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.PEER_INFO_SECTION;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.PROTOCOL_STACK_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.RETRY_INTERVAL_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.SHARED_DIRECTORY_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.SKIP_INTERFACE_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.SOCKET_TIMEOUT_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.STATIC_SUBSECTION;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.STRATEGY_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.SYNCHRONIZE_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.PeerInfo.DEFAULT_PEER_INFO_STRATEGY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.PeerInfo.STRATEGY_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.PeerInfoJGroups.JGROUPS_SUBSECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.PeerInfoJGroups.MY_URL_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.PeerInfoStatic.STATIC_SUBSECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.PeerInfoStatic.URL_KEY;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.THREAD_POOL_SIZE_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.URL_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.USER_KEY;
-import static com.ericsson.gerrit.plugins.highavailability.Configuration.WEBSESSION_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Websession.CLEANUP_INTERVAL_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Websession.DEFAULT_CLEANUP_INTERVAL_MS;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Websession.WEBSESSION_SECTION;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static java.util.concurrent.TimeUnit.SECONDS;
@@ -377,4 +379,12 @@
globalPluginConfig.setBoolean(HEALTH_CHECK_SECTION, null, ENABLE_KEY, true);
assertThat(getConfiguration().healthCheck().enabled()).isTrue();
}
+
+ @Test
+ public void testGetIndexNumStripedLocks() throws Exception {
+ assertThat(getConfiguration().index().numStripedLocks()).isEqualTo(DEFAULT_NUM_STRIPED_LOCKS);
+
+ globalPluginConfig.setInt(INDEX_SECTION, null, NUM_STRIPED_LOCKS, 100);
+ assertThat(getConfiguration().index().numStripedLocks()).isEqualTo(100);
+ }
}
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexAccountHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexAccountHandlerTest.java
index 0a96776..c2d3659 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexAccountHandlerTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexAccountHandlerTest.java
@@ -18,11 +18,14 @@
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import com.ericsson.gerrit.plugins.highavailability.Configuration;
import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexingHandler.Operation;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.server.index.account.AccountIndexer;
import java.io.IOException;
+import java.util.Optional;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -37,18 +40,22 @@
@Rule public ExpectedException exception = ExpectedException.none();
@Mock private AccountIndexer indexerMock;
+ @Mock private Configuration configMock;
+ @Mock private Configuration.Index indexMock;
private ForwardedIndexAccountHandler handler;
private Account.Id id;
@Before
public void setUp() throws Exception {
- handler = new ForwardedIndexAccountHandler(indexerMock);
+ when(configMock.index()).thenReturn(indexMock);
+ when(indexMock.numStripedLocks()).thenReturn(10);
+ handler = new ForwardedIndexAccountHandler(indexerMock, configMock);
id = new Account.Id(123);
}
@Test
public void testSuccessfulIndexing() throws Exception {
- handler.index(id, Operation.INDEX);
+ handler.index(id, Operation.INDEX, Optional.empty());
verify(indexerMock).index(id);
}
@@ -56,7 +63,7 @@
public void deleteIsNotSupported() throws Exception {
exception.expect(UnsupportedOperationException.class);
exception.expectMessage("Delete from account index not supported");
- handler.index(id, Operation.DELETE);
+ handler.index(id, Operation.DELETE, Optional.empty());
}
@Test
@@ -73,7 +80,7 @@
.index(id);
assertThat(Context.isForwardedEvent()).isFalse();
- handler.index(id, Operation.INDEX);
+ handler.index(id, Operation.INDEX, Optional.empty());
assertThat(Context.isForwardedEvent()).isFalse();
verify(indexerMock).index(id);
@@ -92,7 +99,7 @@
assertThat(Context.isForwardedEvent()).isFalse();
try {
- handler.index(id, Operation.INDEX);
+ handler.index(id, Operation.INDEX, Optional.empty());
fail("should have thrown an IOException");
} catch (IOException e) {
assertThat(e.getMessage()).isEqualTo("someMessage");
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandlerTest.java
index 63db939..54cd266 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandlerTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandlerTest.java
@@ -23,6 +23,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import com.ericsson.gerrit.plugins.highavailability.Configuration;
import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexingHandler.Operation;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.server.ReviewDb;
@@ -34,6 +35,7 @@
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.SchemaFactory;
import java.io.IOException;
+import java.util.Optional;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -62,6 +64,8 @@
@Mock private ReviewDb dbMock;
@Mock private ChangeFinder changeFinderMock;
@Mock private ChangeNotes changeNotes;
+ @Mock private Configuration configMock;
+ @Mock private Configuration.Index indexMock;
private ForwardedIndexChangeHandler handler;
private Change.Id id;
private Change change;
@@ -72,26 +76,30 @@
id = new Change.Id(TEST_CHANGE_NUMBER);
change = new Change(null, id, null, null, TimeUtil.nowTs());
when(changeNotes.getChange()).thenReturn(change);
- handler = new ForwardedIndexChangeHandler(indexerMock, schemaFactoryMock, changeFinderMock);
+ when(configMock.index()).thenReturn(indexMock);
+ when(indexMock.numStripedLocks()).thenReturn(10);
+ handler =
+ new ForwardedIndexChangeHandler(
+ indexerMock, schemaFactoryMock, changeFinderMock, configMock);
}
@Test
public void changeIsIndexed() throws Exception {
setupChangeAccessRelatedMocks(CHANGE_EXISTS);
- handler.index(TEST_CHANGE_ID, Operation.INDEX);
+ handler.index(TEST_CHANGE_ID, Operation.INDEX, Optional.empty());
verify(indexerMock, times(1)).index(any(ReviewDb.class), any(Change.class));
}
@Test
public void changeIsDeletedFromIndex() throws Exception {
- handler.index(TEST_CHANGE_ID, Operation.DELETE);
+ handler.index(TEST_CHANGE_ID, Operation.DELETE, Optional.empty());
verify(indexerMock, times(1)).delete(id);
}
@Test
public void changeToIndexDoesNotExist() throws Exception {
setupChangeAccessRelatedMocks(CHANGE_DOES_NOT_EXIST);
- handler.index(TEST_CHANGE_ID, Operation.INDEX);
+ handler.index(TEST_CHANGE_ID, Operation.INDEX, Optional.empty());
verify(indexerMock, times(1)).delete(id);
}
@@ -99,13 +107,13 @@
public void schemaThrowsExceptionWhenLookingUpForChange() throws Exception {
setupChangeAccessRelatedMocks(CHANGE_EXISTS, THROW_ORM_EXCEPTION);
exception.expect(OrmException.class);
- handler.index(TEST_CHANGE_ID, Operation.INDEX);
+ handler.index(TEST_CHANGE_ID, Operation.INDEX, Optional.empty());
}
@Test
public void indexerThrowsNoSuchChangeExceptionTryingToPostChange() throws Exception {
doThrow(new NoSuchChangeException(id)).when(schemaFactoryMock).open();
- handler.index(TEST_CHANGE_ID, Operation.INDEX);
+ handler.index(TEST_CHANGE_ID, Operation.INDEX, Optional.empty());
verify(indexerMock, times(1)).delete(id);
}
@@ -113,7 +121,7 @@
public void indexerThrowsNestedNoSuchChangeExceptionTryingToPostChange() throws Exception {
OrmException e = new OrmException("test", new NoSuchChangeException(id));
doThrow(e).when(schemaFactoryMock).open();
- handler.index(TEST_CHANGE_ID, Operation.INDEX);
+ handler.index(TEST_CHANGE_ID, Operation.INDEX, Optional.empty());
verify(indexerMock, times(1)).delete(id);
}
@@ -121,7 +129,7 @@
public void indexerThrowsIOExceptionTryingToIndexChange() throws Exception {
setupChangeAccessRelatedMocks(CHANGE_EXISTS, DO_NOT_THROW_ORM_EXCEPTION, THROW_IO_EXCEPTION);
exception.expect(IOException.class);
- handler.index(TEST_CHANGE_ID, Operation.INDEX);
+ handler.index(TEST_CHANGE_ID, Operation.INDEX, Optional.empty());
}
@Test
@@ -139,7 +147,7 @@
.index(any(ReviewDb.class), any(Change.class));
assertThat(Context.isForwardedEvent()).isFalse();
- handler.index(TEST_CHANGE_ID, Operation.INDEX);
+ handler.index(TEST_CHANGE_ID, Operation.INDEX, Optional.empty());
assertThat(Context.isForwardedEvent()).isFalse();
verify(indexerMock, times(1)).index(any(ReviewDb.class), any(Change.class));
@@ -159,7 +167,7 @@
assertThat(Context.isForwardedEvent()).isFalse();
try {
- handler.index(TEST_CHANGE_ID, Operation.INDEX);
+ handler.index(TEST_CHANGE_ID, Operation.INDEX, Optional.empty());
fail("should have thrown an IOException");
} catch (IOException e) {
assertThat(e.getMessage()).isEqualTo("someMessage");
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexGroupHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexGroupHandlerTest.java
index d2387d9..ab55b73 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexGroupHandlerTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexGroupHandlerTest.java
@@ -18,11 +18,14 @@
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import com.ericsson.gerrit.plugins.highavailability.Configuration;
import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexingHandler.Operation;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.index.group.GroupIndexer;
import java.io.IOException;
+import java.util.Optional;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -37,18 +40,22 @@
@Rule public ExpectedException exception = ExpectedException.none();
@Mock private GroupIndexer indexerMock;
+ @Mock private Configuration configMock;
+ @Mock private Configuration.Index indexMock;
private ForwardedIndexGroupHandler handler;
private AccountGroup.UUID uuid;
@Before
public void setUp() throws Exception {
- handler = new ForwardedIndexGroupHandler(indexerMock);
+ when(configMock.index()).thenReturn(indexMock);
+ when(indexMock.numStripedLocks()).thenReturn(10);
+ handler = new ForwardedIndexGroupHandler(indexerMock, configMock);
uuid = new AccountGroup.UUID("123");
}
@Test
public void testSuccessfulIndexing() throws Exception {
- handler.index(uuid, Operation.INDEX);
+ handler.index(uuid, Operation.INDEX, Optional.empty());
verify(indexerMock).index(uuid);
}
@@ -56,7 +63,7 @@
public void deleteIsNotSupported() throws Exception {
exception.expect(UnsupportedOperationException.class);
exception.expectMessage("Delete from group index not supported");
- handler.index(uuid, Operation.DELETE);
+ handler.index(uuid, Operation.DELETE, Optional.empty());
}
@Test
@@ -73,7 +80,7 @@
.index(uuid);
assertThat(Context.isForwardedEvent()).isFalse();
- handler.index(uuid, Operation.INDEX);
+ handler.index(uuid, Operation.INDEX, Optional.empty());
assertThat(Context.isForwardedEvent()).isFalse();
verify(indexerMock).index(uuid);
@@ -92,7 +99,7 @@
assertThat(Context.isForwardedEvent()).isFalse();
try {
- handler.index(uuid, Operation.INDEX);
+ handler.index(uuid, Operation.INDEX, Optional.empty());
fail("should have thrown an IOException");
} catch (IOException e) {
assertThat(e.getMessage()).isEqualTo("someMessage");
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexAccountRestApiServletTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexAccountRestApiServletTest.java
index c41a4a9..4622a17 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexAccountRestApiServletTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexAccountRestApiServletTest.java
@@ -17,6 +17,8 @@
import static javax.servlet.http.HttpServletResponse.SC_CONFLICT;
import static javax.servlet.http.HttpServletResponse.SC_METHOD_NOT_ALLOWED;
import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -57,7 +59,7 @@
@Test
public void accountIsIndexed() throws Exception {
servlet.doPost(requestMock, responseMock);
- verify(handlerMock, times(1)).index(id, Operation.INDEX);
+ verify(handlerMock, times(1)).index(eq(id), eq(Operation.INDEX), any());
verify(responseMock).setStatus(SC_NO_CONTENT);
}
@@ -69,14 +71,14 @@
@Test
public void indexerThrowsIOExceptionTryingToIndexAccount() throws Exception {
- doThrow(new IOException(IO_ERROR)).when(handlerMock).index(id, Operation.INDEX);
+ doThrow(new IOException(IO_ERROR)).when(handlerMock).index(eq(id), eq(Operation.INDEX), any());
servlet.doPost(requestMock, responseMock);
verify(responseMock).sendError(SC_CONFLICT, IO_ERROR);
}
@Test
public void sendErrorThrowsIOException() throws Exception {
- doThrow(new IOException(IO_ERROR)).when(handlerMock).index(id, Operation.INDEX);
+ doThrow(new IOException(IO_ERROR)).when(handlerMock).index(eq(id), eq(Operation.INDEX), any());
doThrow(new IOException("someError")).when(responseMock).sendError(SC_CONFLICT, IO_ERROR);
servlet.doPost(requestMock, responseMock);
verify(responseMock).sendError(SC_CONFLICT, IO_ERROR);
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexChangeRestApiServletTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexChangeRestApiServletTest.java
index 7fccc21..c1fa765 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexChangeRestApiServletTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexChangeRestApiServletTest.java
@@ -17,6 +17,8 @@
import static javax.servlet.http.HttpServletResponse.SC_CONFLICT;
import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -58,34 +60,40 @@
@Test
public void changeIsIndexed() throws Exception {
servlet.doPost(requestMock, responseMock);
- verify(handlerMock, times(1)).index(CHANGE_ID, Operation.INDEX);
+ verify(handlerMock, times(1)).index(eq(CHANGE_ID), eq(Operation.INDEX), any());
verify(responseMock).setStatus(SC_NO_CONTENT);
}
@Test
public void changeIsDeletedFromIndex() throws Exception {
servlet.doDelete(requestMock, responseMock);
- verify(handlerMock, times(1)).index(CHANGE_ID, Operation.DELETE);
+ verify(handlerMock, times(1)).index(eq(CHANGE_ID), eq(Operation.DELETE), any());
verify(responseMock).setStatus(SC_NO_CONTENT);
}
@Test
public void indexerThrowsIOExceptionTryingToIndexChange() throws Exception {
- doThrow(new IOException(IO_ERROR)).when(handlerMock).index(CHANGE_ID, Operation.INDEX);
+ doThrow(new IOException(IO_ERROR))
+ .when(handlerMock)
+ .index(eq(CHANGE_ID), eq(Operation.INDEX), any());
servlet.doPost(requestMock, responseMock);
verify(responseMock).sendError(SC_CONFLICT, IO_ERROR);
}
@Test
public void indexerThrowsOrmExceptionTryingToIndexChange() throws Exception {
- doThrow(new OrmException("some message")).when(handlerMock).index(CHANGE_ID, Operation.INDEX);
+ doThrow(new OrmException("some message"))
+ .when(handlerMock)
+ .index(eq(CHANGE_ID), eq(Operation.INDEX), any());
servlet.doPost(requestMock, responseMock);
verify(responseMock).sendError(SC_NOT_FOUND, "Error trying to find change");
}
@Test
public void sendErrorThrowsIOException() throws Exception {
- doThrow(new IOException(IO_ERROR)).when(handlerMock).index(CHANGE_ID, Operation.INDEX);
+ doThrow(new IOException(IO_ERROR))
+ .when(handlerMock)
+ .index(eq(CHANGE_ID), eq(Operation.INDEX), any());
doThrow(new IOException("someError")).when(responseMock).sendError(SC_CONFLICT, IO_ERROR);
servlet.doPost(requestMock, responseMock);
verify(responseMock).sendError(SC_CONFLICT, IO_ERROR);
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexGroupRestApiServletTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexGroupRestApiServletTest.java
index f03727e..6291142 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexGroupRestApiServletTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexGroupRestApiServletTest.java
@@ -17,6 +17,8 @@
import static javax.servlet.http.HttpServletResponse.SC_CONFLICT;
import static javax.servlet.http.HttpServletResponse.SC_METHOD_NOT_ALLOWED;
import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -56,7 +58,7 @@
@Test
public void groupIsIndexed() throws Exception {
servlet.doPost(requestMock, responseMock);
- verify(handlerMock, times(1)).index(uuid, Operation.INDEX);
+ verify(handlerMock, times(1)).index(eq(uuid), eq(Operation.INDEX), any());
verify(responseMock).setStatus(SC_NO_CONTENT);
}
@@ -68,14 +70,18 @@
@Test
public void indexerThrowsIOExceptionTryingToIndexGroup() throws Exception {
- doThrow(new IOException(IO_ERROR)).when(handlerMock).index(uuid, Operation.INDEX);
+ doThrow(new IOException(IO_ERROR))
+ .when(handlerMock)
+ .index(eq(uuid), eq(Operation.INDEX), any());
servlet.doPost(requestMock, responseMock);
verify(responseMock).sendError(SC_CONFLICT, IO_ERROR);
}
@Test
public void sendErrorThrowsIOException() throws Exception {
- doThrow(new IOException(IO_ERROR)).when(handlerMock).index(uuid, Operation.INDEX);
+ doThrow(new IOException(IO_ERROR))
+ .when(handlerMock)
+ .index(eq(uuid), eq(Operation.INDEX), any());
doThrow(new IOException("someError")).when(responseMock).sendError(SC_CONFLICT, IO_ERROR);
servlet.doPost(requestMock, responseMock);
verify(responseMock).sendError(SC_CONFLICT, IO_ERROR);
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderTest.java
index f49f2a3..fd2aa52 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderTest.java
@@ -15,13 +15,16 @@
package com.ericsson.gerrit.plugins.highavailability.forwarder.rest;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.ericsson.gerrit.plugins.highavailability.Configuration;
import com.ericsson.gerrit.plugins.highavailability.cache.Constants;
+import com.ericsson.gerrit.plugins.highavailability.forwarder.IndexEvent;
import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.HttpResponseHandler.HttpResult;
import com.google.common.base.Joiner;
import com.google.gerrit.reviewdb.client.Account;
@@ -64,7 +67,6 @@
// Event
private static final String EVENT_ENDPOINT = Joiner.on("/").join(PLUGINS, PLUGIN_NAME, "event");
private static Event event = new Event("test-event") {};
- private static String eventJson = new GsonBuilder().create().toJson(event);
private RestForwarder forwarder;
private HttpSession httpSessionMock;
@@ -80,99 +82,100 @@
@Test
public void testIndexAccountOK() throws Exception {
- when(httpSessionMock.post(INDEX_ACCOUNT_ENDPOINT))
+ when(httpSessionMock.post(eq(INDEX_ACCOUNT_ENDPOINT), any()))
.thenReturn(new HttpResult(SUCCESSFUL, EMPTY_MSG));
- assertThat(forwarder.indexAccount(ACCOUNT_NUMBER)).isTrue();
+ assertThat(forwarder.indexAccount(ACCOUNT_NUMBER, new IndexEvent())).isTrue();
}
@Test
public void testIndexAccountFailed() throws Exception {
- when(httpSessionMock.post(INDEX_ACCOUNT_ENDPOINT))
+ when(httpSessionMock.post(eq(INDEX_ACCOUNT_ENDPOINT), any()))
.thenReturn(new HttpResult(FAILED, EMPTY_MSG));
- assertThat(forwarder.indexAccount(ACCOUNT_NUMBER)).isFalse();
+ assertThat(forwarder.indexAccount(ACCOUNT_NUMBER, new IndexEvent())).isFalse();
}
@Test
public void testIndexAccountThrowsException() throws Exception {
- doThrow(new IOException()).when(httpSessionMock).post(INDEX_ACCOUNT_ENDPOINT);
- assertThat(forwarder.indexAccount(ACCOUNT_NUMBER)).isFalse();
+ doThrow(new IOException()).when(httpSessionMock).post(eq(INDEX_ACCOUNT_ENDPOINT), any());
+ assertThat(forwarder.indexAccount(ACCOUNT_NUMBER, new IndexEvent())).isFalse();
}
@Test
public void testIndexGroupOK() throws Exception {
- when(httpSessionMock.post(INDEX_GROUP_ENDPOINT))
+ when(httpSessionMock.post(eq(INDEX_GROUP_ENDPOINT), any()))
.thenReturn(new HttpResult(SUCCESSFUL, EMPTY_MSG));
- assertThat(forwarder.indexGroup(UUID)).isTrue();
+ assertThat(forwarder.indexGroup(UUID, new IndexEvent())).isTrue();
}
@Test
public void testIndexGroupFailed() throws Exception {
- when(httpSessionMock.post(INDEX_GROUP_ENDPOINT)).thenReturn(new HttpResult(FAILED, EMPTY_MSG));
- assertThat(forwarder.indexGroup(UUID)).isFalse();
+ when(httpSessionMock.post(eq(INDEX_GROUP_ENDPOINT), any()))
+ .thenReturn(new HttpResult(FAILED, EMPTY_MSG));
+ assertThat(forwarder.indexGroup(UUID, new IndexEvent())).isFalse();
}
@Test
public void testIndexGroupThrowsException() throws Exception {
- doThrow(new IOException()).when(httpSessionMock).post(INDEX_GROUP_ENDPOINT);
- assertThat(forwarder.indexGroup(UUID)).isFalse();
+ doThrow(new IOException()).when(httpSessionMock).post(eq(INDEX_GROUP_ENDPOINT), any());
+ assertThat(forwarder.indexGroup(UUID, new IndexEvent())).isFalse();
}
@Test
public void testIndexChangeOK() throws Exception {
- when(httpSessionMock.post(INDEX_CHANGE_ENDPOINT))
+ when(httpSessionMock.post(eq(INDEX_CHANGE_ENDPOINT), any()))
.thenReturn(new HttpResult(SUCCESSFUL, EMPTY_MSG));
- assertThat(forwarder.indexChange(PROJECT_NAME, CHANGE_NUMBER)).isTrue();
+ assertThat(forwarder.indexChange(PROJECT_NAME, CHANGE_NUMBER, new IndexEvent())).isTrue();
}
@Test
public void testIndexChangeFailed() throws Exception {
- when(httpSessionMock.post(INDEX_CHANGE_ENDPOINT)).thenReturn(new HttpResult(FAILED, EMPTY_MSG));
- assertThat(forwarder.indexChange(PROJECT_NAME, CHANGE_NUMBER)).isFalse();
+ when(httpSessionMock.post(eq(INDEX_CHANGE_ENDPOINT), any()))
+ .thenReturn(new HttpResult(FAILED, EMPTY_MSG));
+ assertThat(forwarder.indexChange(PROJECT_NAME, CHANGE_NUMBER, new IndexEvent())).isFalse();
}
@Test
public void testIndexChangeThrowsException() throws Exception {
- doThrow(new IOException()).when(httpSessionMock).post(INDEX_CHANGE_ENDPOINT);
- assertThat(forwarder.indexChange(PROJECT_NAME, CHANGE_NUMBER)).isFalse();
+ doThrow(new IOException()).when(httpSessionMock).post(eq(INDEX_CHANGE_ENDPOINT), any());
+ assertThat(forwarder.indexChange(PROJECT_NAME, CHANGE_NUMBER, new IndexEvent())).isFalse();
}
@Test
public void testChangeDeletedFromIndexOK() throws Exception {
- when(httpSessionMock.delete(DELETE_CHANGE_ENDPOINT))
+ when(httpSessionMock.delete(eq(DELETE_CHANGE_ENDPOINT), any()))
.thenReturn(new HttpResult(SUCCESSFUL, EMPTY_MSG));
- assertThat(forwarder.deleteChangeFromIndex(CHANGE_NUMBER)).isTrue();
+ assertThat(forwarder.deleteChangeFromIndex(CHANGE_NUMBER, new IndexEvent())).isTrue();
}
@Test
public void testChangeDeletedFromIndexFailed() throws Exception {
- when(httpSessionMock.delete(DELETE_CHANGE_ENDPOINT))
+ when(httpSessionMock.delete(eq(DELETE_CHANGE_ENDPOINT), any()))
.thenReturn(new HttpResult(FAILED, EMPTY_MSG));
- assertThat(forwarder.deleteChangeFromIndex(CHANGE_NUMBER)).isFalse();
+ assertThat(forwarder.deleteChangeFromIndex(CHANGE_NUMBER, new IndexEvent())).isFalse();
}
@Test
public void testChangeDeletedFromThrowsException() throws Exception {
- doThrow(new IOException()).when(httpSessionMock).delete(DELETE_CHANGE_ENDPOINT);
- assertThat(forwarder.deleteChangeFromIndex(CHANGE_NUMBER)).isFalse();
+ doThrow(new IOException()).when(httpSessionMock).delete(eq(DELETE_CHANGE_ENDPOINT), any());
+ assertThat(forwarder.deleteChangeFromIndex(CHANGE_NUMBER, new IndexEvent())).isFalse();
}
@Test
public void testEventSentOK() throws Exception {
- when(httpSessionMock.post(EVENT_ENDPOINT, eventJson))
+ when(httpSessionMock.post(EVENT_ENDPOINT, event))
.thenReturn(new HttpResult(SUCCESSFUL, EMPTY_MSG));
assertThat(forwarder.send(event)).isTrue();
}
@Test
public void testEventSentFailed() throws Exception {
- when(httpSessionMock.post(EVENT_ENDPOINT, eventJson))
- .thenReturn(new HttpResult(FAILED, EMPTY_MSG));
+ when(httpSessionMock.post(EVENT_ENDPOINT, event)).thenReturn(new HttpResult(FAILED, EMPTY_MSG));
assertThat(forwarder.send(event)).isFalse();
}
@Test
public void testEventSentThrowsException() throws Exception {
- doThrow(new IOException()).when(httpSessionMock).post(EVENT_ENDPOINT, eventJson);
+ doThrow(new IOException()).when(httpSessionMock).post(EVENT_ENDPOINT, event);
assertThat(forwarder.send(event)).isFalse();
}
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandlerTest.java
index 39d7128..43c2fd7 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandlerTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandlerTest.java
@@ -15,6 +15,8 @@
package com.ericsson.gerrit.plugins.highavailability.index;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -63,25 +65,25 @@
@Test
public void shouldIndexInRemoteOnChangeIndexedEvent() throws Exception {
indexEventHandler.onChangeIndexed(PROJECT_NAME, changeId.get());
- verify(forwarder).indexChange(PROJECT_NAME, CHANGE_ID);
+ verify(forwarder).indexChange(eq(PROJECT_NAME), eq(CHANGE_ID), any());
}
@Test
public void shouldIndexInRemoteOnAccountIndexedEvent() throws Exception {
indexEventHandler.onAccountIndexed(accountId.get());
- verify(forwarder).indexAccount(ACCOUNT_ID);
+ verify(forwarder).indexAccount(eq(ACCOUNT_ID), any());
}
@Test
public void shouldDeleteFromIndexInRemoteOnChangeDeletedEvent() throws Exception {
indexEventHandler.onChangeDeleted(changeId.get());
- verify(forwarder).deleteChangeFromIndex(CHANGE_ID);
+ verify(forwarder).deleteChangeFromIndex(eq(CHANGE_ID), any());
}
@Test
public void shouldIndexInRemoteOnGroupIndexedEvent() throws Exception {
indexEventHandler.onGroupIndexed(accountGroupUUID.get());
- verify(forwarder).indexGroup(UUID);
+ verify(forwarder).indexGroup(eq(UUID), any());
}
@Test
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebSessionCacheTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebSessionCacheTest.java
index bccf300..d29bb99 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebSessionCacheTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebSessionCacheTest.java
@@ -127,7 +127,7 @@
public void getIfPresentInvalidKeyTest() throws Exception {
loadKeyToCacheDir(INVALID_KEY);
Path path = websessionDir.resolve(INVALID_KEY);
- assertThat(cache.getIfPresent((Object) path)).isNull();
+ assertThat(cache.getIfPresent(path.toString())).isNull();
}
@Test
diff --git a/tools/BUILD b/tools/BUILD
index e69de29..c5ed0b7 100644
--- a/tools/BUILD
+++ b/tools/BUILD
@@ -0,0 +1 @@
+# Empty file required by Bazel
diff --git a/tools/bzl/BUILD b/tools/bzl/BUILD
index e69de29..c5ed0b7 100644
--- a/tools/bzl/BUILD
+++ b/tools/bzl/BUILD
@@ -0,0 +1 @@
+# Empty file required by Bazel