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  
20  package org.apache.hadoop.hbase.namequeues.impl;
21  
22  import com.google.common.collect.Lists;
23  import java.util.Arrays;
24  import java.util.Collections;
25  import java.util.List;
26  import org.apache.hadoop.conf.Configuration;
27  import org.apache.hadoop.hbase.classification.InterfaceAudience;
28  import org.apache.hadoop.hbase.client.BalancerDecision;
29  import org.apache.hadoop.hbase.master.balancer.BaseLoadBalancer;
30  import org.apache.hadoop.hbase.namequeues.BalancerDecisionDetails;
31  import org.apache.hadoop.hbase.namequeues.NamedQueuePayload;
32  import org.apache.hadoop.hbase.namequeues.NamedQueueService;
33  import org.apache.hadoop.hbase.namequeues.queue.EvictingQueue;
34  import org.apache.hadoop.hbase.namequeues.request.NamedQueueGetRequest;
35  import org.apache.hadoop.hbase.namequeues.response.NamedQueueGetResponse;
36  import org.apache.hadoop.hbase.protobuf.generated.RecentLogs;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  
40  /**
41   * In-memory Queue service provider for Balancer Decision events
42   */
43  @InterfaceAudience.Private
44  public class BalancerDecisionQueueService implements NamedQueueService {
45  
46    private static final Logger LOG = LoggerFactory.getLogger(BalancerDecisionQueueService.class);
47  
48    private final boolean isBalancerDecisionRecording;
49  
50    private static final String BALANCER_DECISION_QUEUE_SIZE =
51      "hbase.master.balancer.decision.queue.size";
52    private static final int DEFAULT_BALANCER_DECISION_QUEUE_SIZE = 250;
53  
54    private static final int REGION_PLANS_THRESHOLD_PER_BALANCER = 15;
55  
56    private final EvictingQueue<RecentLogs.BalancerDecision> balancerDecisionQueue;
57  
58    public BalancerDecisionQueueService(Configuration conf) {
59      isBalancerDecisionRecording = conf.getBoolean(BaseLoadBalancer.BALANCER_DECISION_BUFFER_ENABLED,
60        BaseLoadBalancer.DEFAULT_BALANCER_DECISION_BUFFER_ENABLED);
61      if (!isBalancerDecisionRecording) {
62        balancerDecisionQueue = null;
63        return;
64      }
65      final int queueSize =
66        conf.getInt(BALANCER_DECISION_QUEUE_SIZE, DEFAULT_BALANCER_DECISION_QUEUE_SIZE);
67      balancerDecisionQueue = EvictingQueue.create(queueSize);
68    }
69  
70    @Override
71    public NamedQueuePayload.NamedQueueEvent getEvent() {
72      return NamedQueuePayload.NamedQueueEvent.BALANCE_DECISION;
73    }
74  
75    @Override
76    public void consumeEventFromDisruptor(NamedQueuePayload namedQueuePayload) {
77      if (!isBalancerDecisionRecording) {
78        return;
79      }
80      if (!(namedQueuePayload instanceof BalancerDecisionDetails)) {
81        LOG.warn(
82          "BalancerDecisionQueueService: NamedQueuePayload is not of type BalancerDecisionDetails.");
83        return;
84      }
85      BalancerDecisionDetails balancerDecisionDetails = (BalancerDecisionDetails) namedQueuePayload;
86      BalancerDecision balancerDecisionRecords =
87        balancerDecisionDetails.getBalancerDecision();
88      List<String> regionPlans = balancerDecisionRecords.getRegionPlans();
89      List<List<String>> regionPlansList;
90      if (regionPlans.size() > REGION_PLANS_THRESHOLD_PER_BALANCER) {
91        regionPlansList = Lists.partition(regionPlans, REGION_PLANS_THRESHOLD_PER_BALANCER);
92      } else {
93        regionPlansList = Collections.singletonList(regionPlans);
94      }
95      for (List<String> regionPlansPerBalancer : regionPlansList) {
96        RecentLogs.BalancerDecision balancerDecision = RecentLogs.BalancerDecision.newBuilder()
97          .setInitTotalCost(balancerDecisionRecords.getInitTotalCost())
98          .setInitialFunctionCosts(balancerDecisionRecords.getInitialFunctionCosts())
99          .setComputedTotalCost(balancerDecisionRecords.getComputedTotalCost())
100         .setFinalFunctionCosts(balancerDecisionRecords.getFinalFunctionCosts())
101         .setComputedSteps(balancerDecisionRecords.getComputedSteps())
102         .addAllRegionPlans(regionPlansPerBalancer)
103         .build();
104       balancerDecisionQueue.add(balancerDecision);
105     }
106   }
107 
108   @Override
109   public boolean clearNamedQueue() {
110     if (!isBalancerDecisionRecording) {
111       return false;
112     }
113     LOG.debug("Received request to clean up balancer decision queue.");
114     balancerDecisionQueue.clear();
115     return true;
116   }
117 
118   @Override
119   public NamedQueueGetResponse getNamedQueueRecords(NamedQueueGetRequest request) {
120     if (!isBalancerDecisionRecording) {
121       return null;
122     }
123     List<RecentLogs.BalancerDecision> balancerDecisions =
124       Arrays.asList(balancerDecisionQueue.toArray(new RecentLogs.BalancerDecision[0]));
125     // latest records should be displayed first, hence reverse order sorting
126     Collections.reverse(balancerDecisions);
127     int limit = balancerDecisions.size();
128     if (request.getBalancerDecisionsRequest().hasLimit()) {
129       limit = Math.min(request.getBalancerDecisionsRequest().getLimit(), balancerDecisions.size());
130     }
131     // filter limit if provided
132     balancerDecisions = balancerDecisions.subList(0, limit);
133     final NamedQueueGetResponse namedQueueGetResponse = new NamedQueueGetResponse();
134     namedQueueGetResponse.setNamedQueueEvent(BalancerDecisionDetails.BALANCER_DECISION_EVENT);
135     namedQueueGetResponse.setBalancerDecisions(balancerDecisions);
136     return namedQueueGetResponse;
137   }
138 
139   @Override
140   public void persistAll() {
141     // no-op for now
142   }
143 
144 }