Factor out common modules from Reindex As far as programs go, Reindex has about the most complicated injection stack. This will be useful for future programs, for example a Reindex analogue for notedb, so move them to the util package. Change-Id: I7f980c0918b6893e4d421f0ba8a12e96bb01d20d
diff --git a/gerrit-pgm/BUCK b/gerrit-pgm/BUCK index 3cb2c22..cffc0c1 100644 --- a/gerrit-pgm/BUCK +++ b/gerrit-pgm/BUCK
@@ -61,8 +61,11 @@ name = 'util', srcs = glob([SRCS + 'util/*.java']), deps = [ + '//gerrit-cache-h2:cache-h2', + '//gerrit-common:client', '//gerrit-common:server', '//gerrit-extension-api:api', + '//gerrit-reviewdb:server', '//gerrit-server:server', '//gerrit-util-cli:cli', '//lib:args4j',
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Reindex.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Reindex.java index dae11b4..6ade6a9 100644 --- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Reindex.java +++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Reindex.java
@@ -15,50 +15,26 @@ package com.google.gerrit.pgm; import static com.google.gerrit.server.schema.DataSourceProvider.Context.MULTI_USER; -import static com.google.inject.Scopes.SINGLETON; -import com.google.common.cache.Cache; import com.google.common.collect.Lists; import com.google.common.collect.Sets; -import com.google.gerrit.common.ChangeHooks; -import com.google.gerrit.common.DisabledChangeHooks; -import com.google.gerrit.extensions.events.GitReferenceUpdatedListener; -import com.google.gerrit.extensions.events.LifecycleListener; -import com.google.gerrit.extensions.registration.DynamicMap; -import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.lifecycle.LifecycleManager; -import com.google.gerrit.lifecycle.LifecycleModule; import com.google.gerrit.lucene.LuceneIndexModule; +import com.google.gerrit.pgm.util.BatchGitModule; +import com.google.gerrit.pgm.util.BatchProgramModule; import com.google.gerrit.pgm.util.SiteProgram; import com.google.gerrit.pgm.util.ThreadLimiter; import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.server.ReviewDb; -import com.google.gerrit.rules.PrologModule; -import com.google.gerrit.server.CurrentUser; -import com.google.gerrit.server.IdentifiedUser; -import com.google.gerrit.server.account.AccountByEmailCacheImpl; -import com.google.gerrit.server.account.AccountCacheImpl; -import com.google.gerrit.server.account.CapabilityControl; -import com.google.gerrit.server.account.GroupCacheImpl; -import com.google.gerrit.server.account.GroupIncludeCacheImpl; -import com.google.gerrit.server.cache.CacheRemovalListener; -import com.google.gerrit.server.cache.h2.DefaultCacheFactory; -import com.google.gerrit.server.change.ChangeKindCacheImpl; import com.google.gerrit.server.change.MergeabilityChecker; import com.google.gerrit.server.change.MergeabilityChecksExecutor; import com.google.gerrit.server.change.MergeabilityChecksExecutor.Priority; import com.google.gerrit.server.change.PatchSetInserter; -import com.google.gerrit.server.config.CanonicalWebUrl; -import com.google.gerrit.server.config.CanonicalWebUrlProvider; import com.google.gerrit.server.config.FactoryModule; import com.google.gerrit.server.config.GerritServerConfig; -import com.google.gerrit.server.git.GitModule; import com.google.gerrit.server.git.MergeUtil; import com.google.gerrit.server.git.WorkQueue; -import com.google.gerrit.server.git.validators.CommitValidationListener; -import com.google.gerrit.server.git.validators.CommitValidators; -import com.google.gerrit.server.group.GroupModule; import com.google.gerrit.server.index.ChangeBatchIndexer; import com.google.gerrit.server.index.ChangeIndex; import com.google.gerrit.server.index.ChangeSchemas; @@ -67,26 +43,13 @@ import com.google.gerrit.server.index.IndexModule.IndexType; import com.google.gerrit.server.mail.ReplacePatchSetSender; import com.google.gerrit.server.notedb.NoteDbModule; -import com.google.gerrit.server.patch.PatchListCacheImpl; -import com.google.gerrit.server.project.AccessControlModule; -import com.google.gerrit.server.project.CommentLinkInfo; -import com.google.gerrit.server.project.CommentLinkProvider; -import com.google.gerrit.server.project.ProjectCacheImpl; -import com.google.gerrit.server.project.ProjectState; -import com.google.gerrit.server.project.SectionSortCache; -import com.google.gerrit.server.query.change.ChangeData; import com.google.gerrit.solr.SolrIndexModule; -import com.google.gwtorm.server.OrmException; -import com.google.gwtorm.server.SchemaFactory; import com.google.inject.AbstractModule; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Module; -import com.google.inject.Provider; import com.google.inject.Provides; -import com.google.inject.ProvisionException; import com.google.inject.Singleton; -import com.google.inject.TypeLiteral; import com.google.inject.util.Providers; import org.eclipse.jgit.lib.Config; @@ -95,7 +58,6 @@ import org.eclipse.jgit.util.io.NullOutputStream; import org.kohsuke.args4j.Option; -import java.util.Collections; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -159,8 +121,7 @@ private Injector createSysInjector() { List<Module> modules = Lists.newArrayList(); - modules.add(PatchListCacheImpl.module()); - AbstractModule changeIndexModule; + Module changeIndexModule; switch (IndexModule.getIndexType(dbInjector)) { case LUCENE: changeIndexModule = new LuceneIndexModule(version, threads, outputBase); @@ -172,39 +133,10 @@ throw new IllegalStateException("unsupported index.type"); } modules.add(changeIndexModule); - modules.add(new ReviewDbModule()); - modules.add(new FactoryModule() { - @SuppressWarnings("rawtypes") + modules.add(dbInjector.getInstance(BatchProgramModule.class)); + modules.add(new AbstractModule() { @Override protected void configure() { - // Plugins are not loaded and we're just running through each change - // once, so don't worry about cache removal. - bind(new TypeLiteral<DynamicSet<CacheRemovalListener>>() {}) - .toInstance(DynamicSet.<CacheRemovalListener> emptySet()); - bind(new TypeLiteral<DynamicMap<Cache<?, ?>>>() {}) - .toInstance(DynamicMap.<Cache<?, ?>> emptyMap()); - bind(new TypeLiteral<List<CommentLinkInfo>>() {}) - .toProvider(CommentLinkProvider.class).in(SINGLETON); - bind(String.class).annotatedWith(CanonicalWebUrl.class) - .toProvider(CanonicalWebUrlProvider.class); - bind(IdentifiedUser.class) - .toProvider(Providers. <IdentifiedUser>of(null)); - bind(CurrentUser.class).to(IdentifiedUser.class); - install(new AccessControlModule()); - install(new DefaultCacheFactory.Module()); - install(new GroupModule()); - install(new PrologModule()); - install(AccountByEmailCacheImpl.module()); - install(AccountCacheImpl.module()); - install(GroupCacheImpl.module()); - install(GroupIncludeCacheImpl.module()); - install(ProjectCacheImpl.module()); - install(SectionSortCache.module()); - install(ChangeKindCacheImpl.module()); - factory(CapabilityControl.Factory.class); - factory(ChangeData.Factory.class); - factory(ProjectState.Factory.class); - if (recheckMergeable) { install(new MergeabilityModule()); } else { @@ -226,61 +158,16 @@ } } - private class ReviewDbModule extends LifecycleModule { - @Override - protected void configure() { - final SchemaFactory<ReviewDb> schema = dbInjector.getInstance( - Key.get(new TypeLiteral<SchemaFactory<ReviewDb>>() {})); - final List<ReviewDb> dbs = Collections.synchronizedList( - Lists.<ReviewDb> newArrayListWithCapacity(threads + 1)); - final ThreadLocal<ReviewDb> localDb = new ThreadLocal<>(); - - bind(ReviewDb.class).toProvider(new Provider<ReviewDb>() { - @Override - public ReviewDb get() { - ReviewDb db = localDb.get(); - if (db == null) { - try { - db = schema.open(); - dbs.add(db); - localDb.set(db); - } catch (OrmException e) { - throw new ProvisionException("unable to open ReviewDb", e); - } - } - return db; - } - }); - listener().toInstance(new LifecycleListener() { - @Override - public void start() { - // Do nothing. - } - - @Override - public void stop() { - for (ReviewDb db : dbs) { - db.close(); - } - } - }); - } - } - private static class MergeabilityModule extends FactoryModule { @Override public void configure() { factory(PatchSetInserter.Factory.class); - bind(ChangeHooks.class).to(DisabledChangeHooks.class); bind(ReplacePatchSetSender.Factory.class).toProvider( Providers.<ReplacePatchSetSender.Factory>of(null)); factory(MergeUtil.Factory.class); - DynamicSet.setOf(binder(), GitReferenceUpdatedListener.class); - DynamicSet.setOf(binder(), CommitValidationListener.class); - factory(CommitValidators.Factory.class); - install(new GitModule()); install(new NoteDbModule()); + install(new BatchGitModule()); } @Provides
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/BatchGitModule.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/BatchGitModule.java new file mode 100644 index 0000000..11ab073 --- /dev/null +++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/BatchGitModule.java
@@ -0,0 +1,36 @@ +// Copyright (C) 2014 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.pgm.util; + +import com.google.gerrit.common.ChangeHooks; +import com.google.gerrit.common.DisabledChangeHooks; +import com.google.gerrit.extensions.events.GitReferenceUpdatedListener; +import com.google.gerrit.extensions.registration.DynamicSet; +import com.google.gerrit.server.config.FactoryModule; +import com.google.gerrit.server.git.GitModule; +import com.google.gerrit.server.git.validators.CommitValidationListener; +import com.google.gerrit.server.git.validators.CommitValidators; + +/** Module for batch programs that need git access. */ +public class BatchGitModule extends FactoryModule { + @Override + protected void configure() { + bind(ChangeHooks.class).to(DisabledChangeHooks.class); + DynamicSet.setOf(binder(), GitReferenceUpdatedListener.class); + DynamicSet.setOf(binder(), CommitValidationListener.class); + factory(CommitValidators.Factory.class); + install(new GitModule()); + } +}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/BatchProgramModule.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/BatchProgramModule.java new file mode 100644 index 0000000..4a17e68 --- /dev/null +++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/BatchProgramModule.java
@@ -0,0 +1,99 @@ +// Copyright (C) 2014 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.pgm.util; + +import static com.google.inject.Scopes.SINGLETON; +import com.google.common.cache.Cache; +import com.google.gerrit.extensions.registration.DynamicMap; +import com.google.gerrit.extensions.registration.DynamicSet; +import com.google.gerrit.rules.PrologModule; +import com.google.gerrit.server.CurrentUser; +import com.google.gerrit.server.IdentifiedUser; +import com.google.gerrit.server.account.AccountByEmailCacheImpl; +import com.google.gerrit.server.account.AccountCacheImpl; +import com.google.gerrit.server.account.CapabilityControl; +import com.google.gerrit.server.account.GroupCacheImpl; +import com.google.gerrit.server.account.GroupIncludeCacheImpl; +import com.google.gerrit.server.cache.CacheRemovalListener; +import com.google.gerrit.server.cache.h2.DefaultCacheFactory; +import com.google.gerrit.server.change.ChangeKindCacheImpl; +import com.google.gerrit.server.config.CanonicalWebUrl; +import com.google.gerrit.server.config.CanonicalWebUrlProvider; +import com.google.gerrit.server.config.FactoryModule; +import com.google.gerrit.server.group.GroupModule; +import com.google.gerrit.server.patch.PatchListCacheImpl; +import com.google.gerrit.server.project.AccessControlModule; +import com.google.gerrit.server.project.CommentLinkInfo; +import com.google.gerrit.server.project.CommentLinkProvider; +import com.google.gerrit.server.project.ProjectCacheImpl; +import com.google.gerrit.server.project.ProjectState; +import com.google.gerrit.server.project.SectionSortCache; +import com.google.gerrit.server.query.change.ChangeData; +import com.google.inject.Inject; +import com.google.inject.Module; +import com.google.inject.TypeLiteral; +import com.google.inject.util.Providers; + +import java.util.List; + +/** + * Module for programs that perform batch operations on a site. + * <p> + * Any program that requires this module likely also requires using + * {@link ThreadLimiter} to limit the number of threads accessing the database + * concurrently. + */ +public class BatchProgramModule extends FactoryModule { + private final Module reviewDbModule; + + @Inject + BatchProgramModule(PerThreadReviewDbModule reviewDbModule) { + this.reviewDbModule = reviewDbModule; + } + + @SuppressWarnings("rawtypes") + @Override + protected void configure() { + install(reviewDbModule); + install(PatchListCacheImpl.module()); + // Plugins are not loaded and we're just running through each change + // once, so don't worry about cache removal. + bind(new TypeLiteral<DynamicSet<CacheRemovalListener>>() {}) + .toInstance(DynamicSet.<CacheRemovalListener> emptySet()); + bind(new TypeLiteral<DynamicMap<Cache<?, ?>>>() {}) + .toInstance(DynamicMap.<Cache<?, ?>> emptyMap()); + bind(new TypeLiteral<List<CommentLinkInfo>>() {}) + .toProvider(CommentLinkProvider.class).in(SINGLETON); + bind(String.class).annotatedWith(CanonicalWebUrl.class) + .toProvider(CanonicalWebUrlProvider.class); + bind(IdentifiedUser.class) + .toProvider(Providers.<IdentifiedUser> of(null)); + bind(CurrentUser.class).to(IdentifiedUser.class); + install(new AccessControlModule()); + install(new DefaultCacheFactory.Module()); + install(new GroupModule()); + install(new PrologModule()); + install(AccountByEmailCacheImpl.module()); + install(AccountCacheImpl.module()); + install(GroupCacheImpl.module()); + install(GroupIncludeCacheImpl.module()); + install(ProjectCacheImpl.module()); + install(SectionSortCache.module()); + install(ChangeKindCacheImpl.module()); + factory(CapabilityControl.Factory.class); + factory(ChangeData.Factory.class); + factory(ProjectState.Factory.class); + } +}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/PerThreadReviewDbModule.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/PerThreadReviewDbModule.java new file mode 100644 index 0000000..eb12937 --- /dev/null +++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/PerThreadReviewDbModule.java
@@ -0,0 +1,79 @@ +// Copyright (C) 2014 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.pgm.util; + +import com.google.common.collect.Lists; +import com.google.gerrit.extensions.events.LifecycleListener; +import com.google.gerrit.lifecycle.LifecycleModule; +import com.google.gerrit.reviewdb.server.ReviewDb; +import com.google.gwtorm.server.OrmException; +import com.google.gwtorm.server.SchemaFactory; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.ProvisionException; + +import java.util.Collections; +import java.util.List; + +/** + * Module to bind a single {@link ReviewDb} instance per thread. + * <p> + * New instances are opened on demand, but are closed only at shutdown. + */ +class PerThreadReviewDbModule extends LifecycleModule { + private final SchemaFactory<ReviewDb> schema; + + @Inject + PerThreadReviewDbModule(SchemaFactory<ReviewDb> schema) { + this.schema = schema; + } + + @Override + protected void configure() { + final List<ReviewDb> dbs = Collections.synchronizedList( + Lists.<ReviewDb> newArrayList()); + final ThreadLocal<ReviewDb> localDb = new ThreadLocal<>(); + + bind(ReviewDb.class).toProvider(new Provider<ReviewDb>() { + @Override + public ReviewDb get() { + ReviewDb db = localDb.get(); + if (db == null) { + try { + db = schema.open(); + dbs.add(db); + localDb.set(db); + } catch (OrmException e) { + throw new ProvisionException("unable to open ReviewDb", e); + } + } + return db; + } + }); + listener().toInstance(new LifecycleListener() { + @Override + public void start() { + // Do nothing. + } + + @Override + public void stop() { + for (ReviewDb db : dbs) { + db.close(); + } + } + }); + } +}