1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package org.apache.zookeeper.server.quorum; 20 21 import org.apache.zookeeper.server.quorum.QuorumPeer.ServerState; 22 23 public class Vote { 24 Vote(long id, long zxid)25 public Vote(long id, long zxid) { 26 this.version = 0x0; 27 this.id = id; 28 this.zxid = zxid; 29 this.electionEpoch = -1; 30 this.peerEpoch = -1; 31 this.state = ServerState.LOOKING; 32 } 33 Vote(long id, long zxid, long peerEpoch)34 public Vote(long id, long zxid, long peerEpoch) { 35 this.version = 0x0; 36 this.id = id; 37 this.zxid = zxid; 38 this.electionEpoch = -1; 39 this.peerEpoch = peerEpoch; 40 this.state = ServerState.LOOKING; 41 } 42 Vote(long id, long zxid, long electionEpoch, long peerEpoch)43 public Vote(long id, long zxid, long electionEpoch, long peerEpoch) { 44 this.version = 0x0; 45 this.id = id; 46 this.zxid = zxid; 47 this.electionEpoch = electionEpoch; 48 this.peerEpoch = peerEpoch; 49 this.state = ServerState.LOOKING; 50 } 51 Vote(int version, long id, long zxid, long electionEpoch, long peerEpoch, ServerState state)52 public Vote(int version, long id, long zxid, long electionEpoch, long peerEpoch, ServerState state) { 53 this.version = version; 54 this.id = id; 55 this.zxid = zxid; 56 this.electionEpoch = electionEpoch; 57 this.state = state; 58 this.peerEpoch = peerEpoch; 59 } 60 Vote(long id, long zxid, long electionEpoch, long peerEpoch, ServerState state)61 public Vote(long id, long zxid, long electionEpoch, long peerEpoch, ServerState state) { 62 this.id = id; 63 this.zxid = zxid; 64 this.electionEpoch = electionEpoch; 65 this.state = state; 66 this.peerEpoch = peerEpoch; 67 this.version = 0x0; 68 } 69 70 private final int version; 71 72 private final long id; 73 74 private final long zxid; 75 76 private final long electionEpoch; 77 78 private final long peerEpoch; 79 getVersion()80 public int getVersion() { 81 return version; 82 } 83 getId()84 public long getId() { 85 return id; 86 } 87 getZxid()88 public long getZxid() { 89 return zxid; 90 } 91 getElectionEpoch()92 public long getElectionEpoch() { 93 return electionEpoch; 94 } 95 getPeerEpoch()96 public long getPeerEpoch() { 97 return peerEpoch; 98 } 99 getState()100 public ServerState getState() { 101 return state; 102 } 103 104 private final ServerState state; 105 106 @Override equals(Object o)107 public boolean equals(Object o) { 108 if (!(o instanceof Vote)) { 109 return false; 110 } 111 Vote other = (Vote) o; 112 113 if ((state == ServerState.LOOKING) || (other.state == ServerState.LOOKING)) { 114 return id == other.id 115 && zxid == other.zxid 116 && electionEpoch == other.electionEpoch 117 && peerEpoch == other.peerEpoch; 118 } else { 119 /* 120 * There are two things going on in the logic below: 121 * 122 * 1. skip comparing the zxid and electionEpoch for votes for servers 123 * out of election. 124 * 125 * Need to skip those because they can be inconsistent due to 126 * scenarios described in QuorumPeer.updateElectionVote. 127 * 128 * And given that only one ensemble can be running at a single point 129 * in time and that each epoch is used only once, using only id and 130 * epoch to compare the votes is sufficient. 131 * 132 * {@see https://issues.apache.org/jira/browse/ZOOKEEPER-1805} 133 * 134 * 2. skip comparing peerEpoch if if we're running with mixed ensemble 135 * with (version > 0x0) and without the change (version = 0x0) 136 * introduced in ZOOKEEPER-1732. 137 * 138 * {@see https://issues.apache.org/jira/browse/ZOOKEEPER-1732} 139 * 140 * The server running with and without ZOOKEEPER-1732 will return 141 * different peerEpoch. During rolling upgrades, it's possible 142 * that 2/5 servers are returning epoch 1, while the other 2/5 143 * are returning epoch 2, the other server need to ignore the 144 * peerEpoch to be able to join it. 145 */ 146 if ((version > 0x0) ^ (other.version > 0x0)) { 147 return id == other.id; 148 } else { 149 return (id == other.id && peerEpoch == other.peerEpoch); 150 } 151 } 152 } 153 154 @Override hashCode()155 public int hashCode() { 156 return (int) (id & zxid); 157 } 158 toString()159 public String toString() { 160 return "(" + id + ", " + Long.toHexString(zxid) + ", " + Long.toHexString(peerEpoch) + ")"; 161 } 162 163 } 164