blob: 6cba576549e0e44d7d692e95fcc7e0b46c716a68 [file] [log] [blame]
Jonathan Hart6df90172014-04-03 10:13:11 -07001package net.onrc.onos.core.datastore.hazelcast;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -07002
3import java.io.IOException;
4import java.util.ArrayList;
5import java.util.Arrays;
6import java.util.List;
7import java.util.Set;
8import java.util.concurrent.atomic.AtomicLong;
9
Jonathan Hart6df90172014-04-03 10:13:11 -070010import net.onrc.onos.core.datastore.IKVTable;
11import net.onrc.onos.core.datastore.IKVTableID;
12import net.onrc.onos.core.datastore.ObjectDoesntExistException;
13import net.onrc.onos.core.datastore.ObjectExistsException;
14import net.onrc.onos.core.datastore.WrongVersionException;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070015
16import org.slf4j.Logger;
17import org.slf4j.LoggerFactory;
18
19import com.hazelcast.core.IMap;
20import com.hazelcast.nio.ObjectDataInput;
21import com.hazelcast.nio.ObjectDataOutput;
22import com.hazelcast.nio.serialization.IdentifiedDataSerializable;
23
24public class HZTable implements IKVTable, IKVTableID {
25 @SuppressWarnings("unused")
26 private static final Logger log = LoggerFactory.getLogger(HZTable.class);
27
28 // not sure how strict this should be managed
Ray Milkey269ffb92014-04-03 14:43:30 -070029 private static final AtomicLong initialVersion = new AtomicLong(HZClient.VERSION_NONEXISTENT);
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070030
31 /**
32 * generate a new initial version for an entry.
Ray Milkey269ffb92014-04-03 14:43:30 -070033 *
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070034 * @return initial value
35 */
36 protected static long getInitialVersion() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070037 long version = initialVersion.incrementAndGet();
38 if (version == HZClient.VERSION_NONEXISTENT) {
39 // used up whole 64bit space?
40 version = initialVersion.incrementAndGet();
41 }
42 return version;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070043 }
44
45 /**
46 * increment version, avoiding VERSION_NONEXISTENT.
Ray Milkey269ffb92014-04-03 14:43:30 -070047 *
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070048 * @param version
49 * @return
50 */
51 protected static long getNextVersion(final long version) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070052 long nextVersion = version + 1;
53 if (nextVersion == HZClient.VERSION_NONEXISTENT) {
54 ++nextVersion;
55 }
56 return nextVersion;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070057 }
58
59 static class VersionedValue implements IdentifiedDataSerializable {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070060 private static final long serialVersionUID = -3149375966890712708L;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070061
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070062 private byte[] value;
63 private long version;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070064
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070065 protected VersionedValue() {
66 value = new byte[0];
67 version = HZClient.VERSION_NONEXISTENT;
68 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070069
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070070 public VersionedValue(final byte[] value, final long version) {
71 this.value = value;
72 this.version = version;
73 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070074
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070075 public byte[] getValue() {
76 return value;
77 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070078
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070079 public long getVersion() {
80 return version;
81 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070082
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070083 public void setValue(final byte[] value) {
84 this.value = value;
85 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070086
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070087 public void setNextVersion() {
88 this.version = getNextVersion(this.version);
89 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070090
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070091 @Override
92 public void writeData(final ObjectDataOutput out) throws IOException {
93 out.writeLong(version);
94 out.writeInt(value.length);
95 if (value.length > 0) {
96 out.write(value);
97 }
98 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070099
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700100 @Override
101 public void readData(final ObjectDataInput in) throws IOException {
102 version = in.readLong();
103 final int valueLen = in.readInt();
104 value = new byte[valueLen];
105 in.readFully(value);
106 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700107
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700108 @Override
109 public int getFactoryId() {
110 return VersionedValueSerializableFactory.FACTORY_ID;
111 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700112
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700113 @Override
114 public int getId() {
115 return VersionedValueSerializableFactory.VERSIONED_VALUE_ID;
116 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700117
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700118 @Override
119 public int hashCode() {
120 final int prime = 31;
121 int result = 1;
122 result = prime * result + (int) (version ^ (version >>> 32));
123 result = prime * result + Arrays.hashCode(value);
124 return result;
125 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700126
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700127 @Override
128 public boolean equals(final Object obj) {
129 if (this == obj) {
130 return true;
131 }
132 if (obj == null) {
133 return false;
134 }
135 if (getClass() != obj.getClass()) {
136 return false;
137 }
138 VersionedValue other = (VersionedValue) obj;
139 if (version != other.version) {
140 return false;
141 }
142 if (!Arrays.equals(value, other.value)) {
143 return false;
144 }
145 return true;
146 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700147 }
148
149 // TODO Refactor and extract common parts
150 public static class Entry implements IKVEntry {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700151 final byte[] key;
152 byte[] value;
153 long version;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700154
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700155 public Entry(final byte[] key, final byte[] value, final long version) {
156 this.key = key;
157 this.setValue(value);
158 this.setVersion(version);
159 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700160
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700161 public Entry(final byte[] key) {
162 this(key, null, HZClient.VERSION_NONEXISTENT);
163 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700164
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700165 @Override
166 public byte[] getKey() {
167 return key;
168 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700169
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700170 @Override
171 public byte[] getValue() {
172 return value;
173 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700174
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700175 @Override
176 public long getVersion() {
177 return version;
178 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700179
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700180 void setValue(final byte[] value) {
181 this.value = value;
182 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700183
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700184 void setVersion(final long version) {
185 this.version = version;
186 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700187 }
188
189
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700190 private final String mapName;
191 private final IMap<byte[], VersionedValue> map;
192
193 public HZTable(final String mapName, final IMap<byte[], VersionedValue> map) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700194 this.mapName = mapName;
195 this.map = map;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700196 }
197
198 @Override
199 public String getTableName() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700200 return mapName;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700201 }
202
203 @Override
204 public IKVTableID getTableId() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700205 return this;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700206 }
207
208 @Override
209 public long create(final byte[] key, final byte[] value) throws ObjectExistsException {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700210 final long version = getInitialVersion();
211 VersionedValue existing = map.putIfAbsent(key, new VersionedValue(value, version));
212 if (existing != null) {
213 throw new ObjectExistsException(this, key);
214 }
215 return version;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700216 }
217
218 @Override
219 public long forceCreate(final byte[] key, final byte[] value) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700220 final long version = getInitialVersion();
221 map.set(key, new VersionedValue(value, version));
222 return version;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700223 }
224
225 @Override
226 public IKVEntry read(final byte[] key) throws ObjectDoesntExistException {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700227 final VersionedValue value = map.get(key);
228 if (value == null) {
229 throw new ObjectDoesntExistException(this, key);
230 }
231 return new Entry(key, value.getValue(), value.getVersion());
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700232 }
233
234 @Override
235 public long update(final byte[] key, final byte[] value, final long version)
236 throws ObjectDoesntExistException, WrongVersionException {
237
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700238 try {
239 map.lock(key);
240 final VersionedValue oldValue = map.get(key);
241 if (oldValue == null) {
242 throw new ObjectDoesntExistException(this, key);
243 }
244 if (oldValue.getVersion() != version) {
245 throw new WrongVersionException(this, key, version, oldValue.getVersion());
246 }
247 final long nextVersion = getNextVersion(version);
248 map.set(key, new VersionedValue(value, nextVersion));
249 return nextVersion;
250 } finally {
251 map.unlock(key);
252 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700253 }
254
255 @Override
256 public long update(final byte[] key, final byte[] value)
257 throws ObjectDoesntExistException {
258
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700259 try {
260 map.lock(key);
261 final VersionedValue valueInMap = map.get(key);
262 if (valueInMap == null) {
263 throw new ObjectDoesntExistException(this, key);
264 }
265 valueInMap.setValue(value);
266 valueInMap.setNextVersion();
267 map.set(key, valueInMap);
268 return valueInMap.getVersion();
269 } finally {
270 map.unlock(key);
271 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700272 }
273
274 @Override
275 public long delete(final byte[] key, final long version)
276 throws ObjectDoesntExistException, WrongVersionException {
277
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700278 try {
279 map.lock(key);
280 final VersionedValue oldValue = map.get(key);
281 if (oldValue == null) {
282 throw new ObjectDoesntExistException(this, key);
283 }
284 if (oldValue.getVersion() != version) {
285 throw new WrongVersionException(this, key, version, oldValue.getVersion());
286 }
287 map.delete(key);
288 return oldValue.getVersion();
289 } finally {
290 map.unlock(key);
291 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700292 }
293
294 @Override
295 public long forceDelete(final byte[] key) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700296 final VersionedValue valueInMap = map.remove(key);
297 if (valueInMap == null) {
298 return HZClient.VERSION_NONEXISTENT;
299 }
300 return valueInMap.getVersion();
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700301 }
302
303 @Override
304 public Iterable<IKVEntry> getAllEntries() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700305 final Set<IMap.Entry<byte[], VersionedValue>> entries = map.entrySet();
306 List<IKVEntry> entryList = new ArrayList<IKVTable.IKVEntry>(entries.size());
307 for (IMap.Entry<byte[], VersionedValue> entry : entries) {
308 entryList.add(new Entry(entry.getKey(), entry.getValue().getValue(), entry.getValue().getVersion()));
309 }
310 return entryList;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700311 }
312
313 @Override
314 public String toString() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700315 return "[HZTable " + mapName + "]";
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700316 }
317
318 IMap<byte[], VersionedValue> getBackendMap() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700319 return this.map;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700320 }
321
322 @Override
323 public long VERSION_NONEXISTENT() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700324 return HZClient.VERSION_NONEXISTENT;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700325 }
326}