From 6e77b7eefd54068280e5d1a5dd60470b3b341942 Mon Sep 17 00:00:00 2001 From: Michael Stack Date: Fri, 18 May 2012 18:18:20 +0000 Subject: [PATCH] HBASE-5926 Delete the master znode after a master crash git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1340200 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/hadoop/hbase/ZNodeClearer.java | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 src/main/java/org/apache/hadoop/hbase/ZNodeClearer.java diff --git a/src/main/java/org/apache/hadoop/hbase/ZNodeClearer.java b/src/main/java/org/apache/hadoop/hbase/ZNodeClearer.java new file mode 100644 index 00000000000..de2e25d95fd --- /dev/null +++ b/src/main/java/org/apache/hadoop/hbase/ZNodeClearer.java @@ -0,0 +1,152 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hbase; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.zookeeper.MasterAddressTracker; +import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; + +/** + *

Contains a set of methods for the collaboration between the start/stop scripts and the + * servers. It allows to delete immediately the znode when the master or the regions server crashes. + * The region server / master writes a specific file when it starts / becomes main master. When they + * end properly, they delete the file.

+ *

In the script, we check for the existence of these files when the program ends. If they still + * exist we conclude that the server crashed, likely without deleting their znode. To have a faster + * recovery we delete immediately the znode.

+ *

The strategy depends on the server type. For a region server we store the znode path in the + * file, and use it to delete it. for a master, as the znode path constant whatever the server, we + * check its content to make sure that the backup server is not now in charge.

+ */ +public class ZNodeClearer { + public static final Log LOG = LogFactory.getLog(ZNodeClearer.class); + + private ZNodeClearer() {} + + /** + * Logs the errors without failing on exception. + */ + public static void writeMyEphemeralNodeOnDisk(String fileContent) { + String fileName = ZNodeClearer.getMyEphemeralNodeFileName(); + + if (fileName == null) { + LOG.warn("No filename given to save the znode used, it won't be saved " + + "(Environment variable HBASE_ZNODE_FILE is not set)."); + return; + } + + FileWriter fstream; + try { + fstream = new FileWriter(fileName); + } catch (IOException e) { + LOG.warn("Can't write znode file "+fileName, e); + return; + } + + BufferedWriter out = new BufferedWriter(fstream); + + try { + try { + out.write(fileContent + "\n"); + } finally { + try { + out.close(); + } finally { + fstream.close(); + } + } + } catch (IOException e) { + LOG.warn("Can't write znode file "+fileName, e); + } + } + + /** + * read the content of znode file, expects a single line. + */ + public static String readMyEphemeralNodeOnDisk() throws IOException { + String fileName = getMyEphemeralNodeFileName(); + if (fileName == null){ + throw new IOException("No filename"); + } + FileReader znodeFile = new FileReader(fileName); + BufferedReader br = new BufferedReader(znodeFile); + String file_content = br.readLine(); + br.close(); + return file_content; + } + + /** + * Get the name of the file used to store the znode contents + */ + public static String getMyEphemeralNodeFileName() { + return System.getenv().get("HBASE_ZNODE_FILE"); + } + + /** + * delete the znode file + */ + public static void deleteMyEphemeralNodeOnDisk() { + String fileName = getMyEphemeralNodeFileName(); + + if (fileName != null) { + new File(fileName).delete(); + } + } + + /** + * Delete the master znode if its content (ServerName string) is the same + * as the one in the znode file. (env: HBASE_ZNODE_FILE). + * @return true on successful deletion, false otherwise. + */ + public static boolean clear(Configuration conf) { + Configuration tempConf = new Configuration(conf); + tempConf.setInt("zookeeper.recovery.retry", 0); + + ZooKeeperWatcher zkw; + try { + zkw = new ZooKeeperWatcher(tempConf, "clean znode for master", + new Abortable() { + @Override public void abort(String why, Throwable e) {} + @Override public boolean isAborted() { return false; } + }); + } catch (IOException e) { + LOG.warn("Can't connect to zookeeper to read the master znode", e); + return false; + } + + String znodeFileContent; + try { + znodeFileContent = ZNodeClearer.readMyEphemeralNodeOnDisk(); + } catch (IOException e) { + LOG.warn("Can't read the content of the znode file", e); + return false; + } + + return MasterAddressTracker.deleteIfEquals(zkw, znodeFileContent); + } +}