Merge branch 'stable-2.15' into stable-2.16 * stable-2.15: Upgrade bazlets to latest stable-2.15 Upgrade bazlets to latest stable-2.14 Change-Id: Ie0af06aaf9934ecbdc997da1d41fe0a117ce7f6e
diff --git a/.bazelversion b/.bazelversion index 9084fa2..227cea2 100644 --- a/.bazelversion +++ b/.bazelversion
@@ -1 +1 @@ -1.1.0 +2.0.0
diff --git a/WORKSPACE b/WORKSPACE index 61156a9..86b9eca 100644 --- a/WORKSPACE +++ b/WORKSPACE
@@ -3,7 +3,7 @@ load("//:bazlets.bzl", "load_bazlets") load_bazlets( - commit = "f53f51fb660552d0581aa0ba52c3836ed63d56a3", + commit = "59529f046a5cb855d9fe3ee87110d53305ec69b9", #local_path = "/home/<user>/projects/bazlets", )
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 edd96d7..58a21b6 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
@@ -21,6 +21,7 @@ import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import com.google.common.flogger.FluentLogger; import com.google.gerrit.common.Nullable; import com.google.gerrit.extensions.annotations.PluginName; import com.google.gerrit.server.config.ConfigUtil; @@ -39,12 +40,10 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.eclipse.jgit.lib.Config; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; @Singleton public class Configuration { - private static final Logger log = LoggerFactory.getLogger(Configuration.class); + private static final FluentLogger log = FluentLogger.forEnclosingClass(); // common parameter to peerInfo section static final String PEER_INFO_SECTION = "peerInfo"; @@ -153,8 +152,8 @@ try { return cfg.getInt(section, name, defaultValue); } catch (IllegalArgumentException e) { - log.error("invalid value for {}; using default value {}", name, defaultValue); - log.debug("Failed to retrieve integer value: {}", e.getMessage(), e); + log.atSevere().log("invalid value for %s; using default value %d", name, defaultValue); + log.atFine().withCause(e).log("Failed to retrieve integer value"); return defaultValue; } } @@ -234,9 +233,7 @@ private PeerInfo(Config cfg) { strategy = cfg.getEnum(PEER_INFO_SECTION, null, STRATEGY_KEY, DEFAULT_PEER_INFO_STRATEGY); - if (log.isDebugEnabled()) { - log.debug("Strategy: {}", strategy.name()); - } + log.atFine().log("Strategy: %s", strategy.name()); } public PeerInfoStrategy strategy() { @@ -257,7 +254,7 @@ .filter(s -> !s.isEmpty()) .map(s -> CharMatcher.is('/').trimTrailingFrom(s)) .collect(Collectors.toSet()); - log.debug("Urls: {}", urls); + log.atFine().log("Urls: %s", urls); } public Set<String> urls() { @@ -273,7 +270,7 @@ private PeerInfoJGroups(Config cfg) { myUrl = trimTrailingSlash(cfg.getString(PEER_INFO_SECTION, JGROUPS_SUBSECTION, MY_URL_KEY)); - log.debug("My Url: {}", myUrl); + log.atFine().log("My Url: %s", myUrl); } public String myUrl() { @@ -302,12 +299,12 @@ private JGroups(SitePaths site, Config cfg) { String[] skip = cfg.getStringList(JGROUPS_SECTION, null, SKIP_INTERFACE_KEY); skipInterface = skip.length == 0 ? DEFAULT_SKIP_INTERFACE_LIST : ImmutableList.copyOf(skip); - log.debug("Skip interface(s): {}", skipInterface); + log.atFine().log("Skip interface(s): %s", skipInterface); clusterName = getString(cfg, JGROUPS_SECTION, null, CLUSTER_NAME_KEY, DEFAULT_CLUSTER_NAME); - log.debug("Cluster name: {}", clusterName); + log.atFine().log("Cluster name: %s", clusterName); protocolStack = getProtocolStack(cfg, site); - log.debug( - "Protocol stack config {}", + log.atFine().log( + "Protocol stack config %s", protocolStack.isPresent() ? protocolStack.get() : "not configured, using default stack."); } @@ -405,8 +402,8 @@ try { return cfg.getBoolean(section, name, defaultValue); } catch (IllegalArgumentException e) { - log.error("invalid value for {}; using default value {}", name, defaultValue); - log.debug("Failed to retrieve boolean value: {}", e.getMessage(), e); + log.atSevere().log("invalid value for %s; using default value %s", name, defaultValue); + log.atFine().withCause(e).log("Failed to retrieve boolean value"); return defaultValue; } } @@ -450,12 +447,14 @@ static final String INDEX_SECTION = "index"; static final String MAX_TRIES_KEY = "maxTries"; static final String RETRY_INTERVAL_KEY = "retryInterval"; + static final String SYNCHRONIZE_FORCED_KEY = "synchronizeForced"; + static final boolean DEFAULT_SYNCHRONIZE_FORCED = true; private final int threadPoolSize; private final int retryInterval; private final int maxTries; - private final int numStripedLocks; + private final boolean synchronizeForced; private Index(Config cfg) { super(cfg, INDEX_SECTION); @@ -463,6 +462,8 @@ numStripedLocks = getInt(cfg, INDEX_SECTION, NUM_STRIPED_LOCKS, DEFAULT_NUM_STRIPED_LOCKS); retryInterval = getInt(cfg, INDEX_SECTION, RETRY_INTERVAL_KEY, DEFAULT_INDEX_RETRY_INTERVAL); maxTries = getInt(cfg, INDEX_SECTION, MAX_TRIES_KEY, DEFAULT_INDEX_MAX_TRIES); + synchronizeForced = + cfg.getBoolean(INDEX_SECTION, SYNCHRONIZE_FORCED_KEY, DEFAULT_SYNCHRONIZE_FORCED); } public int threadPoolSize() { @@ -480,6 +481,10 @@ public int maxTries() { return maxTries; } + + public boolean synchronizeForced() { + return synchronizeForced; + } } public static class Websession extends Forwarding {
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 165b0dd..6635b80 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Setup.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Setup.java
@@ -105,9 +105,11 @@ ui.message("\n"); ui.header("%s Plugin", pluginName); - if (ui.yesno(true, "Configure %s", pluginName)) { + Path pluginConfigFile = site.etc_dir.resolve(pluginName + ".config"); + boolean autoConfigure = !pluginConfigFile.toFile().exists(); + + if (ui.yesno(autoConfigure, "Configure %s", pluginName)) { ui.header("Configuring %s", pluginName); - Path pluginConfigFile = site.etc_dir.resolve(pluginName + ".config"); config = new FileBasedConfig(pluginConfigFile.toFile(), FS.DETECTED); config.load(); configureAutoReindexSection();
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 index 487f3da..de156a2 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AccountReindexRunnable.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AccountReindexRunnable.java
@@ -17,8 +17,10 @@ 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.common.flogger.FluentLogger; 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; @@ -26,11 +28,9 @@ 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<Account> { - private static final Logger log = LoggerFactory.getLogger(AccountReindexRunnable.class); +public class AccountReindexRunnable extends ReindexRunnable<AccountState> { + private static final FluentLogger log = FluentLogger.forEnclosingClass(); private final ForwardedIndexAccountHandler accountIdx; @@ -48,21 +48,23 @@ } @Override - protected Iterable<Account> fetchItems(ReviewDb db) throws Exception { + protected Iterable<AccountState> fetchItems(ReviewDb db) throws Exception { return accounts.all(); } @Override - protected Optional<Timestamp> indexIfNeeded(ReviewDb db, Account a, Timestamp sinceTs) { + 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); + log.atInfo().log( + "Index %s/%s/%s/%s", 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); + log.atSevere().withCause(e).log("Reindex failed"); } return Optional.empty(); }
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 index c0d90d1..ef7ae86 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AutoReindexScheduler.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AutoReindexScheduler.java
@@ -15,6 +15,7 @@ package com.ericsson.gerrit.plugins.highavailability.autoreindex; import com.ericsson.gerrit.plugins.highavailability.Configuration; +import com.google.common.flogger.FluentLogger; import com.google.gerrit.extensions.events.LifecycleListener; import com.google.gerrit.server.git.WorkQueue; import com.google.inject.Inject; @@ -24,16 +25,15 @@ 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 static final FluentLogger log = FluentLogger.forEnclosingClass(); private final Configuration.AutoReindex cfg; private final ChangeReindexRunnable changeReindex; private final AccountReindexRunnable accountReindex; private final GroupReindexRunnable groupReindex; + private final ProjectReindexRunnable projectReindex; private final ScheduledExecutorService executor; private final List<Future<?>> futureTasks = new ArrayList<>(); @@ -43,18 +43,21 @@ WorkQueue workQueue, ChangeReindexRunnable changeReindex, AccountReindexRunnable accountReindex, - GroupReindexRunnable groupReindex) { + GroupReindexRunnable groupReindex, + ProjectReindexRunnable projectReindex) { this.cfg = cfg.autoReindex(); this.changeReindex = changeReindex; this.accountReindex = accountReindex; this.groupReindex = groupReindex; + this.projectReindex = projectReindex; 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()); + log.atInfo().log( + "Scheduling auto-reindex after %ds and every %ds", cfg.delaySec(), cfg.pollSec()); futureTasks.add( executor.scheduleAtFixedRate( changeReindex, cfg.delaySec(), cfg.pollSec(), TimeUnit.SECONDS)); @@ -64,11 +67,15 @@ futureTasks.add( executor.scheduleAtFixedRate( groupReindex, cfg.delaySec(), cfg.pollSec(), TimeUnit.SECONDS)); + futureTasks.add( + executor.scheduleAtFixedRate( + projectReindex, cfg.delaySec(), cfg.pollSec(), TimeUnit.SECONDS)); } else { - log.info("Scheduling auto-reindex after {}s", cfg.delaySec()); + log.atInfo().log("Scheduling auto-reindex after %ds", 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)); + futureTasks.add(executor.schedule(projectReindex, cfg.delaySec(), TimeUnit.SECONDS)); } }
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 index 1f5b56e..67c8325 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ChangeReindexRunnable.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ChangeReindexRunnable.java
@@ -18,6 +18,7 @@ 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.common.flogger.FluentLogger; import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.server.ReviewDb; @@ -34,11 +35,9 @@ 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 static final FluentLogger log = FluentLogger.forEnclosingClass(); private final ForwardedIndexChangeHandler changeIdx; @@ -98,13 +97,13 @@ try { Timestamp changeTs = c.getLastUpdatedOn(); if (changeTs.after(sinceTs)) { - log.info( - "Index {}/{}/{} was updated after {}", c.getProject(), c.getId(), changeTs, sinceTs); + log.atInfo().log( + "Index %s/%s/%s was updated after %s", 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); + log.atSevere().withCause(e).log("Reindex failed"); } 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 index 640457d..71a0280 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnable.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnable.java
@@ -14,74 +14,32 @@ package com.ericsson.gerrit.plugins.highavailability.autoreindex; -import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexGroupHandler; -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.AccountGroup; -import com.google.gerrit.reviewdb.client.AccountGroup.Id; -import com.google.gerrit.reviewdb.client.AccountGroupByIdAud; -import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit; +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.gwtorm.server.OrmException; -import com.google.gwtorm.server.ResultSet; import com.google.inject.Inject; -import java.io.IOException; import java.sql.Timestamp; -import java.util.Comparator; -import java.util.List; -import java.util.Objects; import java.util.Optional; -import java.util.stream.Stream; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -public class GroupReindexRunnable extends ReindexRunnable<AccountGroup> { - private static final Logger log = LoggerFactory.getLogger(GroupReindexRunnable.class); +public class GroupReindexRunnable extends ReindexRunnable<GroupReference> { - private final ForwardedIndexGroupHandler indexer; + private final Groups groups; @Inject - public GroupReindexRunnable( - ForwardedIndexGroupHandler indexer, IndexTs indexTs, OneOffRequestContext ctx) { + public GroupReindexRunnable(IndexTs indexTs, OneOffRequestContext ctx, Groups groups) { super(AbstractIndexRestApiServlet.IndexName.GROUP, indexTs, ctx); - this.indexer = indexer; + this.groups = groups; } @Override - protected ResultSet<AccountGroup> fetchItems(ReviewDb db) throws OrmException { - return db.accountGroups().all(); + protected Iterable<GroupReference> fetchItems(ReviewDb db) throws Exception { + return groups.getAllGroupReferences()::iterator; } @Override - protected Optional<Timestamp> indexIfNeeded(ReviewDb db, AccountGroup g, Timestamp sinceTs) { - try { - Id groupId = g.getId(); - Stream<Timestamp> groupIdAudTs = - db.accountGroupByIdAud().byGroup(g.getId()).toList().stream() - .map(AccountGroupByIdAud::getRemovedOn) - .filter(Objects::nonNull); - List<AccountGroupMemberAudit> groupMembersAud = - db.accountGroupMembersAudit().byGroup(groupId).toList(); - Stream<Timestamp> groupMemberAudAddedTs = - groupMembersAud.stream().map(ga -> ga.getKey().getAddedOn()).filter(Objects::nonNull); - Stream<Timestamp> groupMemberAudRemovedTs = - groupMembersAud.stream() - .map(AccountGroupMemberAudit::getRemovedOn) - .filter(Objects::nonNull); - Optional<Timestamp> groupLastTs = - Streams.concat(groupIdAudTs, groupMemberAudAddedTs, groupMemberAudRemovedTs) - .max(Comparator.naturalOrder()); - - if (groupLastTs.isPresent() && groupLastTs.get().after(sinceTs)) { - log.info("Index {}/{}/{}", g.getGroupUUID(), g.getName(), groupLastTs.get()); - indexer.index(g.getGroupUUID(), Operation.INDEX, Optional.empty()); - return groupLastTs; - } - } catch (OrmException | IOException e) { - log.error("Reindex failed", e); - } + 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 index 952fcd1..0e0602a 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/IndexTs.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/IndexTs.java
@@ -16,12 +16,15 @@ import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.AbstractIndexRestApiServlet; import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.AbstractIndexRestApiServlet.IndexName; +import com.ericsson.gerrit.plugins.highavailability.index.CurrentRequestContext; +import com.google.common.flogger.FluentLogger; 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.extensions.events.ProjectIndexedListener; import com.google.gerrit.reviewdb.server.ReviewDb; -import com.google.gerrit.server.ChangeFinder; +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.SchemaFactory; @@ -35,13 +38,14 @@ import java.time.format.DateTimeFormatter; 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); + implements ChangeIndexedListener, + AccountIndexedListener, + GroupIndexedListener, + ProjectIndexedListener { + private static final FluentLogger log = FluentLogger.forEnclosingClass(); private static final DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME; private final Path dataDir; @@ -49,10 +53,12 @@ private final FlusherRunner flusher; private final SchemaFactory<ReviewDb> schemaFactory; private final ChangeFinder changeFinder; + private final CurrentRequestContext currCtx; private volatile LocalDateTime changeTs; private volatile LocalDateTime accountTs; private volatile LocalDateTime groupTs; + private volatile LocalDateTime projectTs; class FlusherRunner implements Runnable { @@ -61,6 +67,7 @@ store(AbstractIndexRestApiServlet.IndexName.CHANGE, changeTs); store(AbstractIndexRestApiServlet.IndexName.ACCOUNT, accountTs); store(AbstractIndexRestApiServlet.IndexName.GROUP, groupTs); + store(AbstractIndexRestApiServlet.IndexName.PROJECT, projectTs); } private void store(AbstractIndexRestApiServlet.IndexName index, LocalDateTime latestTs) { @@ -70,7 +77,7 @@ try { Files.write(indexTsFile, latestTs.format(formatter).getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { - log.error("Unable to update last timestamp for index {}", index, e); + log.atSevere().withCause(e).log("Unable to update last timestamp for index %s", index); } } } @@ -81,41 +88,51 @@ @PluginData Path dataDir, WorkQueue queue, SchemaFactory<ReviewDb> schemaFactory, - ChangeFinder changeFinder) { + ChangeFinder changeFinder, + CurrentRequestContext currCtx) { this.dataDir = dataDir; this.exec = queue.getDefaultQueue(); this.flusher = new FlusherRunner(); this.schemaFactory = schemaFactory; this.changeFinder = changeFinder; + this.currCtx = currCtx; + } + + @Override + public void onProjectIndexed(String project) { + currCtx.onlyWithContext((ctx) -> update(IndexName.PROJECT, LocalDateTime.now())); } @Override public void onGroupIndexed(String uuid) { - update(IndexName.GROUP, LocalDateTime.now()); + currCtx.onlyWithContext((ctx) -> update(IndexName.GROUP, LocalDateTime.now())); } @Override public void onAccountIndexed(int id) { - update(IndexName.ACCOUNT, LocalDateTime.now()); + currCtx.onlyWithContext((ctx) -> 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 (Exception e) { - log.warn("Unable to update the latest TS for change {}", id, e); - } + currCtx.onlyWithContext( + (ctx) -> { + try (ReviewDb db = schemaFactory.open()) { + ChangeNotes changeNotes = changeFinder.findOne(projectName + "~" + id); + update( + IndexName.CHANGE, + changeNotes == null + ? LocalDateTime.now() + : changeNotes.getChange().getLastUpdatedOn().toLocalDateTime()); + } catch (Exception e) { + log.atWarning().withCause(e).log("Unable to update the latest TS for change %d", id); + } + }); } @Override public void onChangeDeleted(int id) { - update(IndexName.CHANGE, LocalDateTime.now()); + currCtx.onlyWithContext((ctx) -> update(IndexName.CHANGE, LocalDateTime.now())); } public Optional<LocalDateTime> getUpdateTs(AbstractIndexRestApiServlet.IndexName index) { @@ -126,7 +143,7 @@ return Optional.of(LocalDateTime.parse(tsString, formatter)); } } catch (Exception e) { - log.warn("Unable to read last timestamp for index {}", index, e); + log.atWarning().withCause(e).log("Unable to read last timestamp for index %s", index); } return Optional.empty(); } @@ -142,6 +159,9 @@ case GROUP: groupTs = dateTime; break; + case PROJECT: + projectTs = dateTime; + break; default: throw new IllegalArgumentException("Unsupported index " + index); }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ProjectReindexRunnable.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ProjectReindexRunnable.java new file mode 100644 index 0000000..582227d --- /dev/null +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ProjectReindexRunnable.java
@@ -0,0 +1,46 @@ +// 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.reviewdb.client.Project; +import com.google.gerrit.reviewdb.server.ReviewDb; +import com.google.gerrit.server.project.ProjectCache; +import com.google.gerrit.server.util.OneOffRequestContext; +import com.google.inject.Inject; +import java.sql.Timestamp; +import java.util.Optional; + +public class ProjectReindexRunnable extends ReindexRunnable<Project.NameKey> { + + private final ProjectCache projectCache; + + @Inject + public ProjectReindexRunnable( + IndexTs indexTs, OneOffRequestContext ctx, ProjectCache projectCache) { + super(AbstractIndexRestApiServlet.IndexName.PROJECT, indexTs, ctx); + this.projectCache = projectCache; + } + + @Override + protected Iterable<Project.NameKey> fetchItems(ReviewDb db) { + return projectCache.all(); + } + + @Override + protected Optional<Timestamp> indexIfNeeded(ReviewDb db, Project.NameKey g, Timestamp sinceTs) { + return Optional.empty(); + } +}
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 index df3a0fd..7a5669e 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ReindexRunnable.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ReindexRunnable.java
@@ -16,6 +16,7 @@ import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.AbstractIndexRestApiServlet; import com.google.common.base.Stopwatch; +import com.google.common.flogger.FluentLogger; import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.util.ManualRequestContext; import com.google.gerrit.server.util.OneOffRequestContext; @@ -24,11 +25,9 @@ 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 static final FluentLogger log = FluentLogger.forEnclosingClass(); private final AbstractIndexRestApiServlet.IndexName itemName; private final OneOffRequestContext ctx; @@ -49,7 +48,7 @@ String itemNameString = itemName.name().toLowerCase(); if (maybeIndexTs.isPresent()) { newLastIndexTs = maxTimestamp(newLastIndexTs, Timestamp.valueOf(maybeIndexTs.get())); - log.debug("Scanning for all the {}s after {}", itemNameString, newLastIndexTs); + log.atFine().log("Scanning for all the %ss after %s", itemNameString, newLastIndexTs); try (ManualRequestContext mctx = ctx.open(); ReviewDb db = mctx.getReviewDbProvider().get()) { int count = 0; @@ -63,27 +62,27 @@ newLastIndexTs = maxTimestamp(newLastIndexTs, itemTs.get()); } } catch (Exception e) { - log.error("Unable to reindex {} {}", itemNameString, c, e); + log.atSevere().withCause(e).log("Unable to reindex %s %s", itemNameString, c); errors++; } } long elapsedNanos = stopwatch.stop().elapsed(TimeUnit.NANOSECONDS); if (count > 0) { - log.info( - "{} {}s reindexed in {} msec ({}/sec), {} failed", + log.atInfo().log( + "%d %ss reindexed in %d msec (%d/sec), %d failed", count, itemNameString, elapsedNanos / 1000000L, (count * 1000L) / (elapsedNanos / 1000000L), errors); } else if (errors > 0) { - log.info("{} {}s failed to reindex", errors, itemNameString); + log.atInfo().log("%d %ss failed to reindex", errors, itemNameString); } else { - log.debug("Scanning finished"); + log.atFine().log("Scanning finished"); } indexTs.update(itemName, newLastIndexTs.toLocalDateTime()); } catch (Exception e) { - log.error("Unable to scan " + itemNameString + "s", e); + log.atSevere().withCause(e).log("Unable to scan %ss", itemNameString); } } }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/EventHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/EventHandler.java index f42d115..025115c 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/EventHandler.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/EventHandler.java
@@ -16,9 +16,9 @@ import com.ericsson.gerrit.plugins.highavailability.forwarder.Context; import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder; -import com.google.gerrit.common.EventListener; import com.google.gerrit.extensions.annotations.PluginName; import com.google.gerrit.server.events.Event; +import com.google.gerrit.server.events.EventListener; import com.google.gerrit.server.events.ProjectEvent; import com.google.inject.Inject; import java.util.concurrent.Executor;
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/EventModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/EventModule.java index a848c20..28a9e8e 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/EventModule.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/EventModule.java
@@ -14,9 +14,9 @@ package com.ericsson.gerrit.plugins.highavailability.event; -import com.google.gerrit.common.EventListener; import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.lifecycle.LifecycleModule; +import com.google.gerrit.server.events.EventListener; import java.util.concurrent.Executor; public class EventModule extends LifecycleModule {
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBroker.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBroker.java index b3696fb..3d9fd60 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBroker.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBroker.java
@@ -14,14 +14,14 @@ package com.ericsson.gerrit.plugins.highavailability.forwarder; -import com.google.gerrit.common.EventBroker; -import com.google.gerrit.common.EventListener; -import com.google.gerrit.common.UserScopedEventListener; -import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.events.Event; +import com.google.gerrit.server.events.EventBroker; +import com.google.gerrit.server.events.EventListener; +import com.google.gerrit.server.events.UserScopedEventListener; import com.google.gerrit.server.notedb.ChangeNotes.Factory; import com.google.gerrit.server.permissions.PermissionBackend; +import com.google.gerrit.server.plugincontext.PluginSetContext; import com.google.gerrit.server.project.ProjectCache; import com.google.inject.Inject; import com.google.inject.Provider; @@ -30,8 +30,8 @@ @Inject ForwardedAwareEventBroker( - DynamicSet<UserScopedEventListener> listeners, - DynamicSet<EventListener> unrestrictedListeners, + PluginSetContext<UserScopedEventListener> listeners, + PluginSetContext<EventListener> unrestrictedListeners, PermissionBackend permissionBackend, ProjectCache projectCache, Factory notesFactory,
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedCacheEvictionHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedCacheEvictionHandler.java index c4c2219..27531b0 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedCacheEvictionHandler.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedCacheEvictionHandler.java
@@ -16,11 +16,10 @@ import com.ericsson.gerrit.plugins.highavailability.cache.Constants; import com.google.common.cache.Cache; +import com.google.common.flogger.FluentLogger; import com.google.gerrit.extensions.registration.DynamicMap; import com.google.inject.Inject; import com.google.inject.Singleton; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Evict cache entries. This class is meant to be used on the receiving side of the {@link @@ -29,7 +28,7 @@ */ @Singleton public class ForwardedCacheEvictionHandler { - private static final Logger log = LoggerFactory.getLogger(ForwardedCacheEvictionHandler.class); + private static final FluentLogger log = FluentLogger.forEnclosingClass(); private final DynamicMap<Cache<?, ?>> cacheMap; @@ -55,10 +54,10 @@ if (Constants.PROJECT_LIST.equals(entry.getCacheName())) { // One key is holding the list of projects cache.invalidateAll(); - log.debug("Invalidated cache {}", entry.getCacheName()); + log.atFine().log("Invalidated cache %s", entry.getCacheName()); } else { cache.invalidate(entry.getKey()); - log.debug("Invalidated cache {}[{}]", entry.getCacheName(), entry.getKey()); + log.atFine().log("Invalidated cache %s[%s]", entry.getCacheName(), entry.getKey()); } } finally { Context.unsetForwardedEvent();
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedEventHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedEventHandler.java index 4e01abf..51db006 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedEventHandler.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedEventHandler.java
@@ -14,14 +14,13 @@ package com.ericsson.gerrit.plugins.highavailability.forwarder; -import com.google.gerrit.common.EventDispatcher; +import com.google.common.flogger.FluentLogger; import com.google.gerrit.server.events.Event; +import com.google.gerrit.server.events.EventDispatcher; import com.google.gerrit.server.permissions.PermissionBackendException; import com.google.gwtorm.server.OrmException; import com.google.inject.Inject; import com.google.inject.Singleton; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Dispatch event to the {@link EventDispatcher}. This class is meant to be used on the receiving @@ -30,7 +29,7 @@ */ @Singleton public class ForwardedEventHandler { - private static final Logger log = LoggerFactory.getLogger(ForwardedEventHandler.class); + private static final FluentLogger log = FluentLogger.forEnclosingClass(); private final EventDispatcher dispatcher; @@ -48,7 +47,7 @@ public void dispatch(Event event) throws OrmException, PermissionBackendException { try { Context.setForwardedEvent(true); - log.debug("dispatching event {}", event.getType()); + log.atFine().log("dispatching event %s", event.getType()); dispatcher.postEvent(event); } finally { Context.unsetForwardedEvent();
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 649ffc8..ba60830 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
@@ -41,7 +41,7 @@ @Override protected void doIndex(Account.Id id, Optional<IndexEvent> indexEvent) throws IOException { indexer.index(id); - log.debug("Account {} successfully indexed", id); + log.atFine().log("Account %s successfully indexed", id); } @Override
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 d34959c..d7c7e88 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
@@ -89,29 +89,31 @@ if (checker.isChangeUpToDate(indexEvent)) { if (retryCount > 0) { - log.warn("Change {} has been eventually indexed after {} attempt(s)", id, retryCount); + log.atWarning().log( + "Change %s has been eventually indexed after %d attempt(s)", id, retryCount); } else { - log.debug("Change {} successfully indexed", id); + log.atFine().log("Change %s successfully indexed", id); } } else { - log.warn( - "Change {} seems too old compared to the event timestamp (event-Ts={} >> change-Ts={})", - id, - indexEvent, - checker); + log.atWarning().log( + "Change %s seems too old compared to the event timestamp (event-Ts=%s >> change-Ts=%s)", + id, indexEvent, checker); rescheduleIndex(id, indexEvent, retryCount + 1); } } else { - indexer.delete(parseChangeId(id)); - log.warn( - "Change {} could not be found in the local Git repository (eventTs={}), deleted from index", - id, - indexEvent); + log.atWarning().log( + "Change %s not present yet in local Git repository (event=%s) after %d attempt(s)", + id, indexEvent, retryCount); + if (!rescheduleIndex(id, indexEvent, retryCount + 1)) { + log.atSevere().log( + "Change %s could not be found in the local Git repository (event=%s)", + id, indexEvent); + } } } catch (Exception e) { if (isCausedByNoSuchChangeException(e)) { indexer.delete(parseChangeId(id)); - log.warn("Error trying to index Change {}. Deleted from index", id, e); + log.atWarning().withCause(e).log("Error trying to index Change %s. Deleted from index", id); return; } @@ -126,37 +128,35 @@ } } - private void rescheduleIndex(String id, Optional<IndexEvent> indexEvent, int retryCount) { + private boolean rescheduleIndex(String id, Optional<IndexEvent> indexEvent, int retryCount) { if (retryCount > maxTries) { - log.error( - "Change {} could not be indexed after {} retries. Change index could be stale.", - id, - retryCount); - return; + log.atSevere().log( + "Change %s could not be indexed after %d retries. Change index could be stale.", + id, retryCount); + return false; } - log.warn( - "Retrying for the #{} time to index Change {} after {} msecs", - retryCount, - id, - retryInterval); + log.atWarning().log( + "Retrying for the #%d time to index Change %s after %d msecs", + retryCount, id, retryInterval); indexExecutor.schedule( () -> { try (ManualRequestContext ctx = oneOffCtx.open()) { Context.setForwardedEvent(true); doIndex(id, indexEvent, retryCount); } catch (Exception e) { - log.warn("Change {} could not be indexed", id, e); + log.atWarning().withCause(e).log("Change %s could not be indexed", id); } }, retryInterval, TimeUnit.MILLISECONDS); + return true; } @Override protected void doDelete(String id, Optional<IndexEvent> indexEvent) throws IOException { indexer.delete(parseChangeId(id)); - log.debug("Change {} successfully deleted from index", id); + log.atFine().log("Change %s successfully deleted from index", id); } private static Change.Id parseChangeId(String 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 7c6d723..fb4d2f2 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
@@ -42,7 +42,7 @@ protected void doIndex(AccountGroup.UUID uuid, Optional<IndexEvent> indexEvent) throws IOException { indexer.index(uuid); - log.debug("Group {} successfully indexed", uuid); + log.atFine().log("Group %s successfully indexed", uuid); } @Override
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexProjectHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexProjectHandler.java new file mode 100644 index 0000000..5ae4cc0 --- /dev/null +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexProjectHandler.java
@@ -0,0 +1,52 @@ +// 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 com.ericsson.gerrit.plugins.highavailability.Configuration; +import com.google.gerrit.index.project.ProjectIndexer; +import com.google.gerrit.reviewdb.client.Project; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import java.io.IOException; +import java.util.Optional; + +/** + * Index a project using {@link ProjectIndexer}. This class is meant to be used on the receiving + * side of the {@link Forwarder} since it will prevent indexed project to be forwarded again causing + * an infinite forwarding loop between the 2 nodes. It will also make sure no concurrent indexing is + * done for the same project name. + */ +@Singleton +public class ForwardedIndexProjectHandler extends ForwardedIndexingHandler<Project.NameKey> { + private final ProjectIndexer indexer; + + @Inject + ForwardedIndexProjectHandler(ProjectIndexer indexer, Configuration config) { + super(config.index()); + this.indexer = indexer; + } + + @Override + protected void doIndex(Project.NameKey projectName, Optional<IndexEvent> indexEvent) + throws IOException { + indexer.index(projectName); + log.atFine().log("Project %s successfully indexed", projectName); + } + + @Override + protected void doDelete(Project.NameKey projectName, Optional<IndexEvent> indexEvent) { + throw new UnsupportedOperationException("Delete from project 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 bfedf3f..78e103d 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
@@ -15,13 +15,12 @@ package com.ericsson.gerrit.plugins.highavailability.forwarder; import com.ericsson.gerrit.plugins.highavailability.Configuration; +import com.google.common.flogger.FluentLogger; 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; /** * Base class to handle forwarded indexing. This class is meant to be extended by classes used on @@ -30,7 +29,7 @@ * indexing is done for the same id. */ public abstract class ForwardedIndexingHandler<T> { - protected final Logger log = LoggerFactory.getLogger(getClass()); + protected static final FluentLogger log = FluentLogger.forEnclosingClass(); public enum Operation { INDEX, @@ -64,7 +63,7 @@ */ public void index(T id, Operation operation, Optional<IndexEvent> indexEvent) throws IOException, OrmException { - log.debug("{} {} {}", operation, id, indexEvent); + log.atFine().log("%s %s %s", operation, id, indexEvent); try { Context.setForwardedEvent(true); Lock idLock = idLocks.get(id); @@ -78,7 +77,7 @@ doDelete(id, indexEvent); break; default: - log.error("unexpected operation: {}", operation); + log.atSevere().log("unexpected operation: %s", operation); break; } } finally {
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedProjectListUpdateHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedProjectListUpdateHandler.java index 93e1186..84f4675 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedProjectListUpdateHandler.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedProjectListUpdateHandler.java
@@ -14,12 +14,12 @@ package com.ericsson.gerrit.plugins.highavailability.forwarder; +import com.google.common.flogger.FluentLogger; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.server.project.ProjectCache; import com.google.inject.Inject; import com.google.inject.Singleton; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.io.IOException; /** * Update project list cache. This class is meant to be used on the receiving side of the {@link @@ -28,8 +28,7 @@ */ @Singleton public class ForwardedProjectListUpdateHandler { - private static final Logger log = - LoggerFactory.getLogger(ForwardedProjectListUpdateHandler.class); + private static final FluentLogger log = FluentLogger.forEnclosingClass(); private final ProjectCache projectCache; @@ -43,17 +42,18 @@ * * @param projectName the name of the project to add or remove. * @param remove true to remove, false to add project. + * @throws IOException */ - public void update(String projectName, boolean remove) { + public void update(String projectName, boolean remove) throws IOException { Project.NameKey projectKey = new Project.NameKey(projectName); try { Context.setForwardedEvent(true); if (remove) { projectCache.remove(projectKey); - log.debug("Removed {} from project list", projectName); + log.atFine().log("Removed %s from project list", projectName); } else { projectCache.onCreateProject(projectKey); - log.debug("Added {} to project list", projectName); + log.atFine().log("Added %s to project list", projectName); } } finally { Context.unsetForwardedEvent();
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 b156563..49cdc8b 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
@@ -57,6 +57,15 @@ boolean indexGroup(String uuid, IndexEvent indexEvent); /** + * Forward a project indexing event to the other master. + * + * @param projectName the project to index. + * @param indexEvent the details of the index event. + * @return true if successful, otherwise false. + */ + boolean indexProject(String projectName, IndexEvent indexEvent); + + /** * Forward a stream event to the other master. * * @param event the event to forward.
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwarderModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwarderModule.java index 15fdcfd..99a820e 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwarderModule.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwarderModule.java
@@ -14,8 +14,8 @@ package com.ericsson.gerrit.plugins.highavailability.forwarder; -import com.google.gerrit.common.EventDispatcher; import com.google.gerrit.extensions.registration.DynamicItem; +import com.google.gerrit.server.events.EventDispatcher; import com.google.inject.AbstractModule; public class ForwarderModule extends AbstractModule {
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 8c429de..410aa23 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
@@ -43,7 +43,8 @@ public enum IndexName { CHANGE, ACCOUNT, - GROUP; + GROUP, + PROJECT; @Override public String toString() { @@ -91,11 +92,11 @@ rsp.setStatus(SC_NO_CONTENT); } catch (IOException e) { sendError(rsp, SC_CONFLICT, e.getMessage()); - log.error("Unable to update {} index", indexName, e); + log.atSevere().withCause(e).log("Unable to update %s index", indexName); } catch (OrmException e) { String msg = String.format("Error trying to find %s", indexName); sendError(rsp, SC_NOT_FOUND, msg); - log.debug(msg, e); + log.atFine().withCause(e).log(msg); } }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractRestApiServlet.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractRestApiServlet.java index 054f640..a76d8ea 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractRestApiServlet.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractRestApiServlet.java
@@ -16,15 +16,14 @@ import static java.nio.charset.StandardCharsets.UTF_8; +import com.google.common.flogger.FluentLogger; import java.io.IOException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public abstract class AbstractRestApiServlet extends HttpServlet { private static final long serialVersionUID = 1L; - protected final Logger log = LoggerFactory.getLogger(getClass()); + protected static final FluentLogger log = FluentLogger.forEnclosingClass(); protected static void setHeaders(HttpServletResponse rsp) { rsp.setContentType("text/plain"); @@ -35,7 +34,7 @@ try { rsp.sendError(statusCode, message); } catch (IOException e) { - log.error("Failed to send error messsage: {}", e.getMessage(), e); + log.atSevere().withCause(e).log("Failed to send error messsage"); } } }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServlet.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServlet.java index fb49cf2..60e782f 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServlet.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServlet.java
@@ -54,10 +54,10 @@ CacheEntry.from(cacheName, gson.fromJson(cacheName, json))); rsp.setStatus(SC_NO_CONTENT); } catch (CacheNotFoundException e) { - log.error("Failed to process eviction request: {}", e.getMessage()); + log.atSevere().log("Failed to process eviction request: %s", e.getMessage()); sendError(rsp, SC_BAD_REQUEST, e.getMessage()); } catch (IOException e) { - log.error("Failed to process eviction request: {}", e.getMessage(), e); + log.atSevere().withCause(e).log("Failed to process eviction request"); sendError(rsp, SC_BAD_REQUEST, e.getMessage()); } }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/EventRestApiServlet.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/EventRestApiServlet.java index 3da5081..61b714c 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/EventRestApiServlet.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/EventRestApiServlet.java
@@ -56,10 +56,10 @@ forwardedEventHandler.dispatch(getEventFromRequest(req)); rsp.setStatus(SC_NO_CONTENT); } catch (OrmException e) { - log.debug("Error trying to find a change ", e); + log.atFine().withCause(e).log("Error trying to find a change"); sendError(rsp, SC_NOT_FOUND, "Change not found\n"); } catch (IOException | PermissionBackendException e) { - log.error("Unable to re-trigger event", e); + log.atSevere().withCause(e).log("Unable to re-trigger event"); sendError(rsp, SC_BAD_REQUEST, e.getMessage()); } }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProvider.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProvider.java index 26943c2..0510aed 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProvider.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProvider.java
@@ -15,6 +15,7 @@ package com.ericsson.gerrit.plugins.highavailability.forwarder.rest; import com.ericsson.gerrit.plugins.highavailability.Configuration; +import com.google.common.flogger.FluentLogger; import com.google.inject.Inject; import com.google.inject.Provider; import java.security.KeyManagementException; @@ -37,12 +38,10 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** Provides an HTTP client with SSL capabilities. */ class HttpClientProvider implements Provider<CloseableHttpClient> { - private static final Logger log = LoggerFactory.getLogger(HttpClientProvider.class); + private static final FluentLogger log = FluentLogger.forEnclosingClass(); private static final int CONNECTIONS_PER_ROUTE = 100; // Up to 2 target instances with the max number of connections per host: private static final int MAX_CONNECTIONS = 2 * CONNECTIONS_PER_ROUTE; @@ -101,7 +100,7 @@ context.init(null, trustAllCerts, null); return context; } catch (KeyManagementException | NoSuchAlgorithmException e) { - log.warn("Error building SSLContext object", e); + log.atWarning().withCause(e).log("Error building SSLContext object"); return null; } }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpResponseHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpResponseHandler.java index cfcd519..9a1e635 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpResponseHandler.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpResponseHandler.java
@@ -17,13 +17,12 @@ import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT; import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.HttpResponseHandler.HttpResult; +import com.google.common.flogger.FluentLogger; import java.io.IOException; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ResponseHandler; import org.apache.http.util.EntityUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; class HttpResponseHandler implements ResponseHandler<HttpResult> { @@ -45,7 +44,7 @@ } } - private static final Logger log = LoggerFactory.getLogger(HttpResponseHandler.class); + private static final FluentLogger log = FluentLogger.forEnclosingClass(); @Override public HttpResult handleResponse(HttpResponse response) { @@ -63,7 +62,7 @@ try { asString = EntityUtils.toString(entity); } catch (IOException e) { - log.error("Error parsing entity", e); + log.atSevere().withCause(e).log("Error parsing entity"); } } return asString;
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexProjectRestApiServlet.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexProjectRestApiServlet.java new file mode 100644 index 0000000..cc87442 --- /dev/null +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexProjectRestApiServlet.java
@@ -0,0 +1,36 @@ +// 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.rest; + +import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexProjectHandler; +import com.google.gerrit.extensions.restapi.Url; +import com.google.gerrit.reviewdb.client.Project; +import com.google.inject.Inject; +import com.google.inject.Singleton; + +@Singleton +class IndexProjectRestApiServlet extends AbstractIndexRestApiServlet<Project.NameKey> { + private static final long serialVersionUID = -1L; + + @Inject + IndexProjectRestApiServlet(ForwardedIndexProjectHandler handler) { + super(handler, IndexName.PROJECT); + } + + @Override + Project.NameKey parse(String projectName) { + return new Project.NameKey(Url.decode(projectName)); + } +}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/ProjectListApiServlet.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/ProjectListApiServlet.java index e781a10..7a31ea0 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/ProjectListApiServlet.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/ProjectListApiServlet.java
@@ -14,12 +14,14 @@ package com.ericsson.gerrit.plugins.highavailability.forwarder.rest; +import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST; import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT; import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedProjectListUpdateHandler; import com.google.gerrit.extensions.restapi.Url; import com.google.inject.Inject; import com.google.inject.Singleton; +import java.io.IOException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -48,7 +50,12 @@ setHeaders(rsp); String requestURI = req.getRequestURI(); String projectName = requestURI.substring(requestURI.lastIndexOf('/') + 1); - forwardedProjectListUpdateHandler.update(Url.decode(projectName), delete); - rsp.setStatus(SC_NO_CONTENT); + try { + forwardedProjectListUpdateHandler.update(Url.decode(projectName), delete); + rsp.setStatus(SC_NO_CONTENT); + } catch (IOException e) { + log.atSevere().withCause(e).log("Unable to update project list"); + sendError(rsp, SC_BAD_REQUEST, e.getMessage()); + } } }
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 ef1b26d..fb3aba9 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
@@ -21,6 +21,7 @@ import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.HttpResponseHandler.HttpResult; import com.ericsson.gerrit.plugins.highavailability.peers.PeerInfo; import com.google.common.base.Joiner; +import com.google.common.flogger.FluentLogger; import com.google.gerrit.extensions.annotations.PluginName; import com.google.gerrit.extensions.restapi.Url; import com.google.gerrit.server.events.Event; @@ -34,8 +35,6 @@ import javax.net.ssl.SSLException; import org.apache.http.HttpException; import org.apache.http.client.ClientProtocolException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; class RestForwarder implements Forwarder { enum RequestMethod { @@ -43,7 +42,7 @@ DELETE } - private static final Logger log = LoggerFactory.getLogger(RestForwarder.class); + private static final FluentLogger log = FluentLogger.forEnclosingClass(); private final HttpSession httpSession; private final String pluginRelativePath; @@ -101,6 +100,12 @@ } @Override + public boolean indexProject(String projectName, IndexEvent event) { + return execute( + RequestMethod.POST, "index project", "index/project", Url.encode(projectName), event); + } + + @Override public boolean send(final Event event) { return execute(RequestMethod.POST, "send event", "event", event.type, event); } @@ -185,41 +190,36 @@ } boolean execute() { - log.debug("Executing {} {} towards {}", action, key, destination); + log.atFine().log("Executing %s %s towards %s", action, key, destination); for (; ; ) { try { execCnt++; tryOnce(); - log.debug("{} {} towards {} OK", action, key, destination); + log.atFine().log("%s %s towards %s OK", action, key, destination); return true; } catch (ForwardingException e) { int maxTries = cfg.http().maxTries(); - log.debug( - "Failed to {} {} on {} [{}/{}]", action, key, destination, execCnt, maxTries, e); + log.atFine().withCause(e).log( + "Failed to %s %s on %s [%d/%d]", action, key, destination, execCnt, maxTries); if (!e.isRecoverable()) { - log.error( - "{} {} towards {} failed with unrecoverable error; giving up", - action, - key, - destination, - e); + log.atSevere().withCause(e).log( + "%s %s towards %s failed with unrecoverable error; giving up", + action, key, destination); return false; } if (execCnt >= maxTries) { - log.error( - "Failed to {} {} on {} after {} tries; giving up", - action, - key, - destination, - maxTries); + log.atSevere().log( + "Failed to %s %s on %s after %d tries; giving up", + action, key, destination, maxTries); return false; } - log.debug("Retrying to {} {} on {}", action, key, destination); + log.atFine().log("Retrying to %s %s on %s", action, key, destination); try { Thread.sleep(cfg.http().retryInterval()); } catch (InterruptedException ie) { - log.error("{} {} towards {} was interrupted; giving up", action, key, destination, ie); + log.atSevere().withCause(ie).log( + "%s %s towards %s was interrupted; giving up", action, key, destination); Thread.currentThread().interrupt(); return false; }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderServletModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderServletModule.java index 184157d..589bbef 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderServletModule.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderServletModule.java
@@ -22,6 +22,7 @@ serveRegex("/index/account/\\d+$").with(IndexAccountRestApiServlet.class); serveRegex("/index/change/.*$").with(IndexChangeRestApiServlet.class); serveRegex("/index/group/\\w+$").with(IndexGroupRestApiServlet.class); + serveRegex("/index/project/.*$").with(IndexProjectRestApiServlet.class); serve("/event/*").with(EventRestApiServlet.class); serve("/cache/project_list/*").with(ProjectListApiServlet.class); serve("/cache/*").with(CacheRestApiServlet.class);
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/health/HealthServlet.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/health/HealthServlet.java index 6d98d83..0f8125e 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/health/HealthServlet.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/health/HealthServlet.java
@@ -20,6 +20,7 @@ import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT; import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE; +import com.google.common.flogger.FluentLogger; import com.google.gerrit.extensions.annotations.PluginData; import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.permissions.PermissionBackend; @@ -34,12 +35,10 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; @Singleton public class HealthServlet extends HttpServlet { - private static final Logger log = LoggerFactory.getLogger(HealthServlet.class); + private static final FluentLogger log = FluentLogger.forEnclosingClass(); private static final long serialVersionUID = -1L; private final Provider<CurrentUser> currentUserProvider; @@ -66,7 +65,7 @@ setHealthy(); rsp.setStatus(SC_NO_CONTENT); } catch (IOException e) { - log.error("Failed to set healthy", e); + log.atSevere().withCause(e).log("Failed to set healthy"); sendError(rsp, SC_INTERNAL_SERVER_ERROR); } } @@ -81,7 +80,7 @@ setUnhealthy(); rsp.setStatus(SC_NO_CONTENT); } catch (IOException e) { - log.error("Failed to set unhealthy", e); + log.atSevere().withCause(e).log("Failed to set unhealthy"); sendError(rsp, SC_INTERNAL_SERVER_ERROR); } } @@ -100,7 +99,7 @@ rsp.sendError(statusCode); } catch (IOException e) { rsp.setStatus(SC_INTERNAL_SERVER_ERROR); - log.error("Failed to send error response", e); + log.atSevere().withCause(e).log("Failed to send error response"); } }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerImpl.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerImpl.java index 9dca6dd..4cdf431 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerImpl.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerImpl.java
@@ -15,11 +15,12 @@ package com.ericsson.gerrit.plugins.highavailability.index; import com.ericsson.gerrit.plugins.highavailability.forwarder.IndexEvent; +import com.google.common.flogger.FluentLogger; import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Comment; import com.google.gerrit.reviewdb.server.ReviewDb; -import com.google.gerrit.server.ChangeFinder; import com.google.gerrit.server.CommentsUtil; +import com.google.gerrit.server.change.ChangeFinder; import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.notedb.ChangeNotes; import com.google.gerrit.server.util.ManualRequestContext; @@ -33,11 +34,9 @@ import java.util.Optional; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class ChangeCheckerImpl implements ChangeChecker { - private static final Logger log = LoggerFactory.getLogger(ChangeCheckerImpl.class); + private static final FluentLogger log = FluentLogger.forEnclosingClass(); private final GitRepositoryManager gitRepoMgr; private final CommentsUtil commentsUtil; private final ChangeDb changeDb; @@ -91,9 +90,9 @@ public boolean isChangeUpToDate(Optional<IndexEvent> indexEvent) throws IOException, OrmException { getComputedChangeTs(); - log.debug("Checking change {} against index event {}", this, indexEvent); + log.atFine().log("Checking change %s against index event %s", this, indexEvent); if (!computedChangeTs.isPresent()) { - log.warn("Unable to compute last updated ts for change {}", changeId); + log.atWarning().log("Unable to compute last updated ts for change %s", changeId); return false; } @@ -128,7 +127,7 @@ + "/" + getBranchTargetSha(); } catch (IOException | OrmException e) { - log.error("Unable to render change {}", changeId, e); + log.atSevere().withCause(e).log("Unable to render change %s", changeId); return "change-id=" + changeId; } } @@ -138,12 +137,13 @@ String refName = changeNotes.get().getChange().getDest().get(); Ref ref = repo.exactRef(refName); if (ref == null) { - log.warn("Unable to find target ref {} for change {}", refName, changeId); + log.atWarning().log("Unable to find target ref %s for change %s", refName, changeId); return null; } return ref.getTarget().getObjectId().getName(); } catch (IOException e) { - log.warn("Unable to resolve target branch SHA for change {}", changeId, e); + log.atWarning().withCause(e).log( + "Unable to resolve target branch SHA for change %s", changeId); return null; } } @@ -163,7 +163,7 @@ changeTs = commentTs.after(changeTs) ? commentTs : changeTs; } } catch (OrmException e) { - log.warn("Unable to access draft comments for change {}", change, e); + log.atWarning().withCause(e).log("Unable to access draft comments for change %s", change); } return changeTs.getTime() / 1000; }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/CurrentRequestContext.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/CurrentRequestContext.java new file mode 100644 index 0000000..f8c6e31 --- /dev/null +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/CurrentRequestContext.java
@@ -0,0 +1,61 @@ +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.ericsson.gerrit.plugins.highavailability.index; + +import com.ericsson.gerrit.plugins.highavailability.Configuration; +import com.google.common.flogger.FluentLogger; +import com.google.gerrit.server.util.ManualRequestContext; +import com.google.gerrit.server.util.OneOffRequestContext; +import com.google.gerrit.server.util.RequestContext; +import com.google.gerrit.server.util.ThreadLocalRequestContext; +import com.google.gwtorm.server.OrmException; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import java.util.function.Consumer; + +@Singleton +public class CurrentRequestContext { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); + + private ThreadLocalRequestContext threadLocalCtx; + private Configuration cfg; + private OneOffRequestContext oneOffCtx; + + @Inject + public CurrentRequestContext( + ThreadLocalRequestContext threadLocalCtx, Configuration cfg, OneOffRequestContext oneOffCtx) { + this.threadLocalCtx = threadLocalCtx; + this.cfg = cfg; + this.oneOffCtx = oneOffCtx; + } + + public void onlyWithContext(Consumer<RequestContext> body) { + RequestContext ctx = threadLocalCtx.getContext(); + if (ctx == null && !cfg.index().synchronizeForced()) { + logger.atFine().log("No context, skipping event (index.synchronizeForced is false)"); + return; + } + + if (ctx == null) { + try (ManualRequestContext manualCtx = oneOffCtx.open()) { + body.accept(manualCtx); + } catch (OrmException e) { + logger.atSevere().withCause(e).log("Unable to open request context"); + } + } else { + body.accept(ctx); + } + } +}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/DisabledReviewDb.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/DisabledReviewDb.java index 192ee8c..48c6ecb 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/DisabledReviewDb.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/DisabledReviewDb.java
@@ -16,13 +16,6 @@ import com.google.common.util.concurrent.CheckedFuture; import com.google.gerrit.reviewdb.client.Change; -import com.google.gerrit.reviewdb.client.Change.Id; -import com.google.gerrit.reviewdb.server.AccountGroupAccess; -import com.google.gerrit.reviewdb.server.AccountGroupByIdAccess; -import com.google.gerrit.reviewdb.server.AccountGroupByIdAudAccess; -import com.google.gerrit.reviewdb.server.AccountGroupMemberAccess; -import com.google.gerrit.reviewdb.server.AccountGroupMemberAuditAccess; -import com.google.gerrit.reviewdb.server.AccountGroupNameAccess; import com.google.gerrit.reviewdb.server.ChangeAccess; import com.google.gerrit.reviewdb.server.ChangeMessageAccess; import com.google.gerrit.reviewdb.server.PatchLineCommentAccess; @@ -30,7 +23,6 @@ import com.google.gerrit.reviewdb.server.PatchSetApprovalAccess; import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.SchemaVersionAccess; -import com.google.gerrit.reviewdb.server.SystemConfigAccess; import com.google.gwtorm.server.Access; import com.google.gwtorm.server.AtomicUpdate; import com.google.gwtorm.server.OrmException; @@ -67,22 +59,22 @@ } @Override - public Id primaryKey(Change entity) { + public Change.Id primaryKey(Change entity) { throw new Disabled(); } @Override - public Map<Id, Change> toMap(Iterable<Change> c) { + public Map<Change.Id, Change> toMap(Iterable<Change> c) { throw new Disabled(); } @Override - public CheckedFuture<Change, OrmException> getAsync(Id key) { + public CheckedFuture<Change, OrmException> getAsync(Change.Id key) { throw new Disabled(); } @Override - public ResultSet<Change> get(Iterable<Id> keys) throws OrmException { + public ResultSet<Change> get(Iterable<Change.Id> keys) throws OrmException { throw new Disabled(); } @@ -102,7 +94,7 @@ } @Override - public void deleteKeys(Iterable<Id> keys) throws OrmException { + public void deleteKeys(Iterable<Change.Id> keys) throws OrmException { throw new Disabled(); } @@ -112,17 +104,17 @@ } @Override - public void beginTransaction(Id key) throws OrmException { + public void beginTransaction(Change.Id key) throws OrmException { throw new Disabled(); } @Override - public Change atomicUpdate(Id key, AtomicUpdate<Change> update) throws OrmException { + public Change atomicUpdate(Change.Id key, AtomicUpdate<Change> update) throws OrmException { throw new Disabled(); } @Override - public Change get(Id id) throws OrmException { + public Change get(Change.Id id) throws OrmException { return null; } @@ -168,31 +160,6 @@ } @Override - public SystemConfigAccess systemConfig() { - throw new Disabled(); - } - - @Override - public AccountGroupAccess accountGroups() { - throw new Disabled(); - } - - @Override - public AccountGroupNameAccess accountGroupNames() { - throw new Disabled(); - } - - @Override - public AccountGroupMemberAccess accountGroupMembers() { - throw new Disabled(); - } - - @Override - public AccountGroupMemberAuditAccess accountGroupMembersAudit() { - throw new Disabled(); - } - - @Override public ChangeAccess changes() { return new DisabledChangeAccess(); } @@ -218,16 +185,6 @@ } @Override - public AccountGroupByIdAccess accountGroupById() { - throw new Disabled(); - } - - @Override - public AccountGroupByIdAudAccess accountGroupByIdAud() { - throw new Disabled(); - } - - @Override public int nextAccountId() { throw new Disabled(); }
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 3922f54..0697ad7 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
@@ -18,51 +18,65 @@ 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.common.flogger.FluentLogger; import com.google.gerrit.extensions.annotations.PluginName; 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.ProjectIndexedListener; import com.google.inject.Inject; import java.util.Collections; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; class IndexEventHandler - implements ChangeIndexedListener, AccountIndexedListener, GroupIndexedListener { - private static final Logger log = LoggerFactory.getLogger(IndexEventHandler.class); + implements ChangeIndexedListener, + AccountIndexedListener, + GroupIndexedListener, + ProjectIndexedListener { + private static final FluentLogger log = FluentLogger.forEnclosingClass(); private final Executor executor; private final Forwarder forwarder; private final String pluginName; private final Set<IndexTask> queuedTasks = Collections.newSetFromMap(new ConcurrentHashMap<>()); private final ChangeCheckerImpl.Factory changeChecker; + private final CurrentRequestContext currCtx; @Inject IndexEventHandler( @IndexExecutor Executor executor, @PluginName String pluginName, Forwarder forwarder, - ChangeCheckerImpl.Factory changeChecker) { + ChangeCheckerImpl.Factory changeChecker, + CurrentRequestContext currCtx) { this.forwarder = forwarder; this.executor = executor; this.pluginName = pluginName; this.changeChecker = changeChecker; + this.currCtx = currCtx; } @Override public void onAccountIndexed(int id) { - if (!Context.isForwardedEvent()) { - IndexAccountTask task = new IndexAccountTask(id); - if (queuedTasks.add(task)) { - executor.execute(task); - } - } + currCtx.onlyWithContext( + (ctx) -> { + if (!Context.isForwardedEvent()) { + IndexAccountTask task = new IndexAccountTask(id); + if (queuedTasks.add(task)) { + executor.execute(task); + } + } + }); } @Override public void onChangeIndexed(String projectName, int id) { + currCtx.onlyWithContext((ctx) -> executeIndexChangeTask(projectName, id)); + } + + private void executeIndexChangeTask(String projectName, int id) { + if (!Context.isForwardedEvent()) { String changeId = projectName + "~" + id; try { @@ -77,7 +91,7 @@ } }); } catch (Exception e) { - log.warn("Unable to create task to reindex change {}", changeId, e); + log.atWarning().withCause(e).log("Unable to create task to reindex change {}", changeId); } } } @@ -93,6 +107,16 @@ } @Override + public void onProjectIndexed(String projectName) { + if (!Context.isForwardedEvent()) { + IndexProjectTask task = new IndexProjectTask(projectName); + if (queuedTasks.add(task)) { + executor.execute(task); + } + } + } + + @Override public void onGroupIndexed(String groupUUID) { if (!Context.isForwardedEvent()) { IndexGroupTask task = new IndexGroupTask(groupUUID); @@ -253,4 +277,36 @@ return String.format("[%s] Index group %s in target instance", pluginName, groupUUID); } } + + class IndexProjectTask extends IndexTask { + private final String projectName; + + IndexProjectTask(String projectName) { + this.projectName = projectName; + } + + @Override + public void execute() { + forwarder.indexProject(projectName, indexEvent); + } + + @Override + public int hashCode() { + return Objects.hashCode(IndexProjectTask.class, projectName); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof IndexProjectTask)) { + return false; + } + IndexProjectTask other = (IndexProjectTask) obj; + return projectName.equals(other.projectName); + } + + @Override + public String toString() { + return String.format("[%s] Index project %s in target instance", pluginName, projectName); + } + } }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexModule.java index ebf8fdf..c17731f 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexModule.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexModule.java
@@ -17,6 +17,7 @@ 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.ProjectIndexedListener; import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.lifecycle.LifecycleModule; import com.google.inject.assistedinject.FactoryModuleBuilder; @@ -35,6 +36,7 @@ DynamicSet.bind(binder(), ChangeIndexedListener.class).to(IndexEventHandler.class); DynamicSet.bind(binder(), AccountIndexedListener.class).to(IndexEventHandler.class); DynamicSet.bind(binder(), GroupIndexedListener.class).to(IndexEventHandler.class); + DynamicSet.bind(binder(), ProjectIndexedListener.class).to(IndexEventHandler.class); install( new FactoryModuleBuilder()
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProvider.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProvider.java index 596f86e..ce47390 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProvider.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProvider.java
@@ -17,6 +17,7 @@ import com.ericsson.gerrit.plugins.highavailability.Configuration; import com.ericsson.gerrit.plugins.highavailability.peers.PeerInfo; import com.google.common.collect.ImmutableSet; +import com.google.common.flogger.FluentLogger; import com.google.gerrit.extensions.events.LifecycleListener; import com.google.inject.Inject; import com.google.inject.Provider; @@ -30,8 +31,6 @@ import org.jgroups.Message; import org.jgroups.ReceiverAdapter; import org.jgroups.View; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Provider which uses JGroups to find the peer gerrit instances. On startup every gerrit instance @@ -46,7 +45,7 @@ @Singleton public class JGroupsPeerInfoProvider extends ReceiverAdapter implements Provider<Set<PeerInfo>>, LifecycleListener { - private static final Logger log = LoggerFactory.getLogger(JGroupsPeerInfoProvider.class); + private static final FluentLogger log = FluentLogger.forEnclosingClass(); private static final String JGROUPS_LOG_FACTORY_PROPERTY = "jgroups.logging.log_factory_class"; static { @@ -80,25 +79,25 @@ peerAddress = msg.getSrc(); String url = (String) msg.getObject(); peerInfo = Optional.of(new PeerInfo(url)); - log.info("receive(): Set new peerInfo: {}", url); + log.atInfo().log("receive(): Set new peerInfo: %s", url); } } @Override public void viewAccepted(View view) { - log.info("viewAccepted(view: {}) called", view); + log.atInfo().log("viewAccepted(view: %s) called", view); synchronized (this) { if (view.getMembers().size() > 2) { - log.warn( - "{} members joined the jgroups cluster {} ({}). " - + " Only two members are supported. Members: {}", + log.atWarning().log( + "%d members joined the jgroups cluster %s (%s). " + + " Only two members are supported. Members: %s", view.getMembers().size(), jgroupsConfig.clusterName(), channel.getName(), view.getMembers()); } if (peerAddress != null && !view.getMembers().contains(peerAddress)) { - log.info("viewAccepted(): removed peerInfo"); + log.atInfo().log("viewAccepted(): removed peerInfo"); peerAddress = null; peerInfo = Optional.empty(); } @@ -108,11 +107,9 @@ channel.send(new Message(null, myUrl)); } catch (Exception e) { // channel communication caused an error. Can't do much about it. - log.error( - "Sending a message over channel {} to cluster {} failed", - channel.getName(), - jgroupsConfig.clusterName(), - e); + log.atSevere().withCause(e).log( + "Sending a message over channel %s to cluster %s failed", + channel.getName(), jgroupsConfig.clusterName()); } } } @@ -122,28 +119,25 @@ channel = getChannel(); Optional<InetAddress> address = finder.findAddress(); if (address.isPresent()) { - log.debug("Protocol stack: " + channel.getProtocolStack()); + log.atFine().log("Protocol stack: %s", channel.getProtocolStack()); channel.getProtocolStack().getTransport().setBindAddress(address.get()); - log.debug("Channel bound to {}", address.get()); + log.atFine().log("Channel bound to %s", address.get()); } else { - log.warn("Channel not bound: address not present"); + log.atWarning().log("Channel not bound: address not present"); } channel.setReceiver(this); channel.setDiscardOwnMessages(true); channel.connect(jgroupsConfig.clusterName()); - log.info( - "Channel {} successfully joined jgroups cluster {}", - channel.getName(), - jgroupsConfig.clusterName()); + log.atInfo().log( + "Channel %s successfully joined jgroups cluster %s", + channel.getName(), jgroupsConfig.clusterName()); } catch (Exception e) { if (channel != null) { - log.error( - "joining cluster {} (channel {}) failed", - jgroupsConfig.clusterName(), - channel.getName(), - e); + log.atSevere().withCause(e).log( + "joining cluster %s (channel %s) failed", + jgroupsConfig.clusterName(), channel.getName()); } else { - log.error("joining cluster {} failed", jgroupsConfig.clusterName(), e); + log.atSevere().withCause(e).log("joining cluster %s failed", jgroupsConfig.clusterName()); } } } @@ -156,10 +150,9 @@ } return new JChannel(); } catch (Exception e) { - log.error( - "Unable to create a channel with protocol stack: {}", - protocolStack.isPresent() ? protocolStack : "default", - e); + log.atSevere().withCause(e).log( + "Unable to create a channel with protocol stack: %s", + protocolStack.isPresent() ? protocolStack : "default"); throw e; } } @@ -177,10 +170,9 @@ @Override public void stop() { if (channel != null) { - log.info( - "closing jgroups channel {} (cluster {})", - channel.getName(), - jgroupsConfig.clusterName()); + log.atInfo().log( + "closing jgroups channel %s (cluster %s)", + channel.getName(), jgroupsConfig.clusterName()); channel.close(); } peerInfo = Optional.empty();
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/MyUrlProvider.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/MyUrlProvider.java index adf7d2e..a257eb3 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/MyUrlProvider.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/MyUrlProvider.java
@@ -16,6 +16,7 @@ import com.ericsson.gerrit.plugins.highavailability.Configuration; import com.google.common.base.CharMatcher; +import com.google.common.flogger.FluentLogger; import com.google.gerrit.server.config.GerritServerConfig; import com.google.inject.Inject; import com.google.inject.Provider; @@ -26,12 +27,10 @@ import java.net.UnknownHostException; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.transport.URIish; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; @Singleton class MyUrlProvider implements Provider<String> { - private static final Logger log = LoggerFactory.getLogger(MyUrlProvider.class); + private static final FluentLogger log = FluentLogger.forEnclosingClass(); private static final String HTTPD_SECTION = "httpd"; private static final String LISTEN_URL_KEY = "listenUrl"; @@ -44,7 +43,7 @@ MyUrlProvider(@GerritServerConfig Config srvConfig, Configuration pluginConfiguration) { String url = pluginConfiguration.peerInfoJGroups().myUrl(); if (url == null) { - log.info("myUrl not configured; attempting to determine from {}", LISTEN_URL); + log.atInfo().log("myUrl not configured; attempting to determine from %s", LISTEN_URL); try { url = CharMatcher.is('/').trimTrailingFrom(getMyUrlFromListenUrl(srvConfig)); } catch (MyUrlProviderException e) {
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebSessionCacheCleaner.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebSessionCacheCleaner.java index b9dc245..afc6568 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebSessionCacheCleaner.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebSessionCacheCleaner.java
@@ -18,6 +18,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; import com.ericsson.gerrit.plugins.highavailability.Configuration; +import com.google.common.flogger.FluentLogger; import com.google.gerrit.extensions.annotations.PluginName; import com.google.gerrit.extensions.events.LifecycleListener; import com.google.gerrit.server.git.WorkQueue; @@ -25,8 +26,6 @@ import com.google.inject.Provider; import com.google.inject.Singleton; import java.util.concurrent.ScheduledFuture; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; @Singleton class FileBasedWebSessionCacheCleaner implements LifecycleListener { @@ -37,7 +36,7 @@ private ScheduledFuture<?> scheduledCleanupTask; static class CleanupTask implements Runnable { - private static final Logger log = LoggerFactory.getLogger(CleanupTask.class); + private static final FluentLogger log = FluentLogger.forEnclosingClass(); private final FileBasedWebsessionCache fileBasedWebSessionCache; private final String pluginName; @@ -49,9 +48,9 @@ @Override public void run() { - log.info("Cleaning up expired file based websessions..."); + log.atInfo().log("Cleaning up expired file based websessions..."); fileBasedWebSessionCache.cleanUp(); - log.info("Cleaning up expired file based websessions...Done"); + log.atInfo().log("Cleaning up expired file based websessions...Done"); } @Override
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebsessionCache.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebsessionCache.java index b4c99b5..674de10 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebsessionCache.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebsessionCache.java
@@ -18,6 +18,7 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheStats; import com.google.common.collect.ImmutableMap; +import com.google.common.flogger.FluentLogger; import com.google.gerrit.common.Nullable; import com.google.gerrit.httpd.WebSessionManager; import com.google.gerrit.httpd.WebSessionManager.Val; @@ -44,8 +45,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; @Singleton public class FileBasedWebsessionCache implements Cache<String, WebSessionManager.Val> { @@ -74,7 +73,7 @@ } } - private static final Logger log = LoggerFactory.getLogger(FileBasedWebsessionCache.class); + private static final FluentLogger log = FluentLogger.forEnclosingClass(); private final Path websessionsDir; @@ -179,7 +178,7 @@ StandardCopyOption.ATOMIC_MOVE); } } catch (IOException e) { - log.warn("Cannot put into cache {}", websessionsDir, e); + log.atWarning().withCause(e).log("Cannot put into cache %s", websessionsDir); } } @@ -197,7 +196,7 @@ @Override public CacheStats stats() { - log.warn("stats() unimplemented"); + log.atWarning().log("stats() unimplemented"); return null; } @@ -207,15 +206,14 @@ ObjectInputStream objStream = new ObjectInputStream(fileStream)) { return (Val) objStream.readObject(); } catch (ClassNotFoundException e) { - log.warn( - "Entry {} in cache {} has an incompatible class and can't be" + log.atWarning().log( + "Entry %s in cache %s has an incompatible class and can't be" + " deserialized. Invalidating entry.", - path, - websessionsDir); - log.debug(e.getMessage(), e); + path, websessionsDir); + log.atFine().withCause(e).log(e.getMessage()); invalidate(path.getFileName().toString()); } catch (IOException e) { - log.warn("Cannot read cache {}", websessionsDir, e); + log.atWarning().withCause(e).log("Cannot read cache %s", websessionsDir); } } return null; @@ -225,7 +223,7 @@ try { Files.deleteIfExists(path); } catch (IOException e) { - log.error("Error trying to delete {} from {}", path, websessionsDir, e); + log.atSevere().withCause(e).log("Error trying to delete %s from %s", path, websessionsDir); } } @@ -236,7 +234,7 @@ files.add(path); } } catch (IOException e) { - log.error("Cannot list files in cache {}", websessionsDir, e); + log.atSevere().withCause(e).log("Cannot list files in cache %s", websessionsDir); } return files; }
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md index bb72501..e79cbdd 100644 --- a/src/main/resources/Documentation/config.md +++ b/src/main/resources/Documentation/config.md
@@ -191,6 +191,11 @@ : Whether to synchronize secondary indexes. Defaults to true. +```index.synchronizeForced``` +: Whether to synchronize forced index events. E.g. on-line reindex + automatically triggered upon version upgrades. + Defaults to true. + ```index.threadPoolSize``` : Maximum number of threads used to send index events to the target instance. Defaults to 4.
diff --git a/src/test/docker/etc/gerrit.config b/src/test/docker/etc/gerrit.config index f7ee7ec..c110835 100644 --- a/src/test/docker/etc/gerrit.config +++ b/src/test/docker/etc/gerrit.config
@@ -27,5 +27,3 @@ scheme = http scheme = ssh scheme = anon_http -[plugin "plugin-manager"] - jenkinsUrl = https://archive-ci.gerritforge.com
diff --git a/src/test/docker/gerrit/Dockerfile b/src/test/docker/gerrit/Dockerfile index fb4ab9c..4664ba0 100644 --- a/src/test/docker/gerrit/Dockerfile +++ b/src/test/docker/gerrit/Dockerfile
@@ -1,18 +1,18 @@ -FROM gerritcodereview/gerrit:2.15.18 +FROM gerritcodereview/gerrit:2.16.15 -ENV GERRIT_BRANCH=stable-2.15 +ENV GERRIT_BRANCH=stable-2.16 -ENV GERRIT_CI_URL=https://archive-ci.gerritforge.com/job +ENV GERRIT_CI_URL=https://gerrit-ci.gerritforge.com/job USER root -RUN yum install -y iputils-ping netcat postgresql curl lsof gettext moreutils net-tools netcat inetutils-ping +RUN yum install -y iputils-ping netcat postgresql curl lsof gettext moreutils net-tools netcat inetutils-ping sudo USER gerrit -ADD $GERRIT_CI_URL/plugin-javamelody-bazel-$GERRIT_BRANCH/lastSuccessfulBuild/artifact/bazel-bin/plugins/javamelody/javamelody.jar /var/gerrit/plugins/javamelody.jar -ADD $GERRIT_CI_URL/plugin-javamelody-bazel-$GERRIT_BRANCH/lastSuccessfulBuild/artifact/bazel-bin/plugins/javamelody/javamelody-deps_deploy.jar /var/gerrit/lib/javamelody-deps_deploy.jar -ADD $GERRIT_CI_URL/plugin-high-availability-bazel-$GERRIT_BRANCH/lastSuccessfulBuild/artifact/bazel-bin/plugins/high-availability/high-availability.jar /var/gerrit/plugins/high-availability.jar +ADD --chown=gerrit:gerrit $GERRIT_CI_URL/plugin-javamelody-bazel-$GERRIT_BRANCH/lastSuccessfulBuild/artifact/bazel-bin/plugins/javamelody/javamelody.jar /var/gerrit/plugins/javamelody.jar +ADD --chown=gerrit:gerrit $GERRIT_CI_URL/plugin-javamelody-bazel-$GERRIT_BRANCH/lastSuccessfulBuild/artifact/bazel-bin/plugins/javamelody/javamelody-deps_deploy.jar /var/gerrit/lib/javamelody-deps_deploy.jar +ADD --chown=gerrit:gerrit $GERRIT_CI_URL/plugin-high-availability-bazel-$GERRIT_BRANCH/lastSuccessfulBuild/artifact/bazel-bin/plugins/high-availability/high-availability.jar /var/gerrit/plugins/high-availability.jar USER root
diff --git a/src/test/docker/gerrit/start.sh b/src/test/docker/gerrit/start.sh index f3d4560..7aa3550 100755 --- a/src/test/docker/gerrit/start.sh +++ b/src/test/docker/gerrit/start.sh
@@ -25,4 +25,4 @@ sudo -u gerrit touch /var/gerrit/logs/{gc_log,error_log,httpd_log,sshd_log,replication_log} && tail -f /var/gerrit/logs/* | grep --line-buffered -v 'HEAD /' & echo "Running Gerrit ..." -sudo -u gerrit /etc/init.d/gerrit run +sudo -u gerrit /var/gerrit/bin/gerrit.sh run
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 63ab408..2cf12fc 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
@@ -34,7 +34,9 @@ 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.DEFAULT_SYNCHRONIZE_FORCED; import static com.ericsson.gerrit.plugins.highavailability.Configuration.Index.INDEX_SECTION; +import static com.ericsson.gerrit.plugins.highavailability.Configuration.Index.SYNCHRONIZE_FORCED_KEY; 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; @@ -384,4 +386,13 @@ globalPluginConfig.setInt(INDEX_SECTION, null, NUM_STRIPED_LOCKS, 100); assertThat(getConfiguration().index().numStripedLocks()).isEqualTo(100); } + + @Test + public void testGetIndexSynchronizeForced() throws Exception { + assertThat(getConfiguration().index().synchronizeForced()) + .isEqualTo(DEFAULT_SYNCHRONIZE_FORCED); + + globalPluginConfig.setBoolean(INDEX_SECTION, null, SYNCHRONIZE_FORCED_KEY, false); + assertThat(getConfiguration().index().synchronizeForced()).isFalse(); + } }
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionIT.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionIT.java index 7299238..7233aac 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionIT.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionIT.java
@@ -64,9 +64,9 @@ private final CountDownLatch expectedRequestLatch = new CountDownLatch(1); @Override - public void setUp() throws Exception { + public void setUpTestPlugin() throws Exception { givenThat(any(anyUrl()).willReturn(aResponse().withStatus(HttpStatus.SC_NO_CONTENT))); - super.setUp(); + super.setUpTestPlugin(); } @Test
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListIT.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListIT.java index 9d08f15..22ef89e 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListIT.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListIT.java
@@ -49,9 +49,9 @@ @Rule public WireMockRule wireMockRule = new WireMockRule(options().port(PORT)); @Override - public void setUp() throws Exception { + public void setUpTestPlugin() throws Exception { givenThat(any(anyUrl()).willReturn(aResponse().withStatus(HttpStatus.SC_NO_CONTENT))); - super.setUp(); + super.setUpTestPlugin(); } @Test
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBrokerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBrokerTest.java index 02b4a47..ec5b1de 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBrokerTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBrokerTest.java
@@ -18,9 +18,11 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; -import com.google.gerrit.common.EventListener; import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.server.events.Event; +import com.google.gerrit.server.events.EventListener; +import com.google.gerrit.server.plugincontext.PluginContext.PluginMetrics; +import com.google.gerrit.server.plugincontext.PluginSetContext; import org.junit.Before; import org.junit.Test; @@ -32,9 +34,11 @@ @Before public void setUp() { + PluginMetrics mockMetrics = mock(PluginMetrics.class); listenerMock = mock(EventListener.class); - DynamicSet<EventListener> listeners = DynamicSet.emptySet(); - listeners.add(listenerMock); + DynamicSet<EventListener> set = DynamicSet.emptySet(); + set.add("high-availability", listenerMock); + PluginSetContext<EventListener> listeners = new PluginSetContext<>(set, mockMetrics); broker = new ForwardedAwareEventBroker(null, listeners, null, null, null, null); }
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedCacheEvictionHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedCacheEvictionHandlerTest.java index 3426b05..44bb1ea 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedCacheEvictionHandlerTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedCacheEvictionHandlerTest.java
@@ -15,6 +15,7 @@ package com.ericsson.gerrit.plugins.highavailability.forwarder; import static com.google.common.truth.Truth.assertThat; +import static com.google.gerrit.testing.GerritJUnit.assertThrows; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; @@ -24,9 +25,7 @@ import com.google.gerrit.extensions.registration.DynamicMap; import com.google.gerrit.reviewdb.client.Account; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -35,7 +34,6 @@ @RunWith(MockitoJUnitRunner.class) public class ForwardedCacheEvictionHandlerTest { - @Rule public ExpectedException exception = ExpectedException.none(); @Mock private DynamicMap<Cache<?, ?>> cacheMapMock; @Mock private Cache<?, ?> cacheMock; private ForwardedCacheEvictionHandler handler; @@ -48,11 +46,11 @@ @Test public void shouldThrowAnExceptionWhenCacheNotFound() throws Exception { CacheEntry entry = new CacheEntry("somePlugin", "unexistingCache", null); - - exception.expect(CacheNotFoundException.class); - exception.expectMessage( - String.format("cache %s.%s not found", entry.getPluginName(), entry.getCacheName())); - handler.evict(entry); + String expectedMessage = + String.format("cache %s.%s not found", entry.getPluginName(), entry.getCacheName()); + CacheNotFoundException thrown = + assertThrows(CacheNotFoundException.class, () -> handler.evict(entry)); + assertThat(thrown).hasMessageThat().contains(expectedMessage); } @Test
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedEventHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedEventHandlerTest.java index ecb976e..a855c5e 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedEventHandlerTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedEventHandlerTest.java
@@ -15,18 +15,16 @@ package com.ericsson.gerrit.plugins.highavailability.forwarder; import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.fail; +import static com.google.gerrit.testing.GerritJUnit.assertThrows; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.verify; -import com.google.gerrit.common.EventDispatcher; import com.google.gerrit.server.events.Event; +import com.google.gerrit.server.events.EventDispatcher; import com.google.gerrit.server.events.ProjectCreatedEvent; import com.google.gwtorm.server.OrmException; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -35,7 +33,6 @@ @RunWith(MockitoJUnitRunner.class) public class ForwardedEventHandlerTest { - @Rule public ExpectedException exception = ExpectedException.none(); @Mock private EventDispatcher dispatcherMock; private ForwardedEventHandler handler; @@ -85,12 +82,8 @@ .postEvent(event); assertThat(Context.isForwardedEvent()).isFalse(); - try { - handler.dispatch(event); - fail("should have throw an OrmException"); - } catch (OrmException e) { - assertThat(e.getMessage()).isEqualTo("someMessage"); - } + OrmException thrown = assertThrows(OrmException.class, () -> handler.dispatch(event)); + assertThat(thrown).hasMessageThat().contains("someMessage"); assertThat(Context.isForwardedEvent()).isFalse(); verify(dispatcherMock).postEvent(event);
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 c2d3659..b88e9c0 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
@@ -15,6 +15,7 @@ package com.ericsson.gerrit.plugins.highavailability.forwarder; import static com.google.common.truth.Truth.assertThat; +import static com.google.gerrit.testing.GerritJUnit.assertThrows; import static org.junit.Assert.fail; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.verify; @@ -27,9 +28,7 @@ import java.io.IOException; import java.util.Optional; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -38,7 +37,6 @@ @RunWith(MockitoJUnitRunner.class) public class ForwardedIndexAccountHandlerTest { - @Rule public ExpectedException exception = ExpectedException.none(); @Mock private AccountIndexer indexerMock; @Mock private Configuration configMock; @Mock private Configuration.Index indexMock; @@ -61,9 +59,11 @@ @Test public void deleteIsNotSupported() throws Exception { - exception.expect(UnsupportedOperationException.class); - exception.expectMessage("Delete from account index not supported"); - handler.index(id, Operation.DELETE, Optional.empty()); + UnsupportedOperationException thrown = + assertThrows( + UnsupportedOperationException.class, + () -> handler.index(id, Operation.DELETE, Optional.empty())); + assertThat(thrown).hasMessageThat().contains("Delete from account index not supported"); } @Test
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 8bfe47d..6bfd47d 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
@@ -15,6 +15,7 @@ package com.ericsson.gerrit.plugins.highavailability.forwarder; import static com.google.common.truth.Truth.assertThat; +import static com.google.gerrit.testing.GerritJUnit.assertThrows; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; @@ -28,20 +29,18 @@ import com.ericsson.gerrit.plugins.highavailability.index.ChangeChecker; import com.ericsson.gerrit.plugins.highavailability.index.ChangeCheckerImpl; import com.ericsson.gerrit.plugins.highavailability.index.ChangeDb; -import com.google.gerrit.common.TimeUtil; import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.index.change.ChangeIndexer; import com.google.gerrit.server.notedb.ChangeNotes; import com.google.gerrit.server.util.OneOffRequestContext; +import com.google.gerrit.server.util.time.TimeUtil; import com.google.gwtorm.server.OrmException; import java.io.IOException; import java.util.Optional; import java.util.concurrent.ScheduledExecutorService; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -62,7 +61,6 @@ private static final boolean CHANGE_UP_TO_DATE = true; private static final boolean CHANGE_OUTDATED = false; - @Rule public ExpectedException exception = ExpectedException.none(); @Mock private ChangeIndexer indexerMock; @Mock private ChangeDb changeDbMock; @Mock private ReviewDb dbMock; @@ -120,22 +118,22 @@ public void changeToIndexDoesNotExist() throws Exception { setupChangeAccessRelatedMocks(CHANGE_DOES_NOT_EXIST, CHANGE_OUTDATED); handler.index(TEST_CHANGE_ID, Operation.INDEX, Optional.empty()); - verify(indexerMock, times(1)).delete(id); + verify(indexerMock, times(0)).delete(id); } @Test public void schemaThrowsExceptionWhenLookingUpForChange() throws Exception { setupChangeAccessRelatedMocks(CHANGE_EXISTS, THROW_ORM_EXCEPTION, CHANGE_UP_TO_DATE); - exception.expect(OrmException.class); - handler.index(TEST_CHANGE_ID, Operation.INDEX, Optional.empty()); + assertThrows( + OrmException.class, () -> handler.index(TEST_CHANGE_ID, Operation.INDEX, Optional.empty())); } @Test public void indexerThrowsIOExceptionTryingToIndexChange() throws Exception { setupChangeAccessRelatedMocks( CHANGE_EXISTS, DO_NOT_THROW_ORM_EXCEPTION, THROW_IO_EXCEPTION, CHANGE_UP_TO_DATE); - exception.expect(IOException.class); - handler.index(TEST_CHANGE_ID, Operation.INDEX, Optional.empty()); + assertThrows( + IOException.class, () -> handler.index(TEST_CHANGE_ID, Operation.INDEX, Optional.empty())); } @Test
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 ab55b73..845abb0 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
@@ -15,6 +15,7 @@ package com.ericsson.gerrit.plugins.highavailability.forwarder; import static com.google.common.truth.Truth.assertThat; +import static com.google.gerrit.testing.GerritJUnit.assertThrows; import static org.junit.Assert.fail; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.verify; @@ -27,9 +28,7 @@ import java.io.IOException; import java.util.Optional; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -38,7 +37,6 @@ @RunWith(MockitoJUnitRunner.class) public class ForwardedIndexGroupHandlerTest { - @Rule public ExpectedException exception = ExpectedException.none(); @Mock private GroupIndexer indexerMock; @Mock private Configuration configMock; @Mock private Configuration.Index indexMock; @@ -61,9 +59,11 @@ @Test public void deleteIsNotSupported() throws Exception { - exception.expect(UnsupportedOperationException.class); - exception.expectMessage("Delete from group index not supported"); - handler.index(uuid, Operation.DELETE, Optional.empty()); + UnsupportedOperationException thrown = + assertThrows( + UnsupportedOperationException.class, + () -> handler.index(uuid, Operation.DELETE, Optional.empty())); + assertThat(thrown).hasMessageThat().contains("Delete from group index not supported"); } @Test
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexProjectHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexProjectHandlerTest.java new file mode 100644 index 0000000..a0c6979 --- /dev/null +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexProjectHandlerTest.java
@@ -0,0 +1,111 @@ +// 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 static com.google.common.truth.Truth.assertThat; +import static com.google.gerrit.testing.GerritJUnit.assertThrows; +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.index.project.ProjectIndexer; +import com.google.gerrit.reviewdb.client.Project; +import java.io.IOException; +import java.util.Optional; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; + +@RunWith(MockitoJUnitRunner.class) +public class ForwardedIndexProjectHandlerTest { + + @Mock private ProjectIndexer indexerMock; + @Mock private Configuration configMock; + @Mock private Configuration.Index indexMock; + private ForwardedIndexProjectHandler handler; + private Project.NameKey nameKey; + + @Before + public void setUp() { + when(configMock.index()).thenReturn(indexMock); + when(indexMock.numStripedLocks()).thenReturn(10); + handler = new ForwardedIndexProjectHandler(indexerMock, configMock); + nameKey = new Project.NameKey("project/name"); + } + + @Test + public void testSuccessfulIndexing() throws Exception { + handler.index(nameKey, Operation.INDEX, Optional.empty()); + verify(indexerMock).index(nameKey); + } + + @Test + public void deleteIsNotSupported() throws Exception { + UnsupportedOperationException thrown = + assertThrows( + UnsupportedOperationException.class, + () -> handler.index(nameKey, Operation.DELETE, Optional.empty())); + assertThat(thrown).hasMessageThat().contains("Delete from project index not supported"); + } + + @Test + public void shouldSetAndUnsetForwardedContext() throws Exception { + // this doAnswer is to allow to assert that context is set to forwarded + // while cache eviction is called. + doAnswer( + (Answer<Void>) + invocation -> { + assertThat(Context.isForwardedEvent()).isTrue(); + return null; + }) + .when(indexerMock) + .index(nameKey); + + assertThat(Context.isForwardedEvent()).isFalse(); + handler.index(nameKey, Operation.INDEX, Optional.empty()); + assertThat(Context.isForwardedEvent()).isFalse(); + + verify(indexerMock).index(nameKey); + } + + @Test + public void shouldSetAndUnsetForwardedContextEvenIfExceptionIsThrown() throws Exception { + doAnswer( + (Answer<Void>) + invocation -> { + assertThat(Context.isForwardedEvent()).isTrue(); + throw new IOException("someMessage"); + }) + .when(indexerMock) + .index(nameKey); + + assertThat(Context.isForwardedEvent()).isFalse(); + try { + handler.index(nameKey, Operation.INDEX, Optional.empty()); + fail("should have thrown an IOException"); + } catch (IOException e) { + assertThat(e.getMessage()).isEqualTo("someMessage"); + } + assertThat(Context.isForwardedEvent()).isFalse(); + + verify(indexerMock).index(nameKey); + } +}
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedProjectListUpdateHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedProjectListUpdateHandlerTest.java index 3ee8581..f5521c5 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedProjectListUpdateHandlerTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedProjectListUpdateHandlerTest.java
@@ -15,16 +15,14 @@ package com.ericsson.gerrit.plugins.highavailability.forwarder; import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.fail; +import static com.google.gerrit.testing.GerritJUnit.assertThrows; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.verify; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.server.project.ProjectCache; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -36,7 +34,6 @@ private static final String PROJECT_NAME = "someProject"; private static final String SOME_MESSAGE = "someMessage"; private static final Project.NameKey PROJECT_KEY = new Project.NameKey(PROJECT_NAME); - @Rule public ExpectedException exception = ExpectedException.none(); @Mock private ProjectCache projectCacheMock; private ForwardedProjectListUpdateHandler handler; @@ -109,12 +106,9 @@ .onCreateProject(PROJECT_KEY); assertThat(Context.isForwardedEvent()).isFalse(); - try { - handler.update(PROJECT_NAME, false); - fail("should have thrown a RuntimeException"); - } catch (RuntimeException e) { - assertThat(e.getMessage()).isEqualTo(SOME_MESSAGE); - } + RuntimeException thrown = + assertThrows(RuntimeException.class, () -> handler.update(PROJECT_NAME, false)); + assertThat(thrown).hasMessageThat().contains(SOME_MESSAGE); assertThat(Context.isForwardedEvent()).isFalse(); verify(projectCacheMock).onCreateProject(PROJECT_KEY); @@ -132,12 +126,9 @@ .remove(PROJECT_KEY); assertThat(Context.isForwardedEvent()).isFalse(); - try { - handler.update(PROJECT_NAME, true); - fail("should have thrown a RuntimeException"); - } catch (RuntimeException e) { - assertThat(e.getMessage()).isEqualTo(SOME_MESSAGE); - } + RuntimeException thrown = + assertThrows(RuntimeException.class, () -> handler.update(PROJECT_NAME, true)); + assertThat(thrown).hasMessageThat().contains(SOME_MESSAGE); assertThat(Context.isForwardedEvent()).isFalse(); verify(projectCacheMock).remove(PROJECT_KEY);
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexProjectRestApiServletTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexProjectRestApiServletTest.java new file mode 100644 index 0000000..83420b9 --- /dev/null +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexProjectRestApiServletTest.java
@@ -0,0 +1,91 @@ +// 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.rest; + +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; +import static org.mockito.Mockito.when; + +import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexProjectHandler; +import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexingHandler.Operation; +import com.google.gerrit.extensions.restapi.Url; +import com.google.gerrit.reviewdb.client.Project; +import java.io.IOException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class IndexProjectRestApiServletTest { + private static final String IO_ERROR = "io-error"; + private static final String PROJECT_NAME = "test/project"; + + @Mock private ForwardedIndexProjectHandler handlerMock; + @Mock private HttpServletRequest requestMock; + @Mock private HttpServletResponse responseMock; + + private Project.NameKey nameKey; + private IndexProjectRestApiServlet servlet; + + @Before + public void setUpMocks() { + servlet = new IndexProjectRestApiServlet(handlerMock); + nameKey = new Project.NameKey(PROJECT_NAME); + when(requestMock.getRequestURI()) + .thenReturn("http://gerrit.com/index/project/" + Url.encode(nameKey.get())); + } + + @Test + public void projectIsIndexed() throws Exception { + servlet.doPost(requestMock, responseMock); + verify(handlerMock, times(1)).index(eq(nameKey), eq(Operation.INDEX), any()); + verify(responseMock).setStatus(SC_NO_CONTENT); + } + + @Test + public void cannotDeleteProject() throws Exception { + servlet.doDelete(requestMock, responseMock); + verify(responseMock).sendError(SC_METHOD_NOT_ALLOWED, "cannot delete project from index"); + } + + @Test + public void indexerThrowsIOExceptionTryingToIndexProject() throws Exception { + doThrow(new IOException(IO_ERROR)) + .when(handlerMock) + .index(eq(nameKey), 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(eq(nameKey), 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/index/AbstractIndexForwardingIT.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/AbstractIndexForwardingIT.java index 2eee205..af4637e 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/AbstractIndexForwardingIT.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/AbstractIndexForwardingIT.java
@@ -51,10 +51,10 @@ @Rule public WireMockRule wireMockRule = new WireMockRule(options().port(PORT)); @Override - public void setUp() throws Exception { + public void setUpTestPlugin() throws Exception { givenThat(any(anyUrl()).willReturn(aResponse().withStatus(HttpStatus.SC_NO_CONTENT))); beforeAction(); - super.setUp(); + super.setUpTestPlugin(); } @Test
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 d9e1b22..2d12ca8 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
@@ -18,11 +18,13 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; +import com.ericsson.gerrit.plugins.highavailability.Configuration; import com.ericsson.gerrit.plugins.highavailability.forwarder.Context; import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder; import com.ericsson.gerrit.plugins.highavailability.forwarder.IndexEvent; @@ -34,8 +36,12 @@ import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.Change; +import com.google.gerrit.server.util.OneOffRequestContext; +import com.google.gerrit.server.util.RequestContext; +import com.google.gerrit.server.util.ThreadLocalRequestContext; import java.util.Optional; import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.function.Consumer; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -58,6 +64,15 @@ private Change.Id changeId; private Account.Id accountId; private AccountGroup.UUID accountGroupUUID; + @Mock private RequestContext mockCtx; + + private CurrentRequestContext currCtx = + new CurrentRequestContext(null, null, null) { + @Override + public void onlyWithContext(Consumer<RequestContext> body) { + body.accept(mockCtx); + } + }; @Before public void setUpMocks() throws Exception { @@ -66,9 +81,18 @@ accountGroupUUID = new AccountGroup.UUID(UUID); when(changeCheckerFactoryMock.create(any())).thenReturn(changeCheckerMock); when(changeCheckerMock.newIndexEvent()).thenReturn(Optional.of(new IndexEvent())); + + setUpIndexEventHandler(currCtx); + } + + public void setUpIndexEventHandler(CurrentRequestContext currCtx) throws Exception { indexEventHandler = new IndexEventHandler( - MoreExecutors.directExecutor(), PLUGIN_NAME, forwarder, changeCheckerFactoryMock); + MoreExecutors.directExecutor(), + PLUGIN_NAME, + forwarder, + changeCheckerFactoryMock, + currCtx); } @Test @@ -78,6 +102,33 @@ } @Test + public void shouldNotIndexInRemoteWhenContextIsMissing() throws Exception { + ThreadLocalRequestContext threadLocalCtxMock = mock(ThreadLocalRequestContext.class); + OneOffRequestContext oneOffCtxMock = mock(OneOffRequestContext.class); + Configuration cfgMock = mock(Configuration.class); + Configuration.Index cfgIndex = mock(Configuration.Index.class); + when(cfgMock.index()).thenReturn(cfgIndex); + + setUpIndexEventHandler(new CurrentRequestContext(threadLocalCtxMock, cfgMock, oneOffCtxMock)); + indexEventHandler.onChangeIndexed(PROJECT_NAME, changeId.get()); + verify(forwarder, never()).indexChange(eq(PROJECT_NAME), eq(CHANGE_ID), any()); + } + + @Test + public void shouldReindexInRemoteWhenContextIsMissingButForcedIndexingEnabled() throws Exception { + ThreadLocalRequestContext threadLocalCtxMock = mock(ThreadLocalRequestContext.class); + OneOffRequestContext oneOffCtxMock = mock(OneOffRequestContext.class); + Configuration cfgMock = mock(Configuration.class); + Configuration.Index cfgIndex = mock(Configuration.Index.class); + when(cfgMock.index()).thenReturn(cfgIndex); + when(cfgIndex.synchronizeForced()).thenReturn(true); + + setUpIndexEventHandler(new CurrentRequestContext(threadLocalCtxMock, cfgMock, oneOffCtxMock)); + indexEventHandler.onChangeIndexed(PROJECT_NAME, changeId.get()); + verify(forwarder).indexChange(eq(PROJECT_NAME), eq(CHANGE_ID), any()); + } + + @Test public void shouldIndexInRemoteOnAccountIndexedEvent() throws Exception { indexEventHandler.onAccountIndexed(accountId.get()); verify(forwarder).indexAccount(eq(ACCOUNT_ID), any()); @@ -128,7 +179,7 @@ public void duplicateChangeEventOfAQueuedEventShouldGetDiscarded() { ScheduledThreadPoolExecutor poolMock = mock(ScheduledThreadPoolExecutor.class); indexEventHandler = - new IndexEventHandler(poolMock, PLUGIN_NAME, forwarder, changeCheckerFactoryMock); + new IndexEventHandler(poolMock, PLUGIN_NAME, forwarder, changeCheckerFactoryMock, currCtx); indexEventHandler.onChangeIndexed(PROJECT_NAME, changeId.get()); indexEventHandler.onChangeIndexed(PROJECT_NAME, changeId.get()); verify(poolMock, times(1)) @@ -139,7 +190,7 @@ public void duplicateAccountEventOfAQueuedEventShouldGetDiscarded() { ScheduledThreadPoolExecutor poolMock = mock(ScheduledThreadPoolExecutor.class); indexEventHandler = - new IndexEventHandler(poolMock, PLUGIN_NAME, forwarder, changeCheckerFactoryMock); + new IndexEventHandler(poolMock, PLUGIN_NAME, forwarder, changeCheckerFactoryMock, currCtx); indexEventHandler.onAccountIndexed(accountId.get()); indexEventHandler.onAccountIndexed(accountId.get()); verify(poolMock, times(1)).execute(indexEventHandler.new IndexAccountTask(ACCOUNT_ID)); @@ -149,7 +200,7 @@ public void duplicateGroupEventOfAQueuedEventShouldGetDiscarded() { ScheduledThreadPoolExecutor poolMock = mock(ScheduledThreadPoolExecutor.class); indexEventHandler = - new IndexEventHandler(poolMock, PLUGIN_NAME, forwarder, changeCheckerFactoryMock); + new IndexEventHandler(poolMock, PLUGIN_NAME, forwarder, changeCheckerFactoryMock, currCtx); indexEventHandler.onGroupIndexed(accountGroupUUID.get()); indexEventHandler.onGroupIndexed(accountGroupUUID.get()); verify(poolMock, times(1)).execute(indexEventHandler.new IndexGroupTask(UUID));
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/ProjectIndexForwardingIT.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/ProjectIndexForwardingIT.java new file mode 100644 index 0000000..951e4f6 --- /dev/null +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/ProjectIndexForwardingIT.java
@@ -0,0 +1,36 @@ +// 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.index; + +import com.google.gerrit.extensions.restapi.Url; + +public class ProjectIndexForwardingIT extends AbstractIndexForwardingIT { + private String someProjectName; + + @Override + public void beforeAction() throws Exception { + someProjectName = gApi.projects().create("someProject").get().name; + } + + @Override + public String getExpectedRequest() { + return "/plugins/high-availability/index/project/" + Url.encode(someProjectName); + } + + @Override + public void doAction() throws Exception { + gApi.projects().name(someProjectName).index(false); + } +}
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/MyUrlProviderTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/MyUrlProviderTest.java index f3e8b7d..c337947 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/MyUrlProviderTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/MyUrlProviderTest.java
@@ -15,6 +15,7 @@ package com.ericsson.gerrit.plugins.highavailability.peers.jgroups; import static com.google.common.truth.Truth.assertThat; +import static com.google.gerrit.testing.GerritJUnit.assertThrows; import static java.net.InetAddress.getLocalHost; import static org.mockito.Answers.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.when; @@ -23,9 +24,7 @@ import com.google.inject.ProvisionException; import org.eclipse.jgit.lib.Config; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -38,8 +37,6 @@ private static final String HTTPS = "https://"; private static final String LISTEN_URL = "listenUrl"; - @Rule public ExpectedException exception = ExpectedException.none(); - @Mock(answer = RETURNS_DEEP_STUBS) private Configuration configurationMock; @@ -70,33 +67,29 @@ @Test public void testGetJGroupsMyUrlFromListenUrlWhenNoListenUrlSpecified() throws Exception { - exception.expect(ProvisionException.class); - exception.expectMessage("exactly 1 value configured; found 0"); - getMyUrlProvider(); + ProvisionException thrown = assertThrows(ProvisionException.class, () -> getMyUrlProvider()); + assertThat(thrown).hasMessageThat().contains("exactly 1 value configured; found 0"); } @Test public void testGetJGroupsMyUrlFromListenUrlWhenMultipleListenUrlsSpecified() throws Exception { gerritServerConfig.setStringList(HTTPD, null, LISTEN_URL, Lists.newArrayList("a", "b")); - exception.expect(ProvisionException.class); - exception.expectMessage("exactly 1 value configured; found 2"); - getMyUrlProvider(); + ProvisionException thrown = assertThrows(ProvisionException.class, () -> getMyUrlProvider()); + assertThat(thrown).hasMessageThat().contains("exactly 1 value configured; found 2"); } @Test public void testGetJGroupsMyUrlFromListenUrlWhenReverseProxyConfigured() throws Exception { gerritServerConfig.setString(HTTPD, null, LISTEN_URL, "proxy-https://foo"); - exception.expect(ProvisionException.class); - exception.expectMessage("when configured as reverse-proxy"); - getMyUrlProvider(); + ProvisionException thrown = assertThrows(ProvisionException.class, () -> getMyUrlProvider()); + assertThat(thrown).hasMessageThat().contains("when configured as reverse-proxy"); } @Test public void testGetJGroupsMyUrlFromListenUrlWhenWildcardConfigured() throws Exception { gerritServerConfig.setString(HTTPD, null, LISTEN_URL, "https://*"); - exception.expect(ProvisionException.class); - exception.expectMessage("when configured with wildcard"); - getMyUrlProvider(); + ProvisionException thrown = assertThrows(ProvisionException.class, () -> getMyUrlProvider()); + assertThat(thrown).hasMessageThat().contains("when configured with wildcard"); } @Test