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 finish() method of GZIPOutputStream is broken
83     *
84     * @return whether GZIPOutputStream.finish() is broken.
85     */
86    public static boolean isGZIPOutputStreamFinishBroken() {
87      return ibmvendor && JVMVersion.contains("1.6.0");
88    }
89  
90    /**
91     * Load the implementation of UnixOperatingSystemMXBean for Oracle jvm
92     * and runs the desired method.
93     *
94     * @param mBeanMethodName : method to run from the interface UnixOperatingSystemMXBean
95     *
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);
107         unixos = classRef.cast(osMbean);
108         return (Long) mBeanMethod.invoke(unixos);
109       }
110     } catch (Exception e) {
111       LOG.warn("Not able to load class or method for" +
112           " com.sun.management.UnixOperatingSystemMXBean.", e);
113     }
114     return null;
115   }
116 
117   /**
118    * Get the number of opened filed descriptor for the runtime jvm.
119    * If Oracle java, it will use the com.sun.management interfaces.
120    * Otherwise, this methods implements it (linux only).
121    *
122    * @return number of open file descriptors for the jvm
123    */
124   public long getOpenFileDescriptorCount() {
125     Long ofdc;
126 
127     if (!ibmvendor) {
128       ofdc = runUnixMXBeanMethod("getOpenFileDescriptorCount");
129       return (ofdc != null ? ofdc : -1);
130     }
131     InputStream inputStream = null;
132     InputStreamReader inputStreamReader = null;
133     BufferedReader bufferedReader = 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       inputStream = p.getInputStream();
145       inputStreamReader = new InputStreamReader(inputStream);
146       bufferedReader = new BufferedReader(inputStreamReader);
147       String openFileDesCount;
148       if ((openFileDesCount = bufferedReader.readLine()) != null) {
149         return Long.parseLong(openFileDesCount);
150       }
151     } catch (IOException ie) {
152       LOG.warn("Not able to get the number of open file descriptors", ie);
153     } finally {
154       if (bufferedReader != null) {
155         try {
156           bufferedReader.close();
157         } catch (IOException e) {
158           LOG.warn("Not able to close the BufferedReader", e);
159         }
160       }
161       if (inputStreamReader != null) {
162         try {
163           inputStreamReader.close();
164         } catch (IOException e) {
165           LOG.warn("Not able to close the InputStreamReader", e);
166         }
167       }
168       if (inputStream != null) {
169         try {
170           inputStream.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     InputStream inputStream = null;
214     InputStreamReader inputStreamReader = null;
215     BufferedReader bufferedReader = null;
216 
217     try {
218       int count = 0;
219       Process p = Runtime.getRuntime().exec("ps -e");
220       inputStream = p.getInputStream();
221       inputStreamReader = new InputStreamReader(inputStream);
222       bufferedReader = new BufferedReader(inputStreamReader);
223       while (bufferedReader.readLine() != null) {
224         count++;
225       }
226       return count - 1; //  -1 because there is a headline
227     } catch (IOException e) {
228       return -1;
229     } finally {
230       if (bufferedReader != null) {
231         try {
232           bufferedReader.close();
233         } catch (IOException e) {
234           LOG.warn("Not able to close the BufferedReader", e);
235         }
236       }
237       if (inputStreamReader != null) {
238         try {
239           inputStreamReader.close();
240         } catch (IOException e) {
241           LOG.warn("Not able to close the InputStreamReader", e);
242         }
243       }
244       if (inputStream != null) {
245         try {
246           inputStream.close();
247         } catch (IOException e) {
248           LOG.warn("Not able to close the InputStream", e);
249         }
250       }
251     }
252   }
253 
254   /**
255    * Get the number of the maximum file descriptors the system can use.
256    * If Oracle java, it will use the com.sun.management interfaces.
257    * Otherwise, this methods implements it (linux only).
258    *
259    * @return max number of file descriptors the operating system can use.
260    */
261   public long getMaxFileDescriptorCount() {
262     Long mfdc;
263     if (!ibmvendor) {
264       mfdc = runUnixMXBeanMethod("getMaxFileDescriptorCount");
265       return (mfdc != null ? mfdc : -1);
266     }
267     InputStream in = null;
268     BufferedReader output = null;
269     try {
270       //using linux bash commands to retrieve info
271       Process p = Runtime.getRuntime().exec(new String[]{"bash", "-c", "ulimit -n"});
272       in = p.getInputStream();
273       output = new BufferedReader(new InputStreamReader(in));
274       String maxFileDesCount;
275       if ((maxFileDesCount = output.readLine()) != null) {
276         return Long.parseLong(maxFileDesCount);
277       }
278     } catch (IOException ie) {
279       LOG.warn("Not able to get the max number of file descriptors", ie);
280     } finally {
281       if (output != null) {
282         try {
283           output.close();
284         } catch (IOException e) {
285           LOG.warn("Not able to close the reader", e);
286         }
287       }
288       if (in != null) {
289         try {
290           in.close();
291         } catch (IOException e) {
292           LOG.warn("Not able to close the InputStream", e);
293         }
294       }
295     }
296     return -1;
297   }
298 }