diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeMergeQueue.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeMergeQueue.java index a7a969f5ed..cbe65941e2 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeMergeQueue.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeMergeQueue.java @@ -22,16 +22,13 @@ import com.google.gerrit.reviewdb.Project; import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.RemotePeer; -import com.google.gerrit.server.RequestCleanup; import com.google.gerrit.server.config.GerritRequestModule; import com.google.gerrit.server.ssh.SshInfo; import com.google.inject.AbstractModule; import com.google.inject.Inject; import com.google.inject.Injector; -import com.google.inject.Key; import com.google.inject.OutOfScopeException; import com.google.inject.Provider; -import com.google.inject.Scope; import com.google.inject.servlet.RequestScoped; import com.jcraft.jsch.HostKey; @@ -65,7 +62,7 @@ public class ChangeMergeQueue implements MergeQueue { Injector child = parent.createChildInjector(new AbstractModule() { @Override protected void configure() { - bindScope(RequestScoped.class, MyScope.REQUEST); + bindScope(RequestScoped.class, PerThreadRequestScope.REQUEST); install(new GerritRequestModule()); bind(CurrentUser.class).to(IdentifiedUser.class); @@ -186,8 +183,8 @@ public class ChangeMergeQueue implements MergeQueue { private void mergeImpl(Branch.NameKey branch) { try { - MyScope ctx = new MyScope(); - MyScope old = MyScope.set(ctx); + PerThreadRequestScope ctx = new PerThreadRequestScope(); + PerThreadRequestScope old = PerThreadRequestScope.set(ctx); try { try { bgFactory.get().create(branch).merge(); @@ -195,7 +192,7 @@ public class ChangeMergeQueue implements MergeQueue { ctx.cleanup.run(); } } finally { - MyScope.set(old); + PerThreadRequestScope.set(old); } } catch (Throwable e) { log.error("Merge attempt for " + branch + " failed", e); @@ -261,65 +258,4 @@ public class ChangeMergeQueue implements MergeQueue { return "recheck " + project.get() + " " + dest.getShortName(); } } - - private static class MyScope { - private static final ThreadLocal current = - new ThreadLocal(); - - private static MyScope getContext() { - final MyScope ctx = current.get(); - if (ctx == null) { - throw new OutOfScopeException("Not in command/request"); - } - return ctx; - } - - static MyScope set(MyScope ctx) { - MyScope old = current.get(); - current.set(ctx); - return old; - } - - static final Scope REQUEST = new Scope() { - public Provider scope(final Key key, final Provider creator) { - return new Provider() { - public T get() { - return getContext().get(key, creator); - } - - @Override - public String toString() { - return String.format("%s[%s]", creator, REQUEST); - } - }; - } - - @Override - public String toString() { - return "MergeQueue.REQUEST"; - } - }; - - private static final Key RC_KEY = - Key.get(RequestCleanup.class); - - private final RequestCleanup cleanup; - private final Map, Object> map; - - MyScope() { - cleanup = new RequestCleanup(); - map = new HashMap, Object>(); - map.put(RC_KEY, cleanup); - } - - synchronized T get(Key key, Provider creator) { - @SuppressWarnings("unchecked") - T t = (T) map.get(key); - if (t == null) { - t = creator.get(); - map.put(key, t); - } - return t; - } - } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/PerThreadRequestScope.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/PerThreadRequestScope.java new file mode 100644 index 0000000000..592f44f56e --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/PerThreadRequestScope.java @@ -0,0 +1,85 @@ +// 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.git; + +import com.google.gerrit.server.RequestCleanup; +import com.google.inject.Key; +import com.google.inject.OutOfScopeException; +import com.google.inject.Provider; +import com.google.inject.Scope; + +import java.util.HashMap; +import java.util.Map; + +class PerThreadRequestScope { + private static final ThreadLocal current = + new ThreadLocal(); + + private static PerThreadRequestScope getContext() { + final PerThreadRequestScope ctx = current.get(); + if (ctx == null) { + throw new OutOfScopeException("Not in command/request"); + } + return ctx; + } + + static PerThreadRequestScope set(PerThreadRequestScope ctx) { + PerThreadRequestScope old = current.get(); + current.set(ctx); + return old; + } + + static final Scope REQUEST = new Scope() { + public Provider scope(final Key key, final Provider creator) { + return new Provider() { + public T get() { + return getContext().get(key, creator); + } + + @Override + public String toString() { + return String.format("%s[%s]", creator, REQUEST); + } + }; + } + + @Override + public String toString() { + return "PerThreadRequestScope.REQUEST"; + } + }; + + private static final Key RC_KEY = + Key.get(RequestCleanup.class); + + final RequestCleanup cleanup; + private final Map, Object> map; + + PerThreadRequestScope() { + cleanup = new RequestCleanup(); + map = new HashMap, Object>(); + map.put(RC_KEY, cleanup); + } + + synchronized T get(Key key, Provider creator) { + @SuppressWarnings("unchecked") + T t = (T) map.get(key); + if (t == null) { + t = creator.get(); + map.put(key, t); + } + return t; + } +} \ No newline at end of file diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushOp.java index b28b83968a..902ce3eea0 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushOp.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushOp.java @@ -155,6 +155,16 @@ class PushOp implements ProjectRunnable { } public void run() { + PerThreadRequestScope ctx = new PerThreadRequestScope(); + PerThreadRequestScope old = PerThreadRequestScope.set(ctx); + try { + runPushOperation(); + } finally { + PerThreadRequestScope.set(old); + } + } + + private void runPushOperation() { // Lock the queue, and remove ourselves, so we can't be modified once // we start replication (instead a new instance, with the same URI, is // created and scheduled for a future point in time.) diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java index cb005aa6da..1b41fcfcb2 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java @@ -22,6 +22,7 @@ import com.google.gerrit.server.ReplicationUser; import com.google.gerrit.server.config.ConfigUtil; import com.google.gerrit.server.config.SitePaths; import com.google.gerrit.server.project.NoSuchProjectException; +import com.google.gerrit.server.project.PerRequestProjectControlCache; import com.google.gerrit.server.project.ProjectControl; import com.google.gwtorm.client.SchemaFactory; import com.google.inject.AbstractModule; @@ -29,6 +30,7 @@ import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Singleton; import com.google.inject.assistedinject.FactoryProvider; +import com.google.inject.servlet.RequestScoped; import com.jcraft.jsch.Session; @@ -373,6 +375,8 @@ public class PushReplication implements ReplicationQueue { injector.createChildInjector(new AbstractModule() { @Override protected void configure() { + bindScope(RequestScoped.class, PerThreadRequestScope.REQUEST); + bind(PerRequestProjectControlCache.class).in(RequestScoped.class); bind(CurrentUser.class).toInstance(remoteUser); } }).getInstance(ProjectControl.Factory.class); @@ -396,15 +400,22 @@ public class PushReplication implements ReplicationQueue { void schedule(final Project.NameKey project, final String ref, final URIish uri) { + PerThreadRequestScope ctx = new PerThreadRequestScope(); + PerThreadRequestScope old = PerThreadRequestScope.set(ctx); try { - if (!controlFor(project).isVisible()) { + try { + if (!controlFor(project).isVisible()) { + return; + } + } catch (NoSuchProjectException e1) { + log.error("Internal error: project " + project + + " not found during replication"); return; } - } catch (NoSuchProjectException e1) { - log.error("Internal error: project " + project - + " not found during replication"); - return; + } finally { + PerThreadRequestScope.set(old); } + synchronized (pending) { PushOp e = pending.get(uri); if (e == null) { @@ -443,16 +454,6 @@ public class PushReplication implements ReplicationQueue { * @param pushOp The PushOp instance to be scheduled. */ void reschedule(final PushOp pushOp) { - try { - if (!controlFor(pushOp.getProjectNameKey()).isVisible()) { - return; - } - } catch (NoSuchProjectException e1) { - log.error("Internal error: project " + pushOp.getProjectNameKey() - + " not found during replication"); - return; - } - // It locks access to pending variable. synchronized (pending) { URIish uri = pushOp.getURI();