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