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.master;
20  
21  import java.io.IOException;
22  import java.lang.reflect.InvocationTargetException;
23  import java.lang.reflect.Method;
24  import java.net.InetAddress;
25  import java.util.ArrayList;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.Set;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.hadoop.hbase.CoordinatedStateException;
33  import org.apache.hadoop.hbase.HRegionLocation;
34  import org.apache.hadoop.hbase.classification.InterfaceAudience;
35  import org.apache.hadoop.hbase.HColumnDescriptor;
36  import org.apache.hadoop.hbase.HConstants;
37  import org.apache.hadoop.hbase.HRegionInfo;
38  import org.apache.hadoop.hbase.HTableDescriptor;
39  import org.apache.hadoop.hbase.NamespaceDescriptor;
40  import org.apache.hadoop.hbase.PleaseHoldException;
41  import org.apache.hadoop.hbase.ProcedureInfo;
42  import org.apache.hadoop.hbase.ServerLoad;
43  import org.apache.hadoop.hbase.ServerName;
44  import org.apache.hadoop.hbase.TableName;
45  import org.apache.hadoop.hbase.TableStateManager;
46  import org.apache.hadoop.hbase.UnknownRegionException;
47  import org.apache.hadoop.hbase.MetaTableAccessor;
48  import org.apache.hadoop.hbase.client.Admin;
49  import org.apache.hadoop.hbase.errorhandling.ForeignException;
50  import org.apache.hadoop.hbase.exceptions.MergeRegionException;
51  import org.apache.hadoop.hbase.exceptions.UnknownProtocolException;
52  import org.apache.hadoop.hbase.ipc.PriorityFunction;
53  import org.apache.hadoop.hbase.ipc.QosPriority;
54  import org.apache.hadoop.hbase.ipc.RpcServer;
55  import org.apache.hadoop.hbase.ipc.RpcServer.BlockingServiceAndInterface;
56  import org.apache.hadoop.hbase.ipc.ServerRpcController;
57  import org.apache.hadoop.hbase.namequeues.BalancerDecisionDetails;
58  import org.apache.hadoop.hbase.namequeues.NamedQueueRecorder;
59  import org.apache.hadoop.hbase.namequeues.request.NamedQueueGetRequest;
60  import org.apache.hadoop.hbase.namequeues.response.NamedQueueGetResponse;
61  import org.apache.hadoop.hbase.procedure.MasterProcedureManager;
62  import org.apache.hadoop.hbase.procedure2.Procedure;
63  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
64  import org.apache.hadoop.hbase.protobuf.RequestConverter;
65  import org.apache.hadoop.hbase.protobuf.ResponseConverter;
66  import org.apache.hadoop.hbase.protobuf.generated.*;
67  import org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos.RegionStoreSequenceIds;
68  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.NameStringPair;
69  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.ProcedureDescription;
70  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.RegionSpecifierType;
71  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
72  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.AbortProcedureRequest;
73  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.AbortProcedureResponse;
74  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.AddColumnRequest;
75  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.AddColumnResponse;
76  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.AssignRegionRequest;
77  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.AssignRegionResponse;
78  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.BalanceRequest;
79  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.BalanceResponse;
80  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ClearDeadServersRequest;
81  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ClearDeadServersResponse;
82  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ClientMetaService;
83  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.CreateNamespaceRequest;
84  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.CreateNamespaceResponse;
85  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.CreateTableRequest;
86  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.CreateTableResponse;
87  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.DeleteColumnRequest;
88  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.DeleteColumnResponse;
89  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.DeleteNamespaceRequest;
90  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.DeleteNamespaceResponse;
91  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.DeleteSnapshotRequest;
92  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.DeleteSnapshotResponse;
93  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.DeleteTableRequest;
94  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.DeleteTableResponse;
95  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.DisableTableRequest;
96  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.DisableTableResponse;
97  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.DispatchMergingRegionsRequest;
98  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.DispatchMergingRegionsResponse;
99  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.EnableCatalogJanitorRequest;
100 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.EnableCatalogJanitorResponse;
101 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.EnableTableRequest;
102 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.EnableTableResponse;
103 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ExecProcedureRequest;
104 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ExecProcedureResponse;
105 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetClusterIdRequest;
106 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetClusterIdResponse;
107 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetClusterStatusRequest;
108 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetClusterStatusResponse;
109 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetCompletedSnapshotsRequest;
110 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetCompletedSnapshotsResponse;
111 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetMastersRequest;
112 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetMastersResponse;
113 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetMastersResponseEntry;
114 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetMetaRegionLocationsRequest;
115 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetMetaRegionLocationsResponse;
116 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetNamespaceDescriptorRequest;
117 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetNamespaceDescriptorResponse;
118 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetNumLiveRSRequest;
119 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetNumLiveRSResponse;
120 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetProcedureResultRequest;
121 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetProcedureResultResponse;
122 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetSchemaAlterStatusRequest;
123 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetSchemaAlterStatusResponse;
124 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableDescriptorsRequest;
125 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableDescriptorsResponse;
126 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest;
127 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesResponse;
128 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableStateRequest;
129 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableStateResponse;
130 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsBalancerEnabledRequest;
131 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsBalancerEnabledResponse;
132 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsCleanerChoreEnabledRequest;
133 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsCleanerChoreEnabledResponse;
134 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsCatalogJanitorEnabledRequest;
135 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsCatalogJanitorEnabledResponse;
136 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsInMaintenanceModeRequest;
137 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsInMaintenanceModeResponse;
138 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsMasterRunningRequest;
139 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsMasterRunningResponse;
140 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsNormalizerEnabledRequest;
141 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsNormalizerEnabledResponse;
142 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsProcedureDoneRequest;
143 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsProcedureDoneResponse;
144 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsRestoreSnapshotDoneRequest;
145 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsRestoreSnapshotDoneResponse;
146 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsSnapshotCleanupEnabledRequest;
147 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsSnapshotCleanupEnabledResponse;
148 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsSnapshotDoneRequest;
149 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsSnapshotDoneResponse;
150 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ListNamespacesRequest;
151 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ListNamespacesResponse;
152 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ListNamespaceDescriptorsRequest;
153 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ListNamespaceDescriptorsResponse;
154 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ListProceduresRequest;
155 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ListProceduresResponse;
156 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ListTableDescriptorsByNamespaceRequest;
157 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ListTableDescriptorsByNamespaceResponse;
158 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ListTableNamesByNamespaceRequest;
159 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ListTableNamesByNamespaceResponse;
160 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.MajorCompactionTimestampForRegionRequest;
161 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.MajorCompactionTimestampRequest;
162 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.MajorCompactionTimestampResponse;
163 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.MasterService;
164 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ModifyColumnRequest;
165 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ModifyColumnResponse;
166 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ModifyNamespaceRequest;
167 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ModifyNamespaceResponse;
168 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ModifyTableRequest;
169 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ModifyTableResponse;
170 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.MoveRegionRequest;
171 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.MoveRegionResponse;
172 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.NormalizeRequest;
173 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.NormalizeResponse;
174 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.OfflineRegionRequest;
175 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.OfflineRegionResponse;
176 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.RestoreSnapshotRequest;
177 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.RestoreSnapshotResponse;
178 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.RunCatalogScanRequest;
179 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.RunCatalogScanResponse;
180 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.RunCleanerChoreRequest;
181 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.RunCleanerChoreResponse;
182 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.SecurityCapabilitiesRequest;
183 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.SecurityCapabilitiesResponse;
184 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.SecurityCapabilitiesResponse.Capability;
185 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.SetBalancerRunningRequest;
186 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.SetBalancerRunningResponse;
187 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.SetCleanerChoreRunningRequest;
188 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.SetCleanerChoreRunningResponse;
189 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.SetNormalizerRunningRequest;
190 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.SetNormalizerRunningResponse;
191 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.SetQuotaRequest;
192 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.SetQuotaResponse;
193 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.SetSnapshotCleanupRequest;
194 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.SetSnapshotCleanupResponse;
195 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ShutdownRequest;
196 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.ShutdownResponse;
197 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.SnapshotRequest;
198 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.SnapshotResponse;
199 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.StopMasterRequest;
200 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.StopMasterResponse;
201 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.TruncateTableRequest;
202 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.TruncateTableResponse;
203 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.UnassignRegionRequest;
204 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.UnassignRegionResponse;
205 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.GetLastFlushedSequenceIdRequest;
206 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.GetLastFlushedSequenceIdResponse;
207 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionServerReportRequest;
208 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionServerReportResponse;
209 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionServerStartupRequest;
210 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionServerStartupResponse;
211 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionServerStatusService;
212 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionStateTransition;
213 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.ReportRSFatalErrorRequest;
214 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.ReportRSFatalErrorResponse;
215 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.ReportRegionStateTransitionRequest;
216 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.ReportRegionStateTransitionResponse;
217 import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos.Table.State;
218 import org.apache.hadoop.hbase.regionserver.RSRpcServices;
219 import org.apache.hadoop.hbase.security.User;
220 import org.apache.hadoop.hbase.security.access.AccessChecker;
221 import org.apache.hadoop.hbase.security.access.AccessController;
222 import org.apache.hadoop.hbase.security.access.Permission;
223 import org.apache.hadoop.hbase.security.visibility.VisibilityController;
224 import org.apache.hadoop.hbase.snapshot.ClientSnapshotDescriptionUtils;
225 import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
226 import org.apache.hadoop.hbase.util.Bytes;
227 import org.apache.hadoop.hbase.util.ByteStringer;
228 import org.apache.hadoop.hbase.util.Pair;
229 import org.apache.zookeeper.KeeperException;
230 
231 import com.google.protobuf.ByteString;
232 import com.google.protobuf.Descriptors;
233 import com.google.protobuf.Message;
234 import com.google.protobuf.RpcCallback;
235 import com.google.protobuf.RpcController;
236 import com.google.protobuf.Service;
237 import com.google.protobuf.ServiceException;
238 
239 /**
240  * Implements the master RPC services.
241  */
242 @InterfaceAudience.Private
243 @SuppressWarnings("deprecation")
244 public class MasterRpcServices extends RSRpcServices
245     implements MasterService.BlockingInterface, RegionServerStatusService.BlockingInterface,
246     ClientMetaService.BlockingInterface {
247   private static final Log LOG = LogFactory.getLog(MasterRpcServices.class.getName());
248 
249   private final HMaster master;
250 
251   /**
252    * @return Subset of configuration to pass initializing regionservers: e.g.
253    * the filesystem to use and root directory to use.
254    */
255   private RegionServerStartupResponse.Builder createConfigurationSubset() {
256     RegionServerStartupResponse.Builder resp = addConfig(
257       RegionServerStartupResponse.newBuilder(), HConstants.HBASE_DIR);
258     resp = addConfig(resp, "fs.defaultFS");
259     return addConfig(resp, "hbase.master.info.port");
260   }
261 
262   private RegionServerStartupResponse.Builder addConfig(
263       final RegionServerStartupResponse.Builder resp, final String key) {
264     NameStringPair.Builder entry = NameStringPair.newBuilder()
265       .setName(key)
266       .setValue(master.getConfiguration().get(key));
267     resp.addMapEntries(entry.build());
268     return resp;
269   }
270 
271   public MasterRpcServices(HMaster m) throws IOException {
272     super(m);
273     master = m;
274   }
275 
276   @Override
277   protected PriorityFunction createPriority() {
278     return new MasterAnnotationReadingPriorityFunction(this);
279   }
280 
281   /**
282    * Checks for the following pre-checks in order:
283    * <ol>
284    *   <li>Master is initialized</li>
285    *   <li>Rpc caller has admin permissions</li>
286    * </ol>
287    * @param requestName name of rpc request. Used in reporting failures to provide context.
288    * @throws ServiceException If any of the above listed pre-check fails.
289    */
290   private void rpcPreCheck(String requestName) throws ServiceException {
291     try {
292       master.checkInitialized();
293       requirePermission(requestName, Permission.Action.ADMIN);
294     } catch (IOException ioe) {
295       throw new ServiceException(ioe);
296     }
297   }
298 
299   @Override
300   public HBaseProtos.LogEntry getLogEntries(RpcController controller,
301       HBaseProtos.LogRequest request) throws ServiceException {
302     try {
303       final String logClassName = request.getLogClassName();
304       Class<?> logClass = Class.forName(logClassName)
305         .asSubclass(Message.class);
306       Method method = logClass.getMethod("parseFrom", ByteString.class);
307       if (logClassName.contains("BalancerDecisionsRequest")) {
308         MasterProtos.BalancerDecisionsRequest balancerDecisionsRequest =
309           (MasterProtos.BalancerDecisionsRequest) method
310             .invoke(null, request.getLogMessage());
311         MasterProtos.BalancerDecisionsResponse balancerDecisionsResponse =
312           getBalancerDecisions(balancerDecisionsRequest);
313         return HBaseProtos.LogEntry.newBuilder()
314           .setLogClassName(balancerDecisionsResponse.getClass().getName())
315           .setLogMessage(balancerDecisionsResponse.toByteString())
316           .build();
317       }
318     } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException
319       | InvocationTargetException e) {
320       LOG.error("Error while retrieving log entries.", e);
321       throw new ServiceException(e);
322     }
323     throw new ServiceException("Invalid request params");
324   }
325 
326   private MasterProtos.BalancerDecisionsResponse getBalancerDecisions(
327       MasterProtos.BalancerDecisionsRequest request) {
328     final NamedQueueRecorder namedQueueRecorder = this.regionServer.getNamedQueueRecorder();
329     if (namedQueueRecorder == null) {
330       return MasterProtos.BalancerDecisionsResponse.newBuilder()
331         .addAllBalancerDecision(new ArrayList<RecentLogs.BalancerDecision>()).build();
332     }
333     final NamedQueueGetRequest namedQueueGetRequest = new NamedQueueGetRequest();
334     namedQueueGetRequest.setNamedQueueEvent(BalancerDecisionDetails.BALANCER_DECISION_EVENT);
335     namedQueueGetRequest.setBalancerDecisionsRequest(request);
336     NamedQueueGetResponse namedQueueGetResponse =
337       namedQueueRecorder.getNamedQueueRecords(namedQueueGetRequest);
338     List<RecentLogs.BalancerDecision> balancerDecisions =
339       namedQueueGetResponse.getBalancerDecisions();
340     return MasterProtos.BalancerDecisionsResponse.newBuilder()
341       .addAllBalancerDecision(balancerDecisions).build();
342   }
343 
344   enum BalanceSwitchMode {
345     SYNC,
346     ASYNC
347   }
348 
349   /**
350    * Assigns balancer switch according to BalanceSwitchMode
351    * @param b new balancer switch
352    * @param mode BalanceSwitchMode
353    * @return old balancer switch
354    */
355   boolean switchBalancer(final boolean b, BalanceSwitchMode mode) throws IOException {
356     boolean oldValue = master.loadBalancerTracker.isBalancerOn();
357     boolean newValue = b;
358     try {
359       if (master.cpHost != null) {
360         newValue = master.cpHost.preBalanceSwitch(newValue);
361       }
362       try {
363         if (mode == BalanceSwitchMode.SYNC) {
364           synchronized (master.balancer) {
365             master.loadBalancerTracker.setBalancerOn(newValue);
366           }
367         } else {
368           master.loadBalancerTracker.setBalancerOn(newValue);
369         }
370       } catch (KeeperException ke) {
371         throw new IOException(ke);
372       }
373       LOG.info(master.getClientIdAuditPrefix() + " set balanceSwitch=" + newValue);
374       if (master.cpHost != null) {
375         master.cpHost.postBalanceSwitch(oldValue, newValue);
376       }
377       master.getLoadBalancer().updateBalancerStatus(newValue);
378     } catch (IOException ioe) {
379       LOG.warn("Error flipping balance switch", ioe);
380     }
381     return oldValue;
382   }
383 
384   boolean synchronousBalanceSwitch(final boolean b) throws IOException {
385     return switchBalancer(b, BalanceSwitchMode.SYNC);
386   }
387 
388   /**
389    * @return list of blocking services and their security info classes that this server supports
390    */
391   @Override
392   protected List<BlockingServiceAndInterface> getServices() {
393     List<BlockingServiceAndInterface> bssi = new ArrayList<BlockingServiceAndInterface>(4);
394     bssi.add(new BlockingServiceAndInterface(
395       MasterService.newReflectiveBlockingService(this),
396       MasterService.BlockingInterface.class));
397     bssi.add(new BlockingServiceAndInterface(
398       RegionServerStatusService.newReflectiveBlockingService(this),
399       RegionServerStatusService.BlockingInterface.class));
400     bssi.add(new BlockingServiceAndInterface(
401         ClientMetaService.newReflectiveBlockingService(this),
402         ClientMetaService.BlockingInterface.class));
403     bssi.addAll(super.getServices());
404     return bssi;
405   }
406 
407   @Override
408   @QosPriority(priority = HConstants.ADMIN_QOS)
409   public GetLastFlushedSequenceIdResponse getLastFlushedSequenceId(RpcController controller,
410       GetLastFlushedSequenceIdRequest request) throws ServiceException {
411     try {
412       master.checkServiceStarted();
413     } catch (IOException ioe) {
414       throw new ServiceException(ioe);
415     }
416     byte[] encodedRegionName = request.getRegionName().toByteArray();
417     RegionStoreSequenceIds ids = master.serverManager.getLastFlushedSequenceId(encodedRegionName);
418     return ResponseConverter.buildGetLastFlushedSequenceIdResponse(ids);
419   }
420 
421   @Override
422   public RegionServerReportResponse regionServerReport(
423       RpcController controller, RegionServerReportRequest request) throws ServiceException {
424     try {
425       master.checkServiceStarted();
426       ClusterStatusProtos.ServerLoad sl = request.getLoad();
427       ServerName serverName = ProtobufUtil.toServerName(request.getServer());
428       ServerLoad oldLoad = master.serverManager.getLoad(serverName);
429       master.serverManager.regionServerReport(serverName, new ServerLoad(sl));
430       if (sl != null && master.metricsMaster != null) {
431         // Up our metrics.
432         master.metricsMaster.incrementRequests(sl.getTotalNumberOfRequests()
433             - (oldLoad != null ? oldLoad.getTotalNumberOfRequests() : 0));
434       }
435     } catch (IOException ioe) {
436       throw new ServiceException(ioe);
437     }
438     return RegionServerReportResponse.newBuilder().build();
439   }
440 
441   @Override
442   public RegionServerStartupResponse regionServerStartup(
443       RpcController controller, RegionServerStartupRequest request) throws ServiceException {
444     // Register with server manager
445     try {
446       master.checkServiceStarted();
447       InetAddress ia = master.getRemoteInetAddress(
448         request.getPort(), request.getServerStartCode());
449       // if regionserver passed hostname to use,
450       // then use it instead of doing a reverse DNS lookup
451       ServerName rs = master.serverManager.regionServerStartup(request, ia);
452 
453       // Send back some config info
454       RegionServerStartupResponse.Builder resp = createConfigurationSubset();
455       NameStringPair.Builder entry = NameStringPair.newBuilder()
456         .setName(HConstants.KEY_FOR_HOSTNAME_SEEN_BY_MASTER)
457         .setValue(rs.getHostname());
458       resp.addMapEntries(entry.build());
459 
460       return resp.build();
461     } catch (IOException ioe) {
462       throw new ServiceException(ioe);
463     }
464   }
465 
466   @Override
467   public ReportRSFatalErrorResponse reportRSFatalError(
468       RpcController controller, ReportRSFatalErrorRequest request) throws ServiceException {
469     String errorText = request.getErrorMessage();
470     ServerName sn = ProtobufUtil.toServerName(request.getServer());
471     String msg = "Region server " + sn
472       + " reported a fatal error:\n" + errorText;
473     LOG.error(msg);
474     master.rsFatals.add(msg);
475     return ReportRSFatalErrorResponse.newBuilder().build();
476   }
477 
478   @Override
479   public AddColumnResponse addColumn(RpcController controller,
480       AddColumnRequest req) throws ServiceException {
481     try {
482       master.addColumn(
483           ProtobufUtil.toTableName(req.getTableName()),
484           HColumnDescriptor.convert(req.getColumnFamilies()),
485           req.getNonceGroup(),
486           req.getNonce());
487     } catch (IOException ioe) {
488       throw new ServiceException(ioe);
489     }
490     return AddColumnResponse.newBuilder().build();
491   }
492 
493   @Override
494   public AssignRegionResponse assignRegion(RpcController controller,
495       AssignRegionRequest req) throws ServiceException {
496     try {
497       final byte [] regionName = req.getRegion().getValue().toByteArray();
498       RegionSpecifierType type = req.getRegion().getType();
499       AssignRegionResponse arr = AssignRegionResponse.newBuilder().build();
500 
501       master.checkInitialized();
502       if (type != RegionSpecifierType.REGION_NAME) {
503         LOG.warn("assignRegion specifier type: expected: " + RegionSpecifierType.REGION_NAME
504           + " actual: " + type);
505       }
506       RegionStates regionStates = master.assignmentManager.getRegionStates();
507       HRegionInfo regionInfo = regionStates.getRegionInfo(regionName);
508       if (regionInfo == null) throw new UnknownRegionException(Bytes.toString(regionName));
509       if (master.cpHost != null) {
510         if (master.cpHost.preAssign(regionInfo)) {
511           return arr;
512         }
513       }
514       LOG.info(master.getClientIdAuditPrefix()
515         + " assign " + regionInfo.getRegionNameAsString());
516       master.assignmentManager.assign(regionInfo, true, true);
517       if (master.cpHost != null) {
518         master.cpHost.postAssign(regionInfo);
519       }
520       return arr;
521     } catch (IOException ioe) {
522       throw new ServiceException(ioe);
523     }
524   }
525 
526   @Override
527   public BalanceResponse balance(RpcController controller,
528       BalanceRequest request) throws ServiceException {
529     try {
530       return BalanceResponse.newBuilder().setBalancerRan(master.balance(
531         request.hasForce() ? request.getForce() : false)).build();
532     } catch (IOException ex) {
533       throw new ServiceException(ex);
534     }
535   }
536 
537   @Override
538   public CreateNamespaceResponse createNamespace(RpcController controller,
539      CreateNamespaceRequest request) throws ServiceException {
540     try {
541       master.createNamespace(
542         ProtobufUtil.toNamespaceDescriptor(request.getNamespaceDescriptor()),
543         request.getNonceGroup(),
544         request.getNonce());
545       return CreateNamespaceResponse.getDefaultInstance();
546     } catch (IOException e) {
547       throw new ServiceException(e);
548     }
549   }
550 
551   @Override
552   public CreateTableResponse createTable(RpcController controller, CreateTableRequest req)
553   throws ServiceException {
554     HTableDescriptor hTableDescriptor = HTableDescriptor.convert(req.getTableSchema());
555     byte [][] splitKeys = ProtobufUtil.getSplitKeysArray(req);
556     try {
557       long procId =
558           master.createTable(hTableDescriptor, splitKeys, req.getNonceGroup(), req.getNonce());
559       return CreateTableResponse.newBuilder().setProcId(procId).build();
560     } catch (IOException ioe) {
561       throw new ServiceException(ioe);
562     }
563   }
564 
565   @Override
566   public DeleteColumnResponse deleteColumn(RpcController controller,
567       DeleteColumnRequest req) throws ServiceException {
568     try {
569       master.deleteColumn(
570         ProtobufUtil.toTableName(req.getTableName()),
571         req.getColumnName().toByteArray(),
572         req.getNonceGroup(),
573         req.getNonce());
574     } catch (IOException ioe) {
575       throw new ServiceException(ioe);
576     }
577     return DeleteColumnResponse.newBuilder().build();
578   }
579 
580   @Override
581   public DeleteNamespaceResponse deleteNamespace(RpcController controller,
582       DeleteNamespaceRequest request) throws ServiceException {
583     try {
584       master.deleteNamespace(
585         request.getNamespaceName(),
586         request.getNonceGroup(),
587         request.getNonce());
588       return DeleteNamespaceResponse.getDefaultInstance();
589     } catch (IOException e) {
590       throw new ServiceException(e);
591     }
592   }
593 
594   /**
595    * Execute Delete Snapshot operation.
596    * @return DeleteSnapshotResponse (a protobuf wrapped void) if the snapshot existed and was
597    *    deleted properly.
598    * @throws ServiceException wrapping SnapshotDoesNotExistException if specified snapshot did not
599    *    exist.
600    */
601   @Override
602   public DeleteSnapshotResponse deleteSnapshot(RpcController controller,
603       DeleteSnapshotRequest request) throws ServiceException {
604     try {
605       master.checkInitialized();
606       master.snapshotManager.checkSnapshotSupport();
607 
608       LOG.info(master.getClientIdAuditPrefix() + " delete " + request.getSnapshot());
609       master.snapshotManager.deleteSnapshot(request.getSnapshot());
610       return DeleteSnapshotResponse.newBuilder().build();
611     } catch (IOException e) {
612       throw new ServiceException(e);
613     }
614   }
615 
616   @Override
617   public DeleteTableResponse deleteTable(RpcController controller,
618       DeleteTableRequest request) throws ServiceException {
619     try {
620       long procId = master.deleteTable(ProtobufUtil.toTableName(
621           request.getTableName()), request.getNonceGroup(), request.getNonce());
622       return DeleteTableResponse.newBuilder().setProcId(procId).build();
623     } catch (IOException ioe) {
624       throw new ServiceException(ioe);
625     }
626   }
627 
628   @Override
629   public TruncateTableResponse truncateTable(RpcController controller, TruncateTableRequest request)
630       throws ServiceException {
631     try {
632       master.truncateTable(
633         ProtobufUtil.toTableName(request.getTableName()),
634         request.getPreserveSplits(),
635         request.getNonceGroup(),
636         request.getNonce());
637     } catch (IOException ioe) {
638       throw new ServiceException(ioe);
639     }
640     return TruncateTableResponse.newBuilder().build();
641   }
642 
643   @Override
644   public DisableTableResponse disableTable(RpcController controller,
645       DisableTableRequest request) throws ServiceException {
646     try {
647       long procId = master.disableTable(
648         ProtobufUtil.toTableName(request.getTableName()),
649         request.getNonceGroup(),
650         request.getNonce());
651       return DisableTableResponse.newBuilder().setProcId(procId).build();
652     } catch (IOException ioe) {
653       throw new ServiceException(ioe);
654     }
655   }
656 
657   @Override
658   public DispatchMergingRegionsResponse dispatchMergingRegions(RpcController c,
659       DispatchMergingRegionsRequest request) throws ServiceException {
660     try {
661       master.checkInitialized();
662     } catch (IOException ioe) {
663       throw new ServiceException(ioe);
664     }
665 
666     final byte[] encodedNameOfRegionA = request.getRegionA().getValue()
667       .toByteArray();
668     final byte[] encodedNameOfRegionB = request.getRegionB().getValue()
669       .toByteArray();
670     final boolean forcible = request.getForcible();
671     if (request.getRegionA().getType() != RegionSpecifierType.ENCODED_REGION_NAME
672         || request.getRegionB().getType() != RegionSpecifierType.ENCODED_REGION_NAME) {
673       LOG.warn("mergeRegions specifier type: expected: "
674         + RegionSpecifierType.ENCODED_REGION_NAME + " actual: region_a="
675         + request.getRegionA().getType() + ", region_b="
676         + request.getRegionB().getType());
677     }
678     RegionStates regionStates = master.assignmentManager.getRegionStates();
679     RegionState regionStateA = regionStates.getRegionState(Bytes.toString(encodedNameOfRegionA));
680     RegionState regionStateB = regionStates.getRegionState(Bytes.toString(encodedNameOfRegionB));
681     if (regionStateA == null || regionStateB == null) {
682       throw new ServiceException(new UnknownRegionException(
683           Bytes.toStringBinary(regionStateA == null ? encodedNameOfRegionA
684               : encodedNameOfRegionB)));
685     }
686 
687     if (!regionStateA.isOpened() || !regionStateB.isOpened()) {
688       throw new ServiceException(new MergeRegionException(
689         "Unable to merge regions not online " + regionStateA + ", " + regionStateB));
690     }
691 
692     final HRegionInfo regionInfoA = regionStateA.getRegion();
693     final HRegionInfo regionInfoB = regionStateB.getRegion();
694     if (regionInfoA.getReplicaId() != HRegionInfo.DEFAULT_REPLICA_ID ||
695         regionInfoB.getReplicaId() != HRegionInfo.DEFAULT_REPLICA_ID) {
696       throw new ServiceException(new MergeRegionException("Can't merge non-default replicas"));
697     }
698     if (regionInfoA.compareTo(regionInfoB) == 0) {
699       throw new ServiceException(new MergeRegionException(
700         "Unable to merge a region to itself " + regionInfoA + ", " + regionInfoB));
701     }
702     try {
703       master.cpHost.preDispatchMerge(regionInfoA, regionInfoB);
704     } catch (IOException ioe) {
705       throw new ServiceException(ioe);
706     }
707 
708     if (!forcible && !HRegionInfo.areAdjacent(regionInfoA, regionInfoB)) {
709       throw new ServiceException(new MergeRegionException(
710         "Unable to merge not adjacent regions "
711           + regionInfoA.getRegionNameAsString() + ", "
712           + regionInfoB.getRegionNameAsString()
713           + " where forcible = " + forcible));
714     }
715 
716     try {
717       master.dispatchMergingRegions(regionInfoA, regionInfoB, forcible, RpcServer.getRequestUser());
718       master.cpHost.postDispatchMerge(regionInfoA, regionInfoB);
719     } catch (IOException ioe) {
720       throw new ServiceException(ioe);
721     }
722 
723     return DispatchMergingRegionsResponse.newBuilder().build();
724   }
725 
726   @Override
727   public EnableCatalogJanitorResponse enableCatalogJanitor(RpcController c,
728       EnableCatalogJanitorRequest req) throws ServiceException {
729     rpcPreCheck("enableCatalogJanitor");
730     return EnableCatalogJanitorResponse.newBuilder().setPrevValue(
731       master.catalogJanitorChore.setEnabled(req.getEnable())).build();
732   }
733 
734   @Override
735   public SetCleanerChoreRunningResponse setCleanerChoreRunning(RpcController c,
736       SetCleanerChoreRunningRequest req) throws ServiceException {
737     rpcPreCheck("setCleanerChoreRunning");
738     boolean prevValue =
739       master.getLogCleaner().getEnabled() && master.getHFileCleaner().getEnabled();
740     master.getLogCleaner().setEnabled(req.getOn());
741     master.getHFileCleaner().setEnabled(req.getOn());
742     return SetCleanerChoreRunningResponse.newBuilder().setPrevValue(prevValue).build();
743   }
744 
745   @Override
746   public EnableTableResponse enableTable(RpcController controller,
747       EnableTableRequest request) throws ServiceException {
748     try {
749       long procId = master.enableTable(
750         ProtobufUtil.toTableName(request.getTableName()),
751         request.getNonceGroup(),
752         request.getNonce());
753       return EnableTableResponse.newBuilder().setProcId(procId).build();
754     } catch (IOException ioe) {
755       throw new ServiceException(ioe);
756     }
757   }
758 
759   @Override
760   public ClientProtos.CoprocessorServiceResponse execMasterService(final RpcController controller,
761       final ClientProtos.CoprocessorServiceRequest request) throws ServiceException {
762     rpcPreCheck("execMasterService");
763     try {
764       ServerRpcController execController = new ServerRpcController();
765       ClientProtos.CoprocessorServiceCall call = request.getCall();
766       String serviceName = call.getServiceName();
767       String methodName = call.getMethodName();
768       if (!master.coprocessorServiceHandlers.containsKey(serviceName)) {
769         throw new UnknownProtocolException(null,
770           "No registered master coprocessor service found for name "+serviceName);
771       }
772 
773       Service service = master.coprocessorServiceHandlers.get(serviceName);
774       Descriptors.ServiceDescriptor serviceDesc = service.getDescriptorForType();
775       Descriptors.MethodDescriptor methodDesc = serviceDesc.findMethodByName(methodName);
776       if (methodDesc == null) {
777         throw new UnknownProtocolException(service.getClass(),
778           "Unknown method "+methodName+" called on master service "+serviceName);
779       }
780 
781       //invoke the method
782       Message.Builder builderForType = service.getRequestPrototype(methodDesc).newBuilderForType();
783       ProtobufUtil.mergeFrom(builderForType, call.getRequest());
784       Message execRequest = builderForType.build();
785       final Message.Builder responseBuilder =
786           service.getResponsePrototype(methodDesc).newBuilderForType();
787       service.callMethod(methodDesc, execController, execRequest, new RpcCallback<Message>() {
788         @Override
789         public void run(Message message) {
790           if (message != null) {
791             responseBuilder.mergeFrom(message);
792           }
793         }
794       });
795       Message execResult = responseBuilder.build();
796 
797       if (execController.getFailedOn() != null) {
798         throw execController.getFailedOn();
799       }
800       ClientProtos.CoprocessorServiceResponse.Builder builder =
801         ClientProtos.CoprocessorServiceResponse.newBuilder();
802       builder.setRegion(RequestConverter.buildRegionSpecifier(
803         RegionSpecifierType.REGION_NAME, HConstants.EMPTY_BYTE_ARRAY));
804       builder.setValue(
805         builder.getValueBuilder().setName(execResult.getClass().getName())
806           .setValue(execResult.toByteString()));
807       return builder.build();
808     } catch (IOException ie) {
809       throw new ServiceException(ie);
810     }
811   }
812 
813   /**
814    * Triggers an asynchronous attempt to run a distributed procedure.
815    * {@inheritDoc}
816    */
817   @Override
818   public ExecProcedureResponse execProcedure(RpcController controller,
819       ExecProcedureRequest request) throws ServiceException {
820     rpcPreCheck("execProcedure");
821     try {
822       ProcedureDescription desc = request.getProcedure();
823       MasterProcedureManager mpm = master.getMasterProcedureManagerHost().getProcedureManager(
824         desc.getSignature());
825       if (mpm == null) {
826         throw new ServiceException("The procedure is not registered: "
827           + desc.getSignature());
828       }
829       LOG.info(master.getClientIdAuditPrefix() + " procedure request for: " + desc.getSignature());
830       mpm.execProcedure(desc);
831       // send back the max amount of time the client should wait for the procedure
832       // to complete
833       long waitTime = SnapshotDescriptionUtils.DEFAULT_MAX_WAIT_TIME;
834       return ExecProcedureResponse.newBuilder().setExpectedTimeout(
835         waitTime).build();
836     } catch (ForeignException e) {
837       throw new ServiceException(e.getCause());
838     } catch (IOException e) {
839       throw new ServiceException(e);
840     }
841   }
842 
843   /**
844    * Triggers a synchronous attempt to run a distributed procedure and sets
845    * return data in response.
846    * {@inheritDoc}
847    */
848   @Override
849   public ExecProcedureResponse execProcedureWithRet(RpcController controller,
850       ExecProcedureRequest request) throws ServiceException {
851     rpcPreCheck("execProcedureWithRet");
852     try {
853       ProcedureDescription desc = request.getProcedure();
854       MasterProcedureManager mpm =
855         master.getMasterProcedureManagerHost().getProcedureManager(desc.getSignature());
856       if (mpm == null) {
857         throw new ServiceException("The procedure is not registered: " + desc.getSignature());
858       }
859       LOG.info(master.getClientIdAuditPrefix() + " procedure request for: " + desc.getSignature());
860       byte[] data = mpm.execProcedureWithRet(desc);
861       ExecProcedureResponse.Builder builder = ExecProcedureResponse.newBuilder();
862       // set return data if available
863       if (data != null) {
864         builder.setReturnData(ByteString.copyFrom(data));
865       }
866       return builder.build();
867     } catch (IOException e) {
868       throw new ServiceException(e);
869     }
870   }
871 
872   @Override
873   public GetClusterStatusResponse getClusterStatus(RpcController controller,
874       GetClusterStatusRequest req) throws ServiceException {
875     GetClusterStatusResponse.Builder response = GetClusterStatusResponse.newBuilder();
876     try {
877       master.checkInitialized();
878       response.setClusterStatus(master.getClusterStatus().convert());
879     } catch (IOException e) {
880       throw new ServiceException(e);
881     }
882     return response.build();
883   }
884 
885   /**
886    * List the currently available/stored snapshots. Any in-progress snapshots are ignored
887    */
888   @Override
889   public GetCompletedSnapshotsResponse getCompletedSnapshots(RpcController controller,
890       GetCompletedSnapshotsRequest request) throws ServiceException {
891     try {
892       master.checkInitialized();
893       GetCompletedSnapshotsResponse.Builder builder = GetCompletedSnapshotsResponse.newBuilder();
894       List<SnapshotDescription> snapshots = master.snapshotManager.getCompletedSnapshots();
895 
896       // convert to protobuf
897       for (SnapshotDescription snapshot : snapshots) {
898         builder.addSnapshots(snapshot);
899       }
900       return builder.build();
901     } catch (IOException e) {
902       throw new ServiceException(e);
903     }
904   }
905 
906   @Override
907   public ListNamespacesResponse listNamespaces(
908       RpcController controller, ListNamespacesRequest request)
909       throws ServiceException {
910     try {
911       return ListNamespacesResponse.newBuilder()
912         .addAllNamespaceName(master.listNamespaces())
913         .build();
914     } catch (IOException e) {
915       throw new ServiceException(e);
916     }
917   }
918 
919   @Override
920   public GetNamespaceDescriptorResponse getNamespaceDescriptor(
921       RpcController controller, GetNamespaceDescriptorRequest request)
922       throws ServiceException {
923     try {
924       return GetNamespaceDescriptorResponse.newBuilder()
925         .setNamespaceDescriptor(ProtobufUtil.toProtoNamespaceDescriptor(
926             master.getNamespaceDescriptor(request.getNamespaceName())))
927         .build();
928     } catch (IOException e) {
929       throw new ServiceException(e);
930     }
931   }
932 
933   /**
934    * Get the number of regions of the table that have been updated by the alter.
935    *
936    * @return Pair indicating the number of regions updated Pair.getFirst is the
937    *         regions that are yet to be updated Pair.getSecond is the total number
938    *         of regions of the table
939    * @throws ServiceException
940    */
941   @Override
942   public GetSchemaAlterStatusResponse getSchemaAlterStatus(
943       RpcController controller, GetSchemaAlterStatusRequest req) throws ServiceException {
944     // TODO: currently, we query using the table name on the client side. this
945     // may overlap with other table operations or the table operation may
946     // have completed before querying this API. We need to refactor to a
947     // transaction system in the future to avoid these ambiguities.
948     TableName tableName = ProtobufUtil.toTableName(req.getTableName());
949 
950     try {
951       master.checkInitialized();
952       Pair<Integer,Integer> pair = master.assignmentManager.getReopenStatus(tableName);
953       GetSchemaAlterStatusResponse.Builder ret = GetSchemaAlterStatusResponse.newBuilder();
954       ret.setYetToUpdateRegions(pair.getFirst());
955       ret.setTotalRegions(pair.getSecond());
956       return ret.build();
957     } catch (IOException ioe) {
958       throw new ServiceException(ioe);
959     }
960   }
961 
962   /**
963    * Get list of TableDescriptors for requested tables.
964    * @param c Unused (set to null).
965    * @param req GetTableDescriptorsRequest that contains:
966    * - tableNames: requested tables, or if empty, all are requested
967    * @return GetTableDescriptorsResponse
968    * @throws ServiceException
969    */
970   @Override
971   public GetTableDescriptorsResponse getTableDescriptors(RpcController c,
972       GetTableDescriptorsRequest req) throws ServiceException {
973     try {
974       master.checkInitialized();
975 
976       final String regex = req.hasRegex() ? req.getRegex() : null;
977       final String namespace = req.hasNamespace() ? req.getNamespace() : null;
978       List<TableName> tableNameList = null;
979       if (req.getTableNamesCount() > 0) {
980         tableNameList = new ArrayList<TableName>(req.getTableNamesCount());
981         for (TableProtos.TableName tableNamePB: req.getTableNamesList()) {
982           tableNameList.add(ProtobufUtil.toTableName(tableNamePB));
983         }
984       }
985 
986       List<HTableDescriptor> descriptors = master.listTableDescriptors(namespace, regex,
987           tableNameList, req.getIncludeSysTables());
988 
989       GetTableDescriptorsResponse.Builder builder = GetTableDescriptorsResponse.newBuilder();
990       if (descriptors != null && descriptors.size() > 0) {
991         // Add the table descriptors to the response
992         for (HTableDescriptor htd: descriptors) {
993           builder.addTableSchema(htd.convert());
994         }
995       }
996       return builder.build();
997     } catch (IOException ioe) {
998       throw new ServiceException(ioe);
999     }
1000   }
1001 
1002   /**
1003    * Get list of userspace table names
1004    * @param controller Unused (set to null).
1005    * @param req GetTableNamesRequest
1006    * @return GetTableNamesResponse
1007    * @throws ServiceException
1008    */
1009   @Override
1010   public GetTableNamesResponse getTableNames(RpcController controller,
1011       GetTableNamesRequest req) throws ServiceException {
1012     try {
1013       master.checkInitialized();
1014 
1015       final String regex = req.hasRegex() ? req.getRegex() : null;
1016       final String namespace = req.hasNamespace() ? req.getNamespace() : null;
1017       List<TableName> tableNames = master.listTableNames(namespace, regex,
1018           req.getIncludeSysTables());
1019 
1020       GetTableNamesResponse.Builder builder = GetTableNamesResponse.newBuilder();
1021       if (tableNames != null && tableNames.size() > 0) {
1022         // Add the table names to the response
1023         for (TableName table: tableNames) {
1024           builder.addTableNames(ProtobufUtil.toProtoTableName(table));
1025         }
1026       }
1027       return builder.build();
1028     } catch (IOException e) {
1029       throw new ServiceException(e);
1030     }
1031   }
1032 
1033   @Override
1034   public IsCatalogJanitorEnabledResponse isCatalogJanitorEnabled(RpcController c,
1035       IsCatalogJanitorEnabledRequest req) throws ServiceException {
1036     return IsCatalogJanitorEnabledResponse.newBuilder().setValue(
1037       master.isCatalogJanitorEnabled()).build();
1038   }
1039 
1040   @Override
1041   public IsCleanerChoreEnabledResponse isCleanerChoreEnabled(RpcController c,
1042       IsCleanerChoreEnabledRequest req) throws ServiceException {
1043     return IsCleanerChoreEnabledResponse.newBuilder()
1044         .setValue(master.isCleanerChoreEnabled()).build();
1045   }
1046 
1047   @Override
1048   public IsMasterRunningResponse isMasterRunning(RpcController c,
1049       IsMasterRunningRequest req) throws ServiceException {
1050     try {
1051       master.checkServiceStarted();
1052       return IsMasterRunningResponse.newBuilder().setIsMasterRunning(
1053         !master.isStopped()).build();
1054     } catch (IOException e) {
1055       throw new ServiceException(e);
1056     }
1057   }
1058 
1059   /**
1060    * Checks if the specified procedure is done.
1061    * @return true if the procedure is done,
1062    *   false if the procedure is in the process of completing
1063    * @throws ServiceException if invalid procedure, or
1064    *  a failed procedure with progress failure reason.
1065    */
1066   @Override
1067   public IsProcedureDoneResponse isProcedureDone(RpcController controller,
1068       IsProcedureDoneRequest request) throws ServiceException {
1069     try {
1070       master.checkInitialized();
1071       ProcedureDescription desc = request.getProcedure();
1072       MasterProcedureManager mpm = master.getMasterProcedureManagerHost().getProcedureManager(
1073         desc.getSignature());
1074       if (mpm == null) {
1075         throw new ServiceException("The procedure is not registered: "
1076           + desc.getSignature());
1077       }
1078       LOG.debug("Checking to see if procedure from request:"
1079         + desc.getSignature() + " is done");
1080 
1081       IsProcedureDoneResponse.Builder builder =
1082         IsProcedureDoneResponse.newBuilder();
1083       boolean done = mpm.isProcedureDone(desc);
1084       builder.setDone(done);
1085       return builder.build();
1086     } catch (ForeignException e) {
1087       throw new ServiceException(e.getCause());
1088     } catch (IOException e) {
1089       throw new ServiceException(e);
1090     }
1091   }
1092 
1093   /**
1094    * Returns the status of the requested snapshot restore/clone operation.
1095    * This method is not exposed to the user, it is just used internally by HBaseAdmin
1096    * to verify if the restore is completed.
1097    *
1098    * No exceptions are thrown if the restore is not running, the result will be "done".
1099    *
1100    * @return done <tt>true</tt> if the restore/clone operation is completed.
1101    * @throws ServiceException if the operation failed.
1102    */
1103   @Override
1104   public IsRestoreSnapshotDoneResponse isRestoreSnapshotDone(RpcController controller,
1105       IsRestoreSnapshotDoneRequest request) throws ServiceException {
1106     try {
1107       master.checkInitialized();
1108       SnapshotDescription snapshot = request.getSnapshot();
1109       IsRestoreSnapshotDoneResponse.Builder builder = IsRestoreSnapshotDoneResponse.newBuilder();
1110       boolean done = master.snapshotManager.isRestoreDone(snapshot);
1111       builder.setDone(done);
1112       return builder.build();
1113     } catch (ForeignException e) {
1114       throw new ServiceException(e.getCause());
1115     } catch (IOException e) {
1116       throw new ServiceException(e);
1117     }
1118   }
1119 
1120   /**
1121    * Checks if the specified snapshot is done.
1122    * @return true if the snapshot is in file system ready to use,
1123    *   false if the snapshot is in the process of completing
1124    * @throws ServiceException wrapping UnknownSnapshotException if invalid snapshot, or
1125    *  a wrapped HBaseSnapshotException with progress failure reason.
1126    */
1127   @Override
1128   public IsSnapshotDoneResponse isSnapshotDone(RpcController controller,
1129       IsSnapshotDoneRequest request) throws ServiceException {
1130     LOG.debug("Checking to see if snapshot from request:" +
1131       ClientSnapshotDescriptionUtils.toString(request.getSnapshot()) + " is done");
1132     try {
1133       master.checkInitialized();
1134       IsSnapshotDoneResponse.Builder builder = IsSnapshotDoneResponse.newBuilder();
1135       boolean done = master.snapshotManager.isSnapshotDone(request.getSnapshot());
1136       builder.setDone(done);
1137       return builder.build();
1138     } catch (ForeignException e) {
1139       throw new ServiceException(e.getCause());
1140     } catch (IOException e) {
1141       throw new ServiceException(e);
1142     }
1143   }
1144 
1145   @Override
1146   public GetProcedureResultResponse getProcedureResult(RpcController controller,
1147       GetProcedureResultRequest request) throws ServiceException {
1148     LOG.debug("Checking to see if procedure is done procId=" + request.getProcId());
1149     try {
1150       master.checkInitialized();
1151       GetProcedureResultResponse.Builder builder = GetProcedureResultResponse.newBuilder();
1152 
1153       Pair<ProcedureInfo, Procedure> v = master.getMasterProcedureExecutor()
1154           .getResultOrProcedure(request.getProcId());
1155       if (v.getFirst() != null) {
1156         ProcedureInfo result = v.getFirst();
1157         builder.setState(GetProcedureResultResponse.State.FINISHED);
1158         builder.setStartTime(result.getStartTime());
1159         builder.setLastUpdate(result.getLastUpdate());
1160         if (result.isFailed()) {
1161           builder.setException(result.getForeignExceptionMessage());
1162         }
1163         if (result.hasResultData()) {
1164           builder.setResult(ByteStringer.wrap(result.getResult()));
1165         }
1166         master.getMasterProcedureExecutor().removeResult(request.getProcId());
1167       } else {
1168         Procedure proc = v.getSecond();
1169         if (proc == null) {
1170           builder.setState(GetProcedureResultResponse.State.NOT_FOUND);
1171         } else {
1172           builder.setState(GetProcedureResultResponse.State.RUNNING);
1173           builder.setStartTime(proc.getStartTime());
1174           builder.setLastUpdate(proc.getLastUpdate());
1175         }
1176       }
1177       return builder.build();
1178     } catch (IOException e) {
1179       throw new ServiceException(e);
1180     }
1181   }
1182 
1183   @Override
1184   public AbortProcedureResponse abortProcedure(
1185       RpcController rpcController, AbortProcedureRequest request) throws ServiceException {
1186     try {
1187       AbortProcedureResponse.Builder response = AbortProcedureResponse.newBuilder();
1188       boolean abortResult =
1189           master.abortProcedure(request.getProcId(), request.getMayInterruptIfRunning());
1190       response.setIsProcedureAborted(abortResult);
1191       return response.build();
1192     } catch (IOException e) {
1193       throw new ServiceException(e);
1194     }
1195   }
1196 
1197   @Override
1198   public ListProceduresResponse listProcedures(
1199       RpcController rpcController,
1200       ListProceduresRequest request) throws ServiceException {
1201     try {
1202       ListProceduresResponse.Builder response =
1203           ListProceduresResponse.newBuilder();
1204       for(ProcedureInfo p: master.listProcedures()) {
1205         response.addProcedure(ProcedureInfo.convertToProcedureProto(p));
1206       }
1207       return response.build();
1208     } catch (IOException e) {
1209       throw new ServiceException(e);
1210     }
1211   }
1212 
1213   @Override
1214   public ClearDeadServersResponse clearDeadServers(RpcController controller,
1215       ClearDeadServersRequest request) throws ServiceException {
1216     LOG.debug(master.getClientIdAuditPrefix() + " clear dead region servers.");
1217     ClearDeadServersResponse.Builder response = ClearDeadServersResponse.newBuilder();
1218     try {
1219       master.checkInitialized();
1220       if (master.cpHost != null) {
1221         master.cpHost.preClearDeadServers();
1222       }
1223 
1224       if (master.getServerManager().areDeadServersInProgress()) {
1225         LOG.debug("Some dead server is still under processing, won't clear the dead server list");
1226         response.addAllServerName(request.getServerNameList());
1227       } else {
1228         for (HBaseProtos.ServerName pbServer : request.getServerNameList()) {
1229           if (!master.getServerManager().getDeadServers()
1230                   .removeDeadServer(ProtobufUtil.toServerName(pbServer))) {
1231             response.addServerName(pbServer);
1232           }
1233         }
1234       }
1235 
1236       if (master.cpHost != null) {
1237         master.cpHost.postClearDeadServers(
1238             ProtobufUtil.toServerNameList(request.getServerNameList()),
1239             ProtobufUtil.toServerNameList(response.getServerNameList()));
1240       }
1241     } catch (IOException io) {
1242       throw new ServiceException(io);
1243     }
1244     return response.build();
1245   }
1246 
1247 
1248   @Override
1249   public ListNamespaceDescriptorsResponse listNamespaceDescriptors(RpcController c,
1250       ListNamespaceDescriptorsRequest request) throws ServiceException {
1251     try {
1252       ListNamespaceDescriptorsResponse.Builder response =
1253         ListNamespaceDescriptorsResponse.newBuilder();
1254       for(NamespaceDescriptor ns: master.listNamespaceDescriptors()) {
1255         response.addNamespaceDescriptor(ProtobufUtil.toProtoNamespaceDescriptor(ns));
1256       }
1257       return response.build();
1258     } catch (IOException e) {
1259       throw new ServiceException(e);
1260     }
1261   }
1262 
1263   @Override
1264   public ListTableDescriptorsByNamespaceResponse listTableDescriptorsByNamespace(RpcController c,
1265       ListTableDescriptorsByNamespaceRequest request) throws ServiceException {
1266     try {
1267       ListTableDescriptorsByNamespaceResponse.Builder b =
1268           ListTableDescriptorsByNamespaceResponse.newBuilder();
1269       for (HTableDescriptor htd : master
1270           .listTableDescriptorsByNamespace(request.getNamespaceName())) {
1271         b.addTableSchema(htd.convert());
1272       }
1273       return b.build();
1274     } catch (IOException e) {
1275       throw new ServiceException(e);
1276     }
1277   }
1278 
1279   @Override
1280   public ListTableNamesByNamespaceResponse listTableNamesByNamespace(RpcController c,
1281       ListTableNamesByNamespaceRequest request) throws ServiceException {
1282     try {
1283       ListTableNamesByNamespaceResponse.Builder b =
1284         ListTableNamesByNamespaceResponse.newBuilder();
1285       for (TableName tableName: master.listTableNamesByNamespace(request.getNamespaceName())) {
1286         b.addTableName(ProtobufUtil.toProtoTableName(tableName));
1287       }
1288       return b.build();
1289     } catch (IOException e) {
1290       throw new ServiceException(e);
1291     }
1292   }
1293 
1294   @Override
1295   public ModifyColumnResponse modifyColumn(RpcController controller,
1296       ModifyColumnRequest req) throws ServiceException {
1297     try {
1298       master.modifyColumn(
1299         ProtobufUtil.toTableName(req.getTableName()),
1300         HColumnDescriptor.convert(req.getColumnFamilies()),
1301         req.getNonceGroup(),
1302         req.getNonce());
1303     } catch (IOException ioe) {
1304       throw new ServiceException(ioe);
1305     }
1306     return ModifyColumnResponse.newBuilder().build();
1307   }
1308 
1309   @Override
1310   public ModifyNamespaceResponse modifyNamespace(RpcController controller,
1311       ModifyNamespaceRequest request) throws ServiceException {
1312     try {
1313       master.modifyNamespace(
1314         ProtobufUtil.toNamespaceDescriptor(request.getNamespaceDescriptor()),
1315         request.getNonceGroup(),
1316         request.getNonce());
1317       return ModifyNamespaceResponse.getDefaultInstance();
1318     } catch (IOException e) {
1319       throw new ServiceException(e);
1320     }
1321   }
1322 
1323   @Override
1324   public ModifyTableResponse modifyTable(RpcController controller,
1325       ModifyTableRequest req) throws ServiceException {
1326     try {
1327       master.modifyTable(
1328         ProtobufUtil.toTableName(req.getTableName()),
1329         HTableDescriptor.convert(req.getTableSchema()),
1330         req.getNonceGroup(),
1331         req.getNonce());
1332     } catch (IOException ioe) {
1333       throw new ServiceException(ioe);
1334     }
1335     return ModifyTableResponse.newBuilder().build();
1336   }
1337 
1338   @Override
1339   public MoveRegionResponse moveRegion(RpcController controller,
1340       MoveRegionRequest req) throws ServiceException {
1341     final byte [] encodedRegionName = req.getRegion().getValue().toByteArray();
1342     RegionSpecifierType type = req.getRegion().getType();
1343     final byte [] destServerName = (req.hasDestServerName())?
1344       Bytes.toBytes(ProtobufUtil.toServerName(req.getDestServerName()).getServerName()):null;
1345     MoveRegionResponse mrr = MoveRegionResponse.newBuilder().build();
1346 
1347     if (type != RegionSpecifierType.ENCODED_REGION_NAME) {
1348       LOG.warn("moveRegion specifier type: expected: " + RegionSpecifierType.ENCODED_REGION_NAME
1349         + " actual: " + type);
1350     }
1351 
1352     try {
1353       master.checkInitialized();
1354       master.move(encodedRegionName, destServerName);
1355     } catch (IOException ioe) {
1356       throw new ServiceException(ioe);
1357     }
1358     return mrr;
1359   }
1360 
1361   /**
1362    * Offline specified region from master's in-memory state. It will not attempt to
1363    * reassign the region as in unassign.
1364    *
1365    * This is a special method that should be used by experts or hbck.
1366    *
1367    */
1368   @Override
1369   public OfflineRegionResponse offlineRegion(RpcController controller,
1370       OfflineRegionRequest request) throws ServiceException {
1371     final byte [] regionName = request.getRegion().getValue().toByteArray();
1372     RegionSpecifierType type = request.getRegion().getType();
1373     if (type != RegionSpecifierType.REGION_NAME) {
1374       LOG.warn("moveRegion specifier type: expected: " + RegionSpecifierType.REGION_NAME
1375         + " actual: " + type);
1376     }
1377 
1378     try {
1379       master.checkInitialized();
1380       Pair<HRegionInfo, ServerName> pair =
1381         MetaTableAccessor.getRegion(master.getConnection(), regionName);
1382       if (pair == null) throw new UnknownRegionException(Bytes.toStringBinary(regionName));
1383       HRegionInfo hri = pair.getFirst();
1384       if (master.cpHost != null) {
1385         master.cpHost.preRegionOffline(hri);
1386       }
1387       LOG.info(master.getClientIdAuditPrefix() + " offline " + hri.getRegionNameAsString());
1388       master.assignmentManager.regionOffline(hri, true);
1389       if (master.cpHost != null) {
1390         master.cpHost.postRegionOffline(hri);
1391       }
1392     } catch (IOException ioe) {
1393       throw new ServiceException(ioe);
1394     }
1395     return OfflineRegionResponse.newBuilder().build();
1396   }
1397 
1398   /**
1399    * Execute Restore/Clone snapshot operation.
1400    *
1401    * <p>If the specified table exists a "Restore" is executed, replacing the table
1402    * schema and directory data with the content of the snapshot.
1403    * The table must be disabled, or a UnsupportedOperationException will be thrown.
1404    *
1405    * <p>If the table doesn't exist a "Clone" is executed, a new table is created
1406    * using the schema at the time of the snapshot, and the content of the snapshot.
1407    *
1408    * <p>The restore/clone operation does not require copying HFiles. Since HFiles
1409    * are immutable the table can point to and use the same files as the original one.
1410    */
1411   @Override
1412   public RestoreSnapshotResponse restoreSnapshot(RpcController controller,
1413       RestoreSnapshotRequest request) throws ServiceException {
1414     try {
1415       master.checkInitialized();
1416       master.snapshotManager.checkSnapshotSupport();
1417 
1418       // ensure namespace exists
1419       TableName dstTable = TableName.valueOf(request.getSnapshot().getTable());
1420       master.ensureNamespaceExists(dstTable.getNamespaceAsString());
1421 
1422       SnapshotDescription reqSnapshot = request.getSnapshot();
1423       master.snapshotManager.restoreSnapshot(reqSnapshot,
1424         request.hasRestoreACL() && request.getRestoreACL());
1425       return RestoreSnapshotResponse.newBuilder().build();
1426     } catch (ForeignException e) {
1427       throw new ServiceException(e.getCause());
1428     } catch (IOException e) {
1429       throw new ServiceException(e);
1430     }
1431   }
1432 
1433   @Override
1434   public SetSnapshotCleanupResponse switchSnapshotCleanup(
1435       RpcController controller, SetSnapshotCleanupRequest request)
1436       throws ServiceException {
1437     try {
1438       master.checkInitialized();
1439       final boolean enabled = request.getEnabled();
1440       final boolean isSynchronous = request.hasSynchronous() && request.getSynchronous();
1441       final boolean prevSnapshotCleanupRunning = this.switchSnapshotCleanup(enabled, isSynchronous);
1442       return SetSnapshotCleanupResponse.newBuilder()
1443           .setPrevSnapshotCleanup(prevSnapshotCleanupRunning).build();
1444     } catch (IOException e) {
1445       throw new ServiceException(e);
1446     }
1447   }
1448 
1449   @Override
1450   public IsSnapshotCleanupEnabledResponse isSnapshotCleanupEnabled(
1451       RpcController controller, IsSnapshotCleanupEnabledRequest request)
1452       throws ServiceException {
1453     try {
1454       master.checkInitialized();
1455       final boolean isSnapshotCleanupEnabled = master.snapshotCleanupTracker
1456           .isSnapshotCleanupEnabled();
1457       return IsSnapshotCleanupEnabledResponse.newBuilder()
1458           .setEnabled(isSnapshotCleanupEnabled).build();
1459     } catch (IOException e) {
1460       throw new ServiceException(e);
1461     }
1462   }
1463 
1464   /**
1465    * Turn on/off snapshot auto-cleanup based on TTL
1466    *
1467    * @param enabledNewVal Set to <code>true</code> to enable, <code>false</code> to disable
1468    * @param synchronous If <code>true</code>, it waits until current snapshot cleanup is completed,
1469    *   if outstanding
1470    * @return previous snapshot auto-cleanup mode
1471    */
1472   private synchronized boolean switchSnapshotCleanup(final boolean enabledNewVal,
1473       final boolean synchronous) {
1474     final boolean oldValue = master.snapshotCleanupTracker.isSnapshotCleanupEnabled();
1475     master.switchSnapshotCleanup(enabledNewVal, synchronous);
1476     LOG.info(master.getClientIdAuditPrefix() + " Successfully set snapshot cleanup to {}" +
1477       enabledNewVal);
1478     return oldValue;
1479   }
1480 
1481 
1482   @Override
1483   public RunCatalogScanResponse runCatalogScan(RpcController c,
1484       RunCatalogScanRequest req) throws ServiceException {
1485     rpcPreCheck("runCatalogScan");
1486     try {
1487       return ResponseConverter.buildRunCatalogScanResponse(master.catalogJanitorChore.scan());
1488     } catch (IOException ioe) {
1489       throw new ServiceException(ioe);
1490     }
1491   }
1492 
1493   @Override
1494   public RunCleanerChoreResponse runCleanerChore(RpcController c, RunCleanerChoreRequest req)
1495       throws ServiceException {
1496     rpcPreCheck("runCleanerChore");
1497     Boolean result = master.getHFileCleaner().runCleaner() && master.getLogCleaner().runCleaner();
1498     return ResponseConverter.buildRunCleanerChoreResponse(result);
1499   }
1500 
1501   @Override
1502   public SetBalancerRunningResponse setBalancerRunning(RpcController c,
1503       SetBalancerRunningRequest req) throws ServiceException {
1504     try {
1505       master.checkInitialized();
1506       boolean prevValue = (req.getSynchronous())?
1507         synchronousBalanceSwitch(req.getOn()) : master.balanceSwitch(req.getOn());
1508       return SetBalancerRunningResponse.newBuilder().setPrevBalanceValue(prevValue).build();
1509     } catch (IOException ioe) {
1510       throw new ServiceException(ioe);
1511     }
1512   }
1513 
1514   @Override
1515   public ShutdownResponse shutdown(RpcController controller,
1516       ShutdownRequest request) throws ServiceException {
1517     LOG.info(master.getClientIdAuditPrefix() + " shutdown");
1518     try {
1519       master.shutdown();
1520     } catch (IOException e) {
1521       LOG.error("Exception occurred in HMaster.shutdown()", e);
1522       throw new ServiceException(e);
1523     }
1524     return ShutdownResponse.newBuilder().build();
1525   }
1526 
1527   /**
1528    * Triggers an asynchronous attempt to take a snapshot.
1529    * {@inheritDoc}
1530    */
1531   @Override
1532   public SnapshotResponse snapshot(RpcController controller,
1533       SnapshotRequest request) throws ServiceException {
1534     try {
1535       master.checkInitialized();
1536       master.snapshotManager.checkSnapshotSupport();
1537 
1538       LOG.info(master.getClientIdAuditPrefix() + " snapshot request for:" +
1539         ClientSnapshotDescriptionUtils.toString(request.getSnapshot()));
1540       // get the snapshot information
1541       SnapshotDescription snapshot = SnapshotDescriptionUtils.validate(
1542         request.getSnapshot(), master.getConfiguration());
1543       master.snapshotManager.takeSnapshot(snapshot);
1544 
1545       // send back the max amount of time the client should wait for the snapshot to complete
1546       long waitTime = SnapshotDescriptionUtils.getMaxMasterTimeout(master.getConfiguration(),
1547         snapshot.getType(), SnapshotDescriptionUtils.DEFAULT_MAX_WAIT_TIME);
1548       return SnapshotResponse.newBuilder().setExpectedTimeout(waitTime).build();
1549     } catch (ForeignException e) {
1550       throw new ServiceException(e.getCause());
1551     } catch (IOException e) {
1552       throw new ServiceException(e);
1553     }
1554   }
1555 
1556   @Override
1557   public StopMasterResponse stopMaster(RpcController controller,
1558       StopMasterRequest request) throws ServiceException {
1559     LOG.info(master.getClientIdAuditPrefix() + " stop");
1560     try {
1561       master.stopMaster();
1562     } catch (IOException e) {
1563       LOG.error("Exception occurred while stopping master", e);
1564       throw new ServiceException(e);
1565     }
1566     return StopMasterResponse.newBuilder().build();
1567   }
1568 
1569   @Override
1570   public IsInMaintenanceModeResponse isMasterInMaintenanceMode(
1571       final RpcController controller,
1572       final IsInMaintenanceModeRequest request) throws ServiceException {
1573     IsInMaintenanceModeResponse.Builder response = IsInMaintenanceModeResponse.newBuilder();
1574     try {
1575       response.setInMaintenanceMode(master.isInMaintenanceMode());
1576     } catch (IOException e) {
1577       throw new ServiceException(e);
1578     }
1579     return response.build();
1580   }
1581 
1582   @Override
1583   public UnassignRegionResponse unassignRegion(RpcController controller,
1584       UnassignRegionRequest req) throws ServiceException {
1585     try {
1586       final byte [] regionName = req.getRegion().getValue().toByteArray();
1587       RegionSpecifierType type = req.getRegion().getType();
1588       final boolean force = req.getForce();
1589       UnassignRegionResponse urr = UnassignRegionResponse.newBuilder().build();
1590 
1591       master.checkInitialized();
1592       if (type != RegionSpecifierType.REGION_NAME) {
1593         LOG.warn("unassignRegion specifier type: expected: " + RegionSpecifierType.REGION_NAME
1594           + " actual: " + type);
1595       }
1596       Pair<HRegionInfo, ServerName> pair =
1597         MetaTableAccessor.getRegion(master.getConnection(), regionName);
1598       if (pair == null) throw new UnknownRegionException(Bytes.toString(regionName));
1599       HRegionInfo hri = pair.getFirst();
1600       if (master.cpHost != null) {
1601         if (master.cpHost.preUnassign(hri, force)) {
1602           return urr;
1603         }
1604       }
1605       LOG.debug(master.getClientIdAuditPrefix() + " unassign " + hri.getRegionNameAsString()
1606           + " in current location if it is online and reassign.force=" + force);
1607       master.assignmentManager.unassign(hri, force);
1608       if (master.assignmentManager.getRegionStates().isRegionOffline(hri)) {
1609         LOG.debug("Region " + hri.getRegionNameAsString()
1610             + " is not online on any region server, reassigning it.");
1611         master.assignmentManager.assign(hri, true);
1612       }
1613       if (master.cpHost != null) {
1614         master.cpHost.postUnassign(hri, force);
1615       }
1616 
1617       return urr;
1618     } catch (IOException ioe) {
1619       throw new ServiceException(ioe);
1620     }
1621   }
1622 
1623   @Override
1624   public ReportRegionStateTransitionResponse reportRegionStateTransition(RpcController c,
1625       ReportRegionStateTransitionRequest req) throws ServiceException {
1626     try {
1627       master.checkServiceStarted();
1628       RegionStateTransition rt = req.getTransition(0);
1629       RegionStates regionStates = master.getAssignmentManager().getRegionStates();
1630       for (HBaseProtos.RegionInfo ri : rt.getRegionInfoList())  {
1631         TableName tableName = ProtobufUtil.toTableName(ri.getTableName());
1632         if (!(TableName.META_TABLE_NAME.equals(tableName)
1633             && regionStates.getRegionState(HRegionInfo.FIRST_META_REGIONINFO) != null)
1634               && !master.getAssignmentManager().isFailoverCleanupDone()) {
1635           // Meta region is assigned before master finishes the
1636           // failover cleanup. So no need this check for it
1637           throw new PleaseHoldException("Master is rebuilding user regions");
1638         }
1639       }
1640       ServerName sn = ProtobufUtil.toServerName(req.getServer());
1641       String error = master.assignmentManager.onRegionTransition(sn, rt);
1642       ReportRegionStateTransitionResponse.Builder rrtr =
1643         ReportRegionStateTransitionResponse.newBuilder();
1644       if (error != null) {
1645         rrtr.setErrorMessage(error);
1646       }
1647       return rrtr.build();
1648     } catch (IOException ioe) {
1649       throw new ServiceException(ioe);
1650     }
1651   }
1652 
1653   @Override
1654   public MajorCompactionTimestampResponse getLastMajorCompactionTimestamp(RpcController controller,
1655       MajorCompactionTimestampRequest request) throws ServiceException {
1656     MajorCompactionTimestampResponse.Builder response =
1657         MajorCompactionTimestampResponse.newBuilder();
1658     try {
1659       master.checkInitialized();
1660       response.setCompactionTimestamp(master.getLastMajorCompactionTimestamp(ProtobufUtil
1661           .toTableName(request.getTableName())));
1662     } catch (IOException e) {
1663       throw new ServiceException(e);
1664     }
1665     return response.build();
1666   }
1667 
1668   @Override
1669   public MajorCompactionTimestampResponse getLastMajorCompactionTimestampForRegion(
1670       RpcController controller, MajorCompactionTimestampForRegionRequest request)
1671       throws ServiceException {
1672     MajorCompactionTimestampResponse.Builder response =
1673         MajorCompactionTimestampResponse.newBuilder();
1674     try {
1675       master.checkInitialized();
1676       response.setCompactionTimestamp(master.getLastMajorCompactionTimestampForRegion(request
1677           .getRegion().getValue().toByteArray()));
1678     } catch (IOException e) {
1679       throw new ServiceException(e);
1680     }
1681     return response.build();
1682   }
1683 
1684   @Override
1685   public IsBalancerEnabledResponse isBalancerEnabled(RpcController controller,
1686       IsBalancerEnabledRequest request) throws ServiceException {
1687     IsBalancerEnabledResponse.Builder response = IsBalancerEnabledResponse.newBuilder();
1688     response.setEnabled(master.isBalancerOn());
1689     return response.build();
1690   }
1691 
1692   @Override
1693   public MasterProtos.SetSplitOrMergeEnabledResponse setSplitOrMergeEnabled(
1694     RpcController controller,
1695     MasterProtos.SetSplitOrMergeEnabledRequest request) throws ServiceException {
1696     MasterProtos.SetSplitOrMergeEnabledResponse.Builder response =
1697             MasterProtos.SetSplitOrMergeEnabledResponse.newBuilder();
1698     try {
1699       master.checkInitialized();
1700       boolean newValue = request.getEnabled();
1701       for (MasterProtos.MasterSwitchType masterSwitchType : request.getSwitchTypesList()) {
1702         Admin.MasterSwitchType switchType = convert(masterSwitchType);
1703         boolean oldValue = master.isSplitOrMergeEnabled(switchType);
1704         response.addPrevValue(oldValue);
1705         boolean bypass = false;
1706         if (master.cpHost != null) {
1707           bypass = master.cpHost.preSetSplitOrMergeEnabled(newValue, switchType);
1708         }
1709         if (!bypass) {
1710           master.getSplitOrMergeTracker().setSplitOrMergeEnabled(newValue, switchType);
1711         }
1712         if (master.cpHost != null) {
1713           master.cpHost.postSetSplitOrMergeEnabled(newValue, switchType);
1714         }
1715       }
1716     } catch (IOException e) {
1717       throw new ServiceException(e);
1718     } catch (KeeperException e) {
1719       throw new ServiceException(e);
1720     }
1721     return response.build();
1722   }
1723 
1724   @Override
1725   public MasterProtos.IsSplitOrMergeEnabledResponse isSplitOrMergeEnabled(RpcController controller,
1726     MasterProtos.IsSplitOrMergeEnabledRequest request) throws ServiceException {
1727     MasterProtos.IsSplitOrMergeEnabledResponse.Builder response =
1728             MasterProtos.IsSplitOrMergeEnabledResponse.newBuilder();
1729     response.setEnabled(master.isSplitOrMergeEnabled(convert(request.getSwitchType())));
1730     return response.build();
1731   }
1732 
1733   @Override
1734   public NormalizeResponse normalize(RpcController controller,
1735       NormalizeRequest request) throws ServiceException {
1736     rpcPreCheck("normalize");
1737     try {
1738       return NormalizeResponse.newBuilder().setNormalizerRan(master.normalizeRegions()).build();
1739     } catch (IOException | CoordinatedStateException ex) {
1740       throw new ServiceException(ex);
1741     }
1742   }
1743 
1744   @Override
1745   public SetNormalizerRunningResponse setNormalizerRunning(RpcController controller,
1746       SetNormalizerRunningRequest request) throws ServiceException {
1747     rpcPreCheck("setNormalizerRunning");
1748 
1749     // Sets normalizer on/off flag in ZK.
1750     boolean prevValue = master.getRegionNormalizerTracker().isNormalizerOn();
1751     boolean newValue = request.getOn();
1752     try {
1753       master.getRegionNormalizerTracker().setNormalizerOn(newValue);
1754     } catch (KeeperException ke) {
1755       LOG.warn("Error flipping normalizer switch", ke);
1756     }
1757     LOG.info(master.getClientIdAuditPrefix() + " set normalizerSwitch=" + newValue);
1758     return SetNormalizerRunningResponse.newBuilder().setPrevNormalizerValue(prevValue).build();
1759   }
1760 
1761   @Override
1762   public IsNormalizerEnabledResponse isNormalizerEnabled(RpcController controller,
1763       IsNormalizerEnabledRequest request) throws ServiceException {
1764     IsNormalizerEnabledResponse.Builder response = IsNormalizerEnabledResponse.newBuilder();
1765     response.setEnabled(master.isNormalizerOn());
1766     return response.build();
1767   }
1768 
1769   @Override
1770   public SetQuotaResponse setQuota(RpcController c, SetQuotaRequest req) throws ServiceException {
1771     try {
1772       master.checkInitialized();
1773       return master.getMasterQuotaManager().setQuota(req);
1774     } catch (Exception e) {
1775       throw new ServiceException(e);
1776     }
1777   }
1778 
1779   /**
1780    * Returns the security capabilities in effect on the cluster
1781    */
1782   @Override
1783   public SecurityCapabilitiesResponse getSecurityCapabilities(RpcController controller,
1784       SecurityCapabilitiesRequest request) throws ServiceException {
1785     SecurityCapabilitiesResponse.Builder response = SecurityCapabilitiesResponse.newBuilder();
1786     try {
1787       master.checkInitialized();
1788       Set<Capability> capabilities = new HashSet<>();
1789       // Authentication
1790       if (User.isHBaseSecurityEnabled(master.getConfiguration())) {
1791         capabilities.add(Capability.SECURE_AUTHENTICATION);
1792       } else {
1793         capabilities.add(Capability.SIMPLE_AUTHENTICATION);
1794       }
1795       // The AccessController can provide AUTHORIZATION and CELL_AUTHORIZATION
1796       if (master.cpHost != null &&
1797             master.cpHost.findCoprocessor(AccessController.class.getName()) != null) {
1798         if (AccessChecker.isAuthorizationSupported(master.getConfiguration())) {
1799           capabilities.add(Capability.AUTHORIZATION);
1800         }
1801         if (AccessController.isCellAuthorizationSupported(master.getConfiguration())) {
1802           capabilities.add(Capability.CELL_AUTHORIZATION);
1803         }
1804       }
1805       // The VisibilityController can provide CELL_VISIBILITY
1806       if (master.cpHost != null &&
1807             master.cpHost.findCoprocessor(VisibilityController.class.getName()) != null) {
1808         if (VisibilityController.isCellAuthorizationSupported(master.getConfiguration())) {
1809           capabilities.add(Capability.CELL_VISIBILITY);
1810         }
1811       }
1812       response.addAllCapabilities(capabilities);
1813     } catch (IOException e) {
1814       throw new ServiceException(e);
1815     }
1816     return response.build();
1817   }
1818 
1819   private Admin.MasterSwitchType convert(MasterProtos.MasterSwitchType switchType) {
1820     switch (switchType) {
1821       case SPLIT:
1822         return Admin.MasterSwitchType.SPLIT;
1823       case MERGE:
1824         return Admin.MasterSwitchType.MERGE;
1825       default:
1826         break;
1827     }
1828     return null;
1829   }
1830 
1831   @Override
1832   public GetClusterIdResponse getClusterId(RpcController rpcController, GetClusterIdRequest request)
1833       throws ServiceException {
1834     GetClusterIdResponse.Builder resp = GetClusterIdResponse.newBuilder();
1835     String clusterId = master.getClusterId();
1836     if (clusterId != null) {
1837       resp.setClusterId(clusterId);
1838     }
1839     return resp.build();
1840   }
1841 
1842   @Override
1843   public GetMastersResponse getMasters(RpcController rpcController, GetMastersRequest request)
1844       throws ServiceException {
1845     GetMastersResponse.Builder resp = GetMastersResponse.newBuilder();
1846     // Active master
1847     ServerName serverName = master.getActiveMaster();
1848     if (serverName != null) {
1849       resp.addMasterServers(GetMastersResponseEntry.newBuilder()
1850           .setServerName(ProtobufUtil.toServerName(serverName)).setIsActive(true).build());
1851     }
1852     // Backup masters
1853     for (ServerName backupMaster: master.getBackupMasters()) {
1854       resp.addMasterServers(GetMastersResponseEntry.newBuilder().setServerName(
1855           ProtobufUtil.toServerName(backupMaster)).setIsActive(false).build());
1856     }
1857     return resp.build();
1858   }
1859 
1860   @Override
1861   public GetMetaRegionLocationsResponse getMetaRegionLocations(RpcController rpcController,
1862      GetMetaRegionLocationsRequest request) throws ServiceException {
1863     GetMetaRegionLocationsResponse.Builder response = GetMetaRegionLocationsResponse.newBuilder();
1864     List<HRegionLocation> metaLocations =
1865         master.getMetaRegionLocationCache().getMetaRegionLocations();
1866     for (HRegionLocation location: metaLocations) {
1867       response.addMetaLocations(ProtobufUtil.toRegionLocation(location));
1868     }
1869     return response.build();
1870   }
1871 
1872   @Override
1873   public GetNumLiveRSResponse getNumLiveRS(RpcController rpcController, GetNumLiveRSRequest request)
1874       throws ServiceException {
1875     GetNumLiveRSResponse.Builder response = GetNumLiveRSResponse.newBuilder();
1876     try {
1877       response.setNumRegionServers(master.getNumLiveRegionServers());
1878     } catch (KeeperException ke) {
1879       throw new ServiceException(ke);
1880     }
1881     return response.build();
1882   }
1883 
1884   @Override
1885   public GetTableStateResponse getTableState(RpcController rpcController,
1886     GetTableStateRequest request) throws ServiceException {
1887     final TableStateManager tsm = master.getAssignmentManager().getTableStateManager();
1888     final TableName table = TableName.valueOf(request.getTableName());
1889     final State stateToCheck = request.getIsEnabled() ? State.ENABLED : State.DISABLED;
1890     GetTableStateResponse.Builder resp = GetTableStateResponse.newBuilder();
1891     return resp.setEnabledOrDisabled(tsm.isTableState(table, stateToCheck)).build();
1892   }
1893 }