1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.master.handler;
20
21 import java.io.IOException;
22 import java.io.InterruptedIOException;
23 import java.util.List;
24
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.apache.hadoop.hbase.classification.InterfaceAudience;
28 import org.apache.hadoop.fs.FileSystem;
29 import org.apache.hadoop.fs.Path;
30 import org.apache.hadoop.hbase.HRegionInfo;
31 import org.apache.hadoop.hbase.Server;
32 import org.apache.hadoop.hbase.TableExistsException;
33 import org.apache.hadoop.hbase.TableName;
34 import org.apache.hadoop.hbase.backup.HFileArchiver;
35 import org.apache.hadoop.hbase.catalog.MetaEditor;
36 import org.apache.hadoop.hbase.master.AssignmentManager;
37 import org.apache.hadoop.hbase.master.HMaster;
38 import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
39 import org.apache.hadoop.hbase.master.MasterFileSystem;
40 import org.apache.hadoop.hbase.master.MasterServices;
41 import org.apache.hadoop.hbase.master.RegionState.State;
42 import org.apache.hadoop.hbase.master.RegionStates;
43 import org.apache.hadoop.hbase.regionserver.HRegion;
44 import org.apache.hadoop.hbase.util.FSTableDescriptors;
45 import org.apache.hadoop.hbase.util.FSUtils;
46 import org.apache.hadoop.hbase.util.ModifyRegionUtils;
47 import org.apache.zookeeper.KeeperException;
48
49
50
51
52
53
54
55 @InterfaceAudience.Private
56 public class TruncateTableHandler extends DeleteTableHandler {
57 private static final Log LOG = LogFactory.getLog(TruncateTableHandler.class);
58
59 private final boolean preserveSplits;
60
61 public TruncateTableHandler(final TableName tableName, final Server server,
62 final MasterServices masterServices, boolean preserveSplits) {
63 super(tableName, server, masterServices);
64 this.preserveSplits = preserveSplits;
65 }
66
67 @Override
68 protected void handleTableOperation(List<HRegionInfo> regions)
69 throws IOException, KeeperException {
70 MasterCoprocessorHost cpHost = ((HMaster) this.server).getCoprocessorHost();
71 if (cpHost != null) {
72 cpHost.preTruncateTableHandler(this.tableName);
73 }
74
75
76 waitRegionInTransition(regions);
77
78
79 removeTableData(regions);
80
81
82
83
84
85
86
87 recreateTable(regions);
88
89 if (cpHost != null) {
90 cpHost.postTruncateTableHandler(this.tableName);
91 }
92 }
93
94 private void recreateTable(final List<HRegionInfo> regions) throws IOException {
95 MasterFileSystem mfs = this.masterServices.getMasterFileSystem();
96 Path tempdir = mfs.getTempDir();
97 FileSystem fs = mfs.getFileSystem();
98
99 AssignmentManager assignmentManager = this.masterServices.getAssignmentManager();
100
101
102 checkAndSetEnablingTable(assignmentManager, tableName);
103 try {
104
105 Path tempTableDir = FSUtils.getTableDir(tempdir, this.tableName);
106 new FSTableDescriptors(server.getConfiguration())
107 .createTableDescriptorForTableDirectory(tempTableDir, getTableDescriptor(), false);
108 Path tableDir = FSUtils.getTableDir(mfs.getRootDir(), this.tableName);
109
110 HRegionInfo[] newRegions;
111 if (this.preserveSplits) {
112 newRegions = regions.toArray(new HRegionInfo[regions.size()]);
113 LOG.info("Truncate will preserve " + newRegions.length + " regions");
114 } else {
115 newRegions = new HRegionInfo[1];
116 newRegions[0] = new HRegionInfo(this.tableName, null, null);
117 LOG.info("Truncate will not preserve the regions");
118 }
119
120
121 List<HRegionInfo> regionInfos = ModifyRegionUtils.createRegions(
122 masterServices.getConfiguration(), tempdir,
123 getTableDescriptor(), newRegions, null);
124
125
126 if (!fs.rename(tempTableDir, tableDir)) {
127 throw new IOException("Unable to move table from temp=" + tempTableDir +
128 " to hbase root=" + tableDir);
129 }
130
131
132 MetaEditor.addRegionsToMeta(masterServices.getCatalogTracker(), regionInfos);
133
134
135 ModifyRegionUtils.assignRegions(assignmentManager, regionInfos);
136
137
138 try {
139 assignmentManager.getZKTable().setEnabledTable(tableName);
140 } catch (KeeperException e) {
141 throw new IOException("Unable to ensure that " + tableName + " will be" +
142 " enabled because of a ZooKeeper issue", e);
143 }
144 } catch (IOException e) {
145 removeEnablingTable(assignmentManager, tableName);
146 throw e;
147 }
148 }
149
150 void checkAndSetEnablingTable(final AssignmentManager assignmentManager, final TableName tableName)
151 throws IOException {
152
153
154
155
156
157
158
159
160
161
162 try {
163 if (!assignmentManager.getZKTable().checkAndSetEnablingTable(tableName)) {
164 throw new TableExistsException(tableName);
165 }
166 } catch (KeeperException e) {
167 throw new IOException("Unable to ensure that the table will be"
168 + " enabling because of a ZooKeeper issue", e);
169 }
170 }
171
172 void removeEnablingTable(final AssignmentManager assignmentManager, final TableName tableName) {
173
174
175
176
177 try {
178 assignmentManager.getZKTable().removeEnablingTable(tableName, false);
179 } catch (KeeperException e) {
180
181 LOG.error("Got a keeper exception while removing the ENABLING table znode " + tableName, e);
182 }
183 }
184
185
186
187
188 void removeTableData(final List<HRegionInfo> regions) throws IOException, KeeperException {
189
190 LOG.debug("Deleting regions from META");
191 MetaEditor.deleteRegions(this.server.getCatalogTracker(), regions);
192
193
194
195
196
197
198
199 MasterFileSystem mfs = this.masterServices.getMasterFileSystem();
200 Path tempTableDir = mfs.moveTableToTemp(tableName);
201
202
203 FileSystem fs = mfs.getFileSystem();
204 for (HRegionInfo hri : regions) {
205 LOG.debug("Archiving region " + hri.getRegionNameAsString() + " from FS");
206 HFileArchiver.archiveRegion(fs, mfs.getRootDir(), tempTableDir,
207 HRegion.getRegionDir(tempTableDir, hri.getEncodedName()));
208 }
209
210
211 if (!fs.delete(tempTableDir, true)) {
212 LOG.error("Couldn't delete " + tempTableDir);
213 }
214
215 LOG.debug("Table '" + tableName + "' archived!");
216 }
217
218 void waitRegionInTransition(final List<HRegionInfo> regions) throws IOException {
219 AssignmentManager am = this.masterServices.getAssignmentManager();
220 RegionStates states = am.getRegionStates();
221 long waitTime = server.getConfiguration().getLong("hbase.master.wait.on.region", 5 * 60 * 1000);
222 for (HRegionInfo region : regions) {
223 long done = System.currentTimeMillis() + waitTime;
224 while (System.currentTimeMillis() < done) {
225 if (states.isRegionInState(region, State.FAILED_OPEN)) {
226 am.regionOffline(region);
227 }
228 if (!states.isRegionInTransition(region)) {
229 break;
230 }
231 try {
232 Thread.sleep(waitingTimeForEvents);
233 } catch (InterruptedException e) {
234 LOG.warn("Interrupted while sleeping");
235 throw (InterruptedIOException) new InterruptedIOException().initCause(e);
236 }
237 LOG.debug("Waiting on region to clear regions in transition; "
238 + am.getRegionStates().getRegionTransitionState(region));
239 }
240 if (states.isRegionInTransition(region)) {
241 throw new IOException("Waited hbase.master.wait.on.region (" + waitTime
242 + "ms) for region to leave region " + region.getRegionNameAsString()
243 + " in transitions");
244 }
245 }
246 }
247 }