001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 package org.apache.hadoop.hdfs.server.namenode;
020
021 import java.io.IOException;
022 import org.apache.hadoop.classification.InterfaceAudience;
023 import org.apache.hadoop.classification.InterfaceStability;
024
025 import org.apache.commons.logging.Log;
026 import org.apache.commons.logging.LogFactory;
027
028 /** Context data for an ongoing NameNode metadata recovery process. */
029 @InterfaceAudience.Private
030 @InterfaceStability.Evolving
031 public final class MetaRecoveryContext {
032 public static final Log LOG = LogFactory.getLog(MetaRecoveryContext.class.getName());
033 public final static int FORCE_NONE = 0;
034 public final static int FORCE_FIRST_CHOICE = 1;
035 public final static int FORCE_ALL = 2;
036 private int force;
037
038 /** Exception thrown when the user has requested processing to stop. */
039 static public class RequestStopException extends IOException {
040 private static final long serialVersionUID = 1L;
041 public RequestStopException(String msg) {
042 super(msg);
043 }
044 }
045
046 public MetaRecoveryContext(int force) {
047 this.force = force;
048 }
049
050 /**
051 * Display a prompt to the user and get his or her choice.
052 *
053 * @param prompt The prompt to display
054 * @param default First choice (will be taken if autoChooseDefault is
055 * true)
056 * @param choices Other choies
057 *
058 * @return The choice that was taken
059 * @throws IOException
060 */
061 public String ask(String prompt, String firstChoice, String... choices)
062 throws IOException {
063 while (true) {
064 LOG.info(prompt);
065 if (force > FORCE_NONE) {
066 LOG.info("automatically choosing " + firstChoice);
067 return firstChoice;
068 }
069 StringBuilder responseBuilder = new StringBuilder();
070 while (true) {
071 int c = System.in.read();
072 if (c == -1 || c == '\r' || c == '\n') {
073 break;
074 }
075 responseBuilder.append((char)c);
076 }
077 String response = responseBuilder.toString();
078 if (response.equalsIgnoreCase(firstChoice))
079 return firstChoice;
080 for (String c : choices) {
081 if (response.equalsIgnoreCase(c)) {
082 return c;
083 }
084 }
085 LOG.error("I'm sorry, I cannot understand your response.\n");
086 }
087 }
088
089 public static void editLogLoaderPrompt(String prompt,
090 MetaRecoveryContext recovery, String contStr)
091 throws IOException, RequestStopException
092 {
093 if (recovery == null) {
094 throw new IOException(prompt);
095 }
096 LOG.error(prompt);
097 String answer = recovery.ask("\nEnter 'c' to continue, " + contStr + "\n" +
098 "Enter 's' to stop reading the edit log here, abandoning any later " +
099 "edits\n" +
100 "Enter 'q' to quit without saving\n" +
101 "Enter 'a' to always select the first choice in the future " +
102 "without prompting. " +
103 "(c/s/q/a)\n", "c", "s", "q", "a");
104 if (answer.equals("c")) {
105 LOG.info("Continuing");
106 return;
107 } else if (answer.equals("s")) {
108 throw new RequestStopException("user requested stop");
109 } else if (answer.equals("q")) {
110 recovery.quit();
111 } else {
112 recovery.setForce(FORCE_FIRST_CHOICE);
113 return;
114 }
115 }
116
117 /** Log a message and quit */
118 public void quit() {
119 LOG.error("Exiting on user request.");
120 System.exit(0);
121 }
122
123 public int getForce() {
124 return this.force;
125 }
126
127 public void setForce(int force) {
128 this.force = force;
129 }
130 }