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,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.hadoop.hbase.replication.regionserver;
20  
21  import java.util.Date;
22  import java.util.HashMap;
23  import java.util.List;
24  import java.util.ArrayList;
25  import java.util.Map;
26  
27  import org.apache.hadoop.hbase.classification.InterfaceAudience;
28  import org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos;
29  import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
30  import org.apache.hadoop.hbase.util.Strings;
31  
32  /**
33   * This class is used for exporting some of the info from replication metrics
34   */
35  @InterfaceAudience.Private
36  public class ReplicationLoad {
37  
38    // Empty load instance.
39    public static final ReplicationLoad EMPTY_REPLICATIONLOAD = new ReplicationLoad();
40  
41    private List<MetricsSource> sourceMetricsList;
42    private MetricsSink sinkMetrics;
43  
44    private List<ClusterStatusProtos.ReplicationLoadSource> replicationLoadSourceList;
45    private ClusterStatusProtos.ReplicationLoadSink replicationLoadSink;
46  
47    /** default constructor */
48    public ReplicationLoad() {
49      super();
50    }
51  
52    /**
53     * buildReplicationLoad
54     * @param srMetricsList
55     * @param skMetrics
56     */
57  
58    public void buildReplicationLoad(final List<MetricsSource> srMetricsList,
59        final MetricsSink skMetrics) {
60      this.sourceMetricsList = srMetricsList;
61      this.sinkMetrics = skMetrics;
62  
63      // build the SinkLoad
64      ClusterStatusProtos.ReplicationLoadSink.Builder rLoadSinkBuild =
65          ClusterStatusProtos.ReplicationLoadSink.newBuilder();
66      rLoadSinkBuild.setAgeOfLastAppliedOp(sinkMetrics.getAgeOfLastAppliedOp());
67      rLoadSinkBuild.setTimeStampsOfLastAppliedOp(sinkMetrics.getTimeStampOfLastAppliedOp());
68      this.replicationLoadSink = rLoadSinkBuild.build();
69  
70      // build the SourceLoad List
71      Map<String, ClusterStatusProtos.ReplicationLoadSource> replicationLoadSourceMap =
72          new HashMap<String, ClusterStatusProtos.ReplicationLoadSource>();
73      for (MetricsSource sm : this.sourceMetricsList) {
74        // Get the actual peer id
75        String peerId = sm.getPeerID();
76        String[] parts = peerId.split("-", 2);
77        peerId = parts.length != 1 ? parts[0] : peerId;
78  
79        long ageOfLastShippedOp = sm.getAgeOfLastShippedOp();
80        int sizeOfLogQueue = sm.getSizeOfLogQueue();
81        long timeStampOfLastShippedOp = sm.getTimeStampOfLastShippedOp();
82        long replicationLag =
83            calculateReplicationDelay(ageOfLastShippedOp, timeStampOfLastShippedOp, sizeOfLogQueue);
84  
85        ClusterStatusProtos.ReplicationLoadSource rLoadSource = replicationLoadSourceMap.get(peerId);
86        if (rLoadSource != null) {
87          ageOfLastShippedOp = Math.max(rLoadSource.getAgeOfLastShippedOp(), ageOfLastShippedOp);
88          sizeOfLogQueue += rLoadSource.getSizeOfLogQueue();
89          timeStampOfLastShippedOp = Math.min(rLoadSource.getTimeStampOfLastShippedOp(),
90            timeStampOfLastShippedOp);
91          replicationLag = Math.max(rLoadSource.getReplicationLag(), replicationLag);
92        }
93  
94        ClusterStatusProtos.ReplicationLoadSource.Builder rLoadSourceBuild =
95            ClusterStatusProtos.ReplicationLoadSource.newBuilder();
96        rLoadSourceBuild.setPeerID(peerId);
97        rLoadSourceBuild.setAgeOfLastShippedOp(ageOfLastShippedOp);
98        rLoadSourceBuild.setSizeOfLogQueue(sizeOfLogQueue);
99        rLoadSourceBuild.setTimeStampOfLastShippedOp(timeStampOfLastShippedOp);
100       rLoadSourceBuild.setReplicationLag(replicationLag);
101 
102       replicationLoadSourceMap.put(peerId, rLoadSourceBuild.build());
103     }
104     this.replicationLoadSourceList = new ArrayList<ClusterStatusProtos.ReplicationLoadSource>(
105         replicationLoadSourceMap.values());
106   }
107 
108   static long calculateReplicationDelay(long ageOfLastShippedOp,
109       long timeStampOfLastShippedOp, int sizeOfLogQueue) {
110     long replicationLag;
111     long timePassedAfterLastShippedOp =
112         EnvironmentEdgeManager.currentTime() - timeStampOfLastShippedOp;
113     if (sizeOfLogQueue > 1) {
114       // err on the large side
115       replicationLag = Math.max(ageOfLastShippedOp, timePassedAfterLastShippedOp);
116     } else if (timePassedAfterLastShippedOp < 2 * ageOfLastShippedOp) {
117       replicationLag = ageOfLastShippedOp; // last shipped happen recently
118     } else {
119       // last shipped may happen last night,
120       // so NO real lag although ageOfLastShippedOp is non-zero
121       replicationLag = 0;
122     }
123     return replicationLag;
124   }
125 
126   /**
127    * sourceToString
128    * @return a string contains sourceReplicationLoad information
129    */
130   public String sourceToString() {
131     if (this.sourceMetricsList == null) return null;
132 
133     StringBuilder sb = new StringBuilder();
134 
135     for (ClusterStatusProtos.ReplicationLoadSource rls : this.replicationLoadSourceList) {
136 
137       sb = Strings.appendKeyValue(sb, "\n           PeerID", rls.getPeerID());
138       sb = Strings.appendKeyValue(sb, "AgeOfLastShippedOp", rls.getAgeOfLastShippedOp());
139       sb = Strings.appendKeyValue(sb, "SizeOfLogQueue", rls.getSizeOfLogQueue());
140       sb =
141           Strings.appendKeyValue(sb, "TimeStampsOfLastShippedOp",
142             (new Date(rls.getTimeStampOfLastShippedOp()).toString()));
143       sb = Strings.appendKeyValue(sb, "Replication Lag", rls.getReplicationLag());
144     }
145 
146     return sb.toString();
147   }
148 
149   /**
150    * sinkToString
151    * @return a string contains sinkReplicationLoad information
152    */
153   public String sinkToString() {
154     if (this.replicationLoadSink == null) return null;
155 
156     StringBuilder sb = new StringBuilder();
157     sb =
158         Strings.appendKeyValue(sb, "AgeOfLastAppliedOp",
159           this.replicationLoadSink.getAgeOfLastAppliedOp());
160     sb =
161         Strings.appendKeyValue(sb, "TimeStampsOfLastAppliedOp",
162           (new Date(this.replicationLoadSink.getTimeStampsOfLastAppliedOp()).toString()));
163 
164     return sb.toString();
165   }
166 
167   public ClusterStatusProtos.ReplicationLoadSink getReplicationLoadSink() {
168     return this.replicationLoadSink;
169   }
170 
171   public List<ClusterStatusProtos.ReplicationLoadSource> getReplicationLoadSourceList() {
172     return this.replicationLoadSourceList;
173   }
174 
175   /**
176    * @see java.lang.Object#toString()
177    */
178   @Override
179   public String toString() {
180     return this.sourceToString() + System.getProperty("line.separator") + this.sinkToString();
181   }
182 
183 }