001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.monitoring; 019 020import java.util.Collection; 021import java.util.Collections; 022import java.util.concurrent.ConcurrentLinkedDeque; 023import org.apache.yetus.audience.InterfaceAudience; 024import org.slf4j.Logger; 025import org.slf4j.LoggerFactory; 026 027/** 028 * The {@link TaskGroup} can be seen as a big {@link MonitoredTask}, which contains a list of sub 029 * monitored tasks. The monitored tasks in the group are still be managed by the 030 * {@link TaskMonitor}, but whether to clear/expire the monitored tasks in a task group is optional. 031 * Since the monitored task already has journals, which mark the phases in a task, we still also 032 * need a task group to monitor a big task/process because the journals in a task is serial but the 033 * tasks in the task group can be parallel, then we have more flexible ability to monitor the 034 * process. Grouping the tasks is not strictly necessary but it is cleaner for presentation to 035 * operators. We might want to display the tasks in a group in a list view where each task can be 036 * collapsed (probably by default) or expanded. 037 */ 038@InterfaceAudience.Private 039public class TaskGroup extends MonitoredTaskImpl { 040 private static final Logger LOG = LoggerFactory.getLogger(TaskGroup.class); 041 042 /** Sub-tasks in the group */ 043 private final ConcurrentLinkedDeque<MonitoredTask> tasks = new ConcurrentLinkedDeque<>(); 044 045 /** Whether to ignore to track(e.g. show/clear/expire) in the singleton {@link TaskMonitor} */ 046 private boolean ignoreSubTasksInTaskMonitor; 047 048 /** Used to track this task group in {@link TaskMonitor} */ 049 private final MonitoredTask delegate; 050 051 public TaskGroup(boolean ignoreSubTasksInTaskMonitor, String description) { 052 super(false, description); 053 this.ignoreSubTasksInTaskMonitor = ignoreSubTasksInTaskMonitor; 054 this.delegate = TaskMonitor.get().createStatus(description, false, true); 055 } 056 057 public synchronized MonitoredTask addTask(String description) { 058 return addTask(description, true); 059 } 060 061 /** 062 * Add a new task to the group, and before that might complete the last task in the group 063 * @param description the description of the new task 064 * @param withCompleteLast whether to complete the last task in the group 065 * @return the added new task 066 */ 067 public synchronized MonitoredTask addTask(String description, boolean withCompleteLast) { 068 if (withCompleteLast) { 069 MonitoredTask previousTask = this.tasks.peekLast(); 070 if ( 071 previousTask != null && previousTask.getState() != State.COMPLETE 072 && previousTask.getState() != State.ABORTED 073 ) { 074 previousTask.markComplete("Completed"); 075 } 076 } 077 MonitoredTask task = 078 TaskMonitor.get().createStatus(description, ignoreSubTasksInTaskMonitor, true); 079 this.setStatus(description); 080 this.tasks.addLast(task); 081 delegate.setStatus(description); 082 return task; 083 } 084 085 public synchronized Collection<MonitoredTask> getTasks() { 086 return Collections.unmodifiableCollection(this.tasks); 087 } 088 089 @Override 090 public synchronized void abort(String msg) { 091 setStatus(msg); 092 setState(State.ABORTED); 093 for (MonitoredTask task : tasks) { 094 if (task.getState() != State.COMPLETE && task.getState() != State.ABORTED) { 095 task.abort(msg); 096 } 097 } 098 delegate.abort(msg); 099 } 100 101 @Override 102 public synchronized void markComplete(String msg) { 103 setState(State.COMPLETE); 104 setStatus(msg); 105 if (tasks.getLast() != null) { 106 tasks.getLast().markComplete(msg); 107 } 108 delegate.markComplete(msg); 109 } 110 111 @Override 112 public synchronized void cleanup() { 113 this.tasks.clear(); 114 } 115}