View Javadoc

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.hbase.util;
20  
21  import java.io.BufferedReader;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.InputStreamReader;
25  import java.lang.management.ManagementFactory;
26  import java.lang.management.OperatingSystemMXBean;
27  import java.lang.management.RuntimeMXBean;
28  import java.lang.reflect.Method;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.hadoop.hbase.classification.InterfaceAudience;
33  
34  
35  /**
36   * This class is a wrapper for the implementation of
37   * com.sun.management.UnixOperatingSystemMXBean
38   * It will decide to use the sun api or its own implementation
39   * depending on the runtime (vendor) used.
40   */
41  
42  @InterfaceAudience.Private
43  public class JVM {
44    private static final Log LOG = LogFactory.getLog(JVM.class);
45    private OperatingSystemMXBean osMbean;
46  
47    private static final boolean ibmvendor =
48        System.getProperty("java.vendor") != null &&
49            System.getProperty("java.vendor").contains("IBM");
50    private static final boolean windows =
51        System.getProperty("os.name") != null &&
52            System.getProperty("os.name").startsWith("Windows");
53    private static final boolean linux =
54        System.getProperty("os.name") != null &&
55            System.getProperty("os.name").startsWith("Linux");
56    private static final boolean amd64 =
57        System.getProperty("os.arch") != null &&
58            System.getProperty("os.arch").contains("amd64");
59  
60    private static final String JVMVersion = System.getProperty("java.version");
61  
62    /**
63     * Constructor. Get the running Operating System instance
64     */
65    public JVM() {
66      this.osMbean = ManagementFactory.getOperatingSystemMXBean();
67    }
68  
69    /**
70     * Check if the OS is unix.
71     *
72     * @return whether this is unix or not.
73     */
74    public static boolean isUnix() {
75      if (windows) {
76        return false;
77      }
78      return (ibmvendor ? linux : true);
79    }
80  
81    /**
82     * Check if the OS is linux.
83     *
84     * @return whether this is linux or not.
85     */
86    public static boolean isLinux() {
87      return linux;
88    }
89  
90    /**
91     * Check if the arch is amd64;
92     *
93     * @return whether this is amd64 or not.
94     */
95    public static boolean isAmd64() {
96      return amd64;
97    }
98  
99    /**
100    * Check if the finish() method of GZIPOutputStream is broken
101    *
102    * @return whether GZIPOutputStream.finish() is broken.
103    */
104   public static boolean isGZIPOutputStreamFinishBroken() {
105     return ibmvendor && JVMVersion.contains("1.6.0");
106   }
107 
108   /**
109    * Load the implementation of UnixOperatingSystemMXBean for Oracle jvm
110    * and runs the desired method.
111    *
112    * @param mBeanMethodName : method to run from the interface UnixOperatingSystemMXBean
113    *
114    * @return the method result
115    */
116   private Long runUnixMXBeanMethod(String mBeanMethodName) {
117     Object unixos;
118     Class<?> classRef;
119     Method mBeanMethod;
120 
121     try {
122       classRef = Class.forName("com.sun.management.UnixOperatingSystemMXBean");
123       if (classRef.isInstance(osMbean)) {
124         mBeanMethod = classRef.getMethod(mBeanMethodName);
125         unixos = classRef.cast(osMbean);
126         return (Long) mBeanMethod.invoke(unixos);
127       }
128     } catch (Exception e) {
129       LOG.warn("Not able to load class or method for" +
130           " com.sun.management.UnixOperatingSystemMXBean.", e);
131     }
132     return null;
133   }
134 
135   /**
136    * Get the number of opened filed descriptor for the runtime jvm.
137    * If Oracle java, it will use the com.sun.management interfaces.
138    * Otherwise, this methods implements it (linux only).
139    *
140    * @return number of open file descriptors for the jvm
141    */
142   public long getOpenFileDescriptorCount() {
143     Long ofdc;
144 
145     if (!ibmvendor) {
146       ofdc = runUnixMXBeanMethod("getOpenFileDescriptorCount");
147       return (ofdc != null ? ofdc : -1);
148     }
149     InputStream inputStream = null;
150     InputStreamReader inputStreamReader = null;
151     BufferedReader bufferedReader = null;
152     try {
153       //need to get the PID number of the process first
154       RuntimeMXBean rtmbean = ManagementFactory.getRuntimeMXBean();
155       String rtname = rtmbean.getName();
156       String[] pidhost = rtname.split("@");
157 
158       //using linux bash commands to retrieve info
159       Process p = Runtime.getRuntime().exec(
160           new String[]{"bash", "-c",
161               "ls /proc/" + pidhost[0] + "/fdinfo | wc -l"});
162       inputStream = p.getInputStream();
163       inputStreamReader = new InputStreamReader(inputStream);
164       bufferedReader = new BufferedReader(inputStreamReader);
165       String openFileDesCount;
166       if ((openFileDesCount = bufferedReader.readLine()) != null) {
167         return Long.parseLong(openFileDesCount);
168       }
169     } catch (IOException ie) {
170       LOG.warn("Not able to get the number of open file descriptors", ie);
171     } finally {
172       if (bufferedReader != null) {
173         try {
174           bufferedReader.close();
175         } catch (IOException e) {
176           LOG.warn("Not able to close the BufferedReader", e);
177         }
178       }
179       if (inputStreamReader != null) {
180         try {
181           inputStreamReader.close();
182         } catch (IOException e) {
183           LOG.warn("Not able to close the InputStreamReader", e);
184         }
185       }
186       if (inputStream != null) {
187         try {
188           inputStream.close();
189         } catch (IOException e) {
190           LOG.warn("Not able to close the InputStream", e);
191         }
192       }
193     }
194     return -1;
195   }
196 
197   /**
198    * @see java.lang.management.OperatingSystemMXBean#getSystemLoadAverage
199    */
200   public double getSystemLoadAverage() {
201     return osMbean.getSystemLoadAverage();
202   }
203 
204   /**
205    * @return the physical free memory (not the JVM one, as it's not very useful as it depends on
206    * the GC), but the one from the OS as it allows a little bit more to guess if the machine is
207    * overloaded or not).
208    */
209   public long getFreeMemory() {
210     if (ibmvendor) {
211       return 0;
212     }
213 
214     Long r = runUnixMXBeanMethod("getFreePhysicalMemorySize");
215     return (r != null ? r : -1);
216   }
217 
218 
219   /**
220    * Workaround to get the current number of process running. Approach is the one described here:
221    * http://stackoverflow.com/questions/54686/how-to-get-a-list-of-current-open-windows-process-with-java
222    */
223   @edu.umd.cs.findbugs.annotations.SuppressWarnings(
224       value = "RV_DONT_JUST_NULL_CHECK_READLINE",
225       justification = "used by testing")
226   public int getNumberOfRunningProcess() {
227     if (!isUnix()) {
228       return 0;
229     }
230 
231     InputStream inputStream = null;
232     InputStreamReader inputStreamReader = null;
233     BufferedReader bufferedReader = null;
234 
235     try {
236       int count = 0;
237       Process p = Runtime.getRuntime().exec("ps -e");
238       inputStream = p.getInputStream();
239       inputStreamReader = new InputStreamReader(inputStream);
240       bufferedReader = new BufferedReader(inputStreamReader);
241       while (bufferedReader.readLine() != null) {
242         count++;
243       }
244       return count - 1; //  -1 because there is a headline
245     } catch (IOException e) {
246       return -1;
247     } finally {
248       if (bufferedReader != null) {
249         try {
250           bufferedReader.close();
251         } catch (IOException e) {
252           LOG.warn("Not able to close the BufferedReader", e);
253         }
254       }
255       if (inputStreamReader != null) {
256         try {
257           inputStreamReader.close();
258         } catch (IOException e) {
259           LOG.warn("Not able to close the InputStreamReader", e);
260         }
261       }
262       if (inputStream != null) {
263         try {
264           inputStream.close();
265         } catch (IOException e) {
266           LOG.warn("Not able to close the InputStream", e);
267         }
268       }
269     }
270   }
271 
272   /**
273    * Get the number of the maximum file descriptors the system can use.
274    * If Oracle java, it will use the com.sun.management interfaces.
275    * Otherwise, this methods implements it (linux only).
276    *
277    * @return max number of file descriptors the operating system can use.
278    */
279   public long getMaxFileDescriptorCount() {
280     Long mfdc;
281     if (!ibmvendor) {
282       mfdc = runUnixMXBeanMethod("getMaxFileDescriptorCount");
283       return (mfdc != null ? mfdc : -1);
284     }
285     InputStream in = null;
286     BufferedReader output = null;
287     try {
288       //using linux bash commands to retrieve info
289       Process p = Runtime.getRuntime().exec(new String[]{"bash", "-c", "ulimit -n"});
290       in = p.getInputStream();
291       output = new BufferedReader(new InputStreamReader(in));
292       String maxFileDesCount;
293       if ((maxFileDesCount = output.readLine()) != null) {
294         return Long.parseLong(maxFileDesCount);
295       }
296     } catch (IOException ie) {
297       LOG.warn("Not able to get the max number of file descriptors", ie);
298     } finally {
299       if (output != null) {
300         try {
301           output.close();
302         } catch (IOException e) {
303           LOG.warn("Not able to close the reader", e);
304         }
305       }
306       if (in != null) {
307         try {
308           in.close();
309         } catch (IOException e) {
310           LOG.warn("Not able to close the InputStream", e);
311         }
312       }
313     }
314     return -1;
315   }
316 }