LCOV - code coverage report
Current view: top level - sshd/commands - ShowQueue.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 42 84 50.0 %
Date: 2022-11-19 15:00:39 Functions: 7 9 77.8 %

          Line data    Source code
       1             : // Copyright (C) 2009 The Android Open Source Project
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License");
       4             : // you may not use this file except in compliance with the License.
       5             : // You may obtain a copy of the License at
       6             : //
       7             : // http://www.apache.org/licenses/LICENSE-2.0
       8             : //
       9             : // Unless required by applicable law or agreed to in writing, software
      10             : // distributed under the License is distributed on an "AS IS" BASIS,
      11             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             : // See the License for the specific language governing permissions and
      13             : // limitations under the License.
      14             : 
      15             : package com.google.gerrit.sshd.commands;
      16             : 
      17             : import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER_OR_SLAVE;
      18             : 
      19             : import com.google.common.base.MoreObjects;
      20             : import com.google.common.collect.LinkedListMultimap;
      21             : import com.google.common.collect.ListMultimap;
      22             : import com.google.gerrit.extensions.restapi.AuthException;
      23             : import com.google.gerrit.server.IdentifiedUser;
      24             : import com.google.gerrit.server.config.ConfigResource;
      25             : import com.google.gerrit.server.git.WorkQueue;
      26             : import com.google.gerrit.server.git.WorkQueue.Task;
      27             : import com.google.gerrit.server.permissions.GlobalPermission;
      28             : import com.google.gerrit.server.permissions.PermissionBackend;
      29             : import com.google.gerrit.server.permissions.PermissionBackendException;
      30             : import com.google.gerrit.server.restapi.config.ListTasks;
      31             : import com.google.gerrit.server.restapi.config.ListTasks.TaskInfo;
      32             : import com.google.gerrit.server.util.time.TimeUtil;
      33             : import com.google.gerrit.sshd.AdminHighPriorityCommand;
      34             : import com.google.gerrit.sshd.CommandMetaData;
      35             : import com.google.gerrit.sshd.SshCommand;
      36             : import com.google.inject.Inject;
      37             : import java.io.IOException;
      38             : import java.time.Instant;
      39             : import java.time.ZoneId;
      40             : import java.time.format.DateTimeFormatter;
      41             : import java.util.List;
      42             : import java.util.concurrent.ScheduledThreadPoolExecutor;
      43             : import org.apache.sshd.server.Environment;
      44             : import org.apache.sshd.server.channel.ChannelSession;
      45             : import org.kohsuke.args4j.Option;
      46             : 
      47             : /** Display the current work queue. */
      48             : @AdminHighPriorityCommand
      49             : @CommandMetaData(
      50             :     name = "show-queue",
      51             :     description = "Display the background work queues",
      52             :     runsAt = MASTER_OR_SLAVE)
      53           1 : final class ShowQueue extends SshCommand {
      54             :   @Option(
      55             :       name = "--wide",
      56             :       aliases = {"-w"},
      57             :       usage = "display without line width truncation")
      58             :   private boolean wide;
      59             : 
      60             :   @Option(
      61             :       name = "--by-queue",
      62             :       aliases = {"-q"},
      63             :       usage = "group tasks by queue and print queue info")
      64             :   private boolean groupByQueue;
      65             : 
      66             :   @Inject private PermissionBackend permissionBackend;
      67             :   @Inject private ListTasks listTasks;
      68             :   @Inject private IdentifiedUser currentUser;
      69             :   @Inject private WorkQueue workQueue;
      70             : 
      71           1 :   private int columns = 80;
      72             :   private int maxCommandWidth;
      73             : 
      74             :   @Override
      75             :   public void start(ChannelSession channel, Environment env) throws IOException {
      76           1 :     String s = env.getEnv().get(Environment.ENV_COLUMNS);
      77           1 :     if (s != null && !s.isEmpty()) {
      78             :       try {
      79           0 :         columns = Integer.parseInt(s);
      80           0 :       } catch (NumberFormatException err) {
      81           0 :         columns = 80;
      82           0 :       }
      83             :     }
      84           1 :     super.start(channel, env);
      85           1 :   }
      86             : 
      87             :   @Override
      88             :   protected void run() throws Failure {
      89           1 :     enableGracefulStop();
      90           1 :     maxCommandWidth = wide ? Integer.MAX_VALUE : columns - 8 - 12 - 12 - 4 - 4;
      91           1 :     stdout.print(
      92           1 :         String.format(
      93             :             "%-8s %-12s %-12s %-4s %s\n", //
      94             :             "Task", "State", "StartTime", "", "Command"));
      95           1 :     stdout.print(
      96             :         "------------------------------------------------------------------------------\n");
      97             : 
      98             :     List<TaskInfo> tasks;
      99             :     try {
     100           1 :       tasks = listTasks.apply(new ConfigResource()).value();
     101           0 :     } catch (AuthException e) {
     102           0 :       throw die(e);
     103           0 :     } catch (PermissionBackendException e) {
     104           0 :       throw new Failure(1, "permission backend unavailable", e);
     105           0 :     } catch (Exception e) {
     106           0 :       throw new Failure(1, "unavailable", e);
     107           1 :     }
     108             : 
     109           1 :     boolean viewAll = permissionBackend.user(currentUser).testOrFalse(GlobalPermission.VIEW_QUEUE);
     110           1 :     long now = TimeUtil.nowMs();
     111           1 :     if (groupByQueue) {
     112           0 :       ListMultimap<String, TaskInfo> byQueue = byQueue(tasks);
     113           0 :       for (String queueName : byQueue.keySet()) {
     114           0 :         ScheduledThreadPoolExecutor e = workQueue.getExecutor(queueName);
     115           0 :         stdout.print(String.format("Queue: %s\n", queueName));
     116           0 :         print(byQueue.get(queueName), now, viewAll, e.getCorePoolSize());
     117           0 :       }
     118           0 :     } else {
     119           1 :       print(tasks, now, viewAll, 0);
     120             :     }
     121           1 :   }
     122             : 
     123             :   private ListMultimap<String, TaskInfo> byQueue(List<TaskInfo> tasks) {
     124           0 :     ListMultimap<String, TaskInfo> byQueue = LinkedListMultimap.create();
     125           0 :     for (TaskInfo task : tasks) {
     126           0 :       byQueue.put(task.queueName, task);
     127           0 :     }
     128           0 :     return byQueue;
     129             :   }
     130             : 
     131             :   private void print(List<TaskInfo> tasks, long now, boolean viewAll, int threadPoolSize) {
     132           1 :     for (TaskInfo task : tasks) {
     133             :       String start;
     134           1 :       switch (task.state) {
     135             :         case DONE:
     136             :         case CANCELLED:
     137             :         case STARTING:
     138             :         case RUNNING:
     139             :         case STOPPING:
     140             :         case READY:
     141           0 :           start = format(task.state);
     142           0 :           break;
     143             :         case OTHER:
     144             :         case SLEEPING:
     145             :         default:
     146           1 :           start = time(now, task.delay);
     147             :           break;
     148             :       }
     149             : 
     150             :       // Shows information about tasks depending on the user rights
     151           1 :       if (viewAll || task.projectName == null) {
     152             :         String command =
     153           1 :             task.command.length() < maxCommandWidth
     154           1 :                 ? task.command
     155           1 :                 : task.command.substring(0, maxCommandWidth);
     156             : 
     157           1 :         stdout.print(
     158           1 :             String.format(
     159             :                 "%8s %-12s %-12s %-4s %s\n",
     160           1 :                 task.id, start, startTime(task.startTime.toInstant()), "", command));
     161           1 :       } else {
     162             :         String remoteName =
     163           0 :             task.remoteName != null ? task.remoteName + "/" + task.projectName : task.projectName;
     164             : 
     165           0 :         stdout.print(
     166           0 :             String.format(
     167             :                 "%8s %-12s %-4s %s\n",
     168             :                 task.id,
     169             :                 start,
     170           0 :                 startTime(task.startTime.toInstant()),
     171           0 :                 MoreObjects.firstNonNull(remoteName, "n/a")));
     172             :       }
     173           1 :     }
     174           1 :     stdout.print(
     175             :         "------------------------------------------------------------------------------\n");
     176           1 :     stdout.print("  " + tasks.size() + " tasks");
     177           1 :     if (threadPoolSize > 0) {
     178           0 :       stdout.print(", " + threadPoolSize + " worker threads");
     179             :     }
     180           1 :     stdout.print("\n\n");
     181           1 :   }
     182             : 
     183             :   private static String time(long now, long delay) {
     184           1 :     Instant when = Instant.ofEpochMilli(now + delay);
     185           1 :     return format(when, delay);
     186             :   }
     187             : 
     188             :   private static String startTime(Instant when) {
     189           1 :     return format(when, TimeUtil.nowMs() - when.toEpochMilli());
     190             :   }
     191             : 
     192             :   private static String format(Instant when, long timeFromNow) {
     193           1 :     if (timeFromNow < 24 * 60 * 60 * 1000L) {
     194           1 :       return DateTimeFormatter.ofPattern("HH:mm:ss.SSS")
     195           1 :           .withZone(ZoneId.systemDefault())
     196           1 :           .format(when);
     197             :     }
     198           0 :     return DateTimeFormatter.ofPattern("MMM-dd HH:mm")
     199           0 :         .withZone(ZoneId.systemDefault())
     200           0 :         .format(when);
     201             :   }
     202             : 
     203             :   private static String format(Task.State state) {
     204           0 :     switch (state) {
     205             :       case DONE:
     206           0 :         return "....... done";
     207             :       case CANCELLED:
     208           0 :         return "..... killed";
     209             :       case STOPPING:
     210           0 :         return "... stopping";
     211             :       case RUNNING:
     212           0 :         return "";
     213             :       case STARTING:
     214           0 :         return "starting ...";
     215             :       case READY:
     216           0 :         return "waiting ....";
     217             :       case SLEEPING:
     218           0 :         return "sleeping";
     219             :       case OTHER:
     220             :       default:
     221           0 :         return state.toString();
     222             :     }
     223             :   }
     224             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750