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