Stop creating the entire SchemaVersion chain at runtime

Running Gerrit servers build every Schema_NNN instance at server
startup due to the Guice binding for @Current SchemaVersion implicitly
linking to everything through the constructors and the Guice injector
running in mode PRODUCTION, where all dependencies are resolved
immediately at startup.

Instead get the binary version off the C constant, which does not
require loading all classes.  Use a new injector with mode DEVELOPMENT
to support lazy loading of older versions only as necessary.

Change-Id: I9c62f2603f61bdd58a800b1d03b10c28a0c78773
This commit is contained in:
Shawn Pearce
2015-01-05 13:11:52 -08:00
parent c0e668913e
commit c4377cd3d1
9 changed files with 59 additions and 73 deletions

View File

@@ -1,27 +0,0 @@
// Copyright (C) 2009 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.server.schema;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.google.inject.BindingAnnotation;
import java.lang.annotation.Retention;
/** Indicates the {@link SchemaVersion} is the current one. */
@Retention(RUNTIME)
@BindingAnnotation
public @interface Current {
}

View File

@@ -46,23 +46,19 @@ public class SchemaCreator {
private final PersonIdent serverUser; private final PersonIdent serverUser;
private final DataSourceType dataSourceType; private final DataSourceType dataSourceType;
private final int versionNbr;
private AccountGroup admin; private AccountGroup admin;
private AccountGroup batch; private AccountGroup batch;
@Inject @Inject
public SchemaCreator(SitePaths site, public SchemaCreator(SitePaths site,
@Current SchemaVersion version,
AllProjectsCreator ap, AllProjectsCreator ap,
AllUsersCreator auc, AllUsersCreator auc,
@GerritPersonIdent PersonIdent au, @GerritPersonIdent PersonIdent au,
DataSourceType dst) { DataSourceType dst) {
this(site.site_path, version, ap, auc, au, dst); this(site.site_path, ap, auc, au, dst);
} }
public SchemaCreator(@SitePath File site, public SchemaCreator(@SitePath File site,
@Current SchemaVersion version,
AllProjectsCreator ap, AllProjectsCreator ap,
AllUsersCreator auc, AllUsersCreator auc,
@GerritPersonIdent PersonIdent au, @GerritPersonIdent PersonIdent au,
@@ -72,7 +68,6 @@ public class SchemaCreator {
allUsersCreator = auc; allUsersCreator = auc;
serverUser = au; serverUser = au;
dataSourceType = dst; dataSourceType = dst;
versionNbr = version.getVersionNbr();
} }
public void create(final ReviewDb db) throws OrmException, IOException, public void create(final ReviewDb db) throws OrmException, IOException,
@@ -86,7 +81,7 @@ public class SchemaCreator {
} }
final CurrentSchemaVersion sVer = CurrentSchemaVersion.create(); final CurrentSchemaVersion sVer = CurrentSchemaVersion.create();
sVer.versionNbr = versionNbr; sVer.versionNbr = SchemaVersion.getBinaryVersion();
db.schemaVersion().insert(Collections.singleton(sVer)); db.schemaVersion().insert(Collections.singleton(sVer));
initSystemConfig(db); initSystemConfig(db);

View File

@@ -32,8 +32,6 @@ import org.eclipse.jgit.lib.PersonIdent;
public class SchemaModule extends FactoryModule { public class SchemaModule extends FactoryModule {
@Override @Override
protected void configure() { protected void configure() {
install(new SchemaVersion.Module());
bind(PersonIdent.class).annotatedWith(GerritPersonIdent.class) bind(PersonIdent.class).annotatedWith(GerritPersonIdent.class)
.toProvider(GerritPersonIdentProvider.class); .toProvider(GerritPersonIdentProvider.class);

View File

@@ -17,13 +17,23 @@ package com.google.gerrit.server.schema;
import com.google.gerrit.reviewdb.client.CurrentSchemaVersion; import com.google.gerrit.reviewdb.client.CurrentSchemaVersion;
import com.google.gerrit.reviewdb.client.SystemConfig; import com.google.gerrit.reviewdb.client.SystemConfig;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.gerrit.server.config.SitePaths; import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.SchemaFactory; import com.google.gwtorm.server.SchemaFactory;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.Stage;
import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.PersonIdent;
import java.io.IOException; import java.io.IOException;
import java.sql.SQLException; import java.sql.SQLException;
@@ -37,12 +47,46 @@ public class SchemaUpdater {
private final Provider<SchemaVersion> updater; private final Provider<SchemaVersion> updater;
@Inject @Inject
SchemaUpdater(final SchemaFactory<ReviewDb> schema, final SitePaths site, SchemaUpdater(SchemaFactory<ReviewDb> schema,
final SchemaCreator creator, @Current final Provider<SchemaVersion> update) { SitePaths site,
SchemaCreator creator,
Injector parent) {
this.schema = schema; this.schema = schema;
this.site = site; this.site = site;
this.creator = creator; this.creator = creator;
this.updater = update; this.updater = buildInjector(parent).getProvider(SchemaVersion.class);
}
private static Injector buildInjector(final Injector parent) {
// Use DEVELOPMENT mode to allow lazy initialization of the
// graph. This avoids touching ancient schema versions that
// are behind this installation's current version.
return Guice.createInjector(Stage.DEVELOPMENT, new AbstractModule() {
@Override
protected void configure() {
bind(SchemaVersion.class).to(SchemaVersion.C);
for (Key<?> k : new Key<?>[]{
Key.get(PersonIdent.class, GerritPersonIdent.class),
Key.get(String.class, AnonymousCowardName.class),
}) {
rebind(parent, k);
}
for (Class<?> c : new Class<?>[] {
AllProjectsName.class,
AllUsersCreator.class,
GitRepositoryManager.class,
SitePaths.class,
}) {
rebind(parent, Key.get(c));
}
}
private <T> void rebind(Injector parent, Key<T> c) {
bind(c).toProvider(parent.getProvider(c));
}
});
} }
public void update(final UpdateUI ui) throws OrmException { public void update(final UpdateUI ui) throws OrmException {

View File

@@ -21,7 +21,6 @@ import com.google.gwtorm.jdbc.JdbcExecutor;
import com.google.gwtorm.jdbc.JdbcSchema; import com.google.gwtorm.jdbc.JdbcSchema;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.StatementExecutor; import com.google.gwtorm.server.StatementExecutor;
import com.google.inject.AbstractModule;
import com.google.inject.Provider; import com.google.inject.Provider;
import java.sql.SQLException; import java.sql.SQLException;
@@ -34,11 +33,8 @@ public abstract class SchemaVersion {
/** The current schema version. */ /** The current schema version. */
public static final Class<Schema_103> C = Schema_103.class; public static final Class<Schema_103> C = Schema_103.class;
public static class Module extends AbstractModule { public static int getBinaryVersion() {
@Override return guessVersion(C);
protected void configure() {
bind(SchemaVersion.class).annotatedWith(Current.class).to(C);
}
} }
private final Provider<? extends SchemaVersion> prior; private final Provider<? extends SchemaVersion> prior;
@@ -49,7 +45,7 @@ public abstract class SchemaVersion {
this.versionNbr = guessVersion(getClass()); this.versionNbr = guessVersion(getClass());
} }
public static int guessVersion(Class<?> c) { private static int guessVersion(Class<?> c) {
String n = c.getName(); String n = c.getName();
n = n.substring(n.lastIndexOf('_') + 1); n = n.substring(n.lastIndexOf('_') + 1);
while (n.startsWith("0")) while (n.startsWith("0"))
@@ -57,12 +53,6 @@ public abstract class SchemaVersion {
return Integer.parseInt(n); return Integer.parseInt(n);
} }
protected SchemaVersion(final Provider<? extends SchemaVersion> prior,
final int versionNbr) {
this.prior = prior;
this.versionNbr = versionNbr;
}
/** @return the {@link CurrentSchemaVersion#versionNbr} this step targets. */ /** @return the {@link CurrentSchemaVersion#versionNbr} this step targets. */
public final int getVersionNbr() { public final int getVersionNbr() {
return versionNbr; return versionNbr;

View File

@@ -23,7 +23,6 @@ import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.SchemaFactory; import com.google.gwtorm.server.SchemaFactory;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Module; import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.ProvisionException; import com.google.inject.ProvisionException;
/** Validates the current schema version. */ /** Validates the current schema version. */
@@ -40,16 +39,11 @@ public class SchemaVersionCheck implements LifecycleListener {
private final SchemaFactory<ReviewDb> schema; private final SchemaFactory<ReviewDb> schema;
private final SitePaths site; private final SitePaths site;
@Current
private final Provider<SchemaVersion> version;
@Inject @Inject
public SchemaVersionCheck(SchemaFactory<ReviewDb> schemaFactory, public SchemaVersionCheck(SchemaFactory<ReviewDb> schemaFactory,
final SitePaths site, SitePaths site) {
@Current Provider<SchemaVersion> version) {
this.schema = schemaFactory; this.schema = schemaFactory;
this.site = site; this.site = site;
this.version = version;
} }
@Override @Override
@@ -58,7 +52,7 @@ public class SchemaVersionCheck implements LifecycleListener {
final ReviewDb db = schema.open(); final ReviewDb db = schema.open();
try { try {
final CurrentSchemaVersion currentVer = getSchemaVersion(db); final CurrentSchemaVersion currentVer = getSchemaVersion(db);
final int expectedVer = version.get().getVersionNbr(); final int expectedVer = SchemaVersion.getBinaryVersion();
if (currentVer == null) { if (currentVer == null) {
throw new ProvisionException("Schema not yet initialized." throw new ProvisionException("Schema not yet initialized."

View File

@@ -74,7 +74,6 @@ public class SchemaUpdaterTest {
protected void configure() { protected void configure() {
bind(new TypeLiteral<SchemaFactory<ReviewDb>>() {}).toInstance(db); bind(new TypeLiteral<SchemaFactory<ReviewDb>>() {}).toInstance(db);
bind(SitePaths.class).toInstance(paths); bind(SitePaths.class).toInstance(paths);
install(new SchemaVersion.Module());
Config cfg = new Config(); Config cfg = new Config();
cfg.setString("user", null, "name", "Gerrit Code Review"); cfg.setString("user", null, "name", "Gerrit Code Review");

View File

@@ -67,7 +67,6 @@ public class InMemoryDatabase implements SchemaFactory<ReviewDb> {
} }
} }
private final SchemaVersion schemaVersion;
private final SchemaCreator schemaCreator; private final SchemaCreator schemaCreator;
private Connection openHandle; private Connection openHandle;
@@ -75,9 +74,7 @@ public class InMemoryDatabase implements SchemaFactory<ReviewDb> {
private boolean created; private boolean created;
@Inject @Inject
InMemoryDatabase(SchemaVersion schemaVersion, InMemoryDatabase(SchemaCreator schemaCreator) throws OrmException {
SchemaCreator schemaCreator) throws OrmException {
this.schemaVersion = schemaVersion;
this.schemaCreator = schemaCreator; this.schemaCreator = schemaCreator;
try { try {
@@ -161,6 +158,6 @@ public class InMemoryDatabase implements SchemaFactory<ReviewDb> {
public void assertSchemaVersion() throws OrmException { public void assertSchemaVersion() throws OrmException {
final CurrentSchemaVersion act = getSchemaVersion(); final CurrentSchemaVersion act = getSchemaVersion();
assertEquals(schemaVersion.getVersionNbr(), act.versionNbr); assertEquals(SchemaVersion.getBinaryVersion(), act.versionNbr);
} }
} }

View File

@@ -48,10 +48,8 @@ import com.google.gerrit.server.index.ChangeSchemas;
import com.google.gerrit.server.index.IndexModule.IndexType; import com.google.gerrit.server.index.IndexModule.IndexType;
import com.google.gerrit.server.mail.SignedTokenEmailTokenVerifier; import com.google.gerrit.server.mail.SignedTokenEmailTokenVerifier;
import com.google.gerrit.server.mail.SmtpEmailSender; import com.google.gerrit.server.mail.SmtpEmailSender;
import com.google.gerrit.server.schema.Current;
import com.google.gerrit.server.schema.DataSourceType; import com.google.gerrit.server.schema.DataSourceType;
import com.google.gerrit.server.schema.SchemaCreator; import com.google.gerrit.server.schema.SchemaCreator;
import com.google.gerrit.server.schema.SchemaVersion;
import com.google.gerrit.server.securestore.DefaultSecureStore; import com.google.gerrit.server.securestore.DefaultSecureStore;
import com.google.gerrit.server.securestore.SecureStore; import com.google.gerrit.server.securestore.SecureStore;
import com.google.gerrit.server.ssh.NoSshKeyCache; import com.google.gerrit.server.ssh.NoSshKeyCache;
@@ -127,8 +125,6 @@ public class InMemoryModule extends FactoryModule {
bindScope(RequestScoped.class, PerThreadRequestScope.REQUEST); bindScope(RequestScoped.class, PerThreadRequestScope.REQUEST);
install(new SchemaVersion.Module());
bind(File.class).annotatedWith(SitePath.class).toInstance(new File(".")); bind(File.class).annotatedWith(SitePath.class).toInstance(new File("."));
bind(Config.class).annotatedWith(GerritServerConfig.class).toInstance(cfg); bind(Config.class).annotatedWith(GerritServerConfig.class).toInstance(cfg);
bind(SocketAddress.class).annotatedWith(RemotePeer.class).toInstance( bind(SocketAddress.class).annotatedWith(RemotePeer.class).toInstance(
@@ -197,9 +193,9 @@ public class InMemoryModule extends FactoryModule {
@Provides @Provides
@Singleton @Singleton
InMemoryDatabase getInMemoryDatabase(@Current SchemaVersion schemaVersion, InMemoryDatabase getInMemoryDatabase(SchemaCreator schemaCreator)
SchemaCreator schemaCreator) throws OrmException { throws OrmException {
return new InMemoryDatabase(schemaVersion, schemaCreator); return new InMemoryDatabase(schemaCreator);
} }
private Module luceneIndexModule() { private Module luceneIndexModule() {