View Javadoc

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