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