1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 package org.apache.hadoop.mapreduce.counters;
20 
21 import java.util.List;
22 import java.util.Map;
23 
24 import com.google.common.collect.Lists;
25 import com.google.common.collect.Maps;
26 
27 import org.apache.hadoop.classification.InterfaceAudience;
28 import org.apache.hadoop.mapreduce.Counter;
29 import org.apache.hadoop.mapreduce.FileSystemCounter;
30 import org.apache.hadoop.mapreduce.JobCounter;
31 import org.apache.hadoop.mapreduce.TaskCounter;
32 import org.apache.hadoop.mapreduce.util.ResourceBundles;
33 
34 /**
35  * An abstract class to provide common implementation of the
36  * group factory in both mapred and mapreduce packages.
37  *
38  * @param <C> type of the counter
39  * @param <G> type of the group
40  */
41 @InterfaceAudience.Private
42 public abstract class CounterGroupFactory<C extends Counter,
43                                           G extends CounterGroupBase<C>> {
44 
45   public interface FrameworkGroupFactory<F> {
newGroup(String name)46     F newGroup(String name);
47   }
48 
49   // Integer mapping (for serialization) for framework groups
50   private static final Map<String, Integer> s2i = Maps.newHashMap();
51   private static final List<String> i2s = Lists.newArrayList();
52   private static final int VERSION = 1;
53   private static final String FS_GROUP_NAME = FileSystemCounter.class.getName();
54 
55   private final Map<String, FrameworkGroupFactory<G>> fmap = Maps.newHashMap();
56   {
57     // Add builtin counter class here and the version when changed.
58     addFrameworkGroup(TaskCounter.class);
59     addFrameworkGroup(JobCounter.class);
60   }
61 
62   // Initialize the framework counter group mapping
63   private synchronized <T extends Enum<T>>
addFrameworkGroup(final Class<T> cls)64   void addFrameworkGroup(final Class<T> cls) {
65     updateFrameworkGroupMapping(cls);
66     fmap.put(cls.getName(), newFrameworkGroupFactory(cls));
67   }
68 
69   // Update static mappings (c2i, i2s) of framework groups
updateFrameworkGroupMapping(Class<?> cls)70   private static synchronized void updateFrameworkGroupMapping(Class<?> cls) {
71     String name = cls.getName();
72     Integer i = s2i.get(name);
73     if (i != null) return;
74     i2s.add(name);
75     s2i.put(name, i2s.size() - 1);
76   }
77 
78   /**
79    * Required override to return a new framework group factory
80    * @param <T> type of the counter enum class
81    * @param cls the counter enum class
82    * @return a new framework group factory
83    */
84   protected abstract <T extends Enum<T>>
newFrameworkGroupFactory(Class<T> cls)85   FrameworkGroupFactory<G> newFrameworkGroupFactory(Class<T> cls);
86 
87   /**
88    * Create a new counter group
89    * @param name of the group
90    * @param limits the counters limits policy object
91    * @return a new counter group
92    */
newGroup(String name, Limits limits)93   public G newGroup(String name, Limits limits) {
94     return newGroup(name, ResourceBundles.getCounterGroupName(name, name),
95                     limits);
96   }
97 
98   /**
99    * Create a new counter group
100    * @param name of the group
101    * @param displayName of the group
102    * @param limits the counters limits policy object
103    * @return a new counter group
104    */
newGroup(String name, String displayName, Limits limits)105   public G newGroup(String name, String displayName, Limits limits) {
106     FrameworkGroupFactory<G> gf = fmap.get(name);
107     if (gf != null) return gf.newGroup(name);
108     if (name.equals(FS_GROUP_NAME)) {
109       return newFileSystemGroup();
110     } else if (s2i.get(name) != null) {
111       return newFrameworkGroup(s2i.get(name));
112     }
113     return newGenericGroup(name, displayName, limits);
114   }
115 
116   /**
117    * Create a new framework group
118    * @param id of the group
119    * @return a new framework group
120    */
newFrameworkGroup(int id)121   public G newFrameworkGroup(int id) {
122     String name;
123     synchronized(CounterGroupFactory.class) {
124       if (id < 0 || id >= i2s.size()) throwBadFrameGroupIdException(id);
125       name = i2s.get(id); // should not throw here.
126     }
127     FrameworkGroupFactory<G> gf = fmap.get(name);
128     if (gf == null) throwBadFrameGroupIdException(id);
129     return gf.newGroup(name);
130   }
131 
132   /**
133    * Get the id of a framework group
134    * @param name of the group
135    * @return the framework group id
136    */
getFrameworkGroupId(String name)137   public static synchronized int getFrameworkGroupId(String name) {
138     Integer i = s2i.get(name);
139     if (i == null) throwBadFrameworkGroupNameException(name);
140     return i;
141   }
142 
143   /**
144    * @return the counter factory version
145    */
version()146   public int version() {
147     return VERSION;
148   }
149 
150   /**
151    * Check whether a group name is a name of a framework group (including
152    * the filesystem group).
153    *
154    * @param name  to check
155    * @return true for framework group names
156    */
isFrameworkGroup(String name)157   public static synchronized boolean isFrameworkGroup(String name) {
158     return s2i.get(name) != null || name.equals(FS_GROUP_NAME);
159   }
160 
throwBadFrameGroupIdException(int id)161   private static void throwBadFrameGroupIdException(int id) {
162     throw new IllegalArgumentException("bad framework group id: "+ id);
163   }
164 
throwBadFrameworkGroupNameException(String name)165   private static void throwBadFrameworkGroupNameException(String name) {
166     throw new IllegalArgumentException("bad framework group name: "+ name);
167   }
168 
169   /**
170    * Abstract factory method to create a generic (vs framework) counter group
171    * @param name  of the group
172    * @param displayName of the group
173    * @param limits limits of the counters
174    * @return a new generic counter group
175    */
newGenericGroup(String name, String displayName, Limits limits)176   protected abstract G newGenericGroup(String name, String displayName,
177                                        Limits limits);
178 
179   /**
180    * Abstract factory method to create a file system counter group
181    * @return a new file system counter group
182    */
newFileSystemGroup()183   protected abstract G newFileSystemGroup();
184 }
185