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