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