Atomic replace SSH and HTTP bindings during plugin reload

When a plugin is reloaded with a new version, start the new one
before stopping the old copy of the same plugin. This allows the
SSH and HTTP bindings to atomically swap in the new plugin before
dropping the old one, so users never see the command or URL with
a not found error.

Allow Gerrit-ReloadMode: restart to prevent this atomic replace,
which may be necessary for plugins that acquire an exclusive lock
on a resource in a LifecycleListener's start method, and release
it during stop. When the ReloadMode is restart Gerrit will first
stop the old copy of the plugin before starting the new one. This
means there is a race condition when the command disappears and
is later registered.

Change-Id: Iec165991dfcc89f669e50a9fb21525282307f074
This commit is contained in:
Shawn O. Pearce
2012-05-09 12:58:06 -07:00
parent 2aefecf604
commit a576cc8479
9 changed files with 179 additions and 66 deletions

View File

@@ -30,6 +30,7 @@ import com.google.gerrit.server.config.FactoryModule;
import com.google.gerrit.server.config.GerritRequestModule;
import com.google.gerrit.server.git.QueueProvider;
import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.plugins.ReloadPluginListener;
import com.google.gerrit.server.plugins.StartPluginListener;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.server.ssh.SshInfo;
@@ -91,9 +92,15 @@ public class SshModule extends FactoryModule {
install(new LifecycleModule() {
@Override
protected void configure() {
bind(SshPluginStarterCallback.class);
bind(StartPluginListener.class)
.annotatedWith(UniqueAnnotations.create())
.to(SshPluginStarterCallback.class);
bind(ReloadPluginListener.class)
.annotatedWith(UniqueAnnotations.create())
.to(SshPluginStarterCallback.class);
listener().to(SshLog.class);
listener().to(SshDaemon.class);
}