Index: Extract common parts into AbstractVersionManager
Most of code in LuceneVersionManager and ElasticVersionManager is similar. The only difference is in the way how both implementation get current version of schema. This patch extract common parts into AbstracttVersionManager and refactor both classes to use common parent. Change-Id: I170e16073b03f648e9904401b0b42b807891d471
This commit is contained in:

committed by
David Pursehouse

parent
ea52988afe
commit
535acb1723
@@ -14,54 +14,37 @@
|
||||
|
||||
package com.google.gerrit.lucene;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.gerrit.extensions.events.LifecycleListener;
|
||||
import com.google.gerrit.server.config.GerritServerConfig;
|
||||
import com.google.gerrit.server.config.SitePaths;
|
||||
import com.google.gerrit.server.index.AbstractVersionManager;
|
||||
import com.google.gerrit.server.index.GerritIndexStatus;
|
||||
import com.google.gerrit.server.index.Index;
|
||||
import com.google.gerrit.server.index.IndexCollection;
|
||||
import com.google.gerrit.server.index.IndexDefinition;
|
||||
import com.google.gerrit.server.index.IndexDefinition.IndexFactory;
|
||||
import com.google.gerrit.server.index.OnlineReindexer;
|
||||
import com.google.gerrit.server.index.ReindexerAlreadyRunningException;
|
||||
import com.google.gerrit.server.index.Schema;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.ProvisionException;
|
||||
import com.google.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@Singleton
|
||||
public class LuceneVersionManager implements LifecycleListener {
|
||||
public class LuceneVersionManager extends AbstractVersionManager implements LifecycleListener {
|
||||
private static final Logger log = LoggerFactory.getLogger(LuceneVersionManager.class);
|
||||
|
||||
private static class Version<V> {
|
||||
private final Schema<V> schema;
|
||||
private final int version;
|
||||
private static class Version<V> extends AbstractVersionManager.Version<V> {
|
||||
private final boolean exists;
|
||||
private final boolean ready;
|
||||
|
||||
private Version(Schema<V> schema, int version, boolean exists, boolean ready) {
|
||||
checkArgument(schema == null || schema.getVersion() == version);
|
||||
this.schema = schema;
|
||||
this.version = version;
|
||||
super(schema, version, ready);
|
||||
this.exists = exists;
|
||||
this.ready = ready;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,156 +52,26 @@ public class LuceneVersionManager implements LifecycleListener {
|
||||
return sitePaths.index_dir.resolve(String.format("%s%04d", prefix, schema.getVersion()));
|
||||
}
|
||||
|
||||
private final SitePaths sitePaths;
|
||||
private final Map<String, IndexDefinition<?, ?, ?>> defs;
|
||||
private final Map<String, OnlineReindexer<?, ?, ?>> reindexers;
|
||||
private final boolean onlineUpgrade;
|
||||
private final String runReindexMsg;
|
||||
|
||||
@Inject
|
||||
LuceneVersionManager(
|
||||
@GerritServerConfig Config cfg,
|
||||
SitePaths sitePaths,
|
||||
Collection<IndexDefinition<?, ?, ?>> defs) {
|
||||
this.sitePaths = sitePaths;
|
||||
this.defs = Maps.newHashMapWithExpectedSize(defs.size());
|
||||
for (IndexDefinition<?, ?, ?> def : defs) {
|
||||
this.defs.put(def.getName(), def);
|
||||
}
|
||||
|
||||
reindexers = Maps.newHashMapWithExpectedSize(defs.size());
|
||||
onlineUpgrade = cfg.getBoolean("index", null, "onlineUpgrade", true);
|
||||
runReindexMsg =
|
||||
"No index versions ready; run java -jar "
|
||||
+ sitePaths.gerrit_war.toAbsolutePath()
|
||||
+ " reindex";
|
||||
super(cfg, sitePaths, defs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
GerritIndexStatus cfg;
|
||||
try {
|
||||
cfg = new GerritIndexStatus(sitePaths);
|
||||
} catch (ConfigInvalidException | IOException e) {
|
||||
throw fail(e);
|
||||
}
|
||||
|
||||
if (!Files.exists(sitePaths.index_dir)) {
|
||||
throw new ProvisionException(runReindexMsg);
|
||||
} else if (!Files.exists(sitePaths.index_dir)) {
|
||||
log.warn("Not a directory: %s", sitePaths.index_dir.toAbsolutePath());
|
||||
throw new ProvisionException(runReindexMsg);
|
||||
}
|
||||
|
||||
for (IndexDefinition<?, ?, ?> def : defs.values()) {
|
||||
initIndex(def, cfg);
|
||||
}
|
||||
protected <V> boolean isDirty(
|
||||
Collection<com.google.gerrit.server.index.AbstractVersionManager.Version<V>> inUse,
|
||||
com.google.gerrit.server.index.AbstractVersionManager.Version<V> v) {
|
||||
return !inUse.contains(v) && ((Version<V>) v).exists;
|
||||
}
|
||||
|
||||
private <K, V, I extends Index<K, V>> void initIndex(
|
||||
IndexDefinition<K, V, I> def, GerritIndexStatus cfg) {
|
||||
TreeMap<Integer, Version<V>> versions = scanVersions(def, cfg);
|
||||
// Search from the most recent ready version.
|
||||
// Write to the most recent ready version and the most recent version.
|
||||
Version<V> search = null;
|
||||
List<Version<V>> write = Lists.newArrayListWithCapacity(2);
|
||||
for (Version<V> v : versions.descendingMap().values()) {
|
||||
if (v.schema == null) {
|
||||
continue;
|
||||
}
|
||||
if (write.isEmpty() && onlineUpgrade) {
|
||||
write.add(v);
|
||||
}
|
||||
if (v.ready) {
|
||||
search = v;
|
||||
if (!write.contains(v)) {
|
||||
write.add(v);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (search == null) {
|
||||
throw new ProvisionException(runReindexMsg);
|
||||
}
|
||||
|
||||
IndexFactory<K, V, I> factory = def.getIndexFactory();
|
||||
I searchIndex = factory.create(search.schema);
|
||||
IndexCollection<K, V, I> indexes = def.getIndexCollection();
|
||||
indexes.setSearchIndex(searchIndex);
|
||||
for (Version<V> v : write) {
|
||||
if (v.schema != null) {
|
||||
if (v.version != search.version) {
|
||||
indexes.addWriteIndex(factory.create(v.schema));
|
||||
} else {
|
||||
indexes.addWriteIndex(searchIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
markNotReady(cfg, def.getName(), versions.values(), write);
|
||||
|
||||
int latest = write.get(0).version;
|
||||
OnlineReindexer<K, V, I> reindexer = new OnlineReindexer<>(def, latest);
|
||||
synchronized (this) {
|
||||
if (!reindexers.containsKey(def.getName())) {
|
||||
reindexers.put(def.getName(), reindexer);
|
||||
if (onlineUpgrade && latest != search.version) {
|
||||
reindexer.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the online reindexer if the current index is not already the latest.
|
||||
*
|
||||
* @param force start re-index
|
||||
* @return true if started, otherwise false.
|
||||
* @throws ReindexerAlreadyRunningException
|
||||
*/
|
||||
public synchronized boolean startReindexer(String name, boolean force)
|
||||
throws ReindexerAlreadyRunningException {
|
||||
OnlineReindexer<?, ?, ?> reindexer = reindexers.get(name);
|
||||
validateReindexerNotRunning(reindexer);
|
||||
if (force || !isCurrentIndexVersionLatest(name, reindexer)) {
|
||||
reindexer.start();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate the latest index if the current index is not already the latest.
|
||||
*
|
||||
* @return true if index was activate, otherwise false.
|
||||
* @throws ReindexerAlreadyRunningException
|
||||
*/
|
||||
public synchronized boolean activateLatestIndex(String name)
|
||||
throws ReindexerAlreadyRunningException {
|
||||
OnlineReindexer<?, ?, ?> reindexer = reindexers.get(name);
|
||||
validateReindexerNotRunning(reindexer);
|
||||
if (!isCurrentIndexVersionLatest(name, reindexer)) {
|
||||
reindexer.activateIndex();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isCurrentIndexVersionLatest(String name, OnlineReindexer<?, ?, ?> reindexer) {
|
||||
int readVersion = defs.get(name).getIndexCollection().getSearchIndex().getSchema().getVersion();
|
||||
return reindexer == null || reindexer.getVersion() == readVersion;
|
||||
}
|
||||
|
||||
private static void validateReindexerNotRunning(OnlineReindexer<?, ?, ?> reindexer)
|
||||
throws ReindexerAlreadyRunningException {
|
||||
if (reindexer != null && reindexer.isRunning()) {
|
||||
throw new ReindexerAlreadyRunningException();
|
||||
}
|
||||
}
|
||||
|
||||
private <K, V, I extends Index<K, V>> TreeMap<Integer, Version<V>> scanVersions(
|
||||
IndexDefinition<K, V, I> def, GerritIndexStatus cfg) {
|
||||
TreeMap<Integer, Version<V>> versions = new TreeMap<>();
|
||||
@Override
|
||||
protected <K, V, I extends Index<K, V>>
|
||||
TreeMap<Integer, AbstractVersionManager.Version<V>> scanVersions(
|
||||
IndexDefinition<K, V, I> def, GerritIndexStatus cfg) {
|
||||
TreeMap<Integer, AbstractVersionManager.Version<V>> versions = new TreeMap<>();
|
||||
for (Schema<V> schema : def.getSchemas().values()) {
|
||||
// This part is Lucene-specific.
|
||||
Path p = getDir(sitePaths, def.getName(), schema);
|
||||
@@ -252,36 +105,4 @@ public class LuceneVersionManager implements LifecycleListener {
|
||||
}
|
||||
return versions;
|
||||
}
|
||||
|
||||
private <V> void markNotReady(
|
||||
GerritIndexStatus cfg,
|
||||
String name,
|
||||
Iterable<Version<V>> versions,
|
||||
Collection<Version<V>> inUse) {
|
||||
boolean dirty = false;
|
||||
for (Version<V> v : versions) {
|
||||
if (!inUse.contains(v) && v.exists) {
|
||||
cfg.setReady(name, v.version, false);
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
if (dirty) {
|
||||
try {
|
||||
cfg.save();
|
||||
} catch (IOException e) {
|
||||
throw fail(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ProvisionException fail(Throwable t) {
|
||||
ProvisionException e = new ProvisionException("Error scanning indexes");
|
||||
e.initCause(t);
|
||||
throw e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
// Do nothing; indexes are closed on demand by IndexCollection.
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user