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