Skip to content

Commit 65a6f62

Browse files
committed
Merged #89 "SSH daemon is exhausting threads"
2 parents 9f66a89 + 5bb55fb commit 65a6f62

File tree

7 files changed

+42
-17
lines changed

7 files changed

+42
-17
lines changed

src/main/java/com/gitblit/manager/ServicesManager.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import com.gitblit.utils.IdGenerator;
4848
import com.gitblit.utils.StringUtils;
4949
import com.gitblit.utils.TimeUtils;
50+
import com.gitblit.utils.WorkQueue;
5051

5152
/**
5253
* Services manager manages long-running services/processes that either have no
@@ -66,6 +67,10 @@ public class ServicesManager implements IManager {
6667

6768
private final IGitblit gitblit;
6869

70+
private final IdGenerator idGenerator;
71+
72+
private final WorkQueue workQueue;
73+
6974
private FanoutService fanoutService;
7075

7176
private GitDaemon gitDaemon;
@@ -75,6 +80,8 @@ public class ServicesManager implements IManager {
7580
public ServicesManager(IGitblit gitblit) {
7681
this.settings = gitblit.getSettings();
7782
this.gitblit = gitblit;
83+
this.idGenerator = new IdGenerator();
84+
this.workQueue = new WorkQueue(idGenerator, 1);
7885
}
7986

8087
@Override
@@ -99,6 +106,7 @@ public ServicesManager stop() {
99106
if (sshDaemon != null) {
100107
sshDaemon.stop();
101108
}
109+
workQueue.stop();
102110
return this;
103111
}
104112

@@ -158,7 +166,7 @@ protected void configureSshDaemon() {
158166
String bindInterface = settings.getString(Keys.git.sshBindInterface, "localhost");
159167
if (port > 0) {
160168
try {
161-
sshDaemon = new SshDaemon(gitblit, new IdGenerator());
169+
sshDaemon = new SshDaemon(gitblit, workQueue);
162170
sshDaemon.start();
163171
} catch (IOException e) {
164172
sshDaemon = null;

src/main/java/com/gitblit/transport/ssh/SshDaemon.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@
4141
import com.gitblit.Keys;
4242
import com.gitblit.manager.IGitblit;
4343
import com.gitblit.transport.ssh.commands.SshCommandFactory;
44-
import com.gitblit.utils.IdGenerator;
4544
import com.gitblit.utils.JnaUtils;
4645
import com.gitblit.utils.StringUtils;
46+
import com.gitblit.utils.WorkQueue;
4747
import com.google.common.io.Files;
4848

4949
/**
@@ -76,8 +76,9 @@ public static enum SshSessionBackend {
7676
* Construct the Gitblit SSH daemon.
7777
*
7878
* @param gitblit
79+
* @param workQueue
7980
*/
80-
public SshDaemon(IGitblit gitblit, IdGenerator idGenerator) {
81+
public SshDaemon(IGitblit gitblit, WorkQueue workQueue) {
8182
this.gitblit = gitblit;
8283

8384
IStoredSettings settings = gitblit.getSettings();
@@ -126,7 +127,7 @@ public SshDaemon(IGitblit gitblit, IdGenerator idGenerator) {
126127
sshd.setSessionFactory(new SshServerSessionFactory());
127128
sshd.setFileSystemFactory(new DisabledFilesystemFactory());
128129
sshd.setTcpipForwardingFilter(new NonForwardingFilter());
129-
sshd.setCommandFactory(new SshCommandFactory(gitblit, idGenerator));
130+
sshd.setCommandFactory(new SshCommandFactory(gitblit, workQueue));
130131
sshd.setShellFactory(new WelcomeShell(settings));
131132

132133
// Set the server id. This can be queried with:

src/main/java/com/gitblit/transport/ssh/commands/BaseCommand.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,13 @@
3333
import org.apache.sshd.server.ExitCallback;
3434
import org.apache.sshd.server.SessionAware;
3535
import org.apache.sshd.server.session.ServerSession;
36+
import org.kohsuke.args4j.Argument;
3637
import org.kohsuke.args4j.CmdLineException;
38+
import org.kohsuke.args4j.Option;
3739
import org.slf4j.Logger;
3840
import org.slf4j.LoggerFactory;
3941

4042
import com.gitblit.Keys;
41-
import com.gitblit.utils.IdGenerator;
4243
import com.gitblit.utils.StringUtils;
4344
import com.gitblit.utils.WorkQueue;
4445
import com.gitblit.utils.WorkQueue.CancelableRunnable;
@@ -80,13 +81,10 @@ public abstract class BaseCommand implements Command, SessionAware {
8081
/** The task, as scheduled on a worker thread. */
8182
private final AtomicReference<Future<?>> task;
8283

83-
private final WorkQueue.Executor executor;
84+
private WorkQueue workQueue;
8485

8586
public BaseCommand() {
8687
task = Atomics.newReference();
87-
IdGenerator gen = new IdGenerator();
88-
WorkQueue w = new WorkQueue(gen);
89-
this.executor = w.getDefaultQueue();
9088
}
9189

9290
@Override
@@ -97,6 +95,10 @@ public void setSession(final ServerSession session) {
9795
@Override
9896
public void destroy() {
9997
log.debug("destroying " + getClass().getName());
98+
Future<?> future = task.getAndSet(null);
99+
if (future != null && !future.isDone()) {
100+
future.cancel(true);
101+
}
100102
session = null;
101103
ctx = null;
102104
}
@@ -110,12 +112,21 @@ protected static PrintWriter toPrintWriter(final OutputStream o) {
110112

111113
protected void provideStateTo(final BaseCommand cmd) {
112114
cmd.setContext(ctx);
115+
cmd.setWorkQueue(workQueue);
113116
cmd.setInputStream(in);
114117
cmd.setOutputStream(out);
115118
cmd.setErrorStream(err);
116119
cmd.setExitCallback(exit);
117120
}
118121

122+
public WorkQueue getWorkQueue() {
123+
return workQueue;
124+
}
125+
126+
public void setWorkQueue(WorkQueue workQueue) {
127+
this.workQueue = workQueue;
128+
}
129+
119130
public void setContext(SshCommandContext ctx) {
120131
this.ctx = ctx;
121132
}
@@ -467,7 +478,7 @@ private int handleError(final Throwable e) {
467478
*/
468479
protected void startThread(final CommandRunnable thunk) {
469480
final TaskThunk tt = new TaskThunk(thunk);
470-
task.set(executor.submit(tt));
481+
task.set(workQueue.getDefaultQueue().submit(tt));
471482
}
472483

473484
/** Thrown from {@link CommandRunnable#run()} with client message and code. */

src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ private void registerDispatcher(DispatchCommand dispatcher) {
154154

155155
try {
156156
dispatcher.setContext(getContext());
157+
dispatcher.setWorkQueue(getWorkQueue());
157158
dispatcher.setup();
158159
if (dispatcher.commands.isEmpty() && dispatcher.dispatchers.isEmpty()) {
159160
log.debug(MessageFormat.format("excluding empty dispatcher {0} for {1}",

src/main/java/com/gitblit/transport/ssh/commands/RootDispatcher.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.gitblit.transport.ssh.SshDaemonClient;
2727
import com.gitblit.transport.ssh.git.GitDispatcher;
2828
import com.gitblit.transport.ssh.keys.KeysDispatcher;
29+
import com.gitblit.utils.WorkQueue;
2930

3031
/**
3132
* The root dispatcher is the dispatch command that handles registering all
@@ -37,9 +38,10 @@ class RootDispatcher extends DispatchCommand {
3738

3839
private Logger log = LoggerFactory.getLogger(getClass());
3940

40-
public RootDispatcher(IGitblit gitblit, SshDaemonClient client, String cmdLine) {
41+
public RootDispatcher(IGitblit gitblit, SshDaemonClient client, String cmdLine, WorkQueue workQueue) {
4142
super();
4243
setContext(new SshCommandContext(gitblit, client, cmdLine));
44+
setWorkQueue(workQueue);
4345

4446
register(VersionCommand.class);
4547
register(GitDispatcher.class);

src/main/java/com/gitblit/transport/ssh/commands/SshCommandFactory.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,23 +40,23 @@
4040
import com.gitblit.Keys;
4141
import com.gitblit.manager.IGitblit;
4242
import com.gitblit.transport.ssh.SshDaemonClient;
43-
import com.gitblit.utils.IdGenerator;
4443
import com.gitblit.utils.WorkQueue;
4544
import com.google.common.util.concurrent.Atomics;
4645
import com.google.common.util.concurrent.ThreadFactoryBuilder;
4746

4847
public class SshCommandFactory implements CommandFactory {
4948
private static final Logger logger = LoggerFactory.getLogger(SshCommandFactory.class);
5049

50+
private final WorkQueue workQueue;
5151
private final IGitblit gitblit;
5252
private final ScheduledExecutorService startExecutor;
5353
private final ExecutorService destroyExecutor;
5454

55-
public SshCommandFactory(IGitblit gitblit, IdGenerator idGenerator) {
55+
public SshCommandFactory(IGitblit gitblit, WorkQueue workQueue) {
5656
this.gitblit = gitblit;
57+
this.workQueue = workQueue;
5758

5859
int threads = gitblit.getSettings().getInteger(Keys.git.sshCommandStartThreads, 2);
59-
WorkQueue workQueue = new WorkQueue(idGenerator);
6060
startExecutor = workQueue.createQueue(threads, "SshCommandStart");
6161
destroyExecutor = Executors.newSingleThreadExecutor(
6262
new ThreadFactoryBuilder()
@@ -70,7 +70,7 @@ public void stop() {
7070
}
7171

7272
public RootDispatcher createRootDispatcher(SshDaemonClient client, String commandLine) {
73-
return new RootDispatcher(gitblit, client, commandLine);
73+
return new RootDispatcher(gitblit, client, commandLine, workQueue);
7474
}
7575

7676
@Override

src/main/java/com/gitblit/utils/WorkQueue.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,19 @@ public void uncaughtException(Thread t, Throwable e) {
5151

5252
private Executor defaultQueue;
5353
private final IdGenerator idGenerator;
54+
private final int defaultQueueSize;
5455
private final CopyOnWriteArrayList<Executor> queues;
5556

56-
public WorkQueue(final IdGenerator idGenerator) {
57+
public WorkQueue(final IdGenerator idGenerator, final int defaultQueueSize) {
5758
this.idGenerator = idGenerator;
59+
this.defaultQueueSize = defaultQueueSize;
5860
this.queues = new CopyOnWriteArrayList<Executor>();
5961
}
6062

6163
/** Get the default work queue, for miscellaneous tasks. */
6264
public synchronized Executor getDefaultQueue() {
6365
if (defaultQueue == null) {
64-
defaultQueue = createQueue(1, "WorkQueue");
66+
defaultQueue = createQueue(defaultQueueSize, "WorkQueue");
6567
}
6668
return defaultQueue;
6769
}

0 commit comments

Comments
 (0)