001: /*
002: * All content copyright (c) 2003-2007 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.l2.ha;
006:
007: import com.tc.l2.state.Enrollment;
008: import com.tc.l2.state.StateManager;
009: import com.tc.logging.TCLogger;
010: import com.tc.logging.TCLogging;
011: import com.tc.net.groups.GroupException;
012: import com.tc.net.groups.GroupManager;
013: import com.tc.net.groups.NodeID;
014: import com.tc.net.groups.ZapNodeRequestProcessor;
015: import com.tc.util.Assert;
016:
017: import java.io.PrintWriter;
018: import java.io.StringWriter;
019:
020: public class L2HAZapNodeRequestProcessor implements
021: ZapNodeRequestProcessor {
022: private static final TCLogger logger = TCLogging
023: .getLogger(L2HAZapNodeRequestProcessor.class);
024:
025: public static final int COMMUNICATION_ERROR = 0x01;
026: public static final int PROGRAM_ERROR = 0x02;
027: public static final int NODE_JOINED_WITH_DIRTY_DB = 0x03;
028: public static final int COMMUNICATION_TO_ACTIVE_ERROR = 0x04;
029: public static final int SPLIT_BRAIN = 0xff;
030:
031: private final TCLogger consoleLogger;
032: private final StateManager stateManager;
033: private final WeightGeneratorFactory factory;
034:
035: private final GroupManager groupManager;
036:
037: public L2HAZapNodeRequestProcessor(TCLogger consoleLogger,
038: StateManager stateManager, GroupManager groupManager,
039: WeightGeneratorFactory factory) {
040: this .consoleLogger = consoleLogger;
041: this .stateManager = stateManager;
042: this .groupManager = groupManager;
043: this .factory = factory;
044: }
045:
046: public boolean acceptOutgoingZapNodeRequest(NodeID nodeID,
047: int zapNodeType, String reason) {
048: assertOnType(zapNodeType, reason);
049: if (stateManager.isActiveCoordinator()
050: || (zapNodeType == COMMUNICATION_TO_ACTIVE_ERROR && nodeID
051: .equals(stateManager.getActiveNodeID()))) {
052: consoleLogger
053: .warn("Requesting node to quit due to the following error\n"
054: + getFormatedError(nodeID, zapNodeType,
055: reason));
056: return true;
057: } else {
058: logger.warn("Not allowing to Zap " + nodeID
059: + " since not in "
060: + StateManager.ACTIVE_COORDINATOR);
061: return false;
062: }
063: }
064:
065: public long[] getCurrentNodeWeights() {
066: Assert.assertTrue(stateManager.isActiveCoordinator());
067: return factory.generateWeightSequence();
068: }
069:
070: private String getFormatedError(NodeID nodeID, int zapNodeType,
071: String reason) {
072: return "NodeID : " + nodeID + " Error Type : "
073: + getErrorTypeString(zapNodeType) + " Details : "
074: + reason;
075: }
076:
077: private String getErrorTypeString(int type) {
078: switch (type) {
079: case COMMUNICATION_ERROR:
080: return "COMMUNICATION ERROR";
081: case COMMUNICATION_TO_ACTIVE_ERROR:
082: return "COMMUNICATION TO ACTIVE SERVER ERROR";
083: case PROGRAM_ERROR:
084: return "PROGRAM ERROR";
085: case NODE_JOINED_WITH_DIRTY_DB:
086: return "Newly Joined Node Contains dirty database. (Please clean up DB and restart node)";
087: case SPLIT_BRAIN:
088: return "SPLIT BRAIN DEDUCTED";
089: default:
090: throw new AssertionError("Unknown type : " + type);
091: }
092: }
093:
094: private void assertOnType(int type, String reason) {
095: switch (type) {
096: case COMMUNICATION_ERROR:
097: case COMMUNICATION_TO_ACTIVE_ERROR:
098: case PROGRAM_ERROR:
099: case NODE_JOINED_WITH_DIRTY_DB:
100: case SPLIT_BRAIN:
101: break;
102: default:
103: throw new AssertionError("Unknown type : " + type
104: + " reason : " + reason);
105: }
106: }
107:
108: public void incomingZapNodeRequest(NodeID nodeID, int zapNodeType,
109: String reason, long[] weights) {
110: assertOnType(zapNodeType, reason);
111: if (stateManager.isActiveCoordinator()) {
112: logger.warn(StateManager.ACTIVE_COORDINATOR
113: + " received Zap Node request from another "
114: + StateManager.ACTIVE_COORDINATOR + "\n"
115: + getFormatedError(nodeID, zapNodeType, reason));
116: handleSplitBrainScenario(nodeID, zapNodeType, reason,
117: weights);
118: } else {
119: NodeID activeNode = stateManager.getActiveNodeID();
120: if (activeNode.isNull() || activeNode.equals(nodeID)) {
121: String message = "Terminating due to Zap request from "
122: + getFormatedError(nodeID, zapNodeType, reason);
123: logger.warn(message);
124: consoleLogger.warn(message);
125: System.exit(zapNodeType);
126: } else {
127: logger
128: .warn("Ignoring Zap Node since it did not come from "
129: + StateManager.ACTIVE_COORDINATOR
130: + " "
131: + activeNode
132: + " but from "
133: + getFormatedError(nodeID, zapNodeType,
134: reason));
135: }
136: }
137: }
138:
139: private void handleSplitBrainScenario(NodeID nodeID,
140: int zapNodeType, String reason, long[] weights) {
141: long myWeights[] = factory.generateWeightSequence();
142: logger.warn("Possible Split Brain scenario : My weights = "
143: + toString(myWeights) + " Other servers weights = "
144: + toString(weights));
145: Enrollment mine;
146: try {
147: mine = new Enrollment(groupManager.getLocalNodeID(), false,
148: myWeights);
149: } catch (GroupException e) {
150: throw new AssertionError(e);
151: }
152: Enrollment hisOrHers = new Enrollment(nodeID, false, weights);
153: if (hisOrHers.wins(mine)) {
154: // The other node has more connected clients, so back off
155: logger.warn(nodeID + " wins : Backing off : Exiting !!!");
156: consoleLogger
157: .warn("Found that "
158: + nodeID
159: + " is active and has more clients connected to it than this server. Exiting ... !!");
160: System.exit(zapNodeType);
161: } else {
162: logger.warn("Not quiting since the other servers weight = "
163: + toString(weights)
164: + " is not greater than my weight = "
165: + toString(myWeights));
166: consoleLogger
167: .warn("Ignoring Quit request from "
168: + nodeID
169: + " since remote servers weight is not greater than local weight");
170: }
171: }
172:
173: private String toString(long[] l) {
174: if (l == null)
175: return "null";
176: if (l.length == 0)
177: return "empty";
178: StringBuffer sb = new StringBuffer();
179: for (int i = 0; i < l.length; i++) {
180: sb.append(String.valueOf(l[i])).append(",");
181: }
182: sb.setLength(sb.length() - 1);
183: return sb.toString();
184: }
185:
186: public static String getErrorString(Throwable t) {
187: StringWriter sw = new StringWriter();
188: sw.write(" : Exception : \n");
189: PrintWriter pw = new PrintWriter(sw);
190: t.printStackTrace(pw);
191: pw.flush();
192: sw.write("\n");
193: return sw.toString();
194: }
195:
196: }
|