Skip to content

Commit a63d8f6

Browse files
committed
FEATURE: Add CompletableFuture List APIs
1 parent 1273caf commit a63d8f6

4 files changed

Lines changed: 619 additions & 5 deletions

File tree

src/main/java/net/spy/memcached/v2/AsyncArcusCommands.java

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@
5858
import net.spy.memcached.collection.CollectionUpdate;
5959
import net.spy.memcached.collection.ElementFlagFilter;
6060
import net.spy.memcached.collection.ElementValueType;
61+
import net.spy.memcached.collection.ListCreate;
62+
import net.spy.memcached.collection.ListDelete;
63+
import net.spy.memcached.collection.ListGet;
64+
import net.spy.memcached.collection.ListInsert;
6165
import net.spy.memcached.internal.result.GetsResultImpl;
6266
import net.spy.memcached.ops.APIType;
6367
import net.spy.memcached.ops.BTreeGetBulkOperation;
@@ -83,6 +87,7 @@
8387
import net.spy.memcached.v2.vo.BTreeUpdateElement;
8488
import net.spy.memcached.v2.vo.BopDeleteArgs;
8589
import net.spy.memcached.v2.vo.BopGetArgs;
90+
import net.spy.memcached.v2.vo.GetArgs;
8691
import net.spy.memcached.v2.vo.SMGetElements;
8792

8893
public class AsyncArcusCommands<T> implements AsyncArcusCommandsIF<T> {
@@ -1525,4 +1530,124 @@ public void complete() {
15251530

15261531
return future;
15271532
}
1533+
1534+
public ArcusFuture<Boolean> lopCreate(String key, ElementValueType type,
1535+
CollectionAttributes attributes) {
1536+
if (attributes == null) {
1537+
throw new IllegalArgumentException("CollectionAttributes cannot be null");
1538+
}
1539+
1540+
CollectionCreate create = new ListCreate(TranscoderUtils.examineFlags(type),
1541+
attributes.getExpireTime(), attributes.getMaxCount(),
1542+
attributes.getOverflowAction(), attributes.getReadable(), false);
1543+
return collectionCreate(key, create);
1544+
}
1545+
1546+
public ArcusFuture<Boolean> lopInsert(String key, int index, T value) {
1547+
return lopInsert(key, index, value, null);
1548+
}
1549+
1550+
public ArcusFuture<Boolean> lopInsert(String key, int index, T value,
1551+
CollectionAttributes attributes) {
1552+
ListInsert<T> insert = new ListInsert<>(value, null, attributes);
1553+
return collectionInsert(key, String.valueOf(index), insert);
1554+
}
1555+
1556+
public ArcusFuture<T> lopGet(String key, int index, GetArgs args) {
1557+
AbstractArcusResult<T> result = new AbstractArcusResult<>(new AtomicReference<>());
1558+
ArcusFutureImpl<T> future = new ArcusFutureImpl<>(result);
1559+
ListGet get = new ListGet(index, args.isWithDelete(), args.isDropIfEmpty());
1560+
ArcusClient client = arcusClientSupplier.get();
1561+
1562+
CollectionGetOperation.Callback cb = new CollectionGetOperation.Callback() {
1563+
@Override
1564+
public void receivedStatus(OperationStatus status) {
1565+
switch (status.getStatusCode()) {
1566+
case SUCCESS:
1567+
break;
1568+
case ERR_NOT_FOUND:
1569+
case ERR_NOT_FOUND_ELEMENT:
1570+
result.set(null);
1571+
break;
1572+
case CANCELLED:
1573+
future.internalCancel();
1574+
break;
1575+
default:
1576+
/* TYPE_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement */
1577+
result.addError(key, status);
1578+
}
1579+
}
1580+
1581+
@Override
1582+
public void complete() {
1583+
future.complete();
1584+
}
1585+
1586+
@Override
1587+
public void gotData(String subKey, int flags, byte[] data, byte[] eFlag) {
1588+
CachedData cachedData = new CachedData(flags, data, tc.getMaxSize());
1589+
result.set(tcForCollection.decode(cachedData));
1590+
}
1591+
};
1592+
Operation op = client.getOpFact().collectionGet(key, get, cb);
1593+
future.setOp(op);
1594+
client.addOp(key, op);
1595+
1596+
return future;
1597+
}
1598+
1599+
public ArcusFuture<List<T>> lopGet(String key, int from, int to, GetArgs args) {
1600+
AbstractArcusResult<List<T>> result =
1601+
new AbstractArcusResult<>(new AtomicReference<>(new ArrayList<>()));
1602+
ArcusFutureImpl<List<T>> future = new ArcusFutureImpl<>(result);
1603+
ListGet get = new ListGet(from, to, args.isWithDelete(), args.isDropIfEmpty());
1604+
ArcusClient client = arcusClientSupplier.get();
1605+
1606+
CollectionGetOperation.Callback cb = new CollectionGetOperation.Callback() {
1607+
@Override
1608+
public void receivedStatus(OperationStatus status) {
1609+
switch (status.getStatusCode()) {
1610+
case SUCCESS:
1611+
case ERR_NOT_FOUND_ELEMENT:
1612+
break;
1613+
case ERR_NOT_FOUND:
1614+
result.set(null);
1615+
break;
1616+
1617+
case CANCELLED:
1618+
future.internalCancel();
1619+
break;
1620+
default:
1621+
/* TYPE_MISMATCH / UNREADABLE / NOT_SUPPORTED or unknown statement */
1622+
result.addError(key, status);
1623+
}
1624+
}
1625+
1626+
@Override
1627+
public void complete() {
1628+
future.complete();
1629+
}
1630+
1631+
@Override
1632+
public void gotData(String subKey, int flags, byte[] data, byte[] eFlag) {
1633+
CachedData cachedData = new CachedData(flags, data, tc.getMaxSize());
1634+
result.get().add(tcForCollection.decode(cachedData));
1635+
}
1636+
};
1637+
Operation op = client.getOpFact().collectionGet(key, get, cb);
1638+
future.setOp(op);
1639+
client.addOp(key, op);
1640+
1641+
return future;
1642+
}
1643+
1644+
public ArcusFuture<Boolean> lopDelete(String key, int index, boolean dropIfEmpty) {
1645+
CollectionDelete collectionDelete = new ListDelete(index, dropIfEmpty, false);
1646+
return collectionDelete(key, collectionDelete);
1647+
}
1648+
1649+
public ArcusFuture<Boolean> lopDelete(String key, int from, int to, boolean dropIfEmpty) {
1650+
CollectionDelete collectionDelete = new ListDelete(from, to, dropIfEmpty, false);
1651+
return collectionDelete(key, collectionDelete);
1652+
}
15281653
}

src/main/java/net/spy/memcached/v2/AsyncArcusCommandsIF.java

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import net.spy.memcached.v2.vo.BTreeUpdateElement;
3131
import net.spy.memcached.v2.vo.BopDeleteArgs;
3232
import net.spy.memcached.v2.vo.BopGetArgs;
33+
import net.spy.memcached.v2.vo.GetArgs;
3334
import net.spy.memcached.v2.vo.SMGetElements;
3435

3536
public interface AsyncArcusCommandsIF<T> {
@@ -73,7 +74,7 @@ public interface AsyncArcusCommandsIF<T> {
7374
* @param value the new value to set if the CAS ID matches
7475
* @param casId the CAS ID obtained from {@link #gets(String)}
7576
* @return {@code Boolean.True} if compared and set successfully,
76-
* {@code Boolean.False} if the key does not exist or CAS ID does not match
77+
* {@code Boolean.False} if the key does not exist or CAS ID does not match
7778
*/
7879
ArcusFuture<Boolean> cas(String key, int exp, T value, long casId);
7980

@@ -99,7 +100,7 @@ public interface AsyncArcusCommandsIF<T> {
99100
* Sets multiple key-value pairs.
100101
*
101102
* @param items map of keys and values to store
102-
* @param exp expiration time in seconds
103+
* @param exp expiration time in seconds
103104
* @return Map of key to Boolean result
104105
*/
105106
ArcusFuture<Map<String, Boolean>> multiSet(Map<String, T> items, int exp);
@@ -108,7 +109,7 @@ public interface AsyncArcusCommandsIF<T> {
108109
* Add multiple key-value pairs if they do not exist.
109110
*
110111
* @param items map of keys and values to store
111-
* @param exp expiration time in seconds
112+
* @param exp expiration time in seconds
112113
* @return Map of key to Boolean result
113114
*/
114115
ArcusFuture<Map<String, Boolean>> multiAdd(Map<String, T> items, int exp);
@@ -117,7 +118,7 @@ public interface AsyncArcusCommandsIF<T> {
117118
* Replace multiple key-value pairs if they exist.
118119
*
119120
* @param items map of keys and values to store
120-
* @param exp expiration time in seconds
121+
* @param exp expiration time in seconds
121122
* @return Map of key to Boolean result
122123
*/
123124
ArcusFuture<Map<String, Boolean>> multiReplace(Map<String, T> items, int exp);
@@ -431,7 +432,7 @@ ArcusFuture<SMGetElements<T>> bopSortMergeGet(List<String> keys, BKey from, BKey
431432
* ({@code delta} is ignored) (&ge; 0)
432433
* @param eFlag eFlag of the element to create, or {@code null} if not needed
433434
* @return the new value after decrement,
434-
* or {@code initial} if the element did not exist.
435+
* or {@code initial} if the element did not exist.
435436
*/
436437
ArcusFuture<Long> bopDecr(String key, BKey bKey, int delta, long initial, byte[] eFlag);
437438

@@ -475,4 +476,82 @@ ArcusFuture<SMGetElements<T>> bopSortMergeGet(List<String> keys, BKey from, BKey
475476
* or {@code null} if the key is not found.
476477
*/
477478
ArcusFuture<Long> bopCount(String key, BKey from, BKey to, ElementFlagFilter eFlagFilter);
479+
480+
/**
481+
* Create a list with the given attributes.
482+
*
483+
* @param key key of the list to create
484+
* @param type element value type
485+
* @param attributes initial attributes of the list
486+
* @return {@code true} if created, {@code false} if the key already exists.
487+
*/
488+
ArcusFuture<Boolean> lopCreate(String key, ElementValueType type,
489+
CollectionAttributes attributes);
490+
491+
/**
492+
* Insert an element at the given index into a list.
493+
*
494+
* @param key key of the list
495+
* @param index index at which to insert the element
496+
* @param value the value to insert
497+
* @return {@code true} if the element was inserted, {@code null} if the key is not found.
498+
*/
499+
ArcusFuture<Boolean> lopInsert(String key, int index, T value);
500+
501+
/**
502+
* Insert an element at the given index into a list.
503+
* If the list does not exist, it is created with the given attributes.
504+
*
505+
* @param key key of the list
506+
* @param index index at which to insert the element
507+
* @param value the value to insert
508+
* @param attributes attributes to use when creating the list, or {@code null} to not create
509+
* @return {@code true} if the element was inserted, {@code null} if the key is not found.
510+
*/
511+
ArcusFuture<Boolean> lopInsert(String key, int index, T value, CollectionAttributes attributes);
512+
513+
/**
514+
* Get an element at the given index from a list.
515+
*
516+
* @param key key of the list
517+
* @param index index of the element to get
518+
* @param args get arguments (withDelete, dropIfEmpty)
519+
* @return the element value, {@code null} if the key or element is not found.
520+
*/
521+
ArcusFuture<T> lopGet(String key, int index, GetArgs args);
522+
523+
/**
524+
* Get elements in an index range from a list.
525+
*
526+
* @param key key of the list
527+
* @param from index range start (inclusive)
528+
* @param to index range end (inclusive)
529+
* @param args get arguments (withDelete, dropIfEmpty)
530+
* @return list of element values in order, an empty list if no elements are found in the range,
531+
* {@code null} if the key is not found.
532+
*/
533+
ArcusFuture<List<T>> lopGet(String key, int from, int to, GetArgs args);
534+
535+
/**
536+
* Delete an element at the given index from a list.
537+
*
538+
* @param key key of the list
539+
* @param index index of the element to delete
540+
* @param dropIfEmpty whether to delete the list if it becomes empty after deletion
541+
* @return {@code true} if the element was deleted, {@code null} if the key is not found,
542+
* {@code false} if the element is not found.
543+
*/
544+
ArcusFuture<Boolean> lopDelete(String key, int index, boolean dropIfEmpty);
545+
546+
/**
547+
* Delete elements in an index range from a list.
548+
*
549+
* @param key key of the list
550+
* @param from index range start (inclusive)
551+
* @param to index range end (inclusive)
552+
* @param dropIfEmpty whether to delete the list if it becomes empty after deletion
553+
* @return {@code true} if at least one element was deleted, {@code null} if the key is not found,
554+
* {@code false} if no elements are found in the range.
555+
*/
556+
ArcusFuture<Boolean> lopDelete(String key, int from, int to, boolean dropIfEmpty);
478557
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package net.spy.memcached.v2.vo;
2+
3+
public final class GetArgs {
4+
5+
public static final GetArgs DEFAULT = new GetArgs.Builder().build();
6+
7+
private final boolean withDelete;
8+
private final boolean dropIfEmpty;
9+
10+
public boolean isWithDelete() {
11+
return withDelete;
12+
}
13+
14+
public boolean isDropIfEmpty() {
15+
return dropIfEmpty;
16+
}
17+
18+
private GetArgs(boolean withDelete, boolean dropIfEmpty) {
19+
this.withDelete = withDelete;
20+
this.dropIfEmpty = dropIfEmpty;
21+
}
22+
23+
public static class Builder {
24+
private boolean withDelete = false;
25+
private boolean dropIfEmpty = false;
26+
27+
public Builder withDelete() {
28+
this.withDelete = true;
29+
return this;
30+
}
31+
32+
public Builder dropIfEmpty() {
33+
this.dropIfEmpty = true;
34+
return this;
35+
}
36+
37+
public GetArgs build() {
38+
return new GetArgs(withDelete, dropIfEmpty);
39+
}
40+
}
41+
42+
}

0 commit comments

Comments
 (0)