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