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  
20  package org.apache.hadoop.hbase.master.snapshot;
21  
22  import java.io.IOException;
23  import java.util.List;
24  import java.util.concurrent.CancellationException;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.hadoop.classification.InterfaceAudience;
29  import org.apache.hadoop.fs.FileSystem;
30  import org.apache.hadoop.fs.Path;
31  import org.apache.hadoop.hbase.HRegionInfo;
32  import org.apache.hadoop.hbase.HTableDescriptor;
33  import org.apache.hadoop.hbase.NotAllMetaRegionsOnlineException;
34  import org.apache.hadoop.hbase.TableExistsException;
35  import org.apache.hadoop.hbase.catalog.MetaReader;
36  import org.apache.hadoop.hbase.catalog.CatalogTracker;
37  import org.apache.hadoop.hbase.errorhandling.ForeignException;
38  import org.apache.hadoop.hbase.errorhandling.ForeignExceptionDispatcher;
39  import org.apache.hadoop.hbase.master.MasterServices;
40  import org.apache.hadoop.hbase.master.SnapshotSentinel;
41  import org.apache.hadoop.hbase.master.handler.CreateTableHandler;
42  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
43  import org.apache.hadoop.hbase.snapshot.RestoreSnapshotException;
44  import org.apache.hadoop.hbase.snapshot.RestoreSnapshotHelper;
45  import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
46  import org.apache.hadoop.hbase.util.Bytes;
47  
48  import com.google.common.base.Preconditions;
49  
50  /**
51   * Handler to Clone a snapshot.
52   *
53   * <p>Uses {@link RestoreSnapshotHelper} to create a new table with the same
54   * content of the specified snapshot.
55   */
56  @InterfaceAudience.Private
57  public class CloneSnapshotHandler extends CreateTableHandler implements SnapshotSentinel {
58    private static final Log LOG = LogFactory.getLog(CloneSnapshotHandler.class);
59  
60    private final static String NAME = "Master CloneSnapshotHandler";
61  
62    private final SnapshotDescription snapshot;
63  
64    private final ForeignExceptionDispatcher monitor;
65  
66    private RestoreSnapshotHelper.RestoreMetaChanges metaChanges;
67  
68    private volatile boolean stopped = false;
69  
70    public CloneSnapshotHandler(final MasterServices masterServices,
71        final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
72        throws NotAllMetaRegionsOnlineException, TableExistsException, IOException {
73      super(masterServices, masterServices.getMasterFileSystem(), 
74        masterServices.getServerManager(), hTableDescriptor,
75        masterServices.getConfiguration(), null, masterServices.getCatalogTracker(),
76        masterServices.getAssignmentManager());
77  
78      // Snapshot information
79      this.snapshot = snapshot;
80  
81      // Monitor
82      this.monitor = new ForeignExceptionDispatcher();
83    }
84  
85    /**
86     * Create the on-disk regions, using the tableRootDir provided by the CreateTableHandler.
87     * The cloned table will be created in a temp directory, and then the CreateTableHandler
88     * will be responsible to add the regions returned by this method to META and do the assignment.
89     */
90    @Override
91    protected List<HRegionInfo> handleCreateHdfsRegions(final Path tableRootDir, final String tableName)
92        throws IOException {
93      FileSystem fs = fileSystemManager.getFileSystem();
94      Path rootDir = fileSystemManager.getRootDir();
95      Path tableDir = new Path(tableRootDir, tableName);
96  
97      try {
98        // 1. Execute the on-disk Clone
99        Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshot, rootDir);
100       RestoreSnapshotHelper restoreHelper = new RestoreSnapshotHelper(conf, fs,
101           snapshot, snapshotDir, hTableDescriptor, tableDir, monitor);
102       metaChanges = restoreHelper.restoreHdfsRegions();
103 
104       // Clone operation should not have stuff to restore or remove
105       Preconditions.checkArgument(!metaChanges.hasRegionsToRestore(),
106           "A clone should not have regions to restore");
107       Preconditions.checkArgument(!metaChanges.hasRegionsToRemove(),
108           "A clone should not have regions to remove");
109 
110       // At this point the clone is complete. Next step is enabling the table.
111       LOG.info("Clone snapshot=" + snapshot.getName() + " on table=" + tableName + " completed!");
112 
113       // 2. let the CreateTableHandler add the regions to meta
114       return metaChanges.getRegionsToAdd();
115     } catch (Exception e) {
116       String msg = "clone snapshot=" + SnapshotDescriptionUtils.toString(snapshot) + " failed";
117       LOG.error(msg, e);
118       IOException rse = new RestoreSnapshotException(msg, e, snapshot);
119 
120       // these handlers aren't futures so we need to register the error here.
121       this.monitor.receive(new ForeignException(NAME, rse));
122       throw rse;
123     }
124   }
125 
126   @Override
127   protected void addRegionsToMeta(final CatalogTracker ct, final List<HRegionInfo> regionInfos)
128       throws IOException {
129     super.addRegionsToMeta(ct, regionInfos);
130     metaChanges.updateMetaParentRegions(ct, regionInfos);
131   }
132 
133   @Override
134   protected void completed(final Throwable exception) {
135     this.stopped = true;
136   }
137 
138   @Override
139   public boolean isFinished() {
140     return this.stopped;
141   }
142 
143   @Override
144   public SnapshotDescription getSnapshot() {
145     return snapshot;
146   }
147 
148   @Override
149   public void cancel(String why) {
150     if (this.stopped) return;
151     this.stopped = true;
152     LOG.info("Stopping clone snapshot=" + snapshot + " because: " + why);
153     this.monitor.receive(new ForeignException(NAME, new CancellationException(why)));
154   }
155 
156   @Override
157   public ForeignException getExceptionIfFailed() {
158     return this.monitor.getException();
159   }
160 }