View Javadoc

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