From de980a4dddcb760515ef285504bde2126e5e1e63 Mon Sep 17 00:00:00 2001 From: Sasa Zivkov Date: Thu, 14 Jun 2012 14:57:53 +0200 Subject: [PATCH] Automatic schema upgrade on Gerrit startup In case when Gerrit administrator(s) don't have a direct access to the file system where the review site is located it gets difficult to perform a schema upgrade (run the init program). For such cases it is convenient if Gerrit performs schema upgrade automatically on its startup. Since this is a potentially dangerous operation, by default it will not be performed. Configuration parameter site.upgradeSchemaOnStartup is used to switch on automatic schema upgrade. It has 3 possible values: * OFF - no automatic schema upgrade (default) * AUTO - automatic schema upgrade and drop of unused DB objects * AUTO_NO_PRUNE - like AUTO but without dropping unused DB objects Change-Id: Ief1bf1135fde74146e5a5fdd25f510a4eeae0a73 Signed-off-by: Edwin Kempin Signed-off-by: Sasa Zivkov --- Documentation/config-gerrit.txt | 22 +++++ .../java/com/google/gerrit/pgm/Daemon.java | 80 +++++++++++++++++++ .../gerrit/pgm/SchemaUpgradePolicy.java | 28 +++++++ 3 files changed, 130 insertions(+) create mode 100644 gerrit-pgm/src/main/java/com/google/gerrit/pgm/SchemaUpgradePolicy.java diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt index 5bda0a159e..37463c1673 100644 --- a/Documentation/config-gerrit.txt +++ b/Documentation/config-gerrit.txt @@ -1938,6 +1938,28 @@ If true the deprecated `/query` URL is available to return JSON and text results for changes. If false, the URL is disabled and returns 404 to clients. Default is true, enabling `/query`. +[[site.upgradeSchemaOnStartup]]site.upgradeSchemaOnStartup:: ++ +Control whether schema upgrade should be done on Gerrit startup. The following +values are supported: ++ +* `OFF` ++ +No automatic schema upgrade on startup. ++ +* `AUTO` ++ +Perform schema migration on startup, if necessary. If, as a result of +schema migration, there would be any unused database objects they will +be dropped automatically. ++ +* `AUTO_NO_PRUNE` ++ +Like `AUTO` but unused database objects will not be pruned. + ++ +The default is `OFF`. + [[ssh-alias]] Section ssh-alias ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java index ff5ee17183..282bbc9fe9 100644 --- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java +++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java @@ -35,12 +35,14 @@ import com.google.gerrit.pgm.util.LogFileCompressor; import com.google.gerrit.pgm.util.RuntimeShutdown; import com.google.gerrit.pgm.util.SiteProgram; import com.google.gerrit.reviewdb.client.AuthType; +import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.cache.h2.DefaultCacheFactory; import com.google.gerrit.server.config.AuthConfig; import com.google.gerrit.server.config.AuthConfigModule; import com.google.gerrit.server.config.CanonicalWebUrlModule; import com.google.gerrit.server.config.CanonicalWebUrlProvider; import com.google.gerrit.server.config.GerritGlobalModule; +import com.google.gerrit.server.config.GerritServerConfig; import com.google.gerrit.server.config.MasterNodeStartup; import com.google.gerrit.server.contact.HttpContactStoreConnection; import com.google.gerrit.server.git.ReceiveCommitsExecutorModule; @@ -49,15 +51,24 @@ import com.google.gerrit.server.mail.SignedTokenEmailTokenVerifier; import com.google.gerrit.server.mail.SmtpEmailSender; import com.google.gerrit.server.plugins.PluginGuiceEnvironment; import com.google.gerrit.server.plugins.PluginModule; +import com.google.gerrit.server.schema.SchemaUpdater; import com.google.gerrit.server.schema.SchemaVersionCheck; +import com.google.gerrit.server.schema.UpdateUI; import com.google.gerrit.server.ssh.NoSshModule; import com.google.gerrit.sshd.SshModule; import com.google.gerrit.sshd.commands.MasterCommandModule; import com.google.gerrit.sshd.commands.SlaveCommandModule; +import com.google.gwtorm.jdbc.JdbcExecutor; +import com.google.gwtorm.jdbc.JdbcSchema; +import com.google.gwtorm.server.OrmException; +import com.google.gwtorm.server.SchemaFactory; +import com.google.gwtorm.server.StatementExecutor; +import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Module; import com.google.inject.Provider; +import org.eclipse.jgit.lib.Config; import org.kohsuke.args4j.Option; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -145,6 +156,7 @@ public class Daemon extends SiteProgram { sysInjector = createSysInjector(); sysInjector.getInstance(PluginGuiceEnvironment.class) .setCfgInjector(cfgInjector); + sysInjector.getInstance(SchemaUpgrade.class).upgradeSchema(); manager.add(dbInjector, cfgInjector, sysInjector); if (sshd) { @@ -192,6 +204,74 @@ public class Daemon extends SiteProgram { } } + static class SchemaUpgrade { + + private final Config config; + private final SchemaUpdater updater; + private final SchemaFactory schema; + + @Inject + SchemaUpgrade(@GerritServerConfig Config config, SchemaUpdater updater, + SchemaFactory schema) { + this.config = config; + this.updater = updater; + this.schema = schema; + } + + void upgradeSchema() throws OrmException { + SchemaUpgradePolicy policy = + config.getEnum("site", null, "upgradeSchemaOnStartup", + SchemaUpgradePolicy.OFF); + if (policy == SchemaUpgradePolicy.AUTO + || policy == SchemaUpgradePolicy.AUTO_NO_PRUNE) { + final List pruneList = new ArrayList(); + updater.update(new UpdateUI() { + @Override + public void message(String msg) { + log.info(msg); + } + + @Override + public boolean yesno(boolean def, String msg) { + return true; + } + + @Override + public boolean isBatch() { + return true; + } + + @Override + public void pruneSchema(StatementExecutor e, List prune) { + for (String p : prune) { + if (!pruneList.contains(p)) { + pruneList.add(p); + } + } + } + }); + + if (!pruneList.isEmpty() && policy == SchemaUpgradePolicy.AUTO) { + log.info("Pruning: " + pruneList.toString()); + final JdbcSchema db = (JdbcSchema) schema.open(); + try { + final JdbcExecutor e = new JdbcExecutor(db); + try { + for (String sql : pruneList) { + e.execute(sql); + } + } finally { + e.close(); + } + } finally { + db.close(); + } + } + } + } + } + + private String myVersion() { return com.google.gerrit.common.Version.getVersion(); } diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/SchemaUpgradePolicy.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/SchemaUpgradePolicy.java new file mode 100644 index 0000000000..67f5c91f8c --- /dev/null +++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/SchemaUpgradePolicy.java @@ -0,0 +1,28 @@ +// Copyright (C) 2012 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; + +/** Policy for auto upgrading schema on server startup */ +public enum SchemaUpgradePolicy { + + /** Perform schema migration if necessary and prune unused objects */ + AUTO, + + /** Like AUTO but don't prune unused objects */ + AUTO_NO_PRUNE, + + /** No automatic schema upgrade */ + OFF +}