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