1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.migration;
19
20 import java.io.IOException;
21 import java.util.List;
22
23 import org.apache.commons.cli.CommandLine;
24 import org.apache.commons.cli.CommandLineParser;
25 import org.apache.commons.cli.GnuParser;
26 import org.apache.commons.cli.HelpFormatter;
27 import org.apache.commons.cli.Option;
28 import org.apache.commons.cli.Options;
29 import org.apache.commons.cli.ParseException;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.hadoop.conf.Configured;
33 import org.apache.hadoop.fs.FileStatus;
34 import org.apache.hadoop.fs.FileSystem;
35 import org.apache.hadoop.fs.Path;
36 import org.apache.hadoop.hbase.Abortable;
37 import org.apache.hadoop.hbase.HBaseConfiguration;
38 import org.apache.hadoop.hbase.HConstants;
39 import org.apache.hadoop.hbase.wal.WALFactory;
40 import org.apache.hadoop.hbase.wal.WALSplitter;
41 import org.apache.hadoop.hbase.util.Bytes;
42 import org.apache.hadoop.hbase.util.FSUtils;
43 import org.apache.hadoop.hbase.util.HFileV1Detector;
44 import org.apache.hadoop.hbase.util.ZKDataMigrator;
45 import org.apache.hadoop.hbase.zookeeper.ZKUtil;
46 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
47 import org.apache.hadoop.util.Tool;
48 import org.apache.hadoop.util.ToolRunner;
49
50 public class UpgradeTo96 extends Configured implements Tool {
51 private static final Log LOG = LogFactory.getLog(UpgradeTo96.class);
52
53 private Options options = new Options();
54
55
56
57 private boolean upgrade;
58
59
60
61 private boolean checkForHFileV1;
62
63
64
65 private String dirToCheckForHFileV1;
66
67 UpgradeTo96() {
68 setOptions();
69 }
70
71 private void setOptions() {
72 options.addOption("h", "help", false, "Help");
73 options.addOption(new Option("check", false, "Run upgrade check; looks for HFileV1 "
74 + " under ${hbase.rootdir} or provided 'dir' directory."));
75 options.addOption(new Option("execute", false, "Run upgrade; zk and hdfs must be up, hbase down"));
76 Option pathOption = new Option("dir", true,
77 "Relative path of dir to check for HFileV1s.");
78 pathOption.setRequired(false);
79 options.addOption(pathOption);
80 }
81
82 private boolean parseOption(String[] args) throws ParseException {
83 if (args.length == 0) return false;
84
85 CommandLineParser parser = new GnuParser();
86 CommandLine cmd = parser.parse(options, args);
87 if (cmd.hasOption("h")) {
88 return false;
89 }
90 if (cmd.hasOption("execute")) upgrade = true;
91 if (cmd.hasOption("check")) checkForHFileV1 = true;
92 if (checkForHFileV1 && cmd.hasOption("dir")) {
93 this.dirToCheckForHFileV1 = cmd.getOptionValue("dir");
94 }
95 return true;
96 }
97
98 private void printUsage() {
99 HelpFormatter formatter = new HelpFormatter();
100 formatter.printHelp("$bin/hbase upgrade -check [-dir DIR]|-execute", options);
101 System.out.println("Read http://hbase.apache.org/book.html#upgrade0.96 before attempting upgrade");
102 System.out.println();
103 System.out.println("Example usage:");
104 System.out.println();
105 System.out.println("Run upgrade check; looks for HFileV1s under ${hbase.rootdir}:");
106 System.out.println(" $ bin/hbase upgrade -check");
107 System.out.println();
108 System.out.println("Run the upgrade: ");
109 System.out.println(" $ bin/hbase upgrade -execute");
110 }
111
112 @Override
113 public int run(String[] args) throws Exception {
114 if (!parseOption(args)) {
115 printUsage();
116 return -1;
117 }
118 if (checkForHFileV1) {
119 int res = doHFileV1Check();
120 if (res == 0) LOG.info("No HFileV1 found.");
121 else {
122 LOG.warn("There are some HFileV1, or corrupt files (files with incorrect major version).");
123 }
124 return res;
125 }
126
127
128 else if (upgrade) {
129 if (isAnyHBaseProcessAlive()) {
130 LOG.error("Some HBase processes are still alive, or znodes not expired yet. "
131 + "Please stop them before upgrade or try after some time.");
132 throw new IOException("Some HBase processes are still alive, or znodes not expired yet");
133 }
134 return executeUpgrade();
135 }
136 return -1;
137 }
138
139 private boolean isAnyHBaseProcessAlive() throws IOException {
140 ZooKeeperWatcher zkw = null;
141 try {
142 zkw = new ZooKeeperWatcher(getConf(), "Check Live Processes.", new Abortable() {
143 private boolean aborted = false;
144
145 @Override
146 public void abort(String why, Throwable e) {
147 LOG.warn("Got aborted with reason: " + why + ", and error: " + e);
148 this.aborted = true;
149 }
150
151 @Override
152 public boolean isAborted() {
153 return this.aborted;
154 }
155
156 });
157 boolean liveProcessesExists = false;
158 if (ZKUtil.checkExists(zkw, zkw.baseZNode) == -1) {
159 return false;
160 }
161 if (ZKUtil.checkExists(zkw, zkw.backupMasterAddressesZNode) != -1) {
162 List<String> backupMasters = ZKUtil
163 .listChildrenNoWatch(zkw, zkw.backupMasterAddressesZNode);
164 if (!backupMasters.isEmpty()) {
165 LOG.warn("Backup master(s) " + backupMasters
166 + " are alive or backup-master znodes not expired.");
167 liveProcessesExists = true;
168 }
169 }
170 if (ZKUtil.checkExists(zkw, zkw.rsZNode) != -1) {
171 List<String> regionServers = ZKUtil.listChildrenNoWatch(zkw, zkw.rsZNode);
172 if (!regionServers.isEmpty()) {
173 LOG.warn("Region server(s) " + regionServers + " are alive or rs znodes not expired.");
174 liveProcessesExists = true;
175 }
176 }
177 if (ZKUtil.checkExists(zkw, zkw.getMasterAddressZNode()) != -1) {
178 byte[] data = ZKUtil.getData(zkw, zkw.getMasterAddressZNode());
179 if (data != null && !Bytes.equals(data, HConstants.EMPTY_BYTE_ARRAY)) {
180 LOG.warn("Active master at address " + Bytes.toString(data)
181 + " is still alive or master znode not expired.");
182 liveProcessesExists = true;
183 }
184 }
185 return liveProcessesExists;
186 } catch (Exception e) {
187 LOG.error("Got exception while checking live hbase processes", e);
188 throw new IOException(e);
189 } finally {
190 if (zkw != null) {
191 zkw.close();
192 }
193 }
194 }
195
196 private int doHFileV1Check() throws Exception {
197 String[] args = null;
198 if (dirToCheckForHFileV1 != null) args = new String[] { "-p" + dirToCheckForHFileV1 };
199 return ToolRunner.run(getConf(), new HFileV1Detector(), args);
200 }
201
202
203
204
205
206
207
208
209
210
211 private int executeUpgrade() throws Exception {
212 executeTool("Namespace upgrade", new NamespaceUpgrade(),
213 new String[] { "--upgrade" }, 0);
214 executeTool("Znode upgrade", new ZKDataMigrator(), null, 0);
215 doOfflineLogSplitting();
216 return 0;
217 }
218
219 private void executeTool(String toolMessage, Tool tool, String[] args, int expectedResult)
220 throws Exception {
221 LOG.info("Starting " + toolMessage);
222 int res = ToolRunner.run(getConf(), tool, new String[] { "--upgrade" });
223 if (res != expectedResult) {
224 LOG.error(toolMessage + "returned " + res + ", expected " + expectedResult);
225 throw new Exception("Unexpected return code from " + toolMessage);
226 }
227 LOG.info("Successfully completed " + toolMessage);
228 }
229
230
231
232
233
234 private void doOfflineLogSplitting() throws Exception {
235 LOG.info("Starting Log splitting");
236 final Path rootDir = FSUtils.getRootDir(getConf());
237 final Path oldLogDir = new Path(rootDir, HConstants.HREGION_OLDLOGDIR_NAME);
238
239 final WALFactory factory = WALFactory.getInstance(getConf());
240 FileSystem fs = FSUtils.getCurrentFileSystem(getConf());
241 Path logDir = new Path(rootDir, HConstants.HREGION_LOGDIR_NAME);
242 FileStatus[] regionServerLogDirs = FSUtils.listStatus(fs, logDir);
243 if (regionServerLogDirs == null || regionServerLogDirs.length == 0) {
244 LOG.info("No log directories to split, returning");
245 return;
246 }
247 try {
248 for (FileStatus regionServerLogDir : regionServerLogDirs) {
249
250 WALSplitter.split(rootDir, regionServerLogDir.getPath(), oldLogDir, fs, getConf(), factory);
251 }
252 LOG.info("Successfully completed Log splitting");
253 } catch (Exception e) {
254 LOG.error("Got exception while doing Log splitting ", e);
255 throw e;
256 }
257 }
258
259 public static void main(String[] args) throws Exception {
260 System.exit(ToolRunner.run(HBaseConfiguration.create(), new UpgradeTo96(), args));
261 }
262 }