transfer.timeout: Support configurable timeouts for dead clients

Broken (or simply evil) clients can open a command and hang forever,
without exchanging packets with us.  These connections consume a work
thread from the thread pool, and tie up server memory that could be
used to assist another client.  By configuring transfer.timeout in
gerrit.config a site administrator can now limit how long their
server will wait for a single IO operation to complete before
disconnecting a client with a timeout error.

The timeout is currently disabled by default because it requires
spinning up (and tearing down) a thread for each command executed.
The thread exists only to count-down the timeout period and interrupt
the blocked IO operation on the real work thread.  Hopefully we can
modify JGit to either support non-blocking, asynchronous IO here,
or to permit using timer thread pools, to reduce the thread overhead
involved with setting up a timeout for a network socket.

Change-Id: Ic1608d4905082bb0639c2a0b35fd3bd9a6fccd43
Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
Shawn O. Pearce
2010-05-12 17:26:08 -07:00
parent 533cafc64c
commit 6e4dfddfec
5 changed files with 81 additions and 3 deletions

View File

@@ -18,12 +18,14 @@ import com.google.gerrit.reviewdb.Account;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.git.ReceiveCommits;
import com.google.gerrit.sshd.AbstractGitCommand;
import com.google.gerrit.sshd.TransferConfig;
import com.google.inject.Inject;
import org.eclipse.jgit.transport.ReceivePack;
import org.kohsuke.args4j.Option;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.HashSet;
import java.util.Set;
@@ -38,6 +40,9 @@ final class Receive extends AbstractGitCommand {
@Inject
private IdentifiedUser.GenericFactory identifiedUserFactory;
@Inject
private TransferConfig config;
private final Set<Account.Id> reviewerId = new HashSet<Account.Id>();
private final Set<Account.Id> ccId = new HashSet<Account.Id>();
@@ -68,7 +73,12 @@ final class Receive extends AbstractGitCommand {
final ReceivePack rp = receive.getReceivePack();
rp.setRefLogIdent(currentUser.newRefLogIdent());
rp.receive(in, out, err);
rp.setTimeout(config.getTimeout());
try {
rp.receive(in, out, err);
} catch (InterruptedIOException err) {
throw new Failure(128, "fatal: client IO read/write timeout", err);
}
}
private void verifyProjectVisible(final String type, final Set<Account.Id> who)