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