summaryrefslogtreecommitdiffstats
path: root/java/com/google/gerrit/index/SiteIndexer.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/google/gerrit/index/SiteIndexer.java')
-rw-r--r--java/com/google/gerrit/index/SiteIndexer.java150
1 files changed, 150 insertions, 0 deletions
diff --git a/java/com/google/gerrit/index/SiteIndexer.java b/java/com/google/gerrit/index/SiteIndexer.java
new file mode 100644
index 0000000000..c3ab8a42e5
--- /dev/null
+++ b/java/com/google/gerrit/index/SiteIndexer.java
@@ -0,0 +1,150 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.index;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.Stopwatch;
+import com.google.common.flogger.FluentLogger;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.util.io.NullOutputStream;
+
+public abstract class SiteIndexer<K, V, I extends Index<K, V>> {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ public static class Result {
+ private final long elapsedNanos;
+ private final boolean success;
+ private final int done;
+ private final int failed;
+
+ public Result(Stopwatch sw, boolean success, int done, int failed) {
+ this.elapsedNanos = sw.elapsed(TimeUnit.NANOSECONDS);
+ this.success = success;
+ this.done = done;
+ this.failed = failed;
+ }
+
+ public boolean success() {
+ return success;
+ }
+
+ public int doneCount() {
+ return done;
+ }
+
+ public int failedCount() {
+ return failed;
+ }
+
+ public long elapsed(TimeUnit timeUnit) {
+ return timeUnit.convert(elapsedNanos, TimeUnit.NANOSECONDS);
+ }
+ }
+
+ protected int totalWork = -1;
+ protected OutputStream progressOut = NullOutputStream.INSTANCE;
+ protected PrintWriter verboseWriter = newPrintWriter(NullOutputStream.INSTANCE);
+
+ public void setTotalWork(int num) {
+ totalWork = num;
+ }
+
+ public void setProgressOut(OutputStream out) {
+ progressOut = requireNonNull(out);
+ }
+
+ public void setVerboseOut(OutputStream out) {
+ verboseWriter = newPrintWriter(requireNonNull(out));
+ }
+
+ public abstract Result indexAll(I index);
+
+ protected final void addErrorListener(
+ ListenableFuture<?> future, String desc, ProgressMonitor progress, AtomicBoolean ok) {
+ future.addListener(
+ new ErrorListener(future, desc, progress, ok), MoreExecutors.directExecutor());
+ }
+
+ protected PrintWriter newPrintWriter(OutputStream out) {
+ return new PrintWriter(new OutputStreamWriter(out, UTF_8));
+ }
+
+ private static class ErrorListener implements Runnable {
+ private final ListenableFuture<?> future;
+ private final String desc;
+ private final ProgressMonitor progress;
+ private final AtomicBoolean ok;
+
+ private ErrorListener(
+ ListenableFuture<?> future, String desc, ProgressMonitor progress, AtomicBoolean ok) {
+ this.future = future;
+ this.desc = desc;
+ this.progress = progress;
+ this.ok = ok;
+ }
+
+ @Override
+ public void run() {
+ try {
+ future.get();
+ } catch (RejectedExecutionException e) {
+ // Server shutdown, don't spam the logs.
+ failSilently();
+ } catch (ExecutionException | InterruptedException e) {
+ fail(e);
+ } catch (RuntimeException e) {
+ failAndThrow(e);
+ } catch (Error e) {
+ // Can't join with RuntimeException because "RuntimeException |
+ // Error" becomes Throwable, which messes with signatures.
+ failAndThrow(e);
+ } finally {
+ synchronized (progress) {
+ progress.update(1);
+ }
+ }
+ }
+
+ private void failSilently() {
+ ok.set(false);
+ }
+
+ private void fail(Throwable t) {
+ logger.atSevere().withCause(t).log("Failed to index %s", desc);
+ ok.set(false);
+ }
+
+ private void failAndThrow(RuntimeException e) {
+ fail(e);
+ throw e;
+ }
+
+ private void failAndThrow(Error e) {
+ fail(e);
+ throw e;
+ }
+ }
+}