blob: 0164433bd058f37bc04e4890c2d6e5cc13424c76 [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
Yuta HIGUCHI5bb0a292014-07-23 16:51:24 -07003import static com.google.common.base.Preconditions.checkNotNull;
4import static com.google.common.base.Preconditions.checkArgument;
5
Yuta HIGUCHI6a643132014-03-18 22:39:27 -07006import java.io.IOException;
7import java.util.ArrayList;
8import java.util.Arrays;
9import java.util.List;
10import java.util.Set;
11import java.util.concurrent.atomic.AtomicLong;
12
Yuta HIGUCHId395b932014-05-01 15:15:20 -070013import net.onrc.onos.core.datastore.DataStoreClient;
Jonathan Hart6df90172014-04-03 10:13:11 -070014import net.onrc.onos.core.datastore.IKVTable;
15import net.onrc.onos.core.datastore.IKVTableID;
16import net.onrc.onos.core.datastore.ObjectDoesntExistException;
17import net.onrc.onos.core.datastore.ObjectExistsException;
18import net.onrc.onos.core.datastore.WrongVersionException;
Yuta HIGUCHIf148aac2014-05-05 14:59:06 -070019import net.onrc.onos.core.datastore.utils.ByteArrayUtil;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070020
Yuta HIGUCHIce7e7f82014-04-15 21:37:38 -070021import org.apache.commons.lang.ArrayUtils;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070022import org.slf4j.Logger;
23import org.slf4j.LoggerFactory;
24
25import com.hazelcast.core.IMap;
26import com.hazelcast.nio.ObjectDataInput;
27import com.hazelcast.nio.ObjectDataOutput;
28import com.hazelcast.nio.serialization.IdentifiedDataSerializable;
29
30public class HZTable implements IKVTable, IKVTableID {
31 @SuppressWarnings("unused")
32 private static final Logger log = LoggerFactory.getLogger(HZTable.class);
33
34 // not sure how strict this should be managed
Ray Milkey5c9f2db2014-04-09 10:31:21 -070035 private static final AtomicLong INITIAL_VERSION = new AtomicLong(HZClient.VERSION_NONEXISTENT);
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070036
37 /**
38 * generate a new initial version for an entry.
Ray Milkey269ffb92014-04-03 14:43:30 -070039 *
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070040 * @return initial value
41 */
42 protected static long getInitialVersion() {
Ray Milkey5c9f2db2014-04-09 10:31:21 -070043 long version = INITIAL_VERSION.incrementAndGet();
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070044 if (version == HZClient.VERSION_NONEXISTENT) {
45 // used up whole 64bit space?
Ray Milkey5c9f2db2014-04-09 10:31:21 -070046 version = INITIAL_VERSION.incrementAndGet();
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070047 }
48 return version;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070049 }
50
51 /**
Ray Milkey7531a342014-04-11 15:08:12 -070052 * increment version, avoiding versionNonexistant.
Ray Milkey269ffb92014-04-03 14:43:30 -070053 *
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070054 * @param version
Jonathan Hart99ff20a2014-06-15 16:53:00 -070055 * @return the next version number
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070056 */
57 protected static long getNextVersion(final long version) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070058 long nextVersion = version + 1;
59 if (nextVersion == HZClient.VERSION_NONEXISTENT) {
60 ++nextVersion;
61 }
62 return nextVersion;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070063 }
64
65 static class VersionedValue implements IdentifiedDataSerializable {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070066 private static final long serialVersionUID = -3149375966890712708L;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070067
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070068 private byte[] value;
69 private long version;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070070
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070071 protected VersionedValue() {
72 value = new byte[0];
73 version = HZClient.VERSION_NONEXISTENT;
74 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070075
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070076 public VersionedValue(final byte[] value, final long version) {
Yuta HIGUCHId395b932014-05-01 15:15:20 -070077 setValue(value);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070078 this.version = version;
79 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070080
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070081 public byte[] getValue() {
82 return value;
83 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070084
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070085 public long getVersion() {
86 return version;
87 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070088
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070089 public void setValue(final byte[] value) {
Yuta HIGUCHI5bb0a292014-07-23 16:51:24 -070090 checkArgument(value == null ||
91 value.length <= DataStoreClient.MAX_VALUE_BYTES,
92 "Value must be smaller than 1MB");
93
Yuta HIGUCHIce7e7f82014-04-15 21:37:38 -070094 this.value = ArrayUtils.clone(value);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070095 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -070096
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070097 public void setNextVersion() {
98 this.version = getNextVersion(this.version);
99 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700100
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700101 @Override
102 public void writeData(final ObjectDataOutput out) throws IOException {
103 out.writeLong(version);
104 out.writeInt(value.length);
105 if (value.length > 0) {
106 out.write(value);
107 }
108 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700109
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700110 @Override
111 public void readData(final ObjectDataInput in) throws IOException {
112 version = in.readLong();
113 final int valueLen = in.readInt();
114 value = new byte[valueLen];
115 in.readFully(value);
116 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700117
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700118 @Override
119 public int getFactoryId() {
120 return VersionedValueSerializableFactory.FACTORY_ID;
121 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700122
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700123 @Override
124 public int getId() {
125 return VersionedValueSerializableFactory.VERSIONED_VALUE_ID;
126 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700127
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700128 @Override
129 public int hashCode() {
130 final int prime = 31;
131 int result = 1;
132 result = prime * result + (int) (version ^ (version >>> 32));
133 result = prime * result + Arrays.hashCode(value);
134 return result;
135 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700136
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700137 @Override
138 public boolean equals(final Object obj) {
139 if (this == obj) {
140 return true;
141 }
142 if (obj == null) {
143 return false;
144 }
145 if (getClass() != obj.getClass()) {
146 return false;
147 }
148 VersionedValue other = (VersionedValue) obj;
149 if (version != other.version) {
150 return false;
151 }
152 if (!Arrays.equals(value, other.value)) {
153 return false;
154 }
155 return true;
156 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700157 }
158
159 // TODO Refactor and extract common parts
160 public static class Entry implements IKVEntry {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700161 final byte[] key;
162 byte[] value;
163 long version;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700164
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700165 public Entry(final byte[] key, final byte[] value, final long version) {
Yuta HIGUCHI5bb0a292014-07-23 16:51:24 -0700166 checkNotNull(key);
167 checkArgument(
168 key.length <= DataStoreClient.MAX_KEY_BYTES,
169 "Key must be smaller than 64KB");
170
Yuta HIGUCHIce7e7f82014-04-15 21:37:38 -0700171 this.key = key.clone();
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700172 this.setValue(value);
173 this.setVersion(version);
174 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700175
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700176 public Entry(final byte[] key) {
177 this(key, null, HZClient.VERSION_NONEXISTENT);
178 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700179
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700180 @Override
181 public byte[] getKey() {
Yuta HIGUCHIce7e7f82014-04-15 21:37:38 -0700182 return key.clone();
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700183 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700184
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700185 @Override
186 public byte[] getValue() {
Yuta HIGUCHIce7e7f82014-04-15 21:37:38 -0700187 return ArrayUtils.clone(value);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700188 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700189
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700190 @Override
191 public long getVersion() {
192 return version;
193 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700194
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700195 void setValue(final byte[] value) {
Yuta HIGUCHIce7e7f82014-04-15 21:37:38 -0700196 this.value = ArrayUtils.clone(value);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700197 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700198
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700199 void setVersion(final long version) {
200 this.version = version;
201 }
Yuta HIGUCHIf148aac2014-05-05 14:59:06 -0700202
203 @Override
204 public String toString() {
205 return "[Entry key=" + ByteArrayUtil.toHexStringBuilder(key, ":") + ", value="
206 + ByteArrayUtil.toHexStringBuilder(value, ":") + ", version=" + version + "]";
207 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700208 }
209
210
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700211 private final String mapName;
212 private final IMap<byte[], VersionedValue> map;
213
214 public HZTable(final String mapName, final IMap<byte[], VersionedValue> map) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700215 this.mapName = mapName;
216 this.map = map;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700217 }
218
219 @Override
220 public String getTableName() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700221 return mapName;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700222 }
223
224 @Override
225 public IKVTableID getTableId() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700226 return this;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700227 }
228
229 @Override
230 public long create(final byte[] key, final byte[] value) throws ObjectExistsException {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700231 final long version = getInitialVersion();
232 VersionedValue existing = map.putIfAbsent(key, new VersionedValue(value, version));
233 if (existing != null) {
234 throw new ObjectExistsException(this, key);
235 }
236 return version;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700237 }
238
239 @Override
240 public long forceCreate(final byte[] key, final byte[] value) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700241 final long version = getInitialVersion();
242 map.set(key, new VersionedValue(value, version));
243 return version;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700244 }
245
246 @Override
247 public IKVEntry read(final byte[] key) throws ObjectDoesntExistException {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700248 final VersionedValue value = map.get(key);
249 if (value == null) {
250 throw new ObjectDoesntExistException(this, key);
251 }
252 return new Entry(key, value.getValue(), value.getVersion());
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700253 }
254
255 @Override
256 public long update(final byte[] key, final byte[] value, final long version)
257 throws ObjectDoesntExistException, WrongVersionException {
258
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700259 try {
260 map.lock(key);
261 final VersionedValue oldValue = map.get(key);
262 if (oldValue == null) {
263 throw new ObjectDoesntExistException(this, key);
264 }
265 if (oldValue.getVersion() != version) {
266 throw new WrongVersionException(this, key, version, oldValue.getVersion());
267 }
268 final long nextVersion = getNextVersion(version);
269 map.set(key, new VersionedValue(value, nextVersion));
270 return nextVersion;
271 } finally {
272 map.unlock(key);
273 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700274 }
275
276 @Override
277 public long update(final byte[] key, final byte[] value)
278 throws ObjectDoesntExistException {
279
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700280 try {
281 map.lock(key);
282 final VersionedValue valueInMap = map.get(key);
283 if (valueInMap == null) {
284 throw new ObjectDoesntExistException(this, key);
285 }
286 valueInMap.setValue(value);
287 valueInMap.setNextVersion();
288 map.set(key, valueInMap);
289 return valueInMap.getVersion();
290 } finally {
291 map.unlock(key);
292 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700293 }
294
295 @Override
296 public long delete(final byte[] key, final long version)
297 throws ObjectDoesntExistException, WrongVersionException {
298
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700299 try {
300 map.lock(key);
301 final VersionedValue oldValue = map.get(key);
302 if (oldValue == null) {
303 throw new ObjectDoesntExistException(this, key);
304 }
305 if (oldValue.getVersion() != version) {
306 throw new WrongVersionException(this, key, version, oldValue.getVersion());
307 }
308 map.delete(key);
309 return oldValue.getVersion();
310 } finally {
311 map.unlock(key);
312 }
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700313 }
314
315 @Override
316 public long forceDelete(final byte[] key) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700317 final VersionedValue valueInMap = map.remove(key);
318 if (valueInMap == null) {
319 return HZClient.VERSION_NONEXISTENT;
320 }
321 return valueInMap.getVersion();
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700322 }
323
324 @Override
325 public Iterable<IKVEntry> getAllEntries() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700326 final Set<IMap.Entry<byte[], VersionedValue>> entries = map.entrySet();
327 List<IKVEntry> entryList = new ArrayList<IKVTable.IKVEntry>(entries.size());
328 for (IMap.Entry<byte[], VersionedValue> entry : entries) {
329 entryList.add(new Entry(entry.getKey(), entry.getValue().getValue(), entry.getValue().getVersion()));
330 }
331 return entryList;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700332 }
333
334 @Override
335 public String toString() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700336 return "[HZTable " + mapName + "]";
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700337 }
338
339 IMap<byte[], VersionedValue> getBackendMap() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700340 return this.map;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700341 }
342
343 @Override
Ray Milkey7531a342014-04-11 15:08:12 -0700344 public long getVersionNonexistant() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700345 return HZClient.VERSION_NONEXISTENT;
Yuta HIGUCHI6a643132014-03-18 22:39:27 -0700346 }
347}