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").contains("IBM");
49    private static final boolean windows = 
50      System.getProperty("os.name").startsWith("Windows");
51    private static final boolean linux =
52      System.getProperty("os.name").startsWith("Linux");
53    private static final String JVMVersion = System.getProperty("java.version");
54  
55    /**
56     * Constructor. Get the running Operating System instance
57     */
58    public JVM () {
59      this.osMbean = ManagementFactory.getOperatingSystemMXBean();
60    }
61   
62    /**
63     * Check if the OS is unix. 
64     * 
65     * @return whether this is unix or not.
66     */
67    public static boolean isUnix() {
68      if (windows) {
69        return false;
70      }
71      return (ibmvendor ? linux : true);
72    }
73    
74    /**
75     * Check if the finish() method of GZIPOutputStream is broken
76     * 
77     * @return whether GZIPOutputStream.finish() is broken.
78     */
79    public static boolean isGZIPOutputStreamFinishBroken() {
80      return ibmvendor && JVMVersion.contains("1.6.0");
81    }
82  
83    /**
84     * Load the implementation of UnixOperatingSystemMXBean for Oracle jvm
85     * and runs the desired method. 
86     * @param mBeanMethodName : method to run from the interface UnixOperatingSystemMXBean
87     * @return the method result
88     */
89    private Long runUnixMXBeanMethod (String mBeanMethodName) {  
90      Object unixos;
91      Class<?> classRef;
92      Method mBeanMethod;
93  
94      try {
95        classRef = Class.forName("com.sun.management.UnixOperatingSystemMXBean");
96        if (classRef.isInstance(osMbean)) {
97          mBeanMethod = classRef.getMethod(mBeanMethodName, new Class[0]);
98          unixos = classRef.cast(osMbean);
99          return (Long)mBeanMethod.invoke(unixos);
100       }
101     }
102     catch(Exception e) {
103       LOG.warn("Not able to load class or method for" +
104           " com.sun.management.UnixOperatingSystemMXBean.", e);
105     }
106     return null;
107   }
108 
109   /**
110    * Get the number of opened filed descriptor for the runtime jvm.
111    * If Oracle java, it will use the com.sun.management interfaces.
112    * Otherwise, this methods implements it (linux only).  
113    * @return number of open file descriptors for the jvm
114    */
115   public long getOpenFileDescriptorCount() {
116 
117     Long ofdc;
118     
119     if (!ibmvendor) {
120       ofdc = runUnixMXBeanMethod("getOpenFileDescriptorCount");
121       return (ofdc != null ? ofdc.longValue () : -1);
122     }
123     InputStream in = null;
124     BufferedReader output = null;
125     try {
126       //need to get the PID number of the process first
127       RuntimeMXBean rtmbean = ManagementFactory.getRuntimeMXBean();
128       String rtname = rtmbean.getName();
129       String[] pidhost = rtname.split("@");
130 
131       //using linux bash commands to retrieve info
132       Process p = Runtime.getRuntime().exec(
133       new String[] { "bash", "-c",
134           "ls /proc/" + pidhost[0] + "/fdinfo | wc -l" });
135       in = p.getInputStream();
136       output = new BufferedReader(new InputStreamReader(in));
137       String openFileDesCount;
138       if ((openFileDesCount = output.readLine()) != null)      
139              return Long.parseLong(openFileDesCount);
140      } catch (IOException ie) {
141        LOG.warn("Not able to get the number of open file descriptors", ie);
142      } finally {
143        if (output != null) {
144          try {
145            output.close();
146          } catch (IOException e) {
147            LOG.warn("Not able to close the InputStream", e);
148          }
149        }
150        if (in != null){
151          try {
152            in.close();
153          } catch (IOException e) {
154            LOG.warn("Not able to close the InputStream", e);
155          }
156        }
157     }
158     return -1;
159   }
160 
161   /**
162    * @see java.lang.management.OperatingSystemMXBean#getSystemLoadAverage
163    */
164   public double getSystemLoadAverage() {
165     return osMbean.getSystemLoadAverage();
166   }
167 
168   /**
169    * @return the physical free memory (not the JVM one, as it's not very useful as it depends on
170    *  the GC), but the one from the OS as it allows a little bit more to guess if the machine is
171    *  overloaded or not).
172    */
173   public long getFreeMemory() {
174     if (ibmvendor){
175       return 0;
176     }
177 
178     Long r =  runUnixMXBeanMethod("getFreePhysicalMemorySize");
179     return (r != null ? r : -1);
180   }
181 
182 
183   /**
184    * Workaround to get the current number of process running. Approach is the one described here:
185    * http://stackoverflow.com/questions/54686/how-to-get-a-list-of-current-open-windows-process-with-java
186    */
187   @edu.umd.cs.findbugs.annotations.SuppressWarnings(
188     value="RV_DONT_JUST_NULL_CHECK_READLINE",
189     justification="used by testing")
190   public int getNumberOfRunningProcess(){
191     if (!isUnix()){
192       return 0;
193     }
194 
195     BufferedReader input = null;
196     try {
197       int count = 0;
198       Process p = Runtime.getRuntime().exec("ps -e");
199       input = new BufferedReader(new InputStreamReader(p.getInputStream()));
200       while (input.readLine() != null) {
201         count++;
202       }
203       return count - 1; //  -1 because there is a headline
204     } catch (IOException e) {
205       return -1;
206     }  finally {
207       if (input != null){
208         try {
209           input.close();
210         } catch (IOException e) {
211           LOG.warn("Not able to close the InputStream", e);
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 }