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