View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.monitoring;
20  
21  import java.io.PrintWriter;
22  import java.text.SimpleDateFormat;
23  import java.util.Date;
24  import java.util.LinkedList;
25  import java.util.List;
26  
27  import org.apache.hadoop.classification.InterfaceAudience;
28  
29  import com.google.common.base.Charsets;
30  import com.google.common.base.Preconditions;
31  import com.google.common.collect.Lists;
32  
33  /**
34   * A size-bounded repository of alerts, which are kept
35   * in a linked list. Alerts can be added, and they will
36   * automatically be removed one by one when the specified heap
37   * usage is exhausted.
38   */
39  @InterfaceAudience.Private
40  public class MemoryBoundedLogMessageBuffer {
41    private final long maxSizeBytes;
42    private long usage = 0;
43    private LinkedList<LogMessage> messages;
44    
45    public MemoryBoundedLogMessageBuffer(long maxSizeBytes) {
46      Preconditions.checkArgument(
47          maxSizeBytes > 0);
48      this.maxSizeBytes = maxSizeBytes;
49      this.messages = Lists.newLinkedList();
50    }
51    
52    /**
53     * Append the given message to this buffer, automatically evicting
54     * older messages until the desired memory limit is achieved.
55     */
56    public synchronized void add(String messageText) {
57      LogMessage message = new LogMessage(messageText, System.currentTimeMillis());
58      
59      usage += message.estimateHeapUsage();
60      messages.add(message);
61      while (usage > maxSizeBytes) {
62        LogMessage removed = messages.remove();
63        usage -= removed.estimateHeapUsage();
64        assert usage >= 0;
65      }
66    }
67    
68    /**
69     * Dump the contents of the buffer to the given stream.
70     */
71    public synchronized void dumpTo(PrintWriter out) {
72      SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
73  
74      for (LogMessage msg : messages) {
75        out.write(df.format(new Date(msg.timestamp)));
76        out.write(" ");
77        out.println(new String(msg.message, Charsets.UTF_8));
78      }
79    }
80    
81    synchronized List<LogMessage> getMessages() {
82      // defensive copy
83      return Lists.newArrayList(messages);
84    }
85   
86    /**
87     * Estimate the number of bytes this buffer is currently
88     * using.
89     */
90    synchronized long estimateHeapUsage() {
91      return usage;
92    }
93    
94    private static class LogMessage {
95      /** the error text, encoded in bytes to save memory */
96      public final byte[] message;
97      public final long timestamp;
98      
99      /**
100      * Completely non-scientific estimate of how much one of these
101      * objects takes, along with the LinkedList overhead. This doesn't
102      * need to be exact, since we don't expect a ton of these alerts.
103      */
104     private static final long BASE_USAGE=100;
105     
106     public LogMessage(String message, long timestamp) {
107       this.message = message.getBytes(Charsets.UTF_8);
108       this.timestamp = timestamp;
109     }
110     
111     public long estimateHeapUsage() {
112       return message.length + BASE_USAGE;
113     }
114   }
115 
116 }