Skip to content

Commit 8b18bc6

Browse files
committed
@todo optimized getAndAdd operations
1 parent b4406c9 commit 8b18bc6

2 files changed

Lines changed: 117 additions & 34 deletions

File tree

src/main/java/picoded/dstack/KeyLongMap.java

Lines changed: 5 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -180,39 +180,10 @@ default Long removeValue(Object key) {
180180
**/
181181
default Long addAndGet(Object key, Object delta) {
182182
//
183-
// NOTE : The default implmentation of addAndGet,
184-
// or getAndAdd relies on repetaed tries using
185-
// weakCompareAndSet, while functional.
186-
// Is highly inefficent in most cases
183+
// We simply use get and add, with the delta,
184+
// this reduce the amount of permutation needed to support
187185
//
188-
189-
// Validate and convert the key to String
190-
if (key == null) {
191-
throw new IllegalArgumentException("key cannot be null in addAndGet");
192-
}
193-
String keyAsString = key.toString();
194-
195-
// Attempt to update the key for 5 times before throwing exception
196-
for (int tries = 0; tries < 5; tries++) {
197-
// Retrieve value from key
198-
Long value = getValue(keyAsString);
199-
200-
// Assume value as 0 if not exist
201-
if (value == null) {
202-
value = new Long(0);
203-
}
204-
205-
// Calculate the updated value
206-
Long updatedValue = GenericConvert.toLong(delta) + value;
207-
208-
// Update the value with weakCompareAndSet and return
209-
if (weakCompareAndSet(keyAsString, value, updatedValue)) {
210-
return updatedValue;
211-
}
212-
}
213-
214-
// Throw exception due to number of retries exceeded the limit
215-
throw new RuntimeException("Number of retries exceeded limit for addAndGet");
186+
return getAndAdd(key, delta)+GenericConvert.toLong(delta);
216187
}
217188

218189
/**
@@ -233,7 +204,7 @@ default Long getAndAdd(Object key, Object delta) {
233204

234205
// Validate and convert the key to String
235206
if (key == null) {
236-
throw new IllegalArgumentException("key cannot be null in addAndGet");
207+
throw new IllegalArgumentException("key cannot be null in");
237208
}
238209
String keyAsString = key.toString();
239210

@@ -257,7 +228,7 @@ default Long getAndAdd(Object key, Object delta) {
257228
}
258229

259230
// Throw exception due to number of retries exceeded the limit
260-
throw new RuntimeException("Number of retries exceeded limit for addAndGet");
231+
throw new RuntimeException("Number of retries exceeded limit");
261232
}
262233

263234
/**

src/main/java/picoded/dstack/mongodb/MongoDB_KeyLongMap.java

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,118 @@ public boolean weakCompareAndSet(String key, Long expect, Long update) {
406406
return false;
407407
}
408408

409+
//--------------------------------------------------------------------------
410+
//
411+
// @TODO : Optimized getAndAdd
412+
//
413+
//--------------------------------------------------------------------------
414+
415+
// /**
416+
// * Returns the value, given the key
417+
// *
418+
// * @param key param find the meta key
419+
// * @param delta value to add
420+
// *
421+
// * @return value of the given key after adding
422+
// **/
423+
// public Long getAndAdd(Object key, Object delta) {
424+
425+
// // This is the more optimized varient for weakCompareAndSet
426+
// // ---
427+
428+
// // Validate and convert the key to String
429+
// if (key == null) {
430+
// throw new IllegalArgumentException("key cannot be null in");
431+
// }
432+
// String keyAsString = key.toString();
433+
434+
// // Normalize the delta to a long
435+
// Long deltaLong = GenericConvert.toLong(delta);
436+
437+
// // Configure this to be an "upsert" query
438+
// FindOneAndUpdateOptions opt = new FindOneAndUpdateOptions();
439+
// opt.upsert(true);
440+
441+
// // now timestamp
442+
// Date now = new Date();
443+
444+
// // Lets generate the mongodb "update" document rule
445+
// Document updateDoc = new Document();
446+
447+
// // Disable expire timestamp when using
448+
// // weakCompareAndSet/getAndAdd/addAndGet
449+
// Document unset_doc = new Document();
450+
// unset_doc.append("expireAt", "");
451+
// updateDoc.append("$unset", unset_doc);
452+
453+
// // Setup the value on update/insert/upsert
454+
// Document inc_doc = new Document();
455+
// inc_doc.append("val", deltaLong);
456+
// updateDoc.append("$set", set_doc);
457+
458+
// //
459+
// // In general there are the following compare and set scenerios to handle
460+
// //
461+
// // 1) expecting value is 0
462+
// // a) existing record is expired
463+
// // b) existing record does not exist
464+
// // c) existing record is NOT expired, and is 0
465+
// // 2) expecting value is non-zero
466+
// // a) existing record is NOT expired, and is expected value.
467+
// //
468+
469+
// // Potentially a new upsert, ensure there is something to "update" atleast
470+
// // initializing an empty row if it does not exist
471+
// if (expect == null || expect == 0l) {
472+
// // Expect is now atleast 0
473+
// expect = 0l;
474+
// }
475+
476+
// //
477+
// // We update any existing values
478+
// // this handle scenerio 1a, 1c & 2a
479+
// //
480+
// // We can do this safely here, as mongodb handles the expire
481+
// // natively, so we do not need to worry about race conditions.
482+
// //
483+
484+
// //
485+
// // Upsert the document
486+
// //
487+
// Object ret = collection.findOneAndUpdate(Filters.and(Filters.eq("key", key), //
488+
// Filters.or( //
489+
// // Handles an expired record
490+
// Filters.and(Filters.gt("expireAt", new Date(0l)), Filters.lt("expireAt", now)),
491+
// // Handles an non-expired record
492+
// Filters.and(Filters.eq("val", expect), filterForUnexpired(now)))), updateDoc, opt);
493+
494+
// // Return true on succesful update
495+
// if (ret != null) {
496+
// return true;
497+
// }
498+
499+
// //
500+
// // We insert a record if possible, this handle sceneric 1b
501+
// //
502+
// if (expect == 0l) {
503+
// try {
504+
// InsertOneResult res = collection.insertOne( //
505+
// new Document().append("key", key).append("val", update) //
506+
// );
507+
508+
// if (res.wasAcknowledged()) {
509+
// return true;
510+
// }
511+
// } catch (Exception e) {
512+
// // This is probably due to a conflicting index
513+
// return false;
514+
// }
515+
// }
516+
517+
// // All Failed
518+
// return false;
519+
// }
520+
409521
//--------------------------------------------------------------------------
410522
//
411523
// Remove call

0 commit comments

Comments
 (0)