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