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