blob: 083464f8ff550343cff7ab282404bf3aa518e9d0 [file] [log] [blame]
Yuta HIGUCHI8f182192014-08-02 18:47:42 -07001package net.onrc.onos.core.util.distributed.sharedlog;
2
3import static com.google.common.base.Preconditions.checkArgument;
4import static com.google.common.base.Preconditions.checkNotNull;
5
6import javax.annotation.concurrent.Immutable;
7
8import com.google.common.annotations.Beta;
9import com.google.common.primitives.Longs;
10import com.google.common.primitives.UnsignedLong;
11import com.google.common.primitives.UnsignedLongs;
12
13// TODO register to Kryo
14/**
15 * Sequence number used as log entry key.
16 */
17@Beta
18@Immutable
19public final class SeqNum extends Number implements Comparable<SeqNum> {
20
21 /**
22 * Long value reserved for {@link #INITIAL}.
23 */
24 public static final long ZERO = 0L;
25
26 /**
27 * Special sequence number which will never have LogValue.
28 */
29 public static final SeqNum INITIAL = new SeqNum(ZERO);
30
31
32 private final long seq;
33
34 /**
35 * Constructor.
36 *
37 * @param number sequence number.
38 */
39 protected SeqNum(final long number) {
40 this.seq = number;
41 }
42
43 /**
44 * Gets an instance for specified number.
45 *
46 * @param number must not be {@link #ZERO}
47 * @return SeqNum
48 *
49 * @throws IllegalArgumentException if given number was {@link #ZERO}
50 */
51 public static SeqNum valueOf(final long number) {
52 checkArgument(number != ZERO);
53 return new SeqNum(number);
54 }
55
56 // TODO give better name?
57 /**
58 * Gets an instance for specified number.
59 *
60 * @param number sequence number. Can be {@link #ZERO}
61 * @return SeqNum
62 */
63 public static SeqNum anyValueOf(final long number) {
64 return new SeqNum(number);
65 }
66
67 /**
Yuta HIGUCHI8cc41692014-08-20 21:47:03 -070068 * Gets an instance for specified string.
69 *
70 * @param str parsed result must not be {@link #ZERO}
71 * @return SeqNum
72 */
73 public static SeqNum valueOf(final String str) {
74 return valueOf(UnsignedLongs.decode(str));
75 }
76
77 /**
78 * Gets an instance for specified string.
79 *
80 * @param str string representation of unsigned long
81 * @return SeqNum
82 */
83 public static SeqNum anyValueOf(final String str) {
84 return anyValueOf(UnsignedLongs.decode(str));
85 }
86
87 /**
Yuta HIGUCHI8f182192014-08-02 18:47:42 -070088 * Gets the next sequence number.
89 * <p>
90 * WARN: This is not a atomic sequencer,
91 * this method just returns the next number in sequence.
92 *
93 * @return next sequence number
94 */
95 public SeqNum next() {
96 return step(1);
97 }
98
99 /**
100 * Gets the previous sequence number.
101 * <p>
102 * WARN: This is not a atomic sequencer,
103 * this method just returns the previous number in sequence.
104 *
105 * @return prev sequence number
106 */
107 public SeqNum prev() {
108 return step(-1);
109 }
110
111 /**
112 * Gets the sequence number stepping forward/backward by {@code delta}.
113 *
114 * @param delta step
115 * @return sequence number
116 */
117 public SeqNum step(long delta) {
118 long next = seq + delta;
119 if (next == SeqNum.ZERO) {
120 if (delta >= 0) {
121 return SeqNum.valueOf(next + 1);
122 } else {
123 // XXX Revisit this behavior
124 return SeqNum.valueOf(next - 1);
125 }
126 }
127 return SeqNum.valueOf(next);
128 }
129
130 // TODO comparator which treats long as ring?
131
132 @Override
133 public int intValue() {
134 return UnsignedLong.valueOf(seq).intValue();
135 }
136
137 @Override
138 public long longValue() {
139 return seq;
140 }
141
142 @Override
143 public float floatValue() {
144 return UnsignedLong.valueOf(seq).floatValue();
145 }
146
147 @Override
148 public double doubleValue() {
149 return UnsignedLong.valueOf(seq).doubleValue();
150 }
151
152 @Override
153 public int hashCode() {
154 return Longs.hashCode(seq);
155 }
156
157 @Override
158 public boolean equals(Object obj) {
159 if (this == obj) {
160 return true;
161 }
162 if (obj == null) {
163 return false;
164 }
165 if (getClass() != obj.getClass()) {
166 return false;
167 }
168 SeqNum other = (SeqNum) obj;
169 return seq == other.seq;
170 }
171
172 @Override
173 public String toString() {
174 return UnsignedLongs.toString(seq);
175 }
176
177 @Override
178 public int compareTo(final SeqNum o) {
179 checkNotNull(o);
180
181 return Long.signum(-this.distance(o));
182 }
183
184 /**
185 * Returns the distance between other and this SeqNum.
186 *
187 * @param other other SeqNum
188 * @return {@code other - this}
189 * or -Long.MAX_VALUE, Log.MAX_VALUE if too far apart.
190 */
191 public long distance(final SeqNum other) {
192 checkNotNull(other);
193
194 // distance from INITIAL is always measured clockwise on the ring
195 if (this.equals(INITIAL)) {
196 return (other.seq >= 0) ? other.seq : Long.MAX_VALUE;
197 } else if (other.equals(INITIAL)) {
198 return (this.seq >= 0) ? -this.seq : -Long.MAX_VALUE;
199 }
200
201 /// other cases measures using "shorter" half of the ring
202 final long diff = other.seq - this.seq;
203 if (diff == Long.MIN_VALUE) {
204 // both arc is same distance
205 // treat arc including INITIAL as shorter
206 if (this.seq < 0) {
207 // clock wise arc contain INITIAL
208 return Long.MAX_VALUE;
209 } else {
210 // counter clock wise arc contain INITIAL
211 return -Long.MAX_VALUE;
212 }
213 } else {
214 return diff;
215 }
216 }
217}