1 /*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2002,2008 Oracle and/or its affiliates. All rights reserved. 5 * 6 */ 7 8 package com.sleepycat.je.rep.impl; 9 10 import java.io.Serializable; 11 import java.net.InetSocketAddress; 12 13 import com.sleepycat.je.EnvironmentFailureException; 14 import com.sleepycat.je.JEVersion; 15 import com.sleepycat.je.rep.NodeType; 16 import com.sleepycat.je.rep.ReplicationConfig; 17 import com.sleepycat.je.rep.ReplicationNode; 18 import com.sleepycat.je.rep.impl.RepGroupImpl.BarrierState; 19 import com.sleepycat.je.rep.impl.node.NameIdPair; 20 import com.sleepycat.je.rep.stream.Protocol; 21 import com.sleepycat.je.rep.utilint.HostPortPair; 22 import com.sleepycat.je.utilint.VLSN; 23 24 /** 25 * Describes a node that is a member of the replication group. 26 */ 27 public class RepNodeImpl implements ReplicationNode, Serializable { 28 29 private static final long serialVersionUID = 1L; 30 31 /* Identifies the node both by external name and internal node ID. */ 32 private final NameIdPair nameIdPair; 33 34 /* The node type, electable, monitor, etc. */ 35 private final NodeType type; 36 37 /* 38 * True if the node was acknowledged by a quorum and its entry is therefore 39 * considered durable. SECONDARY nodes are always considered acknowledged. 40 */ 41 private boolean quorumAck; 42 43 /* 44 * True if the node has been removed and is no longer an active part of the 45 * group 46 */ 47 private boolean isRemoved; 48 49 /* The hostname used for communications with the node. */ 50 private String hostName; 51 52 /* The port used by a node. */ 53 private int port; 54 55 /* The Cleaner Barrier state associated with the node. */ 56 private BarrierState barrierState; 57 58 /* 59 * This version is used in conjunction with the group level change 60 * version to identify the incremental changes made to individual 61 * changes made to a group. 62 */ 63 private int changeVersion = NULL_CHANGE; 64 65 private static final int NULL_CHANGE = -1; 66 67 /** 68 * The JE version most recently noted running on this node, or null if not 69 * known. 70 */ 71 private volatile JEVersion jeVersion; 72 73 /** 74 * @hidden 75 * 76 * Constructor used to de-serialize a Node. All other convenience 77 * constructors funnel through this one so that argument checks can 78 * be systematically enforced. 79 */ RepNodeImpl(final NameIdPair nameIdPair, final NodeType type, final boolean quorumAck, final boolean isRemoved, final String hostName, final int port, final BarrierState barrierState, final int changeVersion, final JEVersion jeVersion)80 public RepNodeImpl(final NameIdPair nameIdPair, 81 final NodeType type, 82 final boolean quorumAck, 83 final boolean isRemoved, 84 final String hostName, 85 final int port, 86 final BarrierState barrierState, 87 final int changeVersion, 88 final JEVersion jeVersion) { 89 90 if (nameIdPair.getName().equals(RepGroupDB.GROUP_KEY)) { 91 throw EnvironmentFailureException.unexpectedState 92 ("Member node ID is the reserved key value: " + nameIdPair); 93 } 94 95 if (hostName == null) { 96 throw EnvironmentFailureException.unexpectedState 97 ("The hostname argument must not be null"); 98 } 99 100 if (type == null) { 101 throw EnvironmentFailureException.unexpectedState 102 ("The nodeType argument must not be null"); 103 } 104 105 this.nameIdPair = nameIdPair; 106 this.type = type; 107 this.quorumAck = quorumAck || type.isSecondary(); 108 this.isRemoved = isRemoved; 109 this.hostName = hostName; 110 this.port = port; 111 this.barrierState = barrierState; 112 this.changeVersion = changeVersion; 113 this.jeVersion = jeVersion; 114 } 115 116 /** 117 * @hidden 118 * 119 * Convenience constructor for the above. 120 */ RepNodeImpl(final NameIdPair nameIdPair, final NodeType type, final boolean quorumAck, final boolean isRemoved, final String hostName, final int port, final int changeVersion, final JEVersion jeVersion)121 public RepNodeImpl(final NameIdPair nameIdPair, 122 final NodeType type, 123 final boolean quorumAck, 124 final boolean isRemoved, 125 final String hostName, 126 final int port, 127 final int changeVersion, 128 final JEVersion jeVersion) { 129 this(nameIdPair, type, quorumAck, isRemoved, hostName, port, 130 new BarrierState(VLSN.NULL_VLSN, System.currentTimeMillis()), 131 changeVersion, jeVersion); 132 } 133 134 /** 135 * @hidden 136 * Convenience constructor for transient nodes 137 */ RepNodeImpl(final NameIdPair nameIdPair, final NodeType type, final String hostName, final int port, final JEVersion jeVersion)138 public RepNodeImpl(final NameIdPair nameIdPair, 139 final NodeType type, 140 final String hostName, 141 final int port, 142 final JEVersion jeVersion) { 143 this(nameIdPair, type, false, false, hostName, port, NULL_CHANGE, 144 jeVersion); 145 } 146 147 /** 148 * @hidden 149 * Convenience constructor for transient nodes during unit tests. 150 */ RepNodeImpl(final ReplicationConfig repConfig)151 public RepNodeImpl(final ReplicationConfig repConfig) { 152 this(new NameIdPair(repConfig.getNodeName(), NameIdPair.NULL_NODE_ID), 153 repConfig.getNodeType(), 154 repConfig.getNodeHostname(), 155 repConfig.getNodePort(), 156 JEVersion.CURRENT_VERSION); 157 } 158 159 /** 160 * @hidden 161 * 162 * Convenience constructor for the above. 163 */ RepNodeImpl(final String nodeName, final String hostName, final int port, final JEVersion jeVersion)164 public RepNodeImpl(final String nodeName, 165 final String hostName, 166 final int port, 167 final JEVersion jeVersion) { 168 this(new NameIdPair(nodeName, NameIdPair.NULL.getId()), 169 NodeType.ELECTABLE, hostName, port, jeVersion); 170 } 171 172 /** 173 * @hidden 174 * 175 * Convenience constructor for the above. 176 */ RepNodeImpl(Protocol.NodeGroupInfo mi)177 public RepNodeImpl(Protocol.NodeGroupInfo mi) { 178 this(mi.getNameIdPair(), 179 mi.getNodeType(), 180 mi.getHostName(), 181 mi.port(), 182 mi.getJEVersion()); 183 } 184 185 /* (non-Javadoc) 186 * @see com.sleepycat.je.rep.ReplicationNode#getSocketAddress() 187 */ 188 @Override getSocketAddress()189 public InetSocketAddress getSocketAddress() { 190 return new InetSocketAddress(hostName, port); 191 } 192 193 /** 194 * Returns whether the node was acknowledged by a quorum and its entry is 195 * therefore considered durable. Secondary nodes are always considered 196 * acknowledged. 197 */ isQuorumAck()198 public boolean isQuorumAck() { 199 return quorumAck; 200 } 201 isRemoved()202 public boolean isRemoved() { 203 assert !(isRemoved && type.isSecondary()) 204 : "Secondary nodes are never marked removed"; 205 return isRemoved; 206 } 207 setChangeVersion(int changeVersion)208 public void setChangeVersion(int changeVersion) { 209 this.changeVersion = changeVersion; 210 } 211 getChangeVersion()212 public int getChangeVersion() { 213 return changeVersion; 214 } 215 getNameIdPair()216 public NameIdPair getNameIdPair() { 217 return nameIdPair; 218 } 219 220 /* (non-Javadoc) 221 * @see com.sleepycat.je.rep.ReplicationNode#getName() 222 */ 223 @Override getName()224 public String getName() { 225 return nameIdPair.getName(); 226 } 227 getNodeId()228 public int getNodeId() { 229 return nameIdPair.getId(); 230 } 231 232 /* (non-Javadoc) 233 * @see com.sleepycat.je.rep.ReplicationNode#getNodeType() 234 */ 235 @Override getType()236 public NodeType getType() { 237 return type; 238 } 239 240 /* (non-Javadoc) 241 * @see com.sleepycat.je.rep.ReplicationNode#getHostName() 242 */ 243 @Override getHostName()244 public String getHostName() { 245 return hostName; 246 } 247 setHostName(String hostName)248 public void setHostName(String hostName) { 249 this.hostName = hostName; 250 } 251 252 /* (non-Javadoc) 253 * @see com.sleepycat.je.rep.ReplicationNode#getPort() 254 */ 255 @Override getPort()256 public int getPort() { 257 return port; 258 } 259 setPort(int port)260 public void setPort(int port) { 261 this.port = port; 262 } 263 getHostPortPair()264 public String getHostPortPair() { 265 return HostPortPair.getString(hostName, port); 266 } 267 getBarrierState()268 public BarrierState getBarrierState() { 269 return barrierState; 270 } 271 setBarrierState(BarrierState barrierState)272 public BarrierState setBarrierState(BarrierState barrierState) { 273 return this.barrierState = barrierState; 274 } 275 setQuorumAck(boolean quorumAck)276 public void setQuorumAck(boolean quorumAck) { 277 this.quorumAck = quorumAck; 278 } 279 setRemoved(boolean isRemoved)280 public void setRemoved(boolean isRemoved) { 281 this.isRemoved = isRemoved; 282 } 283 284 /** 285 * Returns the JE Version most recently noted running on this node, or 286 * {@code null} if not known. 287 */ getJEVersion()288 public JEVersion getJEVersion() { 289 return jeVersion; 290 } 291 292 /** 293 * Updates the JE version most recently known running on this node to match 294 * the version specified. Does nothing if the argument is null. 295 * 296 * @param otherJEVersion the version or {@code null} 297 */ updateJEVersion(final JEVersion otherJEVersion)298 public void updateJEVersion(final JEVersion otherJEVersion) { 299 if (otherJEVersion != null) { 300 jeVersion = otherJEVersion; 301 } 302 } 303 304 @Override toString()305 public String toString() { 306 307 String acked = " (is member)"; 308 309 if (!quorumAck) { 310 acked = " (not yet a durable member)"; 311 } 312 313 if (isRemoved) { 314 acked = " (is removed)"; 315 } 316 317 String info = 318 String.format("Node:%s %s:%d%s%s changeVersion:%d %s%s\n", 319 getName(), getHostName(), getPort(), 320 acked, 321 (!type.isElectable() ? " " + type : ""), 322 getChangeVersion(), 323 barrierState, 324 ((jeVersion != null) ? 325 " jeVersion:" + jeVersion : 326 "")); 327 return info; 328 329 } 330 331 /** 332 * Checks if the argument represents the same node, ignoring fields that 333 * might legitimately vary over time. Like the equals method, considers 334 * all fields, except ignores the quorumAck field (which may change 335 * temporarily), the nodeId (since it may not have been resolved as yet), 336 * and the isRemoved, barrierState, changeVersion, and jeVersion fields 337 * (which can change over time). 338 * 339 * @param mi the other object in the comparison 340 * 341 * @return true if the two are equivalent 342 */ equivalent(RepNodeImpl mi)343 public boolean equivalent(RepNodeImpl mi) { 344 if (this == mi) { 345 return true; 346 } 347 348 if (mi == null) { 349 return false; 350 } 351 352 if (port != mi.port) { 353 return false; 354 } 355 356 if (hostName == null) { 357 if (mi.hostName != null) { 358 return false; 359 } 360 } else if (!hostName.equals(mi.hostName)) { 361 return false; 362 } 363 364 /* Ignore the id. */ 365 if (!nameIdPair.getName().equals(mi.nameIdPair.getName())) { 366 return false; 367 } 368 369 if (getType() != mi.getType()) { 370 return false; 371 } 372 373 /* 374 * Ignore quorumAck, isRemoved, barrierState, changeVersion, and 375 * jeVersion 376 */ 377 378 return true; 379 } 380 381 @Override hashCode()382 public int hashCode() { 383 final int prime = 31; 384 int result = 1; 385 result = prime * result 386 + ((hostName == null) ? 0 : hostName.hashCode()); 387 result = prime * result + nameIdPair.hashCode(); 388 result = prime * result + port; 389 result = prime * result + (isQuorumAck() ? 1231 : 1237); 390 result = prime * result + 391 (jeVersion == null ? 0 : jeVersion.hashCode()); 392 return result; 393 } 394 395 @Override equals(Object obj)396 public boolean equals(Object obj) { 397 if (this == obj) { 398 return true; 399 } 400 if (obj == null) { 401 return false; 402 } 403 if (!(obj instanceof RepNodeImpl)) { 404 return false; 405 } 406 final RepNodeImpl other = (RepNodeImpl) obj; 407 if (hostName == null) { 408 if (other.hostName != null) { 409 return false; 410 } 411 } else if (!hostName.equals(other.hostName)) { 412 return false; 413 } 414 if (!nameIdPair.equals(other.nameIdPair)) { 415 return false; 416 } 417 if (getType() != other.getType()) { 418 return false; 419 } 420 if (port != other.port) { 421 return false; 422 } 423 if (isQuorumAck() != other.isQuorumAck()) { 424 return false; 425 } 426 if (jeVersion == null) { 427 if (other.jeVersion != null) { 428 return false; 429 } 430 } else if (!jeVersion.equals(other.getJEVersion())) { 431 return false; 432 } 433 return true; 434 } 435 } 436