* stable-3.1: Set version to 3.1.8-SNAPSHOT Set version to 3.1.7 Use Mockito instead of EasyMock for X-Frame-Options header tests Set version to 3.0.12-SNAPSHOT Set version to 3.0.11 Set X-Frame-Options header to avoid clickjacking PG: Skip unsupported global capabilities Revert "Remove documentation of obsolete gerrit.canLoadInIFrame" Fix typos in note-db.txt Document skipping of reindexing step for offline NoteDB migration Report end of NoteDB migration when skipping reindexing Clarify that index.batchThreads is relevant for offline reindexing Add project to output when reindexing changes in verbose mode Auto-flush SiteIndexer's PrintWriters Allow to re-index in verbose mode during NoteDB migration Avoid closing System.out after All-Users GC in NoteDB migration Honor project watches also for changes created via cherry-pick Report the index state after re-indexing Change-Id: I6038b4d47997d44719923376221f4cc75b24d693
145 lines
4.5 KiB
Java
145 lines
4.5 KiB
Java
// 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.auto.value.AutoValue;
|
|
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;
|
|
|
|
/** Base class for implementations that can index all entities of a given type. */
|
|
public abstract class SiteIndexer<K, V, I extends Index<K, V>> {
|
|
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
|
|
|
/** Result of an operation to index a subset or all of the entities of a given type. */
|
|
@AutoValue
|
|
public abstract static class Result {
|
|
public abstract long elapsedNanos();
|
|
|
|
public abstract boolean success();
|
|
|
|
public abstract int doneCount();
|
|
|
|
public abstract int failedCount();
|
|
|
|
public static Result create(Stopwatch sw, boolean success, int done, int failed) {
|
|
return new AutoValue_SiteIndexer_Result(
|
|
sw.elapsed(TimeUnit.NANOSECONDS), success, done, 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));
|
|
}
|
|
|
|
/** Indexes all entities for the provided index. */
|
|
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), true);
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|