Merge "SSH show-queue: option to group output by queue and print queue info"

This commit is contained in:
Edwin Kempin 2016-07-14 07:15:15 +00:00 committed by Gerrit Code Review
commit ece1d7db72
4 changed files with 105 additions and 44 deletions

View File

@ -39,6 +39,10 @@ Intended for interactive use only.
Do not format the output to the terminal width (default of Do not format the output to the terminal width (default of
80 columns). 80 columns).
--by-queue::
-q::
Group tasks by queue and print queue info.
== DISPLAY == DISPLAY
Task:: Task::

View File

@ -113,6 +113,7 @@ public class ListTasks implements RestReadView<ConfigResource> {
public String command; public String command;
public String remoteName; public String remoteName;
public String projectName; public String projectName;
public String queueName;
public TaskInfo(Task<?> task) { public TaskInfo(Task<?> task) {
this.id = IdGenerator.format(task.getTaskId()); this.id = IdGenerator.format(task.getTaskId());
@ -120,6 +121,7 @@ public class ListTasks implements RestReadView<ConfigResource> {
this.startTime = new Timestamp(task.getStartTime().getTime()); this.startTime = new Timestamp(task.getStartTime().getTime());
this.delay = task.getDelay(TimeUnit.MILLISECONDS); this.delay = task.getDelay(TimeUnit.MILLISECONDS);
this.command = task.toString(); this.command = task.toString();
this.queueName = task.getQueueName();
if (task instanceof ProjectTask) { if (task instanceof ProjectTask) {
ProjectTask<?> projectTask = ((ProjectTask<?>) task); ProjectTask<?> projectTask = ((ProjectTask<?>) task);

View File

@ -152,6 +152,15 @@ public class WorkQueue {
return result; return result;
} }
public Executor getExecutor(String queueName) {
for (Executor e : queues) {
if (e.queueName.equals(queueName)) {
return e;
}
}
return null;
}
private void stop() { private void stop() {
for (final Executor p : queues) { for (final Executor p : queues) {
p.shutdown(); p.shutdown();
@ -170,8 +179,9 @@ public class WorkQueue {
/** An isolated queue. */ /** An isolated queue. */
public class Executor extends ScheduledThreadPoolExecutor { public class Executor extends ScheduledThreadPoolExecutor {
private final ConcurrentHashMap<Integer, Task<?>> all; private final ConcurrentHashMap<Integer, Task<?>> all;
private final String queueName;
Executor(final int corePoolSize, final String prefix) { Executor(int corePoolSize, final String prefix) {
super(corePoolSize, new ThreadFactory() { super(corePoolSize, new ThreadFactory() {
private final ThreadFactory parent = Executors.defaultThreadFactory(); private final ThreadFactory parent = Executors.defaultThreadFactory();
private final AtomicInteger tid = new AtomicInteger(1); private final AtomicInteger tid = new AtomicInteger(1);
@ -190,6 +200,7 @@ public class WorkQueue {
0.75f, // load factor 0.75f, // load factor
corePoolSize + 4 // concurrency level corePoolSize + 4 // concurrency level
); );
queueName = prefix;
} }
public void unregisterWorkQueue() { public void unregisterWorkQueue() {
@ -325,6 +336,10 @@ public class WorkQueue {
return startTime; return startTime;
} }
public String getQueueName() {
return executor.queueName;
}
@Override @Override
public boolean cancel(boolean mayInterruptIfRunning) { public boolean cancel(boolean mayInterruptIfRunning) {
if (task.cancel(mayInterruptIfRunning)) { if (task.cancel(mayInterruptIfRunning)) {

View File

@ -17,12 +17,15 @@ package com.google.gerrit.sshd.commands;
import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER_OR_SLAVE; import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER_OR_SLAVE;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.gerrit.common.TimeUtil; import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.config.ConfigResource; import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.config.ListTasks; import com.google.gerrit.server.config.ListTasks;
import com.google.gerrit.server.config.ListTasks.TaskInfo; import com.google.gerrit.server.config.ListTasks.TaskInfo;
import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.git.WorkQueue.Task; import com.google.gerrit.server.git.WorkQueue.Task;
import com.google.gerrit.sshd.AdminHighPriorityCommand; import com.google.gerrit.sshd.AdminHighPriorityCommand;
import com.google.gerrit.sshd.CommandMetaData; import com.google.gerrit.sshd.CommandMetaData;
@ -39,18 +42,27 @@ import java.util.List;
/** Display the current work queue. */ /** Display the current work queue. */
@AdminHighPriorityCommand @AdminHighPriorityCommand
@CommandMetaData(name = "show-queue", description = "Display the background work queues", @CommandMetaData(name = "show-queue",
runsAt = MASTER_OR_SLAVE) description = "Display the background work queues",
runsAt = MASTER_OR_SLAVE)
final class ShowQueue extends SshCommand { final class ShowQueue extends SshCommand {
@Option(name = "--wide", aliases = {"-w"}, usage = "display without line width truncation") @Option(name = "--wide", aliases = {"-w"},
usage = "display without line width truncation")
private boolean wide; private boolean wide;
@Option(name = "--by-queue", aliases = {"-q"},
usage = "group tasks by queue and print queue info")
private boolean groupByQueue;
@Inject @Inject
private ListTasks listTasks; private ListTasks listTasks;
@Inject @Inject
private IdentifiedUser currentUser; private IdentifiedUser currentUser;
@Inject
private WorkQueue workQueue;
private int columns = 80; private int columns = 80;
private int maxCommandWidth; private int maxCommandWidth;
@ -75,50 +87,78 @@ final class ShowQueue extends SshCommand {
stdout.print("----------------------------------------------" stdout.print("----------------------------------------------"
+ "--------------------------------\n"); + "--------------------------------\n");
List<TaskInfo> tasks;
try { try {
List<TaskInfo> tasks = listTasks.apply(new ConfigResource()); tasks = listTasks.apply(new ConfigResource());
long now = TimeUtil.nowMs();
boolean viewAll = currentUser.getCapabilities().canViewQueue();
for (TaskInfo task : tasks) {
String start;
switch (task.state) {
case DONE:
case CANCELLED:
case RUNNING:
case READY:
start = format(task.state);
break;
case OTHER:
case SLEEPING:
default:
start = time(now, task.delay);
break;
}
// Shows information about tasks depending on the user rights
if (viewAll || task.projectName == null) {
String command = task.command.length() < maxCommandWidth
? task.command
: task.command.substring(0, maxCommandWidth);
stdout.print(String.format("%8s %-12s %-12s %-4s %s\n",
task.id, start, startTime(task.startTime), "", command));
} else {
String remoteName = task.remoteName != null
? task.remoteName + "/" + task.projectName
: task.projectName;
stdout.print(String.format("%8s %-12s %-4s %s\n",
task.id, start, startTime(task.startTime),
MoreObjects.firstNonNull(remoteName, "n/a")));
}
}
stdout.print("----------------------------------------------"
+ "--------------------------------\n");
stdout.print(" " + tasks.size() + " tasks\n");
} catch (AuthException e) { } catch (AuthException e) {
throw die(e); throw die(e);
} }
boolean viewAll = currentUser.getCapabilities().canViewQueue();
long now = TimeUtil.nowMs();
if (groupByQueue) {
ListMultimap<String, TaskInfo> byQueue = byQueue(tasks);
for (String queueName : byQueue.keySet()) {
WorkQueue.Executor e = workQueue.getExecutor(queueName);
stdout.print(String.format("Queue: %s\n", queueName));
print(byQueue.get(queueName), now, viewAll, e.getCorePoolSize());
}
} else {
print(tasks, now, viewAll, 0);
}
}
private ListMultimap<String, TaskInfo> byQueue(List<TaskInfo> tasks) {
ListMultimap<String, TaskInfo> byQueue = LinkedListMultimap.create();
for (TaskInfo task : tasks) {
byQueue.put(task.queueName, task);
}
return byQueue;
}
private void print(List<TaskInfo> tasks, long now, boolean viewAll,
int threadPoolSize) {
for (TaskInfo task : tasks) {
String start;
switch (task.state) {
case DONE:
case CANCELLED:
case RUNNING:
case READY:
start = format(task.state);
break;
case OTHER:
case SLEEPING:
default:
start = time(now, task.delay);
break;
}
// Shows information about tasks depending on the user rights
if (viewAll || task.projectName == null) {
String command = task.command.length() < maxCommandWidth
? task.command
: task.command.substring(0, maxCommandWidth);
stdout.print(String.format("%8s %-12s %-12s %-4s %s\n",
task.id, start, startTime(task.startTime), "", command));
} else {
String remoteName = task.remoteName != null
? task.remoteName + "/" + task.projectName
: task.projectName;
stdout.print(String.format("%8s %-12s %-4s %s\n",
task.id, start, startTime(task.startTime),
MoreObjects.firstNonNull(remoteName, "n/a")));
}
}
stdout.print("----------------------------------------------"
+ "--------------------------------\n");
stdout.print(" " + tasks.size() + " tasks");
if (threadPoolSize > 0) {
stdout.print(", " + threadPoolSize + " worker threads");
}
stdout.print("\n\n");
} }
private static String time(long now, long delay) { private static String time(long now, long delay) {