diff --git a/src/main/java/net/spy/memcached/v2/AsyncArcusCommands.java b/src/main/java/net/spy/memcached/v2/AsyncArcusCommands.java index 893722c05..f6868c6ac 100644 --- a/src/main/java/net/spy/memcached/v2/AsyncArcusCommands.java +++ b/src/main/java/net/spy/memcached/v2/AsyncArcusCommands.java @@ -40,9 +40,9 @@ import net.spy.memcached.collection.BKeyObject; import net.spy.memcached.collection.BTreeCount; import net.spy.memcached.collection.BTreeCreate; +import net.spy.memcached.collection.BTreeDelete; import net.spy.memcached.collection.BTreeFindPosition; import net.spy.memcached.collection.BTreeFindPositionWithGet; -import net.spy.memcached.collection.BTreeDelete; import net.spy.memcached.collection.BTreeGet; import net.spy.memcached.collection.BTreeGetBulk; import net.spy.memcached.collection.BTreeGetBulkWithByteTypeBkey; @@ -70,17 +70,17 @@ import net.spy.memcached.collection.ListDelete; import net.spy.memcached.collection.ListGet; import net.spy.memcached.collection.ListInsert; -import net.spy.memcached.collection.SetCreate; -import net.spy.memcached.collection.SetDelete; -import net.spy.memcached.collection.SetExist; -import net.spy.memcached.collection.SetGet; -import net.spy.memcached.collection.SetInsert; import net.spy.memcached.collection.MapCreate; import net.spy.memcached.collection.MapDelete; import net.spy.memcached.collection.MapGet; import net.spy.memcached.collection.MapInsert; import net.spy.memcached.collection.MapUpdate; import net.spy.memcached.collection.MapUpsert; +import net.spy.memcached.collection.SetCreate; +import net.spy.memcached.collection.SetDelete; +import net.spy.memcached.collection.SetExist; +import net.spy.memcached.collection.SetGet; +import net.spy.memcached.collection.SetInsert; import net.spy.memcached.internal.result.GetsResultImpl; import net.spy.memcached.ops.APIType; import net.spy.memcached.ops.BTreeFindPositionOperation; @@ -105,8 +105,8 @@ import net.spy.memcached.transcoders.TranscoderUtils; import net.spy.memcached.v2.vo.BKey; import net.spy.memcached.v2.vo.BTreeElement; -import net.spy.memcached.v2.vo.BTreePositionElement; import net.spy.memcached.v2.vo.BTreeElements; +import net.spy.memcached.v2.vo.BTreePositionElement; import net.spy.memcached.v2.vo.BTreeUpdateElement; import net.spy.memcached.v2.vo.BopDeleteArgs; import net.spy.memcached.v2.vo.BopGetArgs; @@ -174,22 +174,57 @@ public void complete() { } }; Operation op = client.getOpFact() - .store(type, key, co.getFlags(), exp, co.getData(), cb); + .store(type, key, co.getFlags(), exp, co.getData(), cb); future.setOp(op); client.addOp(key, op); return future; } - public ArcusFuture append(String key, T value) { - return concat(ConcatenationType.append, key, value); + public ArcusFuture> multiSet(Map items, int exp) { + return multiStore(StoreType.set, items, exp); + } + + public ArcusFuture> multiAdd(Map items, int exp) { + return multiStore(StoreType.add, items, exp); + } + + public ArcusFuture> multiReplace(Map items, int exp) { + return multiStore(StoreType.replace, items, exp); + } + + private ArcusFuture> multiStore(StoreType type, + Map items, + int exp) { + Map> keyToFuture = new HashMap<>(items.size()); + + items.forEach((key, value) -> { + CompletableFuture future = store(type, key, exp, value).toCompletableFuture(); + keyToFuture.put(key, future); + }); + + return new ArcusMultiFuture<>(keyToFuture.values(), () -> { + Map results = new HashMap<>(); + keyToFuture.forEach((key, future) -> { + if (future.isCompletedExceptionally()) { + results.put(key, null); + } else { + results.put(key, (Boolean) future.join()); + } + }); + return results; + }); } public ArcusFuture prepend(String key, T value) { return concat(ConcatenationType.prepend, key, value); } - private ArcusFuture concat(ConcatenationType catType, String key, T value) { + public ArcusFuture append(String key, T value) { + return concat(ConcatenationType.append, key, value); + } + + private ArcusFuture concat(ConcatenationType concatType, String key, T value) { AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); ArcusFutureImpl future = new ArcusFutureImpl<>(result); CachedData co = tc.encode(value); @@ -221,7 +256,7 @@ public void complete() { future.complete(); } }; - Operation op = client.getOpFact().cat(catType, 0L, key, co.getData(), cb); + Operation op = client.getOpFact().cat(concatType, 0L, key, co.getData(), cb); future.setOp(op); client.addOp(key, op); @@ -262,46 +297,75 @@ public void complete() { } }; Operation op = client.getOpFact() - .cas(StoreType.set, key, casId, co.getFlags(), exp, co.getData(), cb); + .cas(StoreType.set, key, casId, co.getFlags(), exp, co.getData(), cb); future.setOp(op); client.addOp(key, op); return future; } - public ArcusFuture> multiSet(Map items, int exp) { - return multiStore(StoreType.set, items, exp); + public ArcusFuture incr(String key, int delta) { + return mutate(Mutator.incr, key, delta, -1L, 0); } - public ArcusFuture> multiAdd(Map items, int exp) { - return multiStore(StoreType.add, items, exp); + public ArcusFuture incr(String key, int delta, long initial, int exp) { + if (initial < 0) { + throw new IllegalArgumentException("Initial value must be 0 or greater."); + } + return mutate(Mutator.incr, key, delta, initial, exp); } - public ArcusFuture> multiReplace(Map items, int exp) { - return multiStore(StoreType.replace, items, exp); + public ArcusFuture decr(String key, int delta) { + return mutate(Mutator.decr, key, delta, -1L, 0); } - private ArcusFuture> multiStore(StoreType type, - Map items, - int exp) { - Map> keyToFuture = new HashMap<>(items.size()); + public ArcusFuture decr(String key, int delta, long initial, int exp) { + if (initial < 0) { + throw new IllegalArgumentException("Initial value must be 0 or greater."); + } + return mutate(Mutator.decr, key, delta, initial, exp); + } - items.forEach((key, value) -> { - CompletableFuture future = store(type, key, exp, value).toCompletableFuture(); - keyToFuture.put(key, future); - }); + private ArcusFuture mutate(Mutator mutator, String key, int delta, long initial, int exp) { + if (delta <= 0) { + throw new IllegalArgumentException("Delta must be greater than 0."); + } - return new ArcusMultiFuture<>(keyToFuture.values(), () -> { - Map results = new HashMap<>(); - keyToFuture.forEach((key, future) -> { - if (future.isCompletedExceptionally()) { - results.put(key, null); - } else { - results.put(key, (Boolean) future.join()); + AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); + ArcusFutureImpl future = new ArcusFutureImpl<>(result); + ArcusClient client = arcusClientSupplier.get(); + + OperationCallback cb = new OperationCallback() { + @Override + public void receivedStatus(OperationStatus status) { + switch (status.getStatusCode()) { + case SUCCESS: + result.set(Long.parseLong(status.getMessage())); + break; + case ERR_NOT_FOUND: + result.set(-1L); + break; + case CANCELLED: + future.internalCancel(); + break; + default: + /* + * TYPE_MISMATCH or unknown statement. + */ + result.addError(key, status); } - }); - return results; - }); + } + + @Override + public void complete() { + future.complete(); + } + }; + Operation op = client.getOpFact().mutate(mutator, key, delta, initial, exp, cb); + future.setOp(op); + client.addOp(key, op); + + return future; } public ArcusFuture get(String key) { @@ -347,10 +411,10 @@ public void complete() { public ArcusFuture> gets(String key) { AbstractArcusResult> result - = new AbstractArcusResult<>(new AtomicReference<>()); + = new AbstractArcusResult<>(new AtomicReference<>()); @SuppressWarnings("unchecked") ArcusFutureImpl> future = new ArcusFutureImpl<>( - result, r -> r == null ? null : ((GetsResultImpl) r).getDecodedValue()); + result, r -> r == null ? null : ((GetsResultImpl) r).getDecodedValue()); ArcusClient client = arcusClientSupplier.get(); GetsOperation.Callback cb = new GetsOperation.Callback() { @@ -403,7 +467,7 @@ public ArcusFuture> multiGet(List keys) { MemcachedNode node = entry.getKey(); List keyList = entry.getValue(); CompletableFuture> future = getPerNode(client, node, keyList) - .toCompletableFuture(); + .toCompletableFuture(); futureToKeys.put(future, keyList); futures.add(future); } @@ -478,77 +542,13 @@ public void complete() { return future; } - public ArcusFuture incr(String key, int delta) { - return mutate(Mutator.incr, key, delta, -1L, 0); - } - - public ArcusFuture incr(String key, int delta, long initial, int exp) { - if (initial < 0) { - throw new IllegalArgumentException("Initial value must be 0 or greater."); - } - return mutate(Mutator.incr, key, delta, initial, exp); - } - - public ArcusFuture decr(String key, int delta) { - return mutate(Mutator.decr, key, delta, -1L, 0); - } - - public ArcusFuture decr(String key, int delta, long initial, int exp) { - if (initial < 0) { - throw new IllegalArgumentException("Initial value must be 0 or greater."); - } - return mutate(Mutator.decr, key, delta, initial, exp); - } - - private ArcusFuture mutate(Mutator mutator, String key, int delta, long initial, int exp) { - if (delta <= 0) { - throw new IllegalArgumentException("Delta must be greater than 0."); - } - - AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); - ArcusFutureImpl future = new ArcusFutureImpl<>(result); - ArcusClient client = arcusClientSupplier.get(); - - OperationCallback cb = new OperationCallback() { - @Override - public void receivedStatus(OperationStatus status) { - switch (status.getStatusCode()) { - case SUCCESS: - result.set(Long.parseLong(status.getMessage())); - break; - case ERR_NOT_FOUND: - result.set(-1L); - break; - case CANCELLED: - future.internalCancel(); - break; - default: - /* - * TYPE_MISMATCH or unknown statement. - */ - result.addError(key, status); - } - } - - @Override - public void complete() { - future.complete(); - } - }; - Operation op = client.getOpFact().mutate(mutator, key, delta, initial, exp, cb); - future.setOp(op); - client.addOp(key, op); - - return future; - } - public ArcusFuture>> multiGets(List keys) { keyValidator.validateKey(keys); keyValidator.checkDupKey(keys); ArcusClient client = arcusClientSupplier.get(); Collection>> arrangedKeys - = client.groupingKeys(keys, MemcachedClient.GET_BULK_CHUNK_SIZE, APIType.GETS); + = client.groupingKeys(keys, MemcachedClient.GET_BULK_CHUNK_SIZE, APIType.GETS); Collection> futures = new ArrayList<>(); Map>>, List> futureToKeys = new HashMap<>(); @@ -557,7 +557,7 @@ public ArcusFuture>> multiGets(List keys) { MemcachedNode node = entry.getKey(); List keyList = entry.getValue(); CompletableFuture>> future - = getsPerNode(client, node, keyList).toCompletableFuture(); + = getsPerNode(client, node, keyList).toCompletableFuture(); futureToKeys.put(future, keyList); futures.add(future); } @@ -581,13 +581,13 @@ public ArcusFuture>> multiGets(List keys) { private ArcusFuture>> getsPerNode(ArcusClient client, MemcachedNode node, List keyList) { AbstractArcusResult>> result - = new AbstractArcusResult<>(new AtomicReference<>(new HashMap<>())); + = new AbstractArcusResult<>(new AtomicReference<>(new HashMap<>())); @SuppressWarnings("unchecked") ArcusFutureImpl>> future = new ArcusFutureImpl<>(result, r -> { Map> decodedMap = new HashMap<>(); ((Map>) r).forEach((key, getsResult) -> - decodedMap.put(key, getsResult.getDecodedValue())); + decodedMap.put(key, getsResult.getDecodedValue())); return decodedMap; }); @@ -690,40 +690,50 @@ public ArcusFuture> multiDelete(List keys) { }); } - public ArcusFuture bopCreate(String key, ElementValueType type, + public ArcusFuture lopCreate(String key, ElementValueType type, CollectionAttributes attributes) { if (attributes == null) { throw new IllegalArgumentException("CollectionAttributes cannot be null"); } - CollectionCreate create = new BTreeCreate(TranscoderUtils.examineFlags(type), + ListCreate create = new ListCreate(TranscoderUtils.examineFlags(type), attributes.getExpireTime(), attributes.getMaxCount(), attributes.getOverflowAction(), attributes.getReadable(), false); - return collectionCreate(key, create); } - private ArcusFuture collectionCreate(String key, CollectionCreate collectionCreate) { - AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); - ArcusFutureImpl future = new ArcusFutureImpl<>(result); + public ArcusFuture lopInsert(String key, int index, T value) { + return lopInsert(key, index, value, null); + } + + public ArcusFuture lopInsert(String key, int index, T value, + CollectionAttributes attributes) { + ListInsert insert = new ListInsert<>(value, null, attributes); + return collectionInsert(key, String.valueOf(index), insert); + } + + public ArcusFuture lopGet(String key, int index, GetArgs args) { + AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); + ArcusFutureImpl future = new ArcusFutureImpl<>(result); + ListGet get = new ListGet(index, args.isWithDelete(), args.isDropIfEmpty()); ArcusClient client = arcusClientSupplier.get(); - OperationCallback cb = new OperationCallback() { + CollectionGetOperation.Callback cb = new CollectionGetOperation.Callback() { @Override public void receivedStatus(OperationStatus status) { switch (status.getStatusCode()) { case SUCCESS: - result.set(true); break; - case ERR_EXISTS: - result.set(false); + case ERR_NOT_FOUND: + case ERR_NOT_FOUND_ELEMENT: + result.set(null); break; case CANCELLED: future.internalCancel(); break; default: /* - * NOT_SUPPORTED or unknown statement. + * TYPE_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. */ result.addError(key, status); } @@ -733,56 +743,157 @@ public void receivedStatus(OperationStatus status) { public void complete() { future.complete(); } + + @Override + public void gotData(String subKey, int flags, byte[] data, byte[] eFlag) { + CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); + result.set(tcForCollection.decode(cachedData)); + } }; - CollectionCreateOperation op = client.getOpFact() - .collectionCreate(key, collectionCreate, cb); + Operation op = client.getOpFact().collectionGet(key, get, cb); future.setOp(op); client.addOp(key, op); return future; } - public ArcusFuture bopInsert(String key, BTreeElement element, - CollectionAttributes attributes) { - BTreeInsert insert = new BTreeInsert<>(element.getValue(), element.getEFlag(), - null, attributes); - return collectionInsert(key, element.getBKey().toString(), insert); - } - - public ArcusFuture bopInsert(String key, BTreeElement element) { - return bopInsert(key, element, null); - } + public ArcusFuture> lopGet(String key, int from, int to, GetArgs args) { + AbstractArcusResult> result = + new AbstractArcusResult<>(new AtomicReference<>(new ArrayList<>())); + ArcusFutureImpl> future = new ArcusFutureImpl<>(result); + ListGet get = new ListGet(from, to, args.isWithDelete(), args.isDropIfEmpty()); + ArcusClient client = arcusClientSupplier.get(); - @Override - public ArcusFuture bopUpsert(String key, BTreeElement element, - CollectionAttributes attributes) { - BTreeUpsert upsert = new BTreeUpsert<>(element.getValue(), element.getEFlag(), - null, attributes); - return collectionInsert(key, element.getBKey().toString(), upsert); + CollectionGetOperation.Callback cb = new CollectionGetOperation.Callback() { + @Override + public void receivedStatus(OperationStatus status) { + switch (status.getStatusCode()) { + case SUCCESS: + case ERR_NOT_FOUND_ELEMENT: + break; + case ERR_NOT_FOUND: + result.set(null); + break; + case CANCELLED: + future.internalCancel(); + break; + default: + /* + * TYPE_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. + */ + result.addError(key, status); + } + } + + @Override + public void complete() { + future.complete(); + } + + @Override + public void gotData(String subKey, int flags, byte[] data, byte[] eFlag) { + CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); + result.get().add(tcForCollection.decode(cachedData)); + } + }; + Operation op = client.getOpFact().collectionGet(key, get, cb); + future.setOp(op); + client.addOp(key, op); + + return future; } - @Override - public ArcusFuture bopUpsert(String key, BTreeElement element) { - return bopUpsert(key, element, null); + public ArcusFuture lopDelete(String key, int index, boolean dropIfEmpty) { + ListDelete delete = new ListDelete(index, dropIfEmpty, false); + return collectionDelete(key, delete); } - private ArcusFuture collectionInsert(String key, - String internalKey, - CollectionInsert collectionInsert) { + public ArcusFuture lopDelete(String key, int from, int to, boolean dropIfEmpty) { + ListDelete delete = new ListDelete(from, to, dropIfEmpty, false); + return collectionDelete(key, delete); + } + + public ArcusFuture sopCreate(String key, ElementValueType type, + CollectionAttributes attributes) { + if (attributes == null) { + throw new IllegalArgumentException("CollectionAttributes cannot be null"); + } + + SetCreate create = new SetCreate( + TranscoderUtils.examineFlags(type), attributes.getExpireTime(), + attributes.getMaxCount(), attributes.getReadable(), false); + return collectionCreate(key, create); + } + + public ArcusFuture sopInsert(String key, T value) { + return sopInsert(key, value, null); + } + + public ArcusFuture sopInsert(String key, T value, CollectionAttributes attributes) { + SetInsert insert = new SetInsert<>(value, null, attributes); + return collectionInsert(key, "", insert); + } + + public ArcusFuture> sopGet(String key, int count, GetArgs args) { + AbstractArcusResult> result + = new AbstractArcusResult<>(new AtomicReference<>(new HashSet<>())); + ArcusFutureImpl> future = new ArcusFutureImpl<>(result); + SetGet get = new SetGet(count, args.isWithDelete(), args.isDropIfEmpty()); + ArcusClient client = arcusClientSupplier.get(); + + CollectionGetOperation.Callback cb = new CollectionGetOperation.Callback() { + @Override + public void gotData(String subKey, int flags, byte[] data, byte[] eFlag) { + CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); + result.get().add(tcForCollection.decode(cachedData)); + } + + @Override + public void receivedStatus(OperationStatus status) { + switch (status.getStatusCode()) { + case SUCCESS: + case ERR_NOT_FOUND_ELEMENT: + break; + case ERR_NOT_FOUND: + result.set(null); + break; + case CANCELLED: + future.internalCancel(); + break; + default: + /* + * TYPE_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. + */ + result.addError(key, status); + } + } + + @Override + public void complete() { + future.complete(); + } + }; + Operation op = client.getOpFact().collectionGet(key, get, cb); + future.setOp(op); + client.addOp(key, op); + + return future; + } + + public ArcusFuture sopExist(String key, T value) { AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); ArcusFutureImpl future = new ArcusFutureImpl<>(result); - CachedData co = tcForCollection.encode(collectionInsert.getValue()); - collectionInsert.setFlags(co.getFlags()); + SetExist exist = new SetExist<>(value, tcForCollection); ArcusClient client = arcusClientSupplier.get(); OperationCallback cb = new OperationCallback() { @Override public void receivedStatus(OperationStatus status) { switch (status.getStatusCode()) { - case SUCCESS: + case EXIST: result.set(true); break; - case ERR_ELEMENT_EXISTS: + case NOT_EXIST: result.set(false); break; case ERR_NOT_FOUND: @@ -793,8 +904,7 @@ public void receivedStatus(OperationStatus status) { break; default: /* - * TYPE_MISMATCH / BKEY_MISMATCH / OVERFLOWED / OUT_OF_RANGE / NOT_SUPPORTED - * or unknown statement. + * TYPE_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. */ result.addError(key, status); } @@ -805,40 +915,140 @@ public void complete() { future.complete(); } }; - CollectionInsertOperation op = client.getOpFact() - .collectionInsert(key, internalKey, collectionInsert, co.getData(), cb); + Operation op = client.getOpFact().collectionExist(key, "", exist, cb); future.setOp(op); client.addOp(key, op); return future; } - public ArcusFuture bopUpdate(String key, BTreeUpdateElement element) { - BTreeUpdate update = new BTreeUpdate<>(element.getValue(), element.getEFlagUpdate(), false); - return collectionUpdate(key, element.getBKey().toString(), update); + public ArcusFuture sopDelete(String key, T value, boolean dropIfEmpty) { + SetDelete delete = new SetDelete<>(value, dropIfEmpty, false, tcForCollection); + return collectionDelete(key, delete); } - private ArcusFuture collectionUpdate(String key, - String internalKey, - CollectionUpdate collectionUpdate) { - AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); - ArcusFutureImpl future = new ArcusFutureImpl<>(result); - CachedData co = null; - if (collectionUpdate.getNewValue() != null) { - co = tcForCollection.encode(collectionUpdate.getNewValue()); - collectionUpdate.setFlags(co.getFlags()); + public ArcusFuture mopCreate(String key, ElementValueType type, + CollectionAttributes attributes) { + if (attributes == null) { + throw new IllegalArgumentException("CollectionAttributes cannot be null"); } + + MapCreate create = new MapCreate(TranscoderUtils.examineFlags(type), + attributes.getExpireTime(), attributes.getMaxCount(), + attributes.getReadable(), false); + return collectionCreate(key, create); + } + + public ArcusFuture mopInsert(String key, String mKey, T value) { + return mopInsert(key, mKey, value, null); + } + + public ArcusFuture mopInsert(String key, String mKey, T value, + CollectionAttributes attributes) { + keyValidator.validateMKey(mKey); + + MapInsert insert = new MapInsert<>(value, null, attributes); + return collectionInsert(key, mKey, insert); + } + + public ArcusFuture mopUpsert(String key, String mKey, T value) { + return mopUpsert(key, mKey, value, null); + } + + public ArcusFuture mopUpsert(String key, String mKey, T value, + CollectionAttributes attributes) { + keyValidator.validateMKey(mKey); + + MapUpsert upsert = new MapUpsert<>(value, attributes); + return collectionInsert(key, mKey, upsert); + } + + public ArcusFuture mopUpdate(String key, String mKey, T value) { + keyValidator.validateMKey(mKey); + + MapUpdate update = new MapUpdate<>(value, false); + return collectionUpdate(key, mKey, update); + } + + public ArcusFuture> mopGet(String key, GetArgs args) { + return mopGet(key, new ArrayList<>(), args); + } + + public ArcusFuture mopGet(String key, String mKey, GetArgs args) { + keyValidator.validateMKey(mKey); + + AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); + ArcusFutureImpl future = new ArcusFutureImpl<>(result); + List mKeys = Collections.singletonList(mKey); + MapGet get = new MapGet(mKeys, args.isWithDelete(), args.isDropIfEmpty()); ArcusClient client = arcusClientSupplier.get(); - OperationCallback cb = new OperationCallback() { + CollectionGetOperation.Callback cb = new CollectionGetOperation.Callback() { + @Override + public void gotData(String mKey, int flags, byte[] data, byte[] eFlag) { + CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); + result.set(tcForCollection.decode(cachedData)); + } + @Override public void receivedStatus(OperationStatus status) { switch (status.getStatusCode()) { case SUCCESS: - result.set(true); break; case ERR_NOT_FOUND_ELEMENT: - result.set(false); + case ERR_NOT_FOUND: + result.set(null); + break; + case CANCELLED: + future.internalCancel(); + break; + default: + /* + * TYPE_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. + */ + result.addError(key, status); + } + } + + @Override + public void complete() { + future.complete(); + } + }; + Operation op = client.getOpFact().collectionGet(key, get, cb); + future.setOp(op); + client.addOp(key, op); + + return future; + } + + public ArcusFuture> mopGet(String key, List mKeys, GetArgs args) { + if (mKeys == null) { + throw new IllegalArgumentException("mKeys cannot be null"); + } + + if (!mKeys.isEmpty()) { + keyValidator.validateMKey(mKeys); + } + + AbstractArcusResult> result = + new AbstractArcusResult<>(new AtomicReference<>(new HashMap<>())); + ArcusFutureImpl> future = new ArcusFutureImpl<>(result); + MapGet get = new MapGet(mKeys, args.isWithDelete(), args.isDropIfEmpty()); + ArcusClient client = arcusClientSupplier.get(); + + CollectionGetOperation.Callback cb = new CollectionGetOperation.Callback() { + @Override + public void gotData(String mKey, int flags, byte[] data, byte[] eFlag) { + CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); + result.get().put(mKey, tcForCollection.decode(cachedData)); + } + + @Override + public void receivedStatus(OperationStatus status) { + switch (status.getStatusCode()) { + case SUCCESS: + case ERR_NOT_FOUND_ELEMENT: break; case ERR_NOT_FOUND: result.set(null); @@ -848,8 +1058,7 @@ public void receivedStatus(OperationStatus status) { break; default: /* - * TYPE_MISMATCH / BKEY_MISMATCH / EFLAG_MISMATCH / NOTHING_TO_UPDATE / - * OVERFLOWED / OUT_OF_RANGE / NOT_SUPPORTED or unknown statement. + * TYPE_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. */ result.addError(key, status); } @@ -860,18 +1069,56 @@ public void complete() { future.complete(); } }; - Operation op = client.getOpFact() - .collectionUpdate(key, internalKey, collectionUpdate, - (co == null) ? null : co.getData(), cb); + Operation op = client.getOpFact().collectionGet(key, get, cb); future.setOp(op); client.addOp(key, op); return future; } - public ArcusFuture>> bopInsertAndGetTrimmed( - String key, BTreeElement element, CollectionAttributes attributes) { - return bopInsertOrUpsertAndGetTrimmed(key, element, false, attributes); + public ArcusFuture mopDelete(String key, boolean dropIfEmpty) { + return mopDelete(key, new ArrayList<>(), dropIfEmpty); + } + + public ArcusFuture mopDelete(String key, String mKey, boolean dropIfEmpty) { + return mopDelete(key, Collections.singletonList(mKey), dropIfEmpty); + } + + public ArcusFuture mopDelete(String key, List mKeys, boolean dropIfEmpty) { + if (mKeys == null) { + throw new IllegalArgumentException("mKeys cannot be null"); + } + + if (!mKeys.isEmpty()) { + keyValidator.validateMKey(mKeys); + } + + MapDelete delete = new MapDelete(mKeys, dropIfEmpty, false); + return collectionDelete(key, delete); + } + + public ArcusFuture bopCreate(String key, ElementValueType type, + CollectionAttributes attributes) { + if (attributes == null) { + throw new IllegalArgumentException("CollectionAttributes cannot be null"); + } + + CollectionCreate create = new BTreeCreate(TranscoderUtils.examineFlags(type), + attributes.getExpireTime(), attributes.getMaxCount(), + attributes.getOverflowAction(), attributes.getReadable(), false); + + return collectionCreate(key, create); + } + + public ArcusFuture bopInsert(String key, BTreeElement element) { + return bopInsert(key, element, null); + } + + public ArcusFuture bopInsert(String key, BTreeElement element, + CollectionAttributes attributes) { + BTreeInsert insert = new BTreeInsert<>(element.getValue(), element.getEFlag(), + null, attributes); + return collectionInsert(key, element.getBKey().toString(), insert); } public ArcusFuture>> bopInsertAndGetTrimmed( @@ -879,9 +1126,22 @@ public ArcusFuture>> bopInsertAndGetTrimmed( return bopInsertOrUpsertAndGetTrimmed(key, element, false, null); } - public ArcusFuture>> bopUpsertAndGetTrimmed( + public ArcusFuture>> bopInsertAndGetTrimmed( String key, BTreeElement element, CollectionAttributes attributes) { - return bopInsertOrUpsertAndGetTrimmed(key, element, true, attributes); + return bopInsertOrUpsertAndGetTrimmed(key, element, false, attributes); + } + + @Override + public ArcusFuture bopUpsert(String key, BTreeElement element) { + return bopUpsert(key, element, null); + } + + @Override + public ArcusFuture bopUpsert(String key, BTreeElement element, + CollectionAttributes attributes) { + BTreeUpsert upsert = new BTreeUpsert<>(element.getValue(), element.getEFlag(), + null, attributes); + return collectionInsert(key, element.getBKey().toString(), upsert); } public ArcusFuture>> bopUpsertAndGetTrimmed( @@ -889,6 +1149,11 @@ public ArcusFuture>> bopUpsertAndGetTrimmed( return bopInsertOrUpsertAndGetTrimmed(key, element, true, null); } + public ArcusFuture>> bopUpsertAndGetTrimmed( + String key, BTreeElement element, CollectionAttributes attributes) { + return bopInsertOrUpsertAndGetTrimmed(key, element, true, attributes); + } + private ArcusFutureImpl>> bopInsertOrUpsertAndGetTrimmed( String key, BTreeElement element, boolean isUpsert, CollectionAttributes attributes) { AbstractArcusResult>> result = @@ -934,7 +1199,7 @@ public void complete() { public void gotData(int flags, BKeyObject bKeyObject, byte[] eFlag, byte[] data) { CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); trimmedElement = new BTreeElement<>( - BKey.of(bKeyObject), tcForCollection.decode(cachedData), eFlag); + BKey.of(bKeyObject), tcForCollection.decode(cachedData), eFlag); } }; Operation op = client.getOpFact() @@ -948,15 +1213,38 @@ public void gotData(int flags, BKeyObject bKeyObject, byte[] eFlag, byte[] data) private static BTreeInsertAndGet createBTreeInsertAndGet(BTreeElement element, boolean isUpsert, CollectionAttributes attributes) { - BTreeInsertAndGet insertAndGet; if (element.getBKey().getType() == BKey.BKeyType.LONG) { - insertAndGet = new BTreeInsertAndGet<>((Long) element.getBKey().getData(), - element.getEFlag(), element.getValue(), isUpsert, attributes); - } else { - insertAndGet = new BTreeInsertAndGet<>((byte[]) element.getBKey().getData(), + return new BTreeInsertAndGet<>((long) element.getBKey().getData(), element.getEFlag(), element.getValue(), isUpsert, attributes); } - return insertAndGet; + + return new BTreeInsertAndGet<>((byte[]) element.getBKey().getData(), + element.getEFlag(), element.getValue(), isUpsert, attributes); + } + + public ArcusFuture bopUpdate(String key, BTreeUpdateElement element) { + BTreeUpdate update = new BTreeUpdate<>(element.getValue(), element.getEFlagUpdate(), false); + return collectionUpdate(key, element.getBKey().toString(), update); + } + + public ArcusFuture bopIncr(String key, BKey bKey, int delta) { + CollectionMutate mutate = new BTreeMutate(Mutator.incr, delta); + return collectionMutate(key, bKey.toString(), mutate); + } + + public ArcusFuture bopIncr(String key, BKey bKey, int delta, long initial, byte[] eFlag) { + CollectionMutate mutate = new BTreeMutate(Mutator.incr, delta, initial, eFlag); + return collectionMutate(key, bKey.toString(), mutate); + } + + public ArcusFuture bopDecr(String key, BKey bKey, int delta) { + CollectionMutate mutate = new BTreeMutate(Mutator.decr, delta); + return collectionMutate(key, bKey.toString(), mutate); + } + + public ArcusFuture bopDecr(String key, BKey bKey, int delta, long initial, byte[] eFlag) { + CollectionMutate mutate = new BTreeMutate(Mutator.decr, delta, initial, eFlag); + return collectionMutate(key, bKey.toString(), mutate); } public ArcusFuture> bopGet(String key, BKey bKey, BopGetArgs args) { @@ -1005,18 +1293,6 @@ public void gotData(String bKey, int flags, byte[] data, byte[] eFlag) { return future; } - private static BTreeGet createBTreeGet(BKey bKey, BopGetArgs args) { - BTreeGet get; - if (bKey.getType() == BKey.BKeyType.LONG) { - get = new BTreeGet((long) bKey.getData(), args.getElementFlagFilter(), - args.isWithDelete(), args.isDropIfEmpty()); - } else { - get = new BTreeGet((byte[]) bKey.getData(), args.getElementFlagFilter(), - args.isWithDelete(), args.isDropIfEmpty()); - } - return get; - } - public ArcusFuture> bopGet(String key, BKey from, BKey to, BopGetArgs args) { verifyBKeyTypesMatch(from, to); @@ -1057,7 +1333,7 @@ public void complete() { public void gotData(String bKey, int flags, byte[] data, byte[] eFlag) { CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); result.get().addElement(new BTreeElement<>( - BKey.of(bKey), tcForCollection.decode(cachedData), eFlag)); + BKey.of(bKey), tcForCollection.decode(cachedData), eFlag)); } }; Operation op = client.getOpFact().collectionGet(key, get, cb); @@ -1067,18 +1343,26 @@ public void gotData(String bKey, int flags, byte[] data, byte[] eFlag) { return future; } + private static BTreeGet createBTreeGet(BKey bKey, BopGetArgs args) { + if (bKey.getType() == BKey.BKeyType.LONG) { + return new BTreeGet((long) bKey.getData(), args.getElementFlagFilter(), + args.isWithDelete(), args.isDropIfEmpty()); + } + + return new BTreeGet((byte[]) bKey.getData(), args.getElementFlagFilter(), + args.isWithDelete(), args.isDropIfEmpty()); + } + private static BTreeGet createBTreeGet(BKey from, BKey to, BopGetArgs args) { - BTreeGet get; if (from.getType() == BKey.BKeyType.LONG) { - get = new BTreeGet((Long) from.getData(), (Long) to.getData(), - args.getElementFlagFilter(), args.getOffset(), args.getCount(), - args.isWithDelete(), args.isDropIfEmpty()); - } else { - get = new BTreeGet((byte[]) from.getData(), (byte[]) to.getData(), + return new BTreeGet((long) from.getData(), (long) to.getData(), args.getElementFlagFilter(), args.getOffset(), args.getCount(), args.isWithDelete(), args.isDropIfEmpty()); } - return get; + + return new BTreeGet((byte[]) from.getData(), (byte[]) to.getData(), + args.getElementFlagFilter(), args.getOffset(), args.getCount(), + args.isWithDelete(), args.isDropIfEmpty()); } public ArcusFuture>> bopMultiGet(List keys, @@ -1106,261 +1390,47 @@ public ArcusFuture>> bopMultiGet(List keys, futures.add(future); } - /* - * Combine all futures. If any future fails exceptionally, - * the corresponding keys will have null values in the result map. - * If key not found, the corresponding key will not be present in the result map. - */ return new ArcusMultiFuture<>(futures, () -> { Map> results = new HashMap<>(); for (Map.Entry>>, List> entry - : futureToKeys.entrySet()) { - if (entry.getKey().isCompletedExceptionally()) { - for (String key : entry.getValue()) { - results.put(key, null); - } - } else { - Map> result = entry.getKey().join(); - if (result != null) { - results.putAll(result); - } - } - } - return results; - }); - } - - private void verifyPositiveCountArg(BopGetArgs args, int maxCount) { - int count = args.getCount(); - if (count <= 0 || count > maxCount) { - throw new IllegalArgumentException("Count should be between 1 to " + maxCount); - } - } - - /** - * Use only in bopMultiGet method. - * - * @param getBulk get bulk parameters for single node - * @return ArcusFuture with results - */ - private ArcusFuture>> bopMultiGetPerNode(ArcusClient client, - BTreeGetBulk getBulk) { - AbstractArcusResult>> result = - new AbstractArcusResult<>(new AtomicReference<>(new HashMap<>())); - ArcusFutureImpl>> future = new ArcusFutureImpl<>(result); - - BTreeGetBulkOperation.Callback cb = new BTreeGetBulkOperation.Callback() { - @Override - public void receivedStatus(OperationStatus status) { - switch (status.getStatusCode()) { - case SUCCESS: - break; - case CANCELLED: - future.internalCancel(); - break; - default: - /* - * NOT_SUPPORTED or unknown statement. - */ - for (String key : getBulk.getKeyList()) { - result.addError(key, status); - } - } - } - - @Override - public void complete() { - future.complete(); - } - - @Override - public void gotKey(String key, int elementCount, OperationStatus status) { - switch (status.getStatusCode()) { - case SUCCESS: - result.get().put(key, new BTreeElements<>(new ArrayList<>())); - break; - case TRIMMED: - BTreeElements elements = new BTreeElements<>(new ArrayList<>()); - elements.trimmed(); - result.get().put(key, elements); - break; - case ERR_NOT_FOUND: - break; - case ERR_NOT_FOUND_ELEMENT: - // Put empty BTreeElements for the BTree item key - result.get().put(key, new BTreeElements<>(new ArrayList<>())); - break; - default: - /* - * TYPE_MISMATCH / BKEY_MISMATCH / OUT_OF_RANGE / UNREADABLE - * or unknown statement. - */ - result.addError(key, status); - } - } - - @Override - public void gotElement(String key, int flags, Object bKey, byte[] eFlag, byte[] data) { - CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - BTreeElements elements = result.get().get(key); - elements.addElement(new BTreeElement<>( - BKey.of(bKey), tcForCollection.decode(cachedData), eFlag)); - } - }; - Operation op = client.getOpFact().bopGetBulk(getBulk, cb); - future.setOp(op); - client.addOp(getBulk.getMemcachedNode(), op); - - return future; - } - - private static void verifyBKeyTypesMatch(BKey from, BKey to) { - if (from.getType() != to.getType()) { - throw new IllegalArgumentException("Two BKey types(from, to) must be the same."); - } - } - - private BTreeGetBulk createBTreeGetBulk(MemcachedNode node, List keys, - BKey from, BKey to, BopGetArgs args) { - if (from.getType() == BKey.BKeyType.LONG) { - return new BTreeGetBulkWithLongTypeBkey<>(node, keys, - (Long) from.getData(), (Long) to.getData(), args.getElementFlagFilter(), - args.getOffset(), args.getCount()); - } else { - return new BTreeGetBulkWithByteTypeBkey<>(node, keys, - (byte[]) from.getData(), (byte[]) to.getData(), args.getElementFlagFilter(), - args.getOffset(), args.getCount()); - } - } - - public ArcusFuture bopGetPosition(String key, BKey bKey, BTreeOrder order) { - AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); - ArcusFutureImpl future = new ArcusFutureImpl<>(result); - BTreeFindPosition findPosition = new BTreeFindPosition(bKey.toString(), order); - ArcusClient client = arcusClientSupplier.get(); - - BTreeFindPositionOperation.Callback cb = new BTreeFindPositionOperation.Callback() { - @Override - public void gotData(int position) { - result.set(position); - } - - @Override - public void receivedStatus(OperationStatus status) { - switch (status.getStatusCode()) { - case SUCCESS: - break; - case ERR_NOT_FOUND: - case ERR_NOT_FOUND_ELEMENT: - result.set(null); - break; - case CANCELLED: - future.internalCancel(); - break; - default: - /* - * TYPE_MISMATCH / BKEY_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. - */ - result.addError(key, status); - } - } - - @Override - public void complete() { - future.complete(); - } - }; - Operation op = client.getOpFact().bopFindPosition(key, findPosition, cb); - future.setOp(op); - client.addOp(key, op); - - return future; - } - - public ArcusFuture> bopGetByPosition(String key, int pos, BTreeOrder order) { - AbstractArcusResult> result - = new AbstractArcusResult<>(new AtomicReference<>()); - ArcusFutureImpl> future = new ArcusFutureImpl<>(result); - BTreeGetByPosition getByPosition = new BTreeGetByPosition(order, pos); - ArcusClient client = arcusClientSupplier.get(); - - BTreeGetByPositionOperation.Callback cb = new BTreeGetByPositionOperation.Callback() { - @Override - public void gotData(int pos, int flags, BKeyObject bKey, byte[] eFlag, byte[] data) { - CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - result.set(new BTreeElement<>(BKey.of(bKey), tcForCollection.decode(cachedData), eFlag)); - } - - @Override - public void receivedStatus(OperationStatus status) { - switch (status.getStatusCode()) { - case SUCCESS: - break; - case ERR_NOT_FOUND: - case ERR_NOT_FOUND_ELEMENT: - result.set(null); - break; - case CANCELLED: - future.internalCancel(); - break; - default: - /* - * TYPE_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. - */ - result.addError(key, status); - } - } - - @Override - public void complete() { - future.complete(); - } - }; - Operation op = client.getOpFact().bopGetByPosition(key, getByPosition, cb); - future.setOp(op); - client.addOp(key, op); - - return future; - } - - public ArcusFuture>> bopGetByPosition(String key, - int from, int to, - BTreeOrder order) { - if (from > to) { - throw new IllegalArgumentException("from should be less than or equal to to."); - } - - AbstractArcusResult>> result - = new AbstractArcusResult<>(new AtomicReference<>(new ArrayList<>())); - ArcusFutureImpl>> future = new ArcusFutureImpl<>(result); - BTreeGetByPosition getByPosition = new BTreeGetByPosition(order, from, to); - ArcusClient client = arcusClientSupplier.get(); - - BTreeGetByPositionOperation.Callback cb = new BTreeGetByPositionOperation.Callback() { - @Override - public void gotData(int pos, int flags, BKeyObject bKey, byte[] eFlag, byte[] data) { - CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - result.get().add(new BTreeElement<>( - BKey.of(bKey), tcForCollection.decode(cachedData), eFlag)); + : futureToKeys.entrySet()) { + if (entry.getKey().isCompletedExceptionally()) { + for (String key : entry.getValue()) { + results.put(key, null); + } + } else { + Map> result = entry.getKey().join(); + if (result != null) { + results.putAll(result); + } + } } + return results; + }); + } + + private ArcusFuture>> bopMultiGetPerNode(ArcusClient client, + BTreeGetBulk getBulk) { + AbstractArcusResult>> result = + new AbstractArcusResult<>(new AtomicReference<>(new HashMap<>())); + ArcusFutureImpl>> future = new ArcusFutureImpl<>(result); + BTreeGetBulkOperation.Callback cb = new BTreeGetBulkOperation.Callback() { @Override public void receivedStatus(OperationStatus status) { switch (status.getStatusCode()) { case SUCCESS: - case ERR_NOT_FOUND_ELEMENT: - break; - case ERR_NOT_FOUND: - result.set(null); break; case CANCELLED: future.internalCancel(); break; default: /* - * TYPE_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. + * NOT_SUPPORTED or unknown statement. */ - result.addError(key, status); + for (String key : getBulk.getKeyList()) { + result.addError(key, status); + } } } @@ -1368,67 +1438,61 @@ public void receivedStatus(OperationStatus status) { public void complete() { future.complete(); } - }; - Operation op = client.getOpFact().bopGetByPosition(key, getByPosition, cb); - future.setOp(op); - client.addOp(key, op); - - return future; - } - - public ArcusFuture>> bopPositionWithGet(String key, - BKey bKey, - int count, - BTreeOrder order) { - AbstractArcusResult>> result = - new AbstractArcusResult<>(new AtomicReference<>(new ArrayList<>())); - ArcusFutureImpl>> future = new ArcusFutureImpl<>(result); - BTreeFindPositionWithGet findPositionWithGet = - new BTreeFindPositionWithGet(bKey.toBKeyObject(), order, count); - ArcusClient client = arcusClientSupplier.get(); - - BTreeFindPositionWithGetOperation.Callback cb = new BTreeFindPositionWithGetOperation - .Callback() { - - @Override - public void gotData(int pos, int flags, BKeyObject bKey, byte[] eFlag, byte[] data) { - CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - result.get().add(new BTreePositionElement<>( - BKey.of(bKey), tcForCollection.decode(cachedData), eFlag, pos)); - } @Override - public void receivedStatus(OperationStatus status) { + public void gotKey(String key, int elementCount, OperationStatus status) { switch (status.getStatusCode()) { case SUCCESS: - case ERR_NOT_FOUND_ELEMENT: + result.get().put(key, new BTreeElements<>(new ArrayList<>())); + break; + case TRIMMED: + BTreeElements elements = new BTreeElements<>(new ArrayList<>()); + elements.trimmed(); + result.get().put(key, elements); break; case ERR_NOT_FOUND: - result.set(null); break; - case CANCELLED: - future.internalCancel(); + case ERR_NOT_FOUND_ELEMENT: + // Put empty BTreeElements for the BTree item key + result.get().put(key, new BTreeElements<>(new ArrayList<>())); break; default: /* - * TYPE_MISMATCH / BKEY_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. + * TYPE_MISMATCH / BKEY_MISMATCH / OUT_OF_RANGE / UNREADABLE + * or unknown statement. */ result.addError(key, status); } } @Override - public void complete() { - future.complete(); + public void gotElement(String key, int flags, Object bKey, byte[] eFlag, byte[] data) { + CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); + BTreeElements elements = result.get().get(key); + elements.addElement(new BTreeElement<>( + BKey.of(bKey), tcForCollection.decode(cachedData), eFlag)); } }; - Operation op = client.getOpFact().bopFindPositionWithGet(key, findPositionWithGet, cb); + Operation op = client.getOpFact().bopGetBulk(getBulk, cb); future.setOp(op); - client.addOp(key, op); + client.addOp(getBulk.getMemcachedNode(), op); return future; } + private BTreeGetBulk createBTreeGetBulk(MemcachedNode node, List keys, + BKey from, BKey to, BopGetArgs args) { + if (from.getType() == BKey.BKeyType.LONG) { + return new BTreeGetBulkWithLongTypeBkey<>(node, keys, + (long) from.getData(), (long) to.getData(), args.getElementFlagFilter(), + args.getOffset(), args.getCount()); + } + + return new BTreeGetBulkWithByteTypeBkey<>(node, keys, + (byte[]) from.getData(), (byte[]) to.getData(), args.getElementFlagFilter(), + args.getOffset(), args.getCount()); + } + public ArcusFuture> bopSortMergeGet(List keys, BKey from, BKey to, boolean unique, BopGetArgs args) { keyValidator.validateKey(keys); @@ -1449,9 +1513,6 @@ public ArcusFuture> bopSortMergeGet(List keys, BKey fro smGetFutures.add(future); } - /* - * Combine all futures and merge results from multiple nodes. - */ @SuppressWarnings("unchecked") Collection> futures = (Collection>) (Collection) smGetFutures; @@ -1467,12 +1528,6 @@ public ArcusFuture> bopSortMergeGet(List keys, BKey fro }); } - /** - * Use only in bopSortMergeGet method. - * - * @param smGet sort-merge get parameters for single node - * @return ArcusFuture with results - */ private ArcusFuture> bopSortMergeGetPerNode(ArcusClient client, BTreeSMGet smGet) { List> elementList = new ArrayList<>(); @@ -1517,7 +1572,7 @@ public void complete() { public void gotData(String key, int flags, Object bKey, byte[] eFlag, byte[] data) { CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); BTreeElement btreeElement = new BTreeElement<>( - BKey.of(bKey), tcForCollection.decode(cachedData), eFlag); + BKey.of(bKey), tcForCollection.decode(cachedData), eFlag); elementList.add(new SMGetElements.Element<>(key, btreeElement)); } @@ -1541,50 +1596,33 @@ public void gotTrimmedKey(String key, Object bKey) { private BTreeSMGet createBTreeSMGet(BKey from, BKey to, BopGetArgs args, boolean unique, Map.Entry> entry) { - if (from.getType() == BKey.BKeyType.LONG) { return new BTreeSMGetWithLongTypeBkey<>(entry.getKey(), entry.getValue(), - (Long) from.getData(), (Long) to.getData(), args.getElementFlagFilter(), - args.getCount(), unique); - } else { - return new BTreeSMGetWithByteTypeBkey<>(entry.getKey(), entry.getValue(), - (byte[]) from.getData(), (byte[]) to.getData(), args.getElementFlagFilter(), + (long) from.getData(), (long) to.getData(), args.getElementFlagFilter(), args.getCount(), unique); } - } - - public ArcusFuture bopIncr(String key, BKey bKey, int delta) { - CollectionMutate mutate = new BTreeMutate(Mutator.incr, delta); - return collectionMutate(key, bKey.toString(), mutate); - } - public ArcusFuture bopIncr(String key, BKey bKey, int delta, long initial, byte[] eFlag) { - CollectionMutate mutate = new BTreeMutate(Mutator.incr, delta, initial, eFlag); - return collectionMutate(key, bKey.toString(), mutate); - } - - public ArcusFuture bopDecr(String key, BKey bKey, int delta) { - CollectionMutate mutate = new BTreeMutate(Mutator.decr, delta); - return collectionMutate(key, bKey.toString(), mutate); + return new BTreeSMGetWithByteTypeBkey<>(entry.getKey(), entry.getValue(), + (byte[]) from.getData(), (byte[]) to.getData(), args.getElementFlagFilter(), + args.getCount(), unique); } - public ArcusFuture bopDecr(String key, BKey bKey, int delta, long initial, byte[] eFlag) { - CollectionMutate mutate = new BTreeMutate(Mutator.decr, delta, initial, eFlag); - return collectionMutate(key, bKey.toString(), mutate); - } - - private ArcusFuture collectionMutate(String key, String internalKey, - CollectionMutate mutate) { - AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); - ArcusFutureImpl future = new ArcusFutureImpl<>(result); + public ArcusFuture bopGetPosition(String key, BKey bKey, BTreeOrder order) { + AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); + ArcusFutureImpl future = new ArcusFutureImpl<>(result); + BTreeFindPosition findPosition = new BTreeFindPosition(bKey.toString(), order); ArcusClient client = arcusClientSupplier.get(); - OperationCallback cb = new OperationCallback() { + BTreeFindPositionOperation.Callback cb = new BTreeFindPositionOperation.Callback() { + @Override + public void gotData(int position) { + result.set(position); + } + @Override public void receivedStatus(OperationStatus status) { switch (status.getStatusCode()) { case SUCCESS: - result.set(Long.parseLong(status.getMessage())); break; case ERR_NOT_FOUND: case ERR_NOT_FOUND_ELEMENT: @@ -1595,8 +1633,7 @@ public void receivedStatus(OperationStatus status) { break; default: /* - * TYPE_MISMATCH / BKEY_MISMATCH / OUT_OF_RANGE / - * OVERFLOWED / NOT_SUPPORTED or unknown statement. + * TYPE_MISMATCH / BKEY_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. */ result.addError(key, status); } @@ -1607,50 +1644,42 @@ public void complete() { future.complete(); } }; - Operation op = client.getOpFact().collectionMutate(key, internalKey, mutate, cb); + Operation op = client.getOpFact().bopFindPosition(key, findPosition, cb); future.setOp(op); client.addOp(key, op); return future; } - public ArcusFuture bopDelete(String key, BKey bKey, BopDeleteArgs args) { - BTreeDelete delete = new BTreeDelete(bKey.toString(), - args.getEFlagFilter(), args.isDropIfEmpty(), false); - return collectionDelete(key, delete); - } - - public ArcusFuture bopDelete(String key, BKey from, BKey to, BopDeleteArgs args) { - verifyBKeyTypesMatch(from, to); - BTreeDelete delete = new BTreeDelete(from.toString(), to.toString(), - args.getCount(), args.getEFlagFilter(), args.isDropIfEmpty(), false); - return collectionDelete(key, delete); - } - - private ArcusFuture collectionDelete(String key, CollectionDelete delete) { - AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); - ArcusFutureImpl future = new ArcusFutureImpl<>(result); + public ArcusFuture> bopGetByPosition(String key, int pos, BTreeOrder order) { + AbstractArcusResult> result + = new AbstractArcusResult<>(new AtomicReference<>()); + ArcusFutureImpl> future = new ArcusFutureImpl<>(result); + BTreeGetByPosition getByPosition = new BTreeGetByPosition(order, pos); ArcusClient client = arcusClientSupplier.get(); - OperationCallback cb = new OperationCallback() { + BTreeGetByPositionOperation.Callback cb = new BTreeGetByPositionOperation.Callback() { + @Override + public void gotData(int pos, int flags, BKeyObject bKey, byte[] eFlag, byte[] data) { + CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); + result.set(new BTreeElement<>(BKey.of(bKey), tcForCollection.decode(cachedData), eFlag)); + } + @Override public void receivedStatus(OperationStatus status) { switch (status.getStatusCode()) { case SUCCESS: - result.set(true); break; case ERR_NOT_FOUND: - result.set(null); - break; case ERR_NOT_FOUND_ELEMENT: - result.set(false); + result.set(null); break; case CANCELLED: future.internalCancel(); break; default: /* - * TYPE_MISMATCH / BKEY_MISMATCH / NOT_SUPPORTED or unknown statement. + * TYPE_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. */ result.addError(key, status); } @@ -1661,28 +1690,39 @@ public void complete() { future.complete(); } }; - Operation op = client.getOpFact().collectionDelete(key, delete, cb); + Operation op = client.getOpFact().bopGetByPosition(key, getByPosition, cb); future.setOp(op); client.addOp(key, op); return future; } - public ArcusFuture bopCount(String key, BKey from, BKey to, ElementFlagFilter eFlagFilter) { - verifyBKeyTypesMatch(from, to); + public ArcusFuture>> bopGetByPosition(String key, + int from, int to, + BTreeOrder order) { + if (from > to) { + throw new IllegalArgumentException("from should be less than or equal to to."); + } - AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); - ArcusFutureImpl future = new ArcusFutureImpl<>(result); - CollectionCount collectionCount = new BTreeCount(from.toString(), to.toString(), eFlagFilter); + AbstractArcusResult>> result + = new AbstractArcusResult<>(new AtomicReference<>(new ArrayList<>())); + ArcusFutureImpl>> future = new ArcusFutureImpl<>(result); + BTreeGetByPosition getByPosition = new BTreeGetByPosition(order, from, to); ArcusClient client = arcusClientSupplier.get(); - OperationCallback cb = new OperationCallback() { + BTreeGetByPositionOperation.Callback cb = new BTreeGetByPositionOperation.Callback() { + @Override + public void gotData(int pos, int flags, BKeyObject bKey, byte[] eFlag, byte[] data) { + CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); + result.get().add(new BTreeElement<>( + BKey.of(bKey), tcForCollection.decode(cachedData), eFlag)); + } + @Override public void receivedStatus(OperationStatus status) { switch (status.getStatusCode()) { case SUCCESS: - long count = Long.parseLong(status.getMessage()); - result.set(count); + case ERR_NOT_FOUND_ELEMENT: break; case ERR_NOT_FOUND: result.set(null); @@ -1692,7 +1732,7 @@ public void receivedStatus(OperationStatus status) { break; default: /* - * TYPE_MISMATCH / BKEY_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. + * TYPE_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. */ result.addError(key, status); } @@ -1703,49 +1743,40 @@ public void complete() { future.complete(); } }; - Operation op = client.getOpFact().collectionCount(key, collectionCount, cb); + Operation op = client.getOpFact().bopGetByPosition(key, getByPosition, cb); future.setOp(op); client.addOp(key, op); return future; } - public ArcusFuture lopCreate(String key, ElementValueType type, - CollectionAttributes attributes) { - if (attributes == null) { - throw new IllegalArgumentException("CollectionAttributes cannot be null"); - } - - ListCreate create = new ListCreate(TranscoderUtils.examineFlags(type), - attributes.getExpireTime(), attributes.getMaxCount(), - attributes.getOverflowAction(), attributes.getReadable(), false); - return collectionCreate(key, create); - } - - public ArcusFuture lopInsert(String key, int index, T value) { - return lopInsert(key, index, value, null); - } - - public ArcusFuture lopInsert(String key, int index, T value, - CollectionAttributes attributes) { - ListInsert insert = new ListInsert<>(value, null, attributes); - return collectionInsert(key, String.valueOf(index), insert); - } - - public ArcusFuture lopGet(String key, int index, GetArgs args) { - AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); - ArcusFutureImpl future = new ArcusFutureImpl<>(result); - ListGet get = new ListGet(index, args.isWithDelete(), args.isDropIfEmpty()); + public ArcusFuture>> bopPositionWithGet(String key, + BKey bKey, + int count, + BTreeOrder order) { + AbstractArcusResult>> result = + new AbstractArcusResult<>(new AtomicReference<>(new ArrayList<>())); + ArcusFutureImpl>> future = new ArcusFutureImpl<>(result); + BTreeFindPositionWithGet findPositionWithGet = + new BTreeFindPositionWithGet(bKey.toBKeyObject(), order, count); ArcusClient client = arcusClientSupplier.get(); - CollectionGetOperation.Callback cb = new CollectionGetOperation.Callback() { + BTreeFindPositionWithGetOperation.Callback cb = new BTreeFindPositionWithGetOperation + .Callback() { + @Override + public void gotData(int pos, int flags, BKeyObject bKey, byte[] eFlag, byte[] data) { + CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); + result.get().add(new BTreePositionElement<>( + BKey.of(bKey), tcForCollection.decode(cachedData), eFlag, pos)); + } + @Override public void receivedStatus(OperationStatus status) { switch (status.getStatusCode()) { case SUCCESS: + case ERR_NOT_FOUND_ELEMENT: break; case ERR_NOT_FOUND: - case ERR_NOT_FOUND_ELEMENT: result.set(null); break; case CANCELLED: @@ -1753,7 +1784,7 @@ public void receivedStatus(OperationStatus status) { break; default: /* - * TYPE_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. + * TYPE_MISMATCH / BKEY_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. */ result.addError(key, status); } @@ -1763,33 +1794,29 @@ public void receivedStatus(OperationStatus status) { public void complete() { future.complete(); } - - @Override - public void gotData(String subKey, int flags, byte[] data, byte[] eFlag) { - CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - result.set(tcForCollection.decode(cachedData)); - } }; - Operation op = client.getOpFact().collectionGet(key, get, cb); + Operation op = client.getOpFact().bopFindPositionWithGet(key, findPositionWithGet, cb); future.setOp(op); client.addOp(key, op); return future; } - public ArcusFuture> lopGet(String key, int from, int to, GetArgs args) { - AbstractArcusResult> result = - new AbstractArcusResult<>(new AtomicReference<>(new ArrayList<>())); - ArcusFutureImpl> future = new ArcusFutureImpl<>(result); - ListGet get = new ListGet(from, to, args.isWithDelete(), args.isDropIfEmpty()); + public ArcusFuture bopCount(String key, BKey from, BKey to, ElementFlagFilter eFlagFilter) { + verifyBKeyTypesMatch(from, to); + + AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); + ArcusFutureImpl future = new ArcusFutureImpl<>(result); + CollectionCount collectionCount = new BTreeCount(from.toString(), to.toString(), eFlagFilter); ArcusClient client = arcusClientSupplier.get(); - CollectionGetOperation.Callback cb = new CollectionGetOperation.Callback() { + OperationCallback cb = new OperationCallback() { @Override public void receivedStatus(OperationStatus status) { switch (status.getStatusCode()) { case SUCCESS: - case ERR_NOT_FOUND_ELEMENT: + long count = Long.parseLong(status.getMessage()); + result.set(count); break; case ERR_NOT_FOUND: result.set(null); @@ -1799,7 +1826,7 @@ public void receivedStatus(OperationStatus status) { break; default: /* - * TYPE_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. + * TYPE_MISMATCH / BKEY_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. */ result.addError(key, status); } @@ -1809,79 +1836,63 @@ public void receivedStatus(OperationStatus status) { public void complete() { future.complete(); } - - @Override - public void gotData(String subKey, int flags, byte[] data, byte[] eFlag) { - CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - result.get().add(tcForCollection.decode(cachedData)); - } }; - Operation op = client.getOpFact().collectionGet(key, get, cb); + Operation op = client.getOpFact().collectionCount(key, collectionCount, cb); future.setOp(op); client.addOp(key, op); return future; } - public ArcusFuture lopDelete(String key, int index, boolean dropIfEmpty) { - ListDelete delete = new ListDelete(index, dropIfEmpty, false); + public ArcusFuture bopDelete(String key, BKey bKey, BopDeleteArgs args) { + BTreeDelete delete = new BTreeDelete(bKey.toString(), + args.getEFlagFilter(), args.isDropIfEmpty(), false); return collectionDelete(key, delete); } - public ArcusFuture lopDelete(String key, int from, int to, boolean dropIfEmpty) { - ListDelete delete = new ListDelete(from, to, dropIfEmpty, false); + public ArcusFuture bopDelete(String key, BKey from, BKey to, BopDeleteArgs args) { + verifyBKeyTypesMatch(from, to); + BTreeDelete delete = new BTreeDelete(from.toString(), to.toString(), + args.getCount(), args.getEFlagFilter(), args.isDropIfEmpty(), false); return collectionDelete(key, delete); } - public ArcusFuture sopCreate(String key, ElementValueType type, - CollectionAttributes attributes) { - if (attributes == null) { - throw new IllegalArgumentException("CollectionAttributes cannot be null"); + private static void verifyBKeyTypesMatch(BKey from, BKey to) { + if (from.getType() != to.getType()) { + throw new IllegalArgumentException("Two BKey types(from, to) must be the same."); } - - SetCreate create = new SetCreate( - TranscoderUtils.examineFlags(type), attributes.getExpireTime(), - attributes.getMaxCount(), attributes.getReadable(), false); - return collectionCreate(key, create); } - public ArcusFuture sopInsert(String key, T value) { - return sopInsert(key, value, null); - } - - public ArcusFuture sopInsert(String key, T value, CollectionAttributes attributes) { - SetInsert insert = new SetInsert<>(value, null, attributes); - return collectionInsert(key, "", insert); + private static void verifyPositiveCountArg(BopGetArgs args, int maxCount) { + int count = args.getCount(); + if (count <= 0 || count > maxCount) { + throw new IllegalArgumentException("Count should be between 1 to " + maxCount); + } } - public ArcusFuture sopExist(String key, T value) { + private ArcusFuture collectionCreate(String key, CollectionCreate collectionCreate) { AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); ArcusFutureImpl future = new ArcusFutureImpl<>(result); - SetExist exist = new SetExist<>(value, tcForCollection); ArcusClient client = arcusClientSupplier.get(); OperationCallback cb = new OperationCallback() { @Override public void receivedStatus(OperationStatus status) { switch (status.getStatusCode()) { - case EXIST: + case SUCCESS: result.set(true); break; - case NOT_EXIST: + case ERR_EXISTS: result.set(false); break; - case ERR_NOT_FOUND: - result.set(null); - break; case CANCELLED: future.internalCancel(); break; default: /* - * TYPE_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. + * NOT_SUPPORTED or unknown statement. */ result.addError(key, status); - break; } } @@ -1890,32 +1901,32 @@ public void complete() { future.complete(); } }; - Operation op = client.getOpFact().collectionExist(key, "", exist, cb); + CollectionCreateOperation op = client.getOpFact() + .collectionCreate(key, collectionCreate, cb); future.setOp(op); client.addOp(key, op); return future; } - public ArcusFuture> sopGet(String key, int count, GetArgs args) { - AbstractArcusResult> result - = new AbstractArcusResult<>(new AtomicReference<>(new HashSet<>())); - ArcusFutureImpl> future = new ArcusFutureImpl<>(result); - SetGet get = new SetGet(count, args.isWithDelete(), args.isDropIfEmpty()); + private ArcusFuture collectionInsert(String key, + String internalKey, + CollectionInsert collectionInsert) { + AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); + ArcusFutureImpl future = new ArcusFutureImpl<>(result); + CachedData co = tcForCollection.encode(collectionInsert.getValue()); + collectionInsert.setFlags(co.getFlags()); ArcusClient client = arcusClientSupplier.get(); - CollectionGetOperation.Callback cb = new CollectionGetOperation.Callback() { - @Override - public void gotData(String subKey, int flags, byte[] data, byte[] eFlag) { - CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - result.get().add(tcForCollection.decode(cachedData)); - } - + OperationCallback cb = new OperationCallback() { @Override public void receivedStatus(OperationStatus status) { switch (status.getStatusCode()) { case SUCCESS: - case ERR_NOT_FOUND_ELEMENT: + result.set(true); + break; + case ERR_ELEMENT_EXISTS: + result.set(false); break; case ERR_NOT_FOUND: result.set(null); @@ -1925,7 +1936,8 @@ public void receivedStatus(OperationStatus status) { break; default: /* - * TYPE_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. + * TYPE_MISMATCH / BKEY_MISMATCH / OVERFLOWED / OUT_OF_RANGE / NOT_SUPPORTED + * or unknown statement. */ result.addError(key, status); } @@ -1936,87 +1948,36 @@ public void complete() { future.complete(); } }; - Operation op = client.getOpFact().collectionGet(key, get, cb); + CollectionInsertOperation op = client.getOpFact() + .collectionInsert(key, internalKey, collectionInsert, co.getData(), cb); future.setOp(op); client.addOp(key, op); return future; } - public ArcusFuture sopDelete(String key, T value, boolean dropIfEmpty) { - SetDelete delete = new SetDelete<>(value, dropIfEmpty, false, tcForCollection); - return collectionDelete(key, delete); - } - - public ArcusFuture mopCreate(String key, ElementValueType type, - CollectionAttributes attributes) { - if (attributes == null) { - throw new IllegalArgumentException("CollectionAttributes cannot be null"); + private ArcusFuture collectionUpdate(String key, + String internalKey, + CollectionUpdate collectionUpdate) { + AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); + ArcusFutureImpl future = new ArcusFutureImpl<>(result); + CachedData co = null; + if (collectionUpdate.getNewValue() != null) { + co = tcForCollection.encode(collectionUpdate.getNewValue()); + collectionUpdate.setFlags(co.getFlags()); } - - MapCreate create = new MapCreate(TranscoderUtils.examineFlags(type), - attributes.getExpireTime(), attributes.getMaxCount(), - attributes.getReadable(), false); - return collectionCreate(key, create); - } - - public ArcusFuture mopInsert(String key, String mKey, T value) { - return mopInsert(key, mKey, value, null); - } - - public ArcusFuture mopInsert(String key, String mKey, T value, - CollectionAttributes attributes) { - keyValidator.validateMKey(mKey); - - MapInsert insert = new MapInsert<>(value, null, attributes); - return collectionInsert(key, mKey, insert); - } - - public ArcusFuture mopUpsert(String key, String mKey, T value) { - return mopUpsert(key, mKey, value, null); - } - - public ArcusFuture mopUpsert(String key, String mKey, T value, - CollectionAttributes attributes) { - keyValidator.validateMKey(mKey); - - MapUpsert upsert = new MapUpsert<>(value, attributes); - return collectionInsert(key, mKey, upsert); - } - - public ArcusFuture mopUpdate(String key, String mKey, T value) { - keyValidator.validateMKey(mKey); - - MapUpdate update = new MapUpdate<>(value, false); - return collectionUpdate(key, mKey, update); - } - - public ArcusFuture> mopGet(String key, GetArgs args) { - return mopGet(key, new ArrayList<>(), args); - } - - public ArcusFuture mopGet(String key, String mKey, GetArgs args) { - keyValidator.validateMKey(mKey); - - AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); - ArcusFutureImpl future = new ArcusFutureImpl<>(result); - List mKeys = Collections.singletonList(mKey); - MapGet get = new MapGet(mKeys, args.isWithDelete(), args.isDropIfEmpty()); ArcusClient client = arcusClientSupplier.get(); - CollectionGetOperation.Callback cb = new CollectionGetOperation.Callback() { - @Override - public void gotData(String mKey, int flags, byte[] data, byte[] eFlag) { - CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - result.set(tcForCollection.decode(cachedData)); - } - + OperationCallback cb = new OperationCallback() { @Override public void receivedStatus(OperationStatus status) { switch (status.getStatusCode()) { case SUCCESS: + result.set(true); break; case ERR_NOT_FOUND_ELEMENT: + result.set(false); + break; case ERR_NOT_FOUND: result.set(null); break; @@ -2025,7 +1986,8 @@ public void receivedStatus(OperationStatus status) { break; default: /* - * TYPE_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. + * TYPE_MISMATCH / BKEY_MISMATCH / EFLAG_MISMATCH / NOTHING_TO_UPDATE / + * OVERFLOWED / OUT_OF_RANGE / NOT_SUPPORTED or unknown statement. */ result.addError(key, status); } @@ -2036,42 +1998,30 @@ public void complete() { future.complete(); } }; - Operation op = client.getOpFact().collectionGet(key, get, cb); + Operation op = client.getOpFact() + .collectionUpdate(key, internalKey, collectionUpdate, + (co == null) ? null : co.getData(), cb); future.setOp(op); client.addOp(key, op); return future; } - public ArcusFuture> mopGet(String key, List mKeys, GetArgs args) { - if (mKeys == null) { - throw new IllegalArgumentException("mKeys cannot be null"); - } - - if (!mKeys.isEmpty()) { - keyValidator.validateMKey(mKeys); - } - - AbstractArcusResult> result = - new AbstractArcusResult<>(new AtomicReference<>(new HashMap<>())); - ArcusFutureImpl> future = new ArcusFutureImpl<>(result); - MapGet get = new MapGet(mKeys, args.isWithDelete(), args.isDropIfEmpty()); + private ArcusFuture collectionMutate(String key, String internalKey, + CollectionMutate mutate) { + AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); + ArcusFutureImpl future = new ArcusFutureImpl<>(result); ArcusClient client = arcusClientSupplier.get(); - CollectionGetOperation.Callback cb = new CollectionGetOperation.Callback() { - @Override - public void gotData(String mKey, int flags, byte[] data, byte[] eFlag) { - CachedData cachedData = new CachedData(flags, data, tcForCollection.getMaxSize()); - result.get().put(mKey, tcForCollection.decode(cachedData)); - } - + OperationCallback cb = new OperationCallback() { @Override public void receivedStatus(OperationStatus status) { switch (status.getStatusCode()) { case SUCCESS: - case ERR_NOT_FOUND_ELEMENT: + result.set(Long.parseLong(status.getMessage())); break; case ERR_NOT_FOUND: + case ERR_NOT_FOUND_ELEMENT: result.set(null); break; case CANCELLED: @@ -2079,7 +2029,8 @@ public void receivedStatus(OperationStatus status) { break; default: /* - * TYPE_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement. + * TYPE_MISMATCH / BKEY_MISMATCH / OUT_OF_RANGE / + * OVERFLOWED / NOT_SUPPORTED or unknown statement. */ result.addError(key, status); } @@ -2090,32 +2041,52 @@ public void complete() { future.complete(); } }; - Operation op = client.getOpFact().collectionGet(key, get, cb); + Operation op = client.getOpFact().collectionMutate(key, internalKey, mutate, cb); future.setOp(op); client.addOp(key, op); return future; } - public ArcusFuture mopDelete(String key, boolean dropIfEmpty) { - return mopDelete(key, new ArrayList<>(), dropIfEmpty); - } - - public ArcusFuture mopDelete(String key, String mKey, boolean dropIfEmpty) { - return mopDelete(key, Collections.singletonList(mKey), dropIfEmpty); - } + private ArcusFuture collectionDelete(String key, CollectionDelete delete) { + AbstractArcusResult result = new AbstractArcusResult<>(new AtomicReference<>()); + ArcusFutureImpl future = new ArcusFutureImpl<>(result); + ArcusClient client = arcusClientSupplier.get(); - public ArcusFuture mopDelete(String key, List mKeys, boolean dropIfEmpty) { - if (mKeys == null) { - throw new IllegalArgumentException("mKeys cannot be null"); - } + OperationCallback cb = new OperationCallback() { + @Override + public void receivedStatus(OperationStatus status) { + switch (status.getStatusCode()) { + case SUCCESS: + result.set(true); + break; + case ERR_NOT_FOUND: + result.set(null); + break; + case ERR_NOT_FOUND_ELEMENT: + result.set(false); + break; + case CANCELLED: + future.internalCancel(); + break; + default: + /* + * TYPE_MISMATCH / BKEY_MISMATCH / NOT_SUPPORTED or unknown statement. + */ + result.addError(key, status); + } + } - if (!mKeys.isEmpty()) { - keyValidator.validateMKey(mKeys); - } + @Override + public void complete() { + future.complete(); + } + }; + Operation op = client.getOpFact().collectionDelete(key, delete, cb); + future.setOp(op); + client.addOp(key, op); - MapDelete delete = new MapDelete(mKeys, dropIfEmpty, false); - return collectionDelete(key, delete); + return future; } public ArcusFuture flush() { @@ -2146,7 +2117,6 @@ public void receivedStatus(OperationStatus status) { break; default: result.addError(node.getSocketAddress().toString(), status); - break; } } @@ -2201,7 +2171,6 @@ public void receivedStatus(OperationStatus status) { break; default: result.addError(node.getSocketAddress().toString(), status); - break; } } @@ -2212,7 +2181,7 @@ public void complete() { }; Operation op = client.getOpFact() - .flush(prefix.isEmpty() ? "" : prefix, delay, false, cb); + .flush(prefix.isEmpty() ? "" : prefix, delay, false, cb); future.setOp(op); client.addOp(node, op); futures.add(future); @@ -2241,7 +2210,7 @@ public ArcusFuture>> stats(StatsArg arg) for (MemcachedNode node : nodes) { SocketAddress address = node.getSocketAddress(); AbstractArcusResult> result - = new AbstractArcusResult<>(new AtomicReference<>(new HashMap<>())); + = new AbstractArcusResult<>(new AtomicReference<>(new HashMap<>())); ArcusFutureImpl> future = new ArcusFutureImpl<>(result); StatsOperation.Callback cb = new StatsOperation.Callback() { diff --git a/src/main/java/net/spy/memcached/v2/AsyncArcusCommandsIF.java b/src/main/java/net/spy/memcached/v2/AsyncArcusCommandsIF.java index d78372595..db4cb99b0 100644 --- a/src/main/java/net/spy/memcached/v2/AsyncArcusCommandsIF.java +++ b/src/main/java/net/spy/memcached/v2/AsyncArcusCommandsIF.java @@ -69,37 +69,6 @@ public interface AsyncArcusCommandsIF { */ ArcusFuture replace(String key, int exp, T value); - - /** - * Perform a compare-and-set operation for the given key. - * - * @param key the key to set - * @param exp expiration time in seconds - * @param value the new value to set if the CAS ID matches - * @param casId the CAS ID obtained from {@link #gets(String)} - * @return {@code true} if compared and set successfully, - * {@code false} if the key does not exist or CAS ID does not match - */ - ArcusFuture cas(String key, int exp, T value, long casId); - - /** - * Append String or byte[] to an existing same type of value. - * - * @param key the key - * @param value the value to append - * @return {@code true} if appended, otherwise {@code false} - */ - ArcusFuture append(String key, T value); - - /** - * Prepend String or byte[] to an existing same type of value. - * - * @param key the key - * @param value the value to prepend - * @return {@code true} if prepended, otherwise {@code false} - */ - ArcusFuture prepend(String key, T value); - /** * Sets multiple key-value pairs. * @@ -128,28 +97,34 @@ public interface AsyncArcusCommandsIF { ArcusFuture> multiReplace(Map items, int exp); /** - * Get a value for the given key. + * Prepend String or byte[] to an existing same type of value. * - * @param key the key - * @return the value, or {@code null} if not found + * @param key the key + * @param value the value to prepend + * @return {@code true} if prepended, otherwise {@code false} */ - ArcusFuture get(String key); + ArcusFuture prepend(String key, T value); /** - * Get a value and its CAS ID for the given key. + * Append String or byte[] to an existing same type of value. * - * @param key the key - * @return {@link CASValue}, {@code null} if not found + * @param key the key + * @param value the value to append + * @return {@code true} if appended, otherwise {@code false} */ - ArcusFuture> gets(String key); + ArcusFuture append(String key, T value); /** - * Get values for multiple keys. + * Perform a compare-and-set operation for the given key. * - * @param keys list of keys to get - * @return Map of key to value + * @param key the key to set + * @param exp expiration time in seconds + * @param value the new value to set if the CAS ID matches + * @param casId the CAS ID obtained from {@link #gets(String)} + * @return {@code true} if compared and set successfully, + * {@code false} if the key does not exist or CAS ID does not match */ - ArcusFuture> multiGet(List keys); + ArcusFuture cas(String key, int exp, T value, long casId); /** * Increments a numeric value stored at the given key by {@code delta}. @@ -197,6 +172,31 @@ public interface AsyncArcusCommandsIF { */ ArcusFuture decr(String key, int delta, long initial, int exp); + /** + * Get a value for the given key. + * + * @param key the key + * @return the value, or {@code null} if not found + */ + ArcusFuture get(String key); + + /** + * Get a value and its CAS ID for the given key. + * + * @param key the key + * @return {@link CASValue}, {@code null} if not found + */ + ArcusFuture> gets(String key); + + /** + * Get values for multiple keys. + * + * @param keys list of keys to get + * @return Map of key to value + */ + ArcusFuture> multiGet(List keys); + + /** * Get values with CAS for multiple keys. * @@ -223,600 +223,599 @@ public interface AsyncArcusCommandsIF { ArcusFuture> multiDelete(List keys); /** - * Create a btree item. + * Create a list with the given attributes. * - * @param key key to create - * @param type btree element value type - * @param attributes collection attributes (must not be null) - * @return {@code true} if created, otherwise {@code false} + * @param key key of the list to create + * @param type element value type + * @param attributes initial attributes of the list + * @return {@code true} if created, {@code false} if the key already exists */ - ArcusFuture bopCreate(String key, ElementValueType type, + ArcusFuture lopCreate(String key, ElementValueType type, CollectionAttributes attributes); /** - * Insert an element into a btree item. + * Insert an element at the given index into a list. * - * @param key key to insert - * @param element btree element to insert - * @param attributes collection attributes for creation when the btree does not exist - * @return {@code true} if inserted, - * {@code false} if element exists, - * {@code null} if key is not found + * @param key key of the list + * @param index index at which to insert the element + * @param value the value to insert + * @return {@code true} if the element was inserted, {@code null} if the key is not found */ - ArcusFuture bopInsert(String key, BTreeElement element, - CollectionAttributes attributes); + ArcusFuture lopInsert(String key, int index, T value); /** - * Insert an element into a btree item. + * Insert an element at the given index into a list. + * If the list does not exist, it is created with the given attributes. * - * @param key key to insert - * @param element btree element to insert - * @return {@code true} if inserted, - * {@code false} if element exists, - * {@code null} if key is not found + * @param key key of the list + * @param index index at which to insert the element + * @param value the value to insert + * @param attributes attributes to use when creating the list, or {@code null} to not create + * @return {@code true} if the element was inserted, {@code null} if the key is not found */ - ArcusFuture bopInsert(String key, BTreeElement element); + ArcusFuture lopInsert(String key, int index, T value, CollectionAttributes attributes); /** - * Upsert an element into a btree item. + * Get an element at the given index from a list. * - * @param key key to upsert - * @param element btree element to upsert - * @param attributes collection attributes for creation when the btree does not exist - * @return {@code true} if upserted, {@code null} if the key is not found + * @param key key of the list + * @param index index of the element to get + * @param args arguments for get operation + * @return the element value, {@code null} if the key or element is not found */ - ArcusFuture bopUpsert(String key, BTreeElement element, - CollectionAttributes attributes); + ArcusFuture lopGet(String key, int index, GetArgs args); /** - * Upsert an element into a btree item. + * Get elements in an index range from a list. * - * @param key key to upsert - * @param element btree element to upsert - * @return {@code true} if upserted, {@code null} if the key is not found + * @param key key of the list + * @param from index range start (inclusive) + * @param to index range end (inclusive) + * @param args arguments for get operation + * @return list of element values in order, an empty list if no elements are found in the range, + * {@code null} if the key is not found */ - ArcusFuture bopUpsert(String key, BTreeElement element); + ArcusFuture> lopGet(String key, int from, int to, GetArgs args); /** - * Update an element in a btree item + * Delete an element at the given index from a list. * - * @param key key to update - * @param element btree element to update - * @return {@code true} if updated, - * {@code false} if element does not exist, - * {@code null} if key is not found + * @param key key of the list + * @param index index of the element to delete + * @param dropIfEmpty whether to delete the list if it becomes empty after deletion + * @return {@code true} if the element was deleted, + * {@code false} if the element is not found, + * {@code null} if the key is not found */ - ArcusFuture bopUpdate(String key, BTreeUpdateElement element); + ArcusFuture lopDelete(String key, int index, boolean dropIfEmpty); /** - * Insert an element into a btree item and get trimmed element if overflow trim occurs. + * Delete elements in an index range from a list. * - * @param key key to insert - * @param element btree element to insert - * @param attributes collection attributes for creation when the btree does not exist - * @return {@code Map.Entry} with insertion result and trimmed element + * @param key key of the list + * @param from index range start (inclusive) + * @param to index range end (inclusive) + * @param dropIfEmpty whether to delete the list if it becomes empty after deletion + * @return {@code true} if at least one element was deleted, + * {@code false} if no elements are found in the range, + * {@code null} if the key is not found */ - ArcusFuture>> bopInsertAndGetTrimmed( - String key, BTreeElement element, CollectionAttributes attributes); + ArcusFuture lopDelete(String key, int from, int to, boolean dropIfEmpty); /** - * Insert an element into a btree item and get trimmed element if overflow trim occurs. + * Create a set with the given attributes. * - * @param key key to insert - * @param element btree element to insert - * @return {@code Map.Entry} with insertion result and trimmed element + * @param key key of the set to create + * @param type element value type + * @param attributes initial attributes of the set + * @return {@code true} if created, {@code false} if the key already exists */ - ArcusFuture>> bopInsertAndGetTrimmed(String key, - BTreeElement element); + ArcusFuture sopCreate(String key, ElementValueType type, + CollectionAttributes attributes); /** - * Upsert an element into a btree item and get trimmed element if overflow trim occurs. + * Insert an element into a set. * - * @param key key to upsert - * @param element btree element to upsert - * @param attributes collection attributes for creation when the btree does not exist - * @return {@code Map.Entry} with upsertion result and trimmed element + * @param key key of the set + * @param value the value to insert + * @return {@code true} if the element was inserted, + * {@code false} if the element already exists, + * {@code null} if the key is not found */ - ArcusFuture>> bopUpsertAndGetTrimmed( - String key, BTreeElement element, CollectionAttributes attributes); + ArcusFuture sopInsert(String key, T value); /** - * Upsert an element into a btree item and get trimmed element if overflow trim occurs. + * Insert an element into a set. + * If the set does not exist, it is created with the given attributes. * - * @param key key to upsert - * @param element btree element to upsert - * @return {@code Map.Entry} with upsertion result and trimmed element + * @param key key of the set + * @param value the value to insert + * @param attributes attributes to use when creating the set, or {@code null} to not create + * @return {@code true} if the element was inserted, + * {@code false} if the element already exists, + * {@code null} if the key is not found */ - ArcusFuture>> bopUpsertAndGetTrimmed(String key, - BTreeElement element); + ArcusFuture sopInsert(String key, T value, CollectionAttributes attributes); /** - * Get an element from a btree item. + * Get elements randomly from a set. * - * @param key key to get - * @param bKey BKey of the element to get - * @param args arguments for get operation - * @return the {@code BTreeElement} if found, - * {@code BTreeElement} with null value and null eFlag if element is not found but key exists, - * {@code null} if key is not found + * @param key key of the set + * @param count number of elements to retrieve randomly (0 means all elements, max 1000) + * @param args arguments for get operation + * @return set of element values, an empty set if no elements are found, + * {@code null} if the key is not found */ - ArcusFuture> bopGet(String key, BKey bKey, BopGetArgs args); + ArcusFuture> sopGet(String key, int count, GetArgs args); /** - * Get elements from a btree item. + * Check whether an element exists in a set. * - * @param key key to get - * @param from BKey range start - * @param to BKey range end - * @param args arguments for get operation - * @return {@code BTreeElements} with found elements, - * empty {@code BTreeElements} if no elements are found in the range but key exists, - * {@code null} if key is not found + * @param key key of the set + * @param value the value to check + * @return {@code true} if the element exists, + * {@code false} if the element is not found, + * {@code null} if the key is not found */ - ArcusFuture> bopGet(String key, BKey from, BKey to, BopGetArgs args); + ArcusFuture sopExist(String key, T value); /** - * Get elements from multiple btree items. + * Delete an element from a set. * - * @param keys list of keys to get - * @param from BKey range start - * @param to BKey range end - * @param args arguments for get operation - * @return map of key to {@code BTreeElements} with found elements, - * empty {@code BTreeElements} if no elements are found in the range but key exists, - * no {@code Map.Entry} in the map if the key is not found + * @param key key of the set + * @param value the value to delete + * @param dropIfEmpty whether to delete the set if it becomes empty after deletion + * @return {@code true} if the element was deleted, + * {@code false} if the element is not found, + * {@code null} if the key is not found */ - ArcusFuture>> bopMultiGet(List keys, - BKey from, BKey to, - BopGetArgs args); + ArcusFuture sopDelete(String key, T value, boolean dropIfEmpty); /** - * Get the position of an element with the given bKey in a btree item. + * Create an empty map with the given attributes. * - * @param key key of the btree item - * @param bKey BKey of the element to find - * @param order the order of the btree to determine position - * @return the 0-based position of the element, - * {@code null} if the key or element is not found + * @param key key of the map to create + * @param type element value type + * @param attributes initial attributes of the map + * @return {@code true} if created, {@code false} if the key already exists */ - ArcusFuture bopGetPosition(String key, BKey bKey, BTreeOrder order); + ArcusFuture mopCreate(String key, ElementValueType type, + CollectionAttributes attributes); /** - * Get an element at the given position in a btree item. + * Insert an element with the given MKey into a map. * - * @param key key of the btree item - * @param pos 0-based position of the element to get - * @param order the order of the btree to determine position - * @return the {@code BTreeElement} at the given position, - * {@code null} if the key or element is not found + * @param key key of the map + * @param mKey MKey of the element to insert + * @param value the value to insert + * @return {@code true} if the element was inserted, + * {@code false} if the MKey already exists, + * {@code null} if the key is not found */ - ArcusFuture> bopGetByPosition(String key, int pos, BTreeOrder order); + ArcusFuture mopInsert(String key, String mKey, T value); /** - * Get elements in a position range from a btree item. + * Insert an element with the given MKey into a map. + * If the map does not exist, it is created with the given attributes. * - * @param key key of the btree item - * @param from start position (inclusive) - * @param to end position (inclusive); must be greater than or equal to {@code from} - * @param order the order of the btree to determine position - * @return list of {@code BTreeElement} in the given position range, in traversal order, - * empty list if no elements exist in the range, + * @param key key of the map + * @param mKey MKey of the element to insert + * @param value the value to insert + * @param attributes attributes to use when creating the map + * @return {@code true} if the element was inserted, + * {@code false} if the MKey already exists, * {@code null} if the key is not found */ - ArcusFuture>> bopGetByPosition(String key, - int from, int to, BTreeOrder order); + ArcusFuture mopInsert(String key, String mKey, T value, CollectionAttributes attributes); /** - * Get an element by bKey and its neighboring elements with position information. + * Upsert an element with the given MKey in a map. + * If an element with the given MKey exists, it is replaced, otherwise a new element is inserted. * - * @param key key of the btree item - * @param bKey BKey of the element to find - * @param count the number of neighboring elements to retrieve on each side - * (0 ≤ count ≤ 100) - * @param order the order of the btree to determine position - * @return list of {@code BTreePositionElement} in traversal order, - * empty list if the element is not found, - * {@code null} if the key is not found + * @param key key of the map + * @param mKey MKey of the element to upsert + * @param value the value to insert or replace with + * @return {@code true} if upserted, {@code null} if the key is not found */ - ArcusFuture>> bopPositionWithGet(String key, BKey bKey, - int count, BTreeOrder order); + ArcusFuture mopUpsert(String key, String mKey, T value); /** - * Get sort-merged elements from multiple btree items. + * Upsert an element with the given MKey in a map. + * If an element with the given MKey exists, it is replaced, otherwise a new element is inserted. + * If the map does not exist, it is created with the given attributes. * - * @param keys list of keys to get - * @param from BKey range start - * @param to BKey range end - * @param unique whether to return unique elements only - * @param args arguments for get operation - * @return {@code SMGetElements} containing sort-merged elements, - * empty {@code SMGetElements} if no matching elements exist + * @param key key of the map + * @param mKey MKey of the element to upsert + * @param value the value to insert or replace with + * @param attributes attributes to use when creating the map + * @return {@code true} if upserted, {@code null} if the key is not found */ - ArcusFuture> bopSortMergeGet(List keys, BKey from, BKey to, - boolean unique, BopGetArgs args); + ArcusFuture mopUpsert(String key, String mKey, T value, CollectionAttributes attributes); /** - * Increments a numeric value of an element with the given bKey in a btree item by {@code delta} + * Update the value of an element with the given MKey in a map. * - * @param key key of the btree item - * @param bKey BKey of the element to increment - * @param delta the amount to increment (> 0) - * @return the new value after increment, or {@code null} if the key or element is not found + * @param key key of the map + * @param mKey MKey of the element to update + * @param value the new value + * @return {@code true} if the element was updated, + * {@code false} if the MKey is not found, + * {@code null} if the key is not found */ - ArcusFuture bopIncr(String key, BKey bKey, int delta); + ArcusFuture mopUpdate(String key, String mKey, T value); /** - * Increments a numeric value of an element with the given bKey in a btree item by {@code delta}. - * If the element does not exist, it is created with {@code initial} value and {@code eFlag}. + * Get all elements from a map. * - * @param key key of the btree item - * @param bKey BKey of the element to increment - * @param delta the amount to increment (> 0) - * @param initial the value to store if the element does not exist - * ({@code delta} is ignored) (≥ 0) - * @param eFlag eFlag of the element to create, or {@code null} if not needed - * @return the new value after increment, or {@code initial} if the element did not exist + * @param key key of the map + * @param args arguments for get operation + * @return map of MKey to value, + * empty map if no elements exist, + * {@code null} if the key is not found */ - ArcusFuture bopIncr(String key, BKey bKey, int delta, long initial, byte[] eFlag); + ArcusFuture> mopGet(String key, GetArgs args); /** - * Decrements a numeric value of an element with the given bKey in a btree item by {@code delta}. - *

If the value is decremented below 0, it will be set to 0.

+ * Get an element with the given MKey from a map. * - * @param key key of the btree item - * @param bKey BKey of the element to decrement - * @param delta the amount to decrement (> 0) - * @return the new value after decrement, or {@code null} if the key or element is not found + * @param key key of the map + * @param mKey MKey of the element to get + * @param args arguments for get operation + * @return the element value, + * {@code null} if the key or MKey is not found */ - ArcusFuture bopDecr(String key, BKey bKey, int delta); + ArcusFuture mopGet(String key, String mKey, GetArgs args); /** - * Decrements a numeric value of an element with the given bKey in a btree item by {@code delta}. - * If the element does not exist, it is created with {@code initial} value and {@code eFlag}. - *

If the value is decremented below 0, it will be set to 0.

+ * Get elements with the MKeys from a map. * - * @param key key of the btree item - * @param bKey BKey of the element to decrement - * @param delta the amount to decrement (> 0) - * @param initial the value to store if the element does not exist - * ({@code delta} is ignored) (≥ 0) - * @param eFlag eFlag of the element to create, or {@code null} if not needed - * @return the new value after decrement, or {@code initial} if the element did not exist + * @param key key of the map + * @param mKeys list of MKeys to get + * @param args arguments for get operation + * @return map of MKey to value for found elements, + * empty map if no MKeys are found, + * {@code null} if the key is not found */ - ArcusFuture bopDecr(String key, BKey bKey, int delta, long initial, byte[] eFlag); + ArcusFuture> mopGet(String key, List mKeys, GetArgs args); /** - * Delete an element with the given bKey from a btree item. + * Delete all elements from a map. * - * @param key key of the btree item - * @param bKey BKey of the element to delete - * @param args delete arguments (eFlagFilter, dropIfEmpty) - * @return {@code true} if the element was deleted, - * {@code false} if the element is not found, + * @param key key of the map + * @param dropIfEmpty whether to drop the map if it becomes empty after deletion + * @return {@code true} if at least one element was deleted, + * {@code false} if no elements exist, * {@code null} if the key is not found */ - ArcusFuture bopDelete(String key, BKey bKey, BopDeleteArgs args); + ArcusFuture mopDelete(String key, boolean dropIfEmpty); /** - * Delete elements in a bKey range from a btree item. - * Elements are deleted in order from {@code from} to {@code to}. - *

If {@code args.count} is 0 (default), all elements in the range are deleted.

- * Otherwise, only the first {@code args.count} elements (in {@code from}-to-{@code to} order) - * are deleted. + * Delete an element with the given MKey from a map. * - * @param key key of the btree item - * @param from BKey range start (inclusive) - * @param to BKey range end (inclusive) - * @param args delete arguments (count, eFlagFilter, dropIfEmpty) - * @return {@code true} if at least one element was deleted, - * {@code false} if no elements are found in the range, + * @param key key of the map + * @param mKey MKey of the element to delete + * @param dropIfEmpty whether to drop the map if it becomes empty after deletion + * @return {@code true} if the element was deleted, + * {@code false} if the MKey is not found, * {@code null} if the key is not found */ - ArcusFuture bopDelete(String key, BKey from, BKey to, BopDeleteArgs args); + ArcusFuture mopDelete(String key, String mKey, boolean dropIfEmpty); /** - * Count elements in a bKey range from a btree item. + * Delete elements with the given MKeys from a map. * - * @param key key of the btree item - * @param from BKey range start (inclusive) - * @param to BKey range end (inclusive) - * @param eFlagFilter eFlag filter condition, or {@code null} to count all elements in the range - * @return the number of elements in the range (0 if none exist), + * @param key key of the map + * @param mKeys MKeys of the elements to delete + * @param dropIfEmpty whether to drop the map if it becomes empty after deletion + * @return {@code true} if at least one element was deleted, + * {@code false} if no MKeys are found, * {@code null} if the key is not found */ - ArcusFuture bopCount(String key, BKey from, BKey to, ElementFlagFilter eFlagFilter); + ArcusFuture mopDelete(String key, List mKeys, boolean dropIfEmpty); /** - * Create a list with the given attributes. + * Create a btree item. * - * @param key key of the list to create - * @param type element value type - * @param attributes initial attributes of the list - * @return {@code true} if created, {@code false} if the key already exists + * @param key key to create + * @param type btree element value type + * @param attributes collection attributes (must not be null) + * @return {@code true} if created, otherwise {@code false} */ - ArcusFuture lopCreate(String key, ElementValueType type, + ArcusFuture bopCreate(String key, ElementValueType type, CollectionAttributes attributes); /** - * Insert an element at the given index into a list. + * Insert an element into a btree item. * - * @param key key of the list - * @param index index at which to insert the element - * @param value the value to insert - * @return {@code true} if the element was inserted, {@code null} if the key is not found + * @param key key to insert + * @param element btree element to insert + * @return {@code true} if inserted, + * {@code false} if element exists, + * {@code null} if key is not found */ - ArcusFuture lopInsert(String key, int index, T value); + ArcusFuture bopInsert(String key, BTreeElement element); /** - * Insert an element at the given index into a list. - * If the list does not exist, it is created with the given attributes. + * Insert an element into a btree item. * - * @param key key of the list - * @param index index at which to insert the element - * @param value the value to insert - * @param attributes attributes to use when creating the list, or {@code null} to not create - * @return {@code true} if the element was inserted, {@code null} if the key is not found + * @param key key to insert + * @param element btree element to insert + * @param attributes collection attributes for creation when the btree does not exist + * @return {@code true} if inserted, + * {@code false} if element exists, + * {@code null} if key is not found */ - ArcusFuture lopInsert(String key, int index, T value, CollectionAttributes attributes); + ArcusFuture bopInsert(String key, BTreeElement element, + CollectionAttributes attributes); /** - * Get an element at the given index from a list. + * Insert an element into a btree item and get trimmed element if overflow trim occurs. * - * @param key key of the list - * @param index index of the element to get - * @param args arguments for get operation - * @return the element value, {@code null} if the key or element is not found + * @param key key to insert + * @param element btree element to insert + * @return {@code Map.Entry} with insertion result and trimmed element */ - ArcusFuture lopGet(String key, int index, GetArgs args); + ArcusFuture>> bopInsertAndGetTrimmed( + String key, BTreeElement element); /** - * Get elements in an index range from a list. + * Insert an element into a btree item and get trimmed element if overflow trim occurs. * - * @param key key of the list - * @param from index range start (inclusive) - * @param to index range end (inclusive) - * @param args arguments for get operation - * @return list of element values in order, an empty list if no elements are found in the range, - * {@code null} if the key is not found + * @param key key to insert + * @param element btree element to insert + * @param attributes collection attributes for creation when the btree does not exist + * @return {@code Map.Entry} with insertion result and trimmed element */ - ArcusFuture> lopGet(String key, int from, int to, GetArgs args); + ArcusFuture>> bopInsertAndGetTrimmed( + String key, BTreeElement element, CollectionAttributes attributes); /** - * Delete an element at the given index from a list. + * Upsert an element into a btree item. * - * @param key key of the list - * @param index index of the element to delete - * @param dropIfEmpty whether to delete the list if it becomes empty after deletion - * @return {@code true} if the element was deleted, - * {@code false} if the element is not found, - * {@code null} if the key is not found + * @param key key to upsert + * @param element btree element to upsert + * @return {@code true} if upserted, {@code null} if the key is not found */ - ArcusFuture lopDelete(String key, int index, boolean dropIfEmpty); + ArcusFuture bopUpsert(String key, BTreeElement element); /** - * Delete elements in an index range from a list. + * Upsert an element into a btree item. * - * @param key key of the list - * @param from index range start (inclusive) - * @param to index range end (inclusive) - * @param dropIfEmpty whether to delete the list if it becomes empty after deletion - * @return {@code true} if at least one element was deleted, - * {@code false} if no elements are found in the range, - * {@code null} if the key is not found + * @param key key to upsert + * @param element btree element to upsert + * @param attributes collection attributes for creation when the btree does not exist + * @return {@code true} if upserted, {@code null} if the key is not found */ - ArcusFuture lopDelete(String key, int from, int to, boolean dropIfEmpty); + ArcusFuture bopUpsert(String key, BTreeElement element, + CollectionAttributes attributes); /** - * Create a set with the given attributes. + * Upsert an element into a btree item and get trimmed element if overflow trim occurs. * - * @param key key of the set to create - * @param type element value type - * @param attributes initial attributes of the set - * @return {@code true} if created, {@code false} if the key already exists + * @param key key to upsert + * @param element btree element to upsert + * @return {@code Map.Entry} with upsertion result and trimmed element */ - ArcusFuture sopCreate(String key, ElementValueType type, - CollectionAttributes attributes); + ArcusFuture>> bopUpsertAndGetTrimmed( + String key, BTreeElement element); /** - * Insert an element into a set. + * Upsert an element into a btree item and get trimmed element if overflow trim occurs. * - * @param key key of the set - * @param value the value to insert - * @return {@code true} if the element was inserted, - * {@code false} if the element already exists, - * {@code null} if the key is not found + * @param key key to upsert + * @param element btree element to upsert + * @param attributes collection attributes for creation when the btree does not exist + * @return {@code Map.Entry} with upsertion result and trimmed element */ - ArcusFuture sopInsert(String key, T value); + ArcusFuture>> bopUpsertAndGetTrimmed( + String key, BTreeElement element, CollectionAttributes attributes); /** - * Insert an element into a set. - * If the set does not exist, it is created with the given attributes. + * Update an element in a btree item * - * @param key key of the set - * @param value the value to insert - * @param attributes attributes to use when creating the set, or {@code null} to not create - * @return {@code true} if the element was inserted, - * {@code false} if the element already exists, - * {@code null} if the key is not found + * @param key key to update + * @param element btree element to update + * @return {@code true} if updated, + * {@code false} if element does not exist, + * {@code null} if key is not found */ - ArcusFuture sopInsert(String key, T value, CollectionAttributes attributes); + ArcusFuture bopUpdate(String key, BTreeUpdateElement element); /** - * Check whether an element exists in a set. + * Increments a numeric value of an element with the given bKey in a btree item by {@code delta} * - * @param key key of the set - * @param value the value to check - * @return {@code true} if the element exists, - * {@code false} if the element is not found, - * {@code null} if the key is not found + * @param key key of the btree item + * @param bKey BKey of the element to increment + * @param delta the amount to increment (> 0) + * @return the new value after increment, or {@code null} if the key or element is not found */ - ArcusFuture sopExist(String key, T value); + ArcusFuture bopIncr(String key, BKey bKey, int delta); /** - * Get elements randomly from a set. + * Increments a numeric value of an element with the given bKey in a btree item by {@code delta}. + * If the element does not exist, it is created with {@code initial} value and {@code eFlag}. * - * @param key key of the set - * @param count number of elements to retrieve randomly (0 means all elements, max 1000) - * @param args arguments for get operation - * @return set of element values, an empty set if no elements are found, - * {@code null} if the key is not found + * @param key key of the btree item + * @param bKey BKey of the element to increment + * @param delta the amount to increment (> 0) + * @param initial the value to store if the element does not exist + * ({@code delta} is ignored) (≥ 0) + * @param eFlag eFlag of the element to create, or {@code null} if not needed + * @return the new value after increment, or {@code initial} if the element did not exist */ - ArcusFuture> sopGet(String key, int count, GetArgs args); + ArcusFuture bopIncr(String key, BKey bKey, int delta, long initial, byte[] eFlag); /** - * Delete an element from a set. + * Decrements a numeric value of an element with the given bKey in a btree item by {@code delta}. + *

If the value is decremented below 0, it will be set to 0.

* - * @param key key of the set - * @param value the value to delete - * @param dropIfEmpty whether to delete the set if it becomes empty after deletion - * @return {@code true} if the element was deleted, - * {@code false} if the element is not found, - * {@code null} if the key is not found + * @param key key of the btree item + * @param bKey BKey of the element to decrement + * @param delta the amount to decrement (> 0) + * @return the new value after decrement, or {@code null} if the key or element is not found */ - ArcusFuture sopDelete(String key, T value, boolean dropIfEmpty); + ArcusFuture bopDecr(String key, BKey bKey, int delta); /** - * Create an empty map with the given attributes. + * Decrements a numeric value of an element with the given bKey in a btree item by {@code delta}. + * If the element does not exist, it is created with {@code initial} value and {@code eFlag}. + *

If the value is decremented below 0, it will be set to 0.

* - * @param key key of the map to create - * @param type element value type - * @param attributes initial attributes of the map - * @return {@code true} if created, {@code false} if the key already exists + * @param key key of the btree item + * @param bKey BKey of the element to decrement + * @param delta the amount to decrement (> 0) + * @param initial the value to store if the element does not exist + * ({@code delta} is ignored) (≥ 0) + * @param eFlag eFlag of the element to create, or {@code null} if not needed + * @return the new value after decrement, or {@code initial} if the element did not exist */ - ArcusFuture mopCreate(String key, ElementValueType type, - CollectionAttributes attributes); + ArcusFuture bopDecr(String key, BKey bKey, int delta, long initial, byte[] eFlag); /** - * Insert an element with the given MKey into a map. + * Get an element from a btree item. * - * @param key key of the map - * @param mKey MKey of the element to insert - * @param value the value to insert - * @return {@code true} if the element was inserted, - * {@code false} if the MKey already exists, - * {@code null} if the key is not found + * @param key key to get + * @param bKey BKey of the element to get + * @param args arguments for get operation + * @return the {@code BTreeElement} if found, + * {@code BTreeElement} with null value and null eFlag if element is not found but key exists, + * {@code null} if key is not found */ - ArcusFuture mopInsert(String key, String mKey, T value); + ArcusFuture> bopGet(String key, BKey bKey, BopGetArgs args); /** - * Insert an element with the given MKey into a map. - * If the map does not exist, it is created with the given attributes. + * Get elements from a btree item. * - * @param key key of the map - * @param mKey MKey of the element to insert - * @param value the value to insert - * @param attributes attributes to use when creating the map - * @return {@code true} if the element was inserted, - * {@code false} if the MKey already exists, - * {@code null} if the key is not found + * @param key key to get + * @param from BKey range start + * @param to BKey range end + * @param args arguments for get operation + * @return {@code BTreeElements} with found elements, + * empty {@code BTreeElements} if no elements are found in the range but key exists, + * {@code null} if key is not found */ - ArcusFuture mopInsert(String key, String mKey, T value, CollectionAttributes attributes); + ArcusFuture> bopGet(String key, BKey from, BKey to, BopGetArgs args); /** - * Upsert an element with the given MKey in a map. - * If an element with the given MKey exists, it is replaced, otherwise a new element is inserted. + * Get elements from multiple btree items. * - * @param key key of the map - * @param mKey MKey of the element to upsert - * @param value the value to insert or replace with - * @return {@code true} if upserted, {@code null} if the key is not found + * @param keys list of keys to get + * @param from BKey range start + * @param to BKey range end + * @param args arguments for get operation + * @return map of key to {@code BTreeElements} with found elements, + * empty {@code BTreeElements} if no elements are found in the range but key exists, + * no {@code Map.Entry} in the map if the key is not found */ - ArcusFuture mopUpsert(String key, String mKey, T value); + ArcusFuture>> bopMultiGet( + List keys, BKey from, BKey to, BopGetArgs args); /** - * Upsert an element with the given MKey in a map. - * If an element with the given MKey exists, it is replaced, otherwise a new element is inserted. - * If the map does not exist, it is created with the given attributes. + * Get sort-merged elements from multiple btree items. * - * @param key key of the map - * @param mKey MKey of the element to upsert - * @param value the value to insert or replace with - * @param attributes attributes to use when creating the map - * @return {@code true} if upserted, {@code null} if the key is not found + * @param keys list of keys to get + * @param from BKey range start + * @param to BKey range end + * @param unique whether to return unique elements only + * @param args arguments for get operation + * @return {@code SMGetElements} containing sort-merged elements, + * empty {@code SMGetElements} if no matching elements exist */ - ArcusFuture mopUpsert(String key, String mKey, T value, CollectionAttributes attributes); + ArcusFuture> bopSortMergeGet( + List keys, BKey from, BKey to, boolean unique, BopGetArgs args); /** - * Update the value of an element with the given MKey in a map. + * Get the position of an element with the given bKey in a btree item. * - * @param key key of the map - * @param mKey MKey of the element to update - * @param value the new value - * @return {@code true} if the element was updated, - * {@code false} if the MKey is not found, - * {@code null} if the key is not found + * @param key key of the btree item + * @param bKey BKey of the element to find + * @param order the order of the btree to determine position + * @return the 0-based position of the element, + * {@code null} if the key or element is not found */ - ArcusFuture mopUpdate(String key, String mKey, T value); + ArcusFuture bopGetPosition(String key, BKey bKey, BTreeOrder order); /** - * Get all elements from a map. + * Get an element at the given position in a btree item. * - * @param key key of the map - * @param args arguments for get operation - * @return map of MKey to value, - * empty map if no elements exist, - * {@code null} if the key is not found + * @param key key of the btree item + * @param pos 0-based position of the element to get + * @param order the order of the btree to determine position + * @return the {@code BTreeElement} at the given position, + * {@code null} if the key or element is not found */ - ArcusFuture> mopGet(String key, GetArgs args); + ArcusFuture> bopGetByPosition( + String key, int pos, BTreeOrder order); /** - * Get an element with the given MKey from a map. + * Get elements in a position range from a btree item. * - * @param key key of the map - * @param mKey MKey of the element to get - * @param args arguments for get operation - * @return the element value, - * {@code null} if the key or MKey is not found + * @param key key of the btree item + * @param from start position (inclusive) + * @param to end position (inclusive); must be greater than or equal to {@code from} + * @param order the order of the btree to determine position + * @return list of {@code BTreeElement} in the given position range, in traversal order, + * empty list if no elements exist in the range, + * {@code null} if the key is not found */ - ArcusFuture mopGet(String key, String mKey, GetArgs args); + ArcusFuture>> bopGetByPosition( + String key, int from, int to, BTreeOrder order); /** - * Get elements with the MKeys from a map. + * Get an element by bKey and its neighboring elements with position information. * - * @param key key of the map - * @param mKeys list of MKeys to get - * @param args arguments for get operation - * @return map of MKey to value for found elements, - * empty map if no MKeys are found, + * @param key key of the btree item + * @param bKey BKey of the element to find + * @param count the number of neighboring elements to retrieve on each side + * (0 ≤ count ≤ 100) + * @param order the order of the btree to determine position + * @return list of {@code BTreePositionElement} in traversal order, + * empty list if the element is not found, * {@code null} if the key is not found */ - ArcusFuture> mopGet(String key, List mKeys, GetArgs args); + ArcusFuture>> bopPositionWithGet( + String key, BKey bKey, int count, BTreeOrder order); /** - * Delete all elements from a map. + * Count elements in a bKey range from a btree item. * - * @param key key of the map - * @param dropIfEmpty whether to drop the map if it becomes empty after deletion - * @return {@code true} if at least one element was deleted, - * {@code false} if no elements exist, + * @param key key of the btree item + * @param from BKey range start (inclusive) + * @param to BKey range end (inclusive) + * @param eFlagFilter eFlag filter condition, or {@code null} to count all elements in the range + * @return the number of elements in the range (0 if none exist), * {@code null} if the key is not found */ - ArcusFuture mopDelete(String key, boolean dropIfEmpty); + ArcusFuture bopCount(String key, BKey from, BKey to, ElementFlagFilter eFlagFilter); /** - * Delete an element with the given MKey from a map. + * Delete an element with the given bKey from a btree item. * - * @param key key of the map - * @param mKey MKey of the element to delete - * @param dropIfEmpty whether to drop the map if it becomes empty after deletion + * @param key key of the btree item + * @param bKey BKey of the element to delete + * @param args delete arguments (eFlagFilter, dropIfEmpty) * @return {@code true} if the element was deleted, - * {@code false} if the MKey is not found, + * {@code false} if the element is not found, * {@code null} if the key is not found */ - ArcusFuture mopDelete(String key, String mKey, boolean dropIfEmpty); + ArcusFuture bopDelete(String key, BKey bKey, BopDeleteArgs args); /** - * Delete elements with the given MKeys from a map. + * Delete elements in a bKey range from a btree item. + * Elements are deleted in order from {@code from} to {@code to}. + *

If {@code args.count} is 0 (default), all elements in the range are deleted.

+ * Otherwise, only the first {@code args.count} elements (in {@code from}-to-{@code to} order) + * are deleted. * - * @param key key of the map - * @param mKeys MKeys of the elements to delete - * @param dropIfEmpty whether to drop the map if it becomes empty after deletion + * @param key key of the btree item + * @param from BKey range start (inclusive) + * @param to BKey range end (inclusive) + * @param args delete arguments (count, eFlagFilter, dropIfEmpty) * @return {@code true} if at least one element was deleted, - * {@code false} if no MKeys are found, + * {@code false} if no elements are found in the range, * {@code null} if the key is not found */ - ArcusFuture mopDelete(String key, List mKeys, boolean dropIfEmpty); - + ArcusFuture bopDelete(String key, BKey from, BKey to, BopDeleteArgs args); /** * Flush all items from all servers immediately.