Skip to content

Commit a930396

Browse files
f1v3-devjhpark816
authored andcommitted
FEATURE: Add CompletableFuture List APIs
1 parent 25e16d6 commit a930396

4 files changed

Lines changed: 618 additions & 5 deletions

File tree

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

Lines changed: 124 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> {
@@ -1536,4 +1541,123 @@ public void complete() {
15361541

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

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 arguments for get operation
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 arguments for get operation
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)