diff --git a/docs/01-arcus-cloud-basics.md b/docs/01-arcus-cloud-basics.md index 100744a6..c0e0b910 100644 --- a/docs/01-arcus-cloud-basics.md +++ b/docs/01-arcus-cloud-basics.md @@ -69,6 +69,7 @@ Arcus cache는 simple key-value item 외에 다양한 collection item 유형을 - collection item - list item - 데이터들의 linked list을 가지는 item - set item - 유일한 데이터들의 집합을 가지는 item + - map item - \쌍으로 구성된 데이터 집합을 가지는 item - b+tree item - b+tree key 기반으로 정렬된 데이터 집합을 가지는 item ### Expiration, Eviction, and Sticky Item diff --git a/docs/07-map-API.md b/docs/07-map-API.md new file mode 100644 index 00000000..e8beaf23 --- /dev/null +++ b/docs/07-map-API.md @@ -0,0 +1,467 @@ +## Map Item + +Map item은 하나의 key에 대해 hash 구조 기반으로 mkey & value 쌍을 data 집합으로 가진다. +Map을 Java의 Map 자료형을 저장하는 용도로 사용하길 권장한다. + +**제약 조건** +- 저장 가능한 최대 element 개수 : 디폴트 4,000개 (attribute 설정으로 최대 50,000개 확장 가능) +- 각 element에서 value 최대 크기 : 4KB +- mkey의 입력, Java map type에서 key는 string type만 가능하다. mkey 최대 길이는 250 바이트 이고, 하나의 map에 중복된 mkey는 허용하지 않는다. + +Map item에 대해 수행가능한 기본 연산은 다음과 같다. + +- [Map Item 생성](07-map-API.md#map-item-생성) +- [Map Element 삽입](07-map-API.md#map-element-삽입) +- [Map Element 변경](07-map-API.md#map-element-변경) +- [Map Element 삭제](07-map-API.md#map-element-삭제) +- [Map Element 조회](07-map-API.md#map-element-조회) + +여러 map element들에 대해 한번에 일괄 수행하는 연산은 다음과 같다. + +- [Map Element 일괄 삽입](07-map-API.md#map-element-일괄-삽입) +- [Map Element 일괄 변경](07-map-API.md#map-element-일괄-변경) + +### Map Item 생성 + +새로운 empty map item을 생성한다. + +```java +CollectionFuture asyncMopCreate(String key, ElementValueType valueType, CollectionAttributes attributes) +``` + +- key: 생성할 map item의 key +- valueType: map에 저장할 value의 유형을 지정한다. 아래의 유형이 있다. + - ElementValueType.STRING + - ElementValueType.LONG + - ElementValueType.INTEGER + - ElementValueType.BOOLEAN + - ElementValueType.DATE + - ElementValueType.BYTE + - ElementValueType.FLOAT + - ElementValueType.DOUBLE + - ElementValueType.BYTEARRAY + - ElementValueType.OTHERS : for example, user defined class +- attributes: map item의 속성들을 지정한다. + +수행 결과는 future 객체를 통해 얻는다. + +future.get() | future.operationStatus().getResponse() | 설명 +------------ | -------------------------------------- | ------- +True | CollectionResponse.CREATED | 생성 성공 +False | CollectionResponse.EXISTS | 동일 key가 이미 존재함 + + +Map item을 생성하는 예제는 아래와 같다. + +```java +String key = "Sample:EmptyMap"; +CollectionFuture future = null; +CollectionAttributes attribute = new CollectionAttributes(); // (1) +attribute.setExpireTime(60); // (1) + +try { + future = client.asyncMopCreate(key, ElementValueType.STRING, attribute); // (2) +} catch (IllegalStateException e) { + // handle exception +} + +if (future == null) + return; + +try { + Boolean result = future.get(1000L, TimeUnit.MILLISECONDS); // (3) + System.out.println(result); + System.out.println(future.getOperationStatus().getResponse()); // (4) +} catch (TimeoutException e) { + future.cancel(true); +} catch (InterruptedException e) { + future.cancel(true); +} catch (ExecutionException e) { + future.cancel(true); +} +``` + +1. Map의 expire time을 60초로 지정하였다. + CollectionAttributes의 자세한 사용방법은 [Manual:Attribute_사용](08-attribute-API.md) 장에서 자세히 다룬다. +2. Empty map을 생성할 때에는 map에 어떤 타입의 element를 저장할 것인지를 미리 지정해 두어야 한다. + 이렇게 해야 하는 이유는 Java client에서 value를 encoding/decoding하는 메커니즘 때문이다. + 위 예제는 String 타입을 저장할 수 있는 empty map을 생성한다. + 만약에 empty map을 생성할 때 지정한 element type과 일치하지 않는 값을 map에 저장한다면 + 저장은 성공하겠지만 조회할 때 엉뚱한 값이 조회된다. +3. timeout은 1초로 지정했다. 생성에 성공하면 future는 true를 반환한다. + 지정한 시간에 생성 결과가 넘어 오지 않거나 JVM의 과부하로 operation queue에서 처리되지 않을 경우 + TimeoutException이 발생한다. +4. 생성 결과에 대한 상세 정보는 future.getOperationStatus().getResponse()를 통해 조회 할 수 있다. + + +### Map Element 삽입 + +Map에 하나의 element를 삽입한다. + +```java +CollectionFuture asyncMopInsert(String key, String mkey, Object value, CollectionAttributes attributesForCreate) +``` + +- key: 삽입 대상 map의 key +- mkey: 삽입할 element의 mkey +- value: 삽입할 element의 value +- attributesForCreate: 대상 map이 없을 시, 동작을 지정한다. + - null: element 삽입하지 않는다. + - attributes: 주어진 attributes를 가진 empty map item 생성 후에 element 삽입한다. + +수행 결과는 future 객체를 통해 얻는다. + +future.get() | future.operationStatus().getResponse() | 설명 +------------ | -------------------------------------- | --------- +True | CollectionResponse.STORED | Map collection이 존재하여 element만 삽입함 + | CollectionResponse.CREATED_STORED | Map collection 생성하고 element를 삽입함 +False | CollectionResponse.NOT_FOUND | Key miss (주어진 key에 해당하는 item이 없음) + | CollectionResponse.TYPE_MISMATCH | 해당 item이 map이 아님 + | CollectionResponse.ELEMENT_EXISTS | 주어진 mkey를 가진 element가 이미 존재함 + | CollectionResponse.OVERFLOWED | 최대 저장가능한 개수만큼 element들이 존재함 + +Map element를 삽입하는 예제는 아래와 같다. + +```java +String key = "Prefix:MapKey"; +String mkey = "mkey"; +String value = "This is a value."; + +CollectionAttributes attributesForCreate = new CollectionAttributes(); +CollectionFuture future = null; + +try { + future = client.asyncMopInsert(key, mkey, value, attributesForCreate); // (1) +} catch (IllegalStateException e) { + // handle exception +} + +if (future == null) + return; + +try { + Boolean result = future.get(1000L, TimeUnit.MILLISECONDS); // (2) + System.out.println(result); + System.out.println(future.getOperationStatus().getResponse()); // (3) +} catch (TimeoutException e) { + future.cancel(true); +} catch (InterruptedException e) { + future.cancel(true); +} catch (ExecutionException e) { + future.cancel(true); +} +``` + +1. attributesForCreate값이 null이 아니면 map이 존재하지 않을 때 + attributesForCreate속성을 가진 map을 새로 생성한 다음 element를 저장한다. + 만약 key가 존재하지 않는 상황에서 attributesForCreate값이 null이면 insert에 실패한다. + - 위 예제는 디폴트 CollectionAttributes를 사용하며, 기본 expire time은 0으로 만료되지 않음을 뜻한다. +2. timeout은 1초로 지정했다. Insert가 성공하면 future는 true를 반환한다. + 지정한 시간에 insert 결과가 넘어 오지 않거나 JVM의 과부하로 operation queue에서 처리되지 않을 경우 + TimeoutException이 발생한다. +3. Insert결과에 대한 자세한 결과 코드를 확인하려면 future.getOperationStatus().getResponse()를 사용한다. + +### Map Element 변경 + +Map에서 하나의 element를 변경하는 함수이다. Element의 value를 변경한다. + +```java +CollectionFuture asyncMopUpdate(String key, String mkey, Object value) +``` + +- key: 변경 대상 map의 key +- mkey: 변경 대상 element의 mkey +- value: element의 new value + +수행 결과는 future 객체를 통해 얻는다. + +future.get() | future.operationStatus().getResponse() | 설명 +------------ | -------------------------------------- | --------- +True | CollectionResponse.UPDATED | Element가 변경됨 +False | CollectionResponse.NOT_FOUND | Key miss (주어진 key에 해당하는 item이 없음) + | CollectionResponse.NOT_FOUND_ELEMENT | 주어진 mkey를 가진 element가 없음 + | CollectionResponse.TYPE_MISMATCH | 해당 item이 map이 아님 + +특정 element의 value를 변경한다. + +```java +CollectionFuture future = mc.asyncMopUpdate(key, mkey, value); +``` + +Element 수정에 대한 자세한 수행 결과는 future.getOperationStatus().getResponse()를 통해 조회할 수 있다. + + +### Map Element 삭제 + +Map에서 element를 삭제하는 함수들은 두 가지가 있다. + +첫째, 해당 Map의 모든 element를 삭제한다. + +```java +CollectionFuture +asyncMopDelete(String key, boolean dropIfEmpty) +``` + +둘째, Map에서 주어진 mkey의 element를 삭제한다. + +```java +CollectionFuture +asyncMopDelete(String key, String mkey, boolean dropIfEmpty) +``` + +- key: 삭제 대상 map의 key +- dropIfEmpty: element 삭제로 empty map이 되면, 그 map 자체를 삭제할 지를 지정 + + +수행 결과는 future 객체를 통해 얻는다. + +future.get() | future.operationStatus().getResponse() | 설명 +------------ | -------------------------------------- | --------- +True | CollectionResponse.DELETED | Element만 삭제함 + | CollectionResponse.DELETED_DROPPED | Element 삭제하고 Map 자체도 삭제함 +False | CollectionResponse.NOT_FOUND | Key miss (주어진 key에 해당하는 item이 없음) + | CollectionResponse.NOT_FOUND_ELEMENT | 주어진 mkey를 가진 element가 없음 + | CollectionResponse.TYPE_MISMATCH | 해당 item이 map이 아님 + + +다음은 map에서 mkey가 mkey1인 element를 삭제하는 예제이다. + +```java +String key = "Prefix:MapKey"; +String mkey1 = "mkey1"; +boolean dropIfEmpty = true; +CollectionFuture future = null; + +try { + future = client.asyncMopDelete(key, mkey1, dropIfEmpty); // (1) +} catch (IllegalStateException e) { + // handle exception +} + +if (future == null) + return; + +try { + boolean result = future.get(1000L, TimeUnit.MILLISECONDS); // (2) + System.out.println(result); + CollectionResponse response = future.getOperationStatus().getResponse(); // (3) + System.out.println(response); +} catch (InterruptedException e) { + future.cancel(true); +} catch (TimeoutException e) { + future.cancel(true); +} catch (ExecutionException e) { + future.cancel(true); +} +``` + +1. Map에서 mkey1에 해당하는 element 를 삭제한다. + dropIfEmpty값이 true이면 element를 삭제하고 map이 비어있게 되었을 때 map도 함께 삭제한다. +2. delete timeout은 1초로 지정했다. 지정한 시간에 삭제 결과가 넘어 오지 않거나 JVM의 과부하로 + operation queue에서 처리되지 않을 경우 TimeoutException이 발생한다 +3. 삭제 결과에 대한 상세 정보는 future.getOperationStatus().getResponse()를 통해 조회 할 수 있다. + +## Map Element 조회 + +Map element를 조회하는 함수는 세 유형이 있다. + +첫째, 해당 Map의 모든 element를 조회한다. + +```java +CollectionFuture> +asyncMopGet(String key, boolean withDelete, boolean dropIfEmpty) +``` + +둘째, 해당 Map에서 주어진 mkey 하나의 element를 조회한다. + +```java +CollectionFuture> +asyncMopGet(String key, String mkey, boolean withDelete, boolean dropIfEmpty) +``` + +셋째, Map에서 주어진 mkeyList의 element를 조회한다. + +```java +CollectionFuture> +asyncMopGet(String key, List mkeyList, boolean withDelete, boolean dropIfEmpty) +``` + +- key: map item의 key +- mkey: 조회할 element의 mkey +- mkeyList: 조회할 element의 mkeyLists +- withDelete: element 조회와 함께 그 element를 삭제할 것인지를 지정 +- dropIfEmpty: element 삭제로 empty map이 되면, 그 map 자체도 삭제할 것인지를 지정 + +수행 결과는 future 객체를 통해 얻는다. + +future.get() | future.operationStatus().getResponse() | 설명 +------------ | -------------------------------------- | ------- +조회결과있음 | CollectionResponse.END | Element만 조회 + | CollectionResponse.DELETED | Element를 조회하고 삭제한 상태 + | CollectionResponse.DELETED_DROPPED | Element를 조회하고 삭제한 다음 map을 drop한 상태 +null | CollectionResponse.NOT_FOUND | Key miss (주어진 key에 해당하는 item이 없음) + | CollectionResponse.NOT_FOUND_ELEMENT | 조회된 element가 없음, 조회 범위에 map 영역 없음 + | CollectionResponse.TYPE_MISMATCH | 해당 key가 map이 아님 + | CollectionResponse.UNREADABLE | 해당 key를 읽을 수 없는 상태임. (unreadable item상태) + + +Map element를 조회하는 예제는 아래와 같다. + +```java +String key = "Prefix:MapKey"; +List mkeyList = new ArrayList(); +mkeyList.add("mkey1"); +mkeyList.add("mkey2"); +boolean withDelete = false; +boolean dropIfEmpty = false; +CollectionFuture> future = null; + +try { + future = client.asyncMopGet(key, mkeyList, withDelete, dropIfEmpty); // (1) +} catch (IllegalStateException e) { + // handle exception +} + +if (future == null) + return; + +try { + Map result = future.get(1000L, TimeUnit.MILLISECONDS); // (2) + System.out.println(result); + + CollectionResponse response = future.getOperationStatus().getResponse(); // (3) + if (response.equals(CollectionResponse.NOT_FOUND)) { + System.out.println("Key가 없습니다.(Key에 저장된 Map이 없음."); + } else if (response.equals(CollectionResponse.NOT_FOUND_ELEMENT)) { + System.out.println("Key에 map은 존재하지만 저장된 값 중 조건에 맞는 것이 없음."); + } + +} catch (InterruptedException e) { + future.cancel(true); +} catch (TimeoutException e) { + future.cancel(true); +} catch (ExecutionException e) { + future.cancel(true); +} +``` + +1. map에서 mkey1, mkey2를 한번에 조회하기 위해 List에 add하고 mkeyList를 조회했다. +2. timeout은 1초로 지정했다. 지정한 시간에 조회 결과가 넘어 오지 않거나 + JVM의 과부하로 operation queue에서 처리되지 않을 경우 TimeoutException이 발생한다. + 반환되는 Map 인터페이스의 구현체는 HashMap이며, 그 결과는 다음 중의 하나이다. + - key 존재하지 않음 : null 반환 + - key 존재하지만 조회 조건을 만족하는 elements 없음: empty map 반환 + - key 존재하고 조회 조건을 만족하는 elements 있음: non-empty map 반환 +3. 조회 결과에 대한 상세 정보는 future.getOperationStatus().getResponse()으로 확인한다. + + +## Map Element 일괄 삽입 + +Map에 여러 element를 한번에 삽입하는 함수는 두 유형이 있다. + +첫째, 하나의 key가 가리키는 Map에 다수의 element를 삽입하는 함수이다. + +```java +CollectionFuture> +asyncMopPipedInsertBulk(String key, Map elements, CollectionAttributes attributesForCreate) +``` + +- key: 삽입 대상 map의 key +- elements: 삽입할 element들 + - Map\ 유형 +- attributesForCreate: 대상 map이 없을 시, 동작을 지정한다. + - null: element 삽입하지 않는다. + - attributes: 주어진 attributes를 가진 empty map item 생성 후에 element 삽입한다. + + +둘째, 여러 key들이 가리키는 map들에 각각 하나의 element를 삽입하는 함수이다. + +```java +Future> +asyncMopInsertBulk(List keyList, String mkey, Object value, CollectionAttributes attributesForCreate) +``` + +- keyList: 삽입 대상 map들의 key list +- mkey: 삽입할 element의 mkey +- value: 삽입할 element의 value +- attributesForCreate: 대상 map이 없을 시, 동작을 지정한다. + - null: element 삽입하지 않는다. + - attributes: 주어진 attributes를 가진 empty map item 생성 후에 element 삽입한다. + + +하나의 map에 여러 개의 elements을 bulk insert하고 각각의 element에 대해 insert 결과를 확인하는 코드이다. + +```java +String key = "Sample:MapBulk"; +Map elements = new HashMap(); + +elements.put("mkey1", "value1"); +elements.put("mkey2", "value2"); +elements.put("mkey3", "value3"); + +boolean createKeyIfNotExists = true; + +if (elements.size() > mc.getMaxPipedItemCount()) { // (1) + System.out.println("insert 할 아이템 개수는 mc.getMaxPipedItemCount개를 초과할 수 없다."); + return; +} + +CollectionFuture> future = null; + +try { + future = mc.asyncMopPipedInsertBulk(key, elements, new CollectionAttributes()); // (2) + +} catch (IllegalStateException e) { + // handle exception +} + +if (future == null) + return; + +try { + Map result = future.get(1000L, TimeUnit.MILLISECONDS); // (3) + + if (!result.isEmpty()) { // (4) + System.out.println("일부 item이 insert 실패 하였음."); + + for (Map.Entry entry : result.entrySet()) { + System.out.print("실패한 아이템=" + elements.get(entry.getKey())); + System.out.println(", 실패원인=" + entry.getValue().getResponse()); + } + } else { + System.out.println("모두 insert 성공함."); + } +} catch (TimeoutException e) { + future.cancel(true); +} catch (InterruptedException e) { + future.cancel(true); +} catch (ExecutionException e) { + future.cancel(true); +} +``` + +1. 한꺼번에 insert할 아이템은 client.getMaxPipedItemCount()개를 초과할 수 없다. (기본값은 500개 이다.) + 만약 개수를 초과하면 IllegalArguementException이 발생한다. +2. Key에 저장된 map에 bulkData를 한꺼번에 insert하고 그 결과를 담은 future객체를 반환한다. + 이 future로부터 각 아이템의 insert성공 실패 여부를 조회할 수 있다. + 여기에서는 attributesForCreate값을 지정하여 bulk insert하기 전에 key가 없으면 생성하고 element를 insert되도록 하였다. +3. delete timeout은 1초로 지정했다. 지정한 시간에 모든 아이템의 insert 결과가 넘어 오지 않거나 + JVM의 과부하로 operation queue에서 처리되지 않을 경우 TimeoutException이 발생한다. +4. 모든 아이템이 insert에 성공하면 empty map이 반환된다. + - 반환된 Map의 Key= insert한 값(bulkData)를 iteration했을 때의 index값. + - 반환된 Map의 Value= insert실패사유 +5. 일부 실패한 아이템의 실패 원인을 조회하려면 insert할 때 사용된 값(bulkData)의 iteration 순서에 따라 + 결과 Map을 조회하면 된다. +6. Future로부터 얻은 Map의 Key가 입력된 값(bulkData)의 mapKey이기 때문에 위와 같은 방법으로 실패 원인을 조회하면 된다. + + +### Map Element 일괄 변경 + +Map에서 주어진 elements에 해당하는 모든 element의 value를 일괄 변경한다. + +```java +CollectionFuture> +asyncMopPipedUpdateBulk(String key, Map> elements) +``` +- key: 변경 대상 map의 key +- elements: 변경 대상 map에 대해 mkey, new value를 가진다. diff --git a/docs/07-attribute-API.md b/docs/08-attribute-API.md similarity index 100% rename from docs/07-attribute-API.md rename to docs/08-attribute-API.md diff --git a/docs/08-other-API.md b/docs/09-other-API.md similarity index 100% rename from docs/08-other-API.md rename to docs/09-other-API.md diff --git a/docs/09-log-message.md b/docs/10-log-message.md similarity index 100% rename from docs/09-log-message.md rename to docs/10-log-message.md diff --git a/docs/10-client-notes.md b/docs/11-client-notes.md similarity index 100% rename from docs/10-client-notes.md rename to docs/11-client-notes.md diff --git a/docs/arcus-java-client-user-guide.md b/docs/arcus-java-client-user-guide.md index c2280440..13509aa2 100644 --- a/docs/arcus-java-client-user-guide.md +++ b/docs/arcus-java-client-user-guide.md @@ -50,10 +50,18 @@ Arcus Java Client User Guide - [B+Tree Position 조회](06-btree-API.md#btree-position-%EC%A1%B0%ED%9A%8C) - [B+Tree Position 기반의 Element 조회](06-btree-API.md#btree-position-%EA%B8%B0%EB%B0%98%EC%9D%98-element-%EC%A1%B0%ED%9A%8C) - [B+Tree Position과 Element 동시 조회](06-btree-API.md#btree-position%EA%B3%BC-element-%EB%8F%99%EC%8B%9C-%EC%A1%B0%ED%9A%8C) -- [Item Attribute 연산](07-attribute-API.md) - - [Attribute 변경](07-attribute-API.md#attribute-%EB%B3%80%EA%B2%BD) - - [Attribute 조회](07-attribute-API.md#attribute-%EC%A1%B0%ED%9A%8C) -- [그 외의 연산](08-other-API.md) - - [Flush](08-other-API.md#flush) -- [Java Client Log Messages](09-log-message.md) -- [Java Client 사용시 주의사항](10-client-notes.md) +- [Map Item 연산](07-map-API.md) + - [Map Item 생성](07-map-API.md#map-item-생성) + - [Map Element 삽입](07-map-API.md#map-element-삽입) + - [Map Element 변경](07-map-API.md#map-element-변경) + - [Map Element 삭제](07-map-API.md#map-element-삭제) + - [Map Element 조회](07-map-API.md#map-element-조회) + - [Map Element 일괄 삽입](07-map-API.md#map-element-일괄-삽입) + - [Map Element 일괄 변경](07-map-API.md#map-element-일괄-변경) +- [Item Attribute 연산](08-attribute-API.md) + - [Attribute 변경](08-attribute-API.md#attribute-%EB%B3%80%EA%B2%BD) + - [Attribute 조회](08-attribute-API.md#attribute-%EC%A1%B0%ED%9A%8C) +- [그 외의 연산](09-other-API.md) + - [Flush](09-other-API.md#flush) +- [Java Client Log Messages](10-log-message.md) +- [Java Client 사용시 주의사항](11-client-notes.md) diff --git a/install-arcus-memcached.sh b/install-arcus-memcached.sh deleted file mode 100644 index 0b77707f..00000000 --- a/install-arcus-memcached.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh -set -e -CWD=$(pwd) - -# check to see if arcus-memcached folder is empty -if [ ! -x "$HOME/arcus/bin/memcached" ] || [ ! -x "$HOME/arcus/zookeeper/bin/zkServer.sh" ] -then - echo "No arcus installation! running clone and build..." - git clone --recursive git://github.com/naver/arcus.git $HOME/arcus - cd $HOME/arcus/scripts && ./build.sh -else - echo "Using cached arcus installation" -fi - -rm -rf $HOME/arcus/zookeeper/data -cp $CWD/mvnTestConf.json $HOME/arcus/scripts/conf/ -cd $HOME/arcus/scripts && - ./arcus.sh quicksetup conf/mvnTestConf.json - -cd $CWD diff --git a/src/main/java/net/spy/memcached/ArcusClient.java b/src/main/java/net/spy/memcached/ArcusClient.java index 37d2a893..5c4e8920 100644 --- a/src/main/java/net/spy/memcached/ArcusClient.java +++ b/src/main/java/net/spy/memcached/ArcusClient.java @@ -85,8 +85,10 @@ import net.spy.memcached.collection.CollectionPipedStore.ByteArraysBTreePipedStore; import net.spy.memcached.collection.CollectionPipedStore.ListPipedStore; import net.spy.memcached.collection.CollectionPipedStore.SetPipedStore; +import net.spy.memcached.collection.CollectionPipedStore.MapPipedStore; import net.spy.memcached.collection.CollectionPipedUpdate; import net.spy.memcached.collection.CollectionPipedUpdate.BTreePipedUpdate; +import net.spy.memcached.collection.CollectionPipedUpdate.MapPipedUpdate; import net.spy.memcached.collection.CollectionResponse; import net.spy.memcached.collection.CollectionStore; import net.spy.memcached.collection.CollectionUpdate; @@ -101,6 +103,11 @@ import net.spy.memcached.collection.SMGetElement; import net.spy.memcached.collection.SMGetTrimKey; import net.spy.memcached.collection.SMGetMode; +import net.spy.memcached.collection.MapCreate; +import net.spy.memcached.collection.MapDelete; +import net.spy.memcached.collection.MapGet; +import net.spy.memcached.collection.MapStore; +import net.spy.memcached.collection.MapUpdate; import net.spy.memcached.collection.SetCreate; import net.spy.memcached.collection.SetDelete; import net.spy.memcached.collection.SetExist; @@ -730,7 +737,82 @@ public void gotData(String key, String subkey, int flags, addOp(k, op); return rv; } - + + /** + * Generic get operation for map items. Public methods for b+tree items call this method. + * + * @param k map item's key + * @param collectionGet operation parameters (element keys and so on) + * @param tc transcoder to serialize and unserialize value + * @return future holding the map of fetched elements and their keys + */ + private CollectionFuture> asyncMopGet( + final String k, final CollectionGet collectionGet, final Transcoder tc) { + final CountDownLatch latch = new CountDownLatch(1); + final CollectionFuture> rv = new CollectionFuture>( + latch, operationTimeout); + Operation op = opFact.collectionGet(k, collectionGet, + new CollectionGetOperation.Callback() { + HashMap map = new HashMap(); + + public void receivedStatus(OperationStatus status) { + CollectionOperationStatus cstatus; + if (status instanceof CollectionOperationStatus) { + cstatus = (CollectionOperationStatus) status; + } else { + getLogger().warn("Unhandled state: " + status); + cstatus = new CollectionOperationStatus(status); + } + if (cstatus.isSuccess()) { + rv.set(map, cstatus); + return; + } + switch (cstatus.getResponse()) { + case NOT_FOUND: + rv.set(null, cstatus); + if (getLogger().isDebugEnabled()) { + getLogger().debug("Key(%s) not found : %s", k, + cstatus); + } + break; + case NOT_FOUND_ELEMENT: + rv.set(map, cstatus); + if (getLogger().isDebugEnabled()) { + getLogger().debug("Element(%s) not found : %s", + k, cstatus); + } + break; + case UNREADABLE: + rv.set(null, cstatus); + if (getLogger().isDebugEnabled()) { + getLogger().debug("Element(%s) is not readable : %s", + k, cstatus); + } + break; + default: + rv.set(null, cstatus); + if (getLogger().isDebugEnabled()) { + getLogger().debug("Key(%s) Unknown response : %s", + k, cstatus); + } + break; + } + } + public void complete() { + latch.countDown(); + } + public void gotData(String key, String subkey, int flags, + byte[] data) { + assert key.equals(k) : "Wrong key returned"; + map.put(subkey, tc.decode(new CachedData(flags, data, tc + .getMaxSize()))); + } + }); + rv.setOperation(op); + addOp(k, op); + return rv; + } + /** * Generic store operation for collection items. Public methods for collection items call this method. * @@ -1206,6 +1288,20 @@ public CollectionFuture asyncBopCreate(String key, return asyncCollectionCreate(key, bTreeCreate); } + /* + * (non-Javadoc) + * @see net.spy.memcached.ArcusClientIF#asyncMopCreate(java.lang.String, net.spy.memcached.collection.ElementValueType, net.spy.memcached.collection.CollectionAttributes) + */ + @Override + public CollectionFuture asyncMopCreate(String key, + ElementValueType type, CollectionAttributes attributes) { + int flag = CollectionTranscoder.examineFlags(type); + boolean noreply = false; + CollectionCreate mapCreate = new MapCreate(flag, + attributes.getExpireTime(), attributes.getMaxCount(), attributes.getReadable(), noreply); + return asyncCollectionCreate(key, mapCreate); + } + /* * (non-Javadoc) * @see net.spy.memcached.ArcusClientIF#asyncSopCreate(java.lang.String, net.spy.memcached.collection.CollectionAttributes) @@ -1336,6 +1432,89 @@ public CollectionFuture>> asyncBopGet(String key, return asyncBopGet(key, get, reverse, tc); } + /* + * (non-Javadoc) + * @see net.spy.memcached.ArcusClientIF#asyncMopGet(java.lang.String, boolean, boolean) + */ + @Override + public CollectionFuture> asyncMopGet(String key, + boolean withDelete, boolean dropIfEmpty) { + List mkeyList = new ArrayList(); + MapGet get = new MapGet(mkeyList, withDelete, dropIfEmpty); + return asyncMopGet(key, get, collectionTranscoder); + } + + + /* + * (non-Javadoc) + * @see net.spy.memcached.ArcusClientIF#asyncMopGet(java.lang.String, java.lang.String, boolean, boolean) + */ + @Override + public CollectionFuture> asyncMopGet(String key, + String mkey, boolean withDelete, boolean dropIfEmpty) { + if (mkey == null) { + throw new IllegalArgumentException("mkey is null"); + } + List mkeyList = new ArrayList(1); mkeyList.add(mkey); + MapGet get = new MapGet(mkeyList, withDelete, dropIfEmpty); + return asyncMopGet(key, get, collectionTranscoder); + } + + /* + * (non-Javadoc) + * @see net.spy.memcached.ArcusClientIF#asyncMopGet(java.lang.String, java.util.List, boolean, boolean) + */ + @Override + public CollectionFuture> asyncMopGet(String key, + List mkeyList, boolean withDelete, boolean dropIfEmpty) { + if (mkeyList == null) { + throw new IllegalArgumentException("mkeyList is null"); + } + MapGet get = new MapGet(mkeyList, withDelete, dropIfEmpty); + return asyncMopGet(key, get, collectionTranscoder); + } + + /* + * (non-Javadoc) + * @see net.spy.memcached.ArcusClientIF#asyncMopGet(java.lang.String, boolean, boolean, net.spy.memcached.transcoders.Transcoder) + */ + @Override + public CollectionFuture> asyncMopGet(String key, + boolean withDelete, boolean dropIfEmpty, Transcoder tc) { + List mkeyList = new ArrayList(); + MapGet get = new MapGet(mkeyList, withDelete, dropIfEmpty); + return asyncMopGet(key, get, tc); + } + + /* + * (non-Javadoc) + * @see net.spy.memcached.ArcusClientIF#asyncMopGet(java.lang.String, java.lang.String, boolean, boolean, net.spy.memcached.transcoders.Transcoder) + */ + @Override + public CollectionFuture> asyncMopGet(String key, + String mkey, boolean withDelete, boolean dropIfEmpty, Transcoder tc) { + if (mkey == null) { + throw new IllegalArgumentException("mkey is null"); + } + List mkeyList = new ArrayList(1); mkeyList.add(mkey); + MapGet get = new MapGet(mkeyList, withDelete, dropIfEmpty); + return asyncMopGet(key, get, tc); + } + + /* + * (non-Javadoc) + * @see net.spy.memcached.ArcusClientIF#asyncMopGet(java.lang.String, java.util.List, boolean, boolean, net.spy.memcached.transcoders.Transcoder) + */ + @Override + public CollectionFuture> asyncMopGet(String key, + List mkeyList, boolean withDelete, boolean dropIfEmpty, Transcoder tc) { + if (mkeyList == null) { + throw new IllegalArgumentException("mkeyList is null"); + } + MapGet get = new MapGet(mkeyList, withDelete, dropIfEmpty); + return asyncMopGet(key, get, tc); + } + /* * (non-Javadoc) * @see net.spy.memcached.ArcusClientIF#asyncLopGet(java.lang.String, int, boolean, boolean) @@ -1426,6 +1605,35 @@ public CollectionFuture asyncBopDelete(String key, long from, return asyncCollectionDelete(key, delete); } + /* + * (non-Javadoc) + * @see net.spy.memcached.ArcusClientIF#asyncMopDelete(java.lang.String, boolean) + */ + @Override + public CollectionFuture asyncMopDelete(String key, + boolean dropIfEmpty) { + List mkeyList = new ArrayList(); + MapDelete delete = new MapDelete(mkeyList, false, + dropIfEmpty); + return asyncCollectionDelete(key, delete); + } + + /* + * (non-Javadoc) + * @see net.spy.memcached.ArcusClientIF#asyncMopDelete(java.lang.String, java.lang.String, boolean) + */ + @Override + public CollectionFuture asyncMopDelete(String key, String mkey, + boolean dropIfEmpty) { + if (mkey == null) { + throw new IllegalArgumentException("mkey is null"); + } + List mkeyList = new ArrayList(1); mkeyList.add(mkey); + MapDelete delete = new MapDelete(mkeyList, false, + dropIfEmpty); + return asyncCollectionDelete(key, delete); + } + /* * (non-Javadoc) * @see net.spy.memcached.ArcusClientIF#asyncLopDelete(java.lang.String, int, boolean) @@ -1547,6 +1755,20 @@ public CollectionFuture asyncBopInsert(String key, long bkey, collectionTranscoder); } + + /* + * (non-Javadoc) + * @see net.spy.memcached.ArcusClientIF#asyncMopInsert(java.lang.String, java.lang.String, java.lang.Object, boolean, net.spy.memcached.collection.CollectionAttributes) + */ + @Override + public CollectionFuture asyncMopInsert(String key, String mkey, + Object value, CollectionAttributes attributesForCreate) { + MapStore mapStore = new MapStore(value, + (attributesForCreate != null), null, attributesForCreate); + return asyncCollectionStore(key, mkey, mapStore, + collectionTranscoder); + } + /* * (non-Javadoc) * @see net.spy.memcached.ArcusClientIF#asyncLopInsert(java.lang.String, int, java.lang.Object, boolean, net.spy.memcached.collection.CollectionAttributes) @@ -1584,6 +1806,18 @@ public CollectionFuture asyncBopInsert(String key, long bkey, return asyncCollectionStore(key, String.valueOf(bkey), bTreeStore, tc); } + /* + * (non-Javadoc) + * @see net.spy.memcached.ArcusClientIF#asyncMopInsert(java.lang.String, java.lang.String, java.lang.Object, boolean, net.spy.memcached.collection.CollectionAttributes, net.spy.memcached.transcoders.Transcoder) + */ + @Override + public CollectionFuture asyncMopInsert(String key, String mkey, + T value, CollectionAttributes attributesForCreate, Transcoder tc) { + MapStore mapStore = new MapStore(value, + (attributesForCreate != null), null, attributesForCreate); + return asyncCollectionStore(key, mkey, mapStore, tc); + } + /* * (non-Javadoc) * @see net.spy.memcached.ArcusClientIF#asyncLopInsert(java.lang.String, int, java.lang.Object, boolean, net.spy.memcached.collection.CollectionAttributes, net.spy.memcached.transcoders.Transcoder) @@ -1620,6 +1854,17 @@ public CollectionFuture> asyncBopPipedIn collectionTranscoder); } + /* + * (non-Javadoc) + * @see net.spy.memcached.ArcusClientIF#asyncMopPipedInsertBulk(java.lang.String, java.util.Map, net.spy.memcached.collection.CollectionAttributes) + */ + @Override + public CollectionFuture> asyncMopPipedInsertBulk( + String key, Map elements, + CollectionAttributes attributesForCreate) { + return asyncMopPipedInsertBulk(key, elements, attributesForCreate, + collectionTranscoder); + } /* * (non-Javadoc) @@ -1671,6 +1916,33 @@ public CollectionFuture> asyncBopPip } } + /* + * (non-Javadoc) + * @see net.spy.memcached.ArcusClientIF#asyncMopPipedInsertBulk(java.lang.String, java.util.Map, net.spy.memcached.collection.CollectionAttributes, net.spy.memcached.transcoders.Transcoder) + */ + @Override + public CollectionFuture> asyncMopPipedInsertBulk( + String key, Map elements, + CollectionAttributes attributesForCreate, Transcoder tc) { + if (elements.size() <= CollectionPipedStore.MAX_PIPED_ITEM_COUNT) { + MapPipedStore store = new MapPipedStore(key, elements, + (attributesForCreate != null), attributesForCreate, tc); + return asyncCollectionPipedStore(key, store); + } else { + List> storeList = new ArrayList>(); + + PartitionedMap list = new PartitionedMap( + elements, CollectionPipedStore.MAX_PIPED_ITEM_COUNT); + + for (int i = 0; i < list.size(); i++) { + storeList + .add(new MapPipedStore(key, list.get(i), + (attributesForCreate != null), + attributesForCreate, tc)); + } + return asyncCollectionPipedStore(key, storeList); + } + } /* * (non-Javadoc) @@ -2642,6 +2914,31 @@ public CollectionFuture asyncBopUpdate(String key, collectionUpdate, tc); } + /* + * (non-Javadoc) + * @see net.spy.memcached.ArcusClientIF#asyncMopUpdate(java.lang.String, java.lang.String, java.lang.Object) + */ + @Override + public CollectionFuture asyncMopUpdate(String key, String mkey, + Object value) { + MapUpdate collectionUpdate = new MapUpdate( + value, false); + return asyncCollectionUpdate(key, String.valueOf(mkey), + collectionUpdate, collectionTranscoder); + } + + /* + * (non-Javadoc) + * @see net.spy.memcached.ArcusClientIF#asyncMopUpdate(java.lang.String, java.lang.String, java.lang.Objeat, net.spy.memcached.transcoders.Transcoder) + */ + @Override + public CollectionFuture asyncMopUpdate(String key, String mkey, + T value, Transcoder tc) { + MapUpdate collectionUpdate = new MapUpdate(value, false); + return asyncCollectionUpdate(key, String.valueOf(mkey), + collectionUpdate, tc); + } + /** * Generic update operation for collection items. Public methods for collection items call this method. * @@ -2737,6 +3034,42 @@ public CollectionFuture> asyncBopPip } } + /* + * (non-Javadoc) + * + * @see net.spy.memcached.ArcusClientIF#asyncMopUpdate(java.lang.String, + * java.util.Map, net.spy.memcached.transcoders.Transcoder) + */ + @Override + public CollectionFuture> asyncMopPipedUpdateBulk( + String key, Map elements) { + return asyncMopPipedUpdateBulk(key, elements, collectionTranscoder); + } + + @Override + public CollectionFuture> asyncMopPipedUpdateBulk( + String key, Map elements, Transcoder tc) { + + if (elements.size() <= CollectionPipedUpdate.MAX_PIPED_ITEM_COUNT) { + CollectionPipedUpdate collectionPipedUpdate = new MapPipedUpdate( + key, elements, tc); + return asyncCollectionPipedUpdate(key, collectionPipedUpdate); + } else { + PartitionedMap list = new PartitionedMap( + elements, CollectionPipedUpdate.MAX_PIPED_ITEM_COUNT); + + List> collectionPipedUpdateList = new ArrayList>( + list.size()); + + for (int i = 0; i < list.size(); i++) { + collectionPipedUpdateList.add(new MapPipedUpdate(key, list + .get(i), tc)); + } + + return asyncCollectionPipedUpdate(key, collectionPipedUpdateList); + } + } + /* * (non-Javadoc) * @see net.spy.memcached.ArcusClientIF#asyncBopInsert(java.lang.String, byte[], java.lang.Object, byte[], boolean, net.spy.memcached.collection.CollectionAttributes) @@ -3890,6 +4223,41 @@ public Future> asyncBopInsertBulk( return asyncCollectionInsertBulk2(storeList); } + /* + * (non-Javadoc) + * @see net.spy.memcached.ArcusClientIF#asyncMopInsertBulk(java.util.List, java.lang.String, java.lang.Object, net.spy.memcached.collection.CollectionAttributes) + */ + @Override + public Future> asyncMopInsertBulk( + List keyList, String mkey, Object value, + CollectionAttributes attributesForCreate) { + + return asyncMopInsertBulk(keyList, mkey, value, + attributesForCreate, collectionTranscoder); + } + + /* + * (non-Javadoc) + * @see net.spy.memcached.ArcusClientIF#asyncMopInsertBulk(java.util.List, java.lang.String, java.lang.Object, net.spy.memcached.collection.CollectionAttributes, net.spy.memcached.transcoders.Transcoder) + */ + @Override + public Future> asyncMopInsertBulk( + List keyList, String mkey, T value, + CollectionAttributes attributesForCreate, Transcoder tc) { + + Map> arrangedKey = groupingKeys(keyList, NON_PIPED_BULK_INSERT_CHUNK_SIZE); + + List> storeList = new ArrayList>( + arrangedKey.size()); + + for (List eachKeyList : arrangedKey.values()) { + storeList.add(new CollectionBulkStore.MapBulkStore( + eachKeyList, mkey, value, attributesForCreate, tc)); + } + + return asyncCollectionInsertBulk2(storeList); + } + /* * (non-Javadoc) * @see net.spy.memcached.ArcusClientIF#asyncSopInsertBulk(java.util.List, java.lang.Object, net.spy.memcached.collection.CollectionAttributes) diff --git a/src/main/java/net/spy/memcached/ArcusClientIF.java b/src/main/java/net/spy/memcached/ArcusClientIF.java index 3f3bc3f9..c216282c 100644 --- a/src/main/java/net/spy/memcached/ArcusClientIF.java +++ b/src/main/java/net/spy/memcached/ArcusClientIF.java @@ -48,9 +48,9 @@ public interface ArcusClientIF { /** * Sets attributes (metadata) associated with each key - * of collections including lists, sets, and B+ trees. + * of collections including lists, sets, maps, and B+ trees. * - * @param key key of a collection (list, set, B+ tree) + * @param key key of a collection (list, set, map, B+ tree) * @param attrs a collectionAttribute object to set * @return whether or not the operation was performed */ @@ -59,9 +59,9 @@ public abstract CollectionFuture asyncSetAttr(String key, /** * Gets attributes (metadata) associated with each key - * of collections including lists, sets, and B+ trees. + * of collections including lists, sets, maps, and B+ trees. * - * @param key key of a collection (list, set, B+ tree) + * @param key key of a collection (list, set, map, B+ tree) * @return a CollectionAttributes object containing attributes */ public abstract CollectionFuture asyncGetAttr( @@ -199,7 +199,44 @@ public abstract Future> asyncBopInser */ public abstract Future> asyncBopInsertBulk( List keyList, long bkey, byte[] eFlag, Object value, CollectionAttributes attributesForCreate); - + + /** + * Insert one item into multiple map at once. + * + * @param keyList + * key list of map + * @param mkey + * mkey of map. + * @param value + * value of map + * @param attributesForCreate + * create a map with this attributes, if given key is not + * exists. + * @param tc + * transcoder to encode value + * @return a future indicating success + */ + public abstract Future> asyncMopInsertBulk( + List keyList, String mkey, T value, CollectionAttributes attributesForCreate, + Transcoder tc); + + /** + * Insert one item into multiple map at once. + * + * @param keyList + * key list of map + * @param mkey + * mkey of map. + * @param value + * value of map + * @param attributesForCreate + * create a map with this attributes, if given key is not + * exists. + * @return a future indicating success + */ + public abstract Future> asyncMopInsertBulk( + List keyList, String mkey, Object value, CollectionAttributes attributesForCreate); + /** * Insert a value into each list * @@ -342,6 +379,20 @@ public abstract Future> asyncSopInsertBul public CollectionFuture asyncBopCreate(String key, ElementValueType valueType, CollectionAttributes attributes); + /** + * Create an empty map + * + * @param key + * key of a map + * @param type + * element data type of the map + * @param attributes + * attributes of the map + * @return a future indicating success, false if there was a key + */ + public CollectionFuture asyncMopCreate(String key, + ElementValueType type, CollectionAttributes attributes); + /** * Create an empty set * @@ -452,6 +503,82 @@ public CollectionFuture>> asyncBopGet(String key, long from, long to, ElementFlagFilter eFlagFilter, int offset, int count, boolean withDelete, boolean dropIfEmpty, Transcoder tc); + /** + * Retrieves all items from the map + * + * @param key key of a map + * @param withDelete true to remove the returned item in the map + * @param dropIfEmpty true to remove the key when all elements are removed. false map will remain empty even if all the elements are removed + * @return a future that will hold the return value map of the fetch + */ + public CollectionFuture> asyncMopGet(String key, + boolean withDelete, boolean dropIfEmpty); + + /** + * Retrieves an item on given mkey in the map. + * + * @param key key of a map + * @param mkey mkey of a map + * @param withDelete true to remove the returned item in the map + * @param dropIfEmpty true to remove the key when all elements are removed. false map will remain empty even if all the elements are removed + * @return a future that will hold the return value map of the fetch + */ + public CollectionFuture> asyncMopGet(String key, + String mkey, boolean withDelete, boolean dropIfEmpty); + + /** + * Retrieves items on given mkey list in the map. + * + * @param key key of a map + * @param mkeyList mkeyList + * @param withDelete true to remove the returned item in the map + * @param dropIfEmpty true to remove the key when all elements are removed. false map will remain empty even if all the elements are removed + * @return a future that will hold the return value map of the fetch. + */ + public CollectionFuture> asyncMopGet(String key, + List mkeyList, boolean withDelete, boolean dropIfEmpty); + + /** + * Retrieves all items from the map + * + * @param + * @param key key of a map + * @param withDelete true to remove the returned item in the map + * @param dropIfEmpty true to remove the key when all elements are removed. false map will remain empty even if all the elements are removed + * @param tc a transcoder to decode returned values + * @return a future that will hold the return value map of the fetch + */ + public CollectionFuture> asyncMopGet(String key, + boolean withDelete, boolean dropIfEmpty, Transcoder tc); + + /** + * Retrieves an item on given mkey in the map. + * + * @param + * @param key key of a map + * @param mkey mkey of a map + * @param withDelete true to remove the returned item in the map + * @param dropIfEmpty true to remove the key when all elements are removed. false map will remain empty even if all the elements are removed + * @param tc a transcoder to decode returned values + * @return a future that will hold the return value map of the fetch + */ + public CollectionFuture> asyncMopGet(String key, + String mkey, boolean withDelete, boolean dropIfEmpty, Transcoder tc); + + /** + * Retrieves items on given mkey list in the map. + * + * @param + * @param key key of a map + * @param mkeyList mkeyList + * @param withDelete true to remove the returned item in the map + * @param dropIfEmpty true to remove the key when all elements are removed. false map will remain empty even if all the elements are removed + * @param tc a transcoder to decode returned values + * @return a future that will hold the return value map of the fetch. + */ + public CollectionFuture> asyncMopGet(String key, + List mkeyList, boolean withDelete, boolean dropIfEmpty, Transcoder tc); + /** * Retrieves an item on given index in the list. * @@ -584,7 +711,28 @@ public CollectionFuture asyncBopDelete(String key, */ public CollectionFuture asyncBopDelete(String key, byte[] bkey, ElementFlagFilter eFlagFilter, boolean dropIfEmpty); - + + /** + * Deletes an item on given index in the map. + * + * @param key key of a map + * @param dropIfEmpty false to remove the key when all elements are removed. true b+ tree will remain empty even if all the elements are removed + * @return whether or not the operation was performed + */ + public CollectionFuture asyncMopDelete(String key, + boolean dropIfEmpty); + + /** + * Deletes an item on given index in the map. + * + * @param key key of a map + * @param mkey mkey of a map + * @param dropIfEmpty false to remove the key when all elements are removed. true b+ tree will remain empty even if all the elements are removed + * @return whether or not the operation was performed + */ + public CollectionFuture asyncMopDelete(String key, String mkey, + boolean dropIfEmpty); + /** * Deletes an item on given index in the list. * @@ -667,6 +815,23 @@ public CollectionFuture asyncBopGetItemCount(String key, public CollectionFuture asyncBopInsert(String key, long bkey, byte[] eFlag, Object value, CollectionAttributes attributesForCreate); + /** + * Inserts an item into the map + * + * @param key + * key of a map + * @param mkey + * key of a map node + * @param value + * a value to insert into the map + * @param attributesForCreate + * attributes of the key + * @return a future indicating success, false if there was no key and + * attributesForCreate is null + */ + public CollectionFuture asyncMopInsert(String key, String mkey, + Object value, CollectionAttributes attributesForCreate); + /** * Insert a value into each list * @@ -713,6 +878,22 @@ public CollectionFuture asyncBopInsert(String key, long bkey, byte[] eFlag, T value, CollectionAttributes attributesForCreate, Transcoder tc); + /** + * Inserts an item into the map + * + * @param + * @param key key of a map + * @param mkey key of a map node + * @param value a value to insert into the map + * @param attributesForCreate attributes of the key + * @param tc a trancoder to encode the value + * @return a future indicating success, false if there was no key + * and attributesForCreate parameter is null. + */ + public CollectionFuture asyncMopInsert(String key, String mkey, + T value, CollectionAttributes attributesForCreate, + Transcoder tc); + /** * Insert a value into each list * @@ -755,6 +936,17 @@ public CollectionFuture asyncSopInsert(String key, T value, public CollectionFuture> asyncBopPipedInsertBulk( String key, Map elements, CollectionAttributes attributesForCreate); + /** + * Insert values into a map + * + * @param key a key list of map + * @param elements mkey and value list of map + * @param attributesForCreate attributes of the key + * @return a future that will indicate the failure list of each operation + */ + public CollectionFuture> asyncMopPipedInsertBulk( + String key, Map elements, CollectionAttributes attributesForCreate); + /** * Insert values into a list * @@ -798,6 +990,20 @@ public CollectionFuture> asyncBopPip String key, Map elements, CollectionAttributes attributesForCreate, Transcoder tc); + /** + * Insert values into a map + * + * @param + * @param key a key list of map + * @param elements mkey and value list of map + * @param attributesForCreate attributes of the key + * @param tc transcoder to encode value + * @return a future that will indicate the failure list of each operation + */ + public CollectionFuture> asyncMopPipedInsertBulk( + String key, Map elements, CollectionAttributes attributesForCreate, + Transcoder tc); + /** * Insert values into a list * @@ -982,6 +1188,36 @@ public CollectionFuture asyncBopUpdate(String key, long bkey, public CollectionFuture asyncBopUpdate(String key, long bkey, ElementFlagUpdate eFlagUpdate, T value, Transcoder tc); + /** + * Update an element from the map + * + * @param key + * key of a map + * @param mkey + * key of a map element + * @param value + * new value of element. + * @return a future indicating success + */ + public CollectionFuture asyncMopUpdate (String key, String mkey, + Object value); + + /** + * Update an element from the map + * + * @param key + * key of a map + * @param mkey + * key of a map element + * @param value + * new value of element. + * @param tc + * a transcoder to encode the value of element + * @return a future indicating success + */ + public CollectionFuture asyncMopUpdate (String key, String mkey, + T value, Transcoder tc); + /** * Update elements from the b+tree * @@ -1008,6 +1244,32 @@ public CollectionFuture> asyncBopPipedUp public CollectionFuture> asyncBopPipedUpdateBulk( String key, List> elements, Transcoder tc); + /** + * Update elements from the map + * + * @param key + * key of a map + * @param elements + * Map of map element + * @return a future indicating success + */ + public CollectionFuture> asyncMopPipedUpdateBulk( + String key, Map elements); + + /** + * Update elements from the map + * + * @param key + * key of a map + * @param elements + * Map of map element + * @param tc + * a transcoder to encode the value of element + * @return a future indicating success + */ + public CollectionFuture> asyncMopPipedUpdateBulk( + String key, Map elements, Transcoder tc); + /** * Insert an item into the b+tree * @@ -1236,7 +1498,7 @@ public CollectionFuture> asyncSopPipedExistBulk( */ public CollectionFuture> asyncSopPipedExistBulk( String key, List values, Transcoder tc); - + /** * Insert elements into a b+tree * diff --git a/src/main/java/net/spy/memcached/ArcusClientPool.java b/src/main/java/net/spy/memcached/ArcusClientPool.java index ae7211b2..bc5ff558 100644 --- a/src/main/java/net/spy/memcached/ArcusClientPool.java +++ b/src/main/java/net/spy/memcached/ArcusClientPool.java @@ -373,6 +373,22 @@ public Future> asyncBopInsertBulk( attributesForCreate); } + @Override + public Future> asyncMopInsertBulk( + List keyList, String mkey, T value, + CollectionAttributes attributesForCreate, Transcoder tc) { + return this.getClient().asyncMopInsertBulk(keyList, mkey, value, + attributesForCreate, tc); + } + + @Override + public Future> asyncMopInsertBulk( + List keyList, String mkey, Object value, + CollectionAttributes attributesForCreate) { + return this.getClient().asyncMopInsertBulk(keyList, mkey, value, + attributesForCreate); + } + @Override public Future> asyncLopInsertBulk( List keyList, int index, T value, @@ -416,6 +432,12 @@ public CollectionFuture asyncBopCreate(String key, return this.getClient().asyncBopCreate(key, valueType, attributes); } + @Override + public CollectionFuture asyncMopCreate(String key, + ElementValueType type, CollectionAttributes attributes) { + return this.getClient().asyncMopCreate(key, type, attributes); + } + @Override public CollectionFuture asyncSopCreate(String key, ElementValueType type, CollectionAttributes attributes) { @@ -460,6 +482,42 @@ public CollectionFuture>> asyncBopGet(String key, count, withDelete, dropIfEmpty, tc); } + @Override + public CollectionFuture> asyncMopGet(String key, + List mkeyList, boolean withDelete, boolean dropIfEmpty) { + return this.getClient().asyncMopGet(key, mkeyList, withDelete, dropIfEmpty); + } + + @Override + public CollectionFuture> asyncMopGet(String key, + boolean withDelete, boolean dropIfEmpty) { + return this.getClient().asyncMopGet(key, withDelete, dropIfEmpty); + } + + @Override + public CollectionFuture> asyncMopGet(String key, + String mkey, boolean withDelete, boolean dropIfEmpty) { + return this.getClient().asyncMopGet(key, mkey, withDelete, dropIfEmpty); + } + + @Override + public CollectionFuture> asyncMopGet(String key, + List mkeyList, boolean withDelete, boolean dropIfEmpty, Transcoder tc) { + return this.getClient().asyncMopGet(key, mkeyList, withDelete, dropIfEmpty, tc); + } + + @Override + public CollectionFuture> asyncMopGet(String key, + boolean withDelete, boolean dropIfEmpty, Transcoder tc) { + return this.getClient().asyncMopGet(key, withDelete, dropIfEmpty, tc); + } + + @Override + public CollectionFuture> asyncMopGet(String key, + String mkey, boolean withDelete, boolean dropIfEmpty, Transcoder tc) { + return this.getClient().asyncMopGet(key, mkey, withDelete, dropIfEmpty, tc); + } + @Override public CollectionFuture> asyncLopGet(String key, int index, boolean withDelete, boolean dropIfEmpty) { @@ -517,6 +575,18 @@ public CollectionFuture asyncBopDelete(String key, long from, count, dropIfEmpty); } + @Override + public CollectionFuture asyncMopDelete(String key, + boolean dropIfEmpty) { + return this.getClient().asyncMopDelete(key, dropIfEmpty); + } + + @Override + public CollectionFuture asyncMopDelete(String key, String mkey, + boolean dropIfEmpty) { + return this.getClient().asyncMopDelete(key, mkey, dropIfEmpty); + } + @Override public CollectionFuture asyncLopDelete(String key, int index, boolean dropIfEmpty) { @@ -555,6 +625,13 @@ public CollectionFuture asyncBopInsert(String key, long bkey, attributesForCreate); } + @Override + public CollectionFuture asyncMopInsert(String key, String mkey, + Object value, CollectionAttributes attributesForCreate) { + return this.getClient().asyncMopInsert(key, mkey, value, + attributesForCreate); + } + @Override public CollectionFuture asyncLopInsert(String key, int index, Object value, CollectionAttributes attributesForCreate) { @@ -576,6 +653,14 @@ public CollectionFuture asyncBopInsert(String key, long bkey, attributesForCreate); } + @Override + public CollectionFuture asyncMopInsert(String key, String mkey, + T value, CollectionAttributes attributesForCreate, + Transcoder tc) { + return this.getClient().asyncMopInsert(key, mkey, value, + attributesForCreate, tc); + } + @Override public CollectionFuture asyncLopInsert(String key, int index, T value, CollectionAttributes attributesForCreate, Transcoder tc) { @@ -598,6 +683,14 @@ public CollectionFuture> asyncBopPipedIn attributesForCreate); } + @Override + public CollectionFuture> asyncMopPipedInsertBulk( + String key, Map elements, + CollectionAttributes attributesForCreate) { + return this.getClient().asyncMopPipedInsertBulk(key, elements, + attributesForCreate); + } + @Override public CollectionFuture> asyncLopPipedInsertBulk( String key, int index, List valueList, @@ -622,6 +715,14 @@ public CollectionFuture> asyncBopPip attributesForCreate, tc); } + @Override + public CollectionFuture> asyncMopPipedInsertBulk( + String key, Map elements, + CollectionAttributes attributesForCreate, Transcoder tc) { + return this.getClient().asyncMopPipedInsertBulk(key, elements, + attributesForCreate, tc); + } + @Override public CollectionFuture> asyncLopPipedInsertBulk( String key, int index, List valueList, @@ -777,6 +878,18 @@ public CollectionFuture asyncBopUpdate(String key, tc); } + @Override + public CollectionFuture asyncMopUpdate(String key, String mkey, + Object value) { + return this.getClient().asyncMopUpdate(key, mkey, value); + } + + @Override + public CollectionFuture asyncMopUpdate(String key, String mkey, + T value, Transcoder tc) { + return this.getClient().asyncMopUpdate(key, mkey, value, tc); + } + @Override public CollectionFuture> asyncBopPipedUpdateBulk( String key, List> elements) { @@ -789,6 +902,18 @@ public CollectionFuture> asyncBopPip return this.getClient().asyncBopPipedUpdateBulk(key, elements, tc); } + @Override + public CollectionFuture> asyncMopPipedUpdateBulk( + String key, Map elements) { + return this.getClient().asyncMopPipedUpdateBulk(key, elements); + } + + @Override + public CollectionFuture> asyncMopPipedUpdateBulk( + String key, Map elements, Transcoder tc) { + return this.getClient().asyncMopPipedUpdateBulk(key, elements, tc); + } + @Override public CollectionFuture> asyncSopPipedExistBulk( String key, List values) { diff --git a/src/main/java/net/spy/memcached/collection/CollectionBulkStore.java b/src/main/java/net/spy/memcached/collection/CollectionBulkStore.java index 4d3ab445..8d72388e 100644 --- a/src/main/java/net/spy/memcached/collection/CollectionBulkStore.java +++ b/src/main/java/net/spy/memcached/collection/CollectionBulkStore.java @@ -161,6 +161,88 @@ public ByteBuffer getBinaryCommand() { } } + public static class MapBulkStore extends CollectionBulkStore { + + private static final String COMMAND = "mop insert"; + private final String mkey; + + public MapBulkStore(List keyList, String mkey, T value, + CollectionAttributes attr, Transcoder tc) { + if (attr != null) { + CollectionOverflowAction overflowAction = attr.getOverflowAction(); + if (overflowAction != null && !CollectionType.map.isAvailableOverflowAction(overflowAction)) + throw new IllegalArgumentException(overflowAction + " is unavailable overflow action in " + CollectionType.map + "."); + } + this.keyList = keyList; + this.mkey = mkey; + this.value = value; + this.attribute = attr; + this.tc = tc; + this.itemCount = keyList.size(); + this.createKeyIfNotExists = (attr != null); + this.cachedData = tc.encode(value); + } + + public ByteBuffer getAsciiCommand() { + int capacity = 0; + + // estimate the buffer capacity + int eachExtraSize = KeyUtil.getKeyBytes(mkey).length + + cachedData.getData().length + 64; + for (String eachKey : keyList) { + capacity += KeyUtil.getKeyBytes(eachKey).length; + } + capacity += eachExtraSize * keyList.size(); + + // allocate the buffer + ByteBuffer bb = ByteBuffer.allocate(capacity); + + // create ascii operation string + int kSize = this.keyList.size(); + for (int i = this.nextOpIndex; i < kSize; i++) { + String key = keyList.get(i); + byte[] value = cachedData.getData(); + + setArguments( + bb, + COMMAND, + key, + mkey, + value.length, + (createKeyIfNotExists) ? "create" : "", + (createKeyIfNotExists) ? cachedData.getFlags() : "", + (createKeyIfNotExists) ? (attribute != null && attribute + .getExpireTime() != null) ? attribute + .getExpireTime() + : CollectionAttributes.DEFAULT_EXPIRETIME : "", + (createKeyIfNotExists) ? (attribute != null && attribute + .getMaxCount() != null) ? attribute + .getMaxCount() + : CollectionAttributes.DEFAULT_MAXCOUNT : "", + (createKeyIfNotExists) ? (attribute != null && attribute + .getOverflowAction() != null) ? attribute + .getOverflowAction() + : "" : "", + (createKeyIfNotExists) ? (attribute != null && attribute + .getReadable() != null && !attribute.getReadable()) ? + "unreadable" + : "" : "", + (i < kSize - 1) ? PIPE : ""); + bb.put(value); + bb.put(CRLF); + } + + // flip the buffer + bb.flip(); + + return bb; + } + + public ByteBuffer getBinaryCommand() { + throw new RuntimeException("not supported in binary protocol yet."); + } + } + public static class SetBulkStore extends CollectionBulkStore { private static final String COMMAND = "sop insert"; diff --git a/src/main/java/net/spy/memcached/collection/CollectionCreate.java b/src/main/java/net/spy/memcached/collection/CollectionCreate.java index b7961109..186a39e7 100644 --- a/src/main/java/net/spy/memcached/collection/CollectionCreate.java +++ b/src/main/java/net/spy/memcached/collection/CollectionCreate.java @@ -36,6 +36,9 @@ public CollectionCreate(int flags, Integer expTime, Long maxCount, CollectionOve } else if ((this instanceof ListCreate) && !CollectionType.list.isAvailableOverflowAction(overflowAction)) { throw new IllegalArgumentException(overflowAction + " is unavailable overflow action in " + CollectionType.list + "."); + } else if ((this instanceof MapCreate) && + !CollectionType.map.isAvailableOverflowAction(overflowAction)) { + throw new IllegalArgumentException(overflowAction + " is unavailable overflow action in" + CollectionType.map + "."); } else if ((this instanceof BTreeCreate) && !CollectionType.btree.isAvailableOverflowAction(overflowAction)) { throw new IllegalArgumentException(overflowAction + " is unavailable overflow action in " + CollectionType.btree + "."); diff --git a/src/main/java/net/spy/memcached/collection/CollectionPipedStore.java b/src/main/java/net/spy/memcached/collection/CollectionPipedStore.java index 8e45acc3..8fd82c9d 100644 --- a/src/main/java/net/spy/memcached/collection/CollectionPipedStore.java +++ b/src/main/java/net/spy/memcached/collection/CollectionPipedStore.java @@ -368,7 +368,83 @@ public ByteBuffer getBinaryCommand() { throw new RuntimeException("not supported in binary protocol yet."); } } - + + /** + * + */ + public static class MapPipedStore extends CollectionPipedStore { + + private static final String COMMAND = "mop insert"; + private Map map; + + public MapPipedStore(String key, Map map, + boolean createKeyIfNotExists, CollectionAttributes attr, Transcoder tc) { + if (createKeyIfNotExists) { + CollectionOverflowAction overflowAction = attr.getOverflowAction(); + if (overflowAction != null && + !CollectionType.map.isAvailableOverflowAction(overflowAction)) + throw new IllegalArgumentException(overflowAction + " is unavailable overflow action in " + CollectionType.map + "."); + } + this.key = key; + this.map = map; + this.createKeyIfNotExists = createKeyIfNotExists; + this.attribute = attr; + this.tc = tc; + this.itemCount = map.size(); + } + + public ByteBuffer getAsciiCommand() { + int capacity = 0; + + // encode values + List encodedList = new ArrayList(map.size()); + CachedData cd = null; + for (T each : map.values()) { + cd = tc.encode(each); + encodedList.add(cd.getData()); + } + + // estimate the buffer capacity + int i = 0; + for (String eachMkey : map.keySet()) { + capacity += KeyUtil.getKeyBytes(key).length; + capacity += KeyUtil.getKeyBytes(eachMkey).length; + capacity += encodedList.get(i++).length; + capacity += 64; + } + + // allocate the buffer + ByteBuffer bb = ByteBuffer.allocate(capacity); + + // create ascii operation string + int mkeySize = map.keySet().size(); + List keyList = new ArrayList(map.keySet()); + for(i = this.nextOpIndex; i < mkeySize; i++) { + String mkey = keyList.get(i); + byte[] value = encodedList.get(i); + + setArguments(bb, COMMAND, key, mkey, value.length, + (createKeyIfNotExists) ? "create" : "", (createKeyIfNotExists) ? cd.getFlags() : "", + (createKeyIfNotExists) ? (attribute != null && attribute.getExpireTime() != null) ? attribute.getExpireTime() : CollectionAttributes.DEFAULT_EXPIRETIME : "", + (createKeyIfNotExists) ? (attribute != null && attribute.getMaxCount() != null) ? attribute.getMaxCount() : CollectionAttributes.DEFAULT_MAXCOUNT : "", + (createKeyIfNotExists) ? (attribute != null && attribute.getOverflowAction() != null) ? attribute.getOverflowAction() : "" : "", + (createKeyIfNotExists) ? (attribute != null && attribute.getReadable() != null && !attribute.getReadable()) ? "unreadable" : "" : "", + (i < mkeySize - 1) ? PIPE : ""); + bb.put(value); + bb.put(CRLF); + } + + // flip the buffer + bb.flip(); + + return bb; + } + + public ByteBuffer getBinaryCommand() { + throw new RuntimeException("not supported in binary protocol yet."); + } + } + public String getKey() { return key; } diff --git a/src/main/java/net/spy/memcached/collection/CollectionPipedUpdate.java b/src/main/java/net/spy/memcached/collection/CollectionPipedUpdate.java index 92c507fd..8f3e5032 100644 --- a/src/main/java/net/spy/memcached/collection/CollectionPipedUpdate.java +++ b/src/main/java/net/spy/memcached/collection/CollectionPipedUpdate.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Map; import net.spy.memcached.CachedData; import net.spy.memcached.KeyUtil; @@ -34,6 +35,7 @@ public abstract class CollectionPipedUpdate extends CollectionObject { protected String key; protected Transcoder tc; protected int itemCount; + protected int nextOpIndex = 0; public abstract ByteBuffer getAsciiCommand(); @@ -141,6 +143,76 @@ public ByteBuffer getBinaryCommand() { } } + + public static class MapPipedUpdate extends CollectionPipedUpdate { + + private static final String COMMAND = "mop update"; + private Map elements; + + public MapPipedUpdate(String key, Map elements, + Transcoder tc) { + this.key = key; + this.elements = elements; + this.tc = tc; + this.itemCount = elements.size(); + } + + public ByteBuffer getAsciiCommand() { + int capacity = 0; + + // encode parameters + List encodedList = new ArrayList(elements.size()); + CachedData cd = null; + for (T each : elements.values()) { + cd = tc.encode(each); + encodedList.add(cd.getData()); + } + + // estimate the buffer capacity + int i = 0; + byte[] value; + StringBuilder b; + + for (String eachMkey : elements.keySet()) { + capacity += KeyUtil.getKeyBytes(key).length; + capacity += KeyUtil.getKeyBytes(eachMkey).length; + capacity += encodedList.get(i++).length; + capacity += 64; + } + + // allocate the buffer + ByteBuffer bb = ByteBuffer.allocate(capacity); + + // create ascii operation string + int mkeySize = elements.keySet().size(); + List keyList = new ArrayList(elements.keySet()); + for (i = this.nextOpIndex; i < mkeySize; i++) { + String mkey = keyList.get(i); + value = encodedList.get(i); + b = new StringBuilder(); + + setArguments(bb, COMMAND, key, mkey, + b.toString(), (value == null ? -1 : value.length), + (i < mkeySize - 1) ? PIPE : ""); + if (value != null) { + if (value.length > 0) { + bb.put(value); + } + bb.put(CRLF); + } + } + + // flip the buffer + bb.flip(); + + return bb; + } + + public ByteBuffer getBinaryCommand() { + throw new RuntimeException("not supported in binary protocol yet."); + } + } + public String getKey() { return key; } diff --git a/src/main/java/net/spy/memcached/collection/CollectionStore.java b/src/main/java/net/spy/memcached/collection/CollectionStore.java index e0f3dbec..b936f23a 100644 --- a/src/main/java/net/spy/memcached/collection/CollectionStore.java +++ b/src/main/java/net/spy/memcached/collection/CollectionStore.java @@ -40,6 +40,9 @@ public CollectionStore(T value, byte[] elementFlag, boolean createKeyIfNotExists if ((this instanceof SetStore) && !CollectionType.set.isAvailableOverflowAction(overflowAction)) { throw new IllegalArgumentException(overflowAction + " is unavailable overflow action in " + CollectionType.set + "."); + } else if ((this instanceof MapStore) && + !CollectionType.map.isAvailableOverflowAction(overflowAction)) { + throw new IllegalArgumentException(overflowAction + " is unavailable overflow action in " + CollectionType.map + "."); } else if ((this instanceof ListStore) && !CollectionType.list.isAvailableOverflowAction(overflowAction)) { throw new IllegalArgumentException(overflowAction + " is unavailable overflow action in " + CollectionType.list + "."); diff --git a/src/main/java/net/spy/memcached/collection/CollectionType.java b/src/main/java/net/spy/memcached/collection/CollectionType.java index f40d7163..58560159 100644 --- a/src/main/java/net/spy/memcached/collection/CollectionType.java +++ b/src/main/java/net/spy/memcached/collection/CollectionType.java @@ -38,6 +38,10 @@ public enum CollectionType { * Set collection */ set("set", EnumSet.of(CollectionOverflowAction.error)), + /** + * Map collection + */ + map("map", EnumSet.of(CollectionOverflowAction.error)), /** * B+ tree collection */ diff --git a/src/main/java/net/spy/memcached/collection/MapCreate.java b/src/main/java/net/spy/memcached/collection/MapCreate.java new file mode 100644 index 00000000..a42b9840 --- /dev/null +++ b/src/main/java/net/spy/memcached/collection/MapCreate.java @@ -0,0 +1,34 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.collection; + +public class MapCreate extends CollectionCreate { + + private static final String command = "mop create"; + + public MapCreate() { + super(); + } + + public MapCreate(int flags, Integer expTime, Long maxCount, Boolean readable, boolean noreply) { + super(flags, expTime, maxCount, null, readable, noreply); + } + + public String getCommand() { + return command; + } +} \ No newline at end of file diff --git a/src/main/java/net/spy/memcached/collection/MapDelete.java b/src/main/java/net/spy/memcached/collection/MapDelete.java new file mode 100644 index 00000000..48b32b09 --- /dev/null +++ b/src/main/java/net/spy/memcached/collection/MapDelete.java @@ -0,0 +1,89 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.collection; + +import java.util.List; + +public class MapDelete extends CollectionDelete { + private static final String command = "mop delete"; + + protected List mkeyList; + private String commaSeparatedKeys; + protected byte[] additionalArgs; + + public MapDelete(List mkeyList, boolean noreply) { + this.mkeyList = mkeyList; + this.noreply = noreply; + if (mkeyList.size() == 0) { + this.additionalArgs = null; + } else { + this.additionalArgs = getCommaSeparatedMkeys().getBytes(); + } + } + + public MapDelete(List mkeyList, boolean noreply, boolean dropIfEmpty) { + this(mkeyList, noreply); + this.dropIfEmpty = dropIfEmpty; + } + + public String getCommaSeparatedMkeys() { + if (commaSeparatedKeys != null) { + return commaSeparatedKeys; + } + + StringBuilder sb = new StringBuilder(); + int numkeys = mkeyList.size(); + for (int i = 0; i < numkeys; i++) { + sb.append(mkeyList.get(i)); + if ((i + 1) < numkeys) { + sb.append(","); + } + } + commaSeparatedKeys = sb.toString(); + return commaSeparatedKeys; + } + + public byte[] getAdditionalArgs() { + return additionalArgs; + } + + public String stringify() { + if (str != null) return str; + + StringBuilder b = new StringBuilder(); + if (additionalArgs == null) { + b.append("0"); + } else { + b.append(additionalArgs.length); + } + b.append(" ").append(mkeyList.size()); + + if (dropIfEmpty) { + b.append(" drop"); + } + if (noreply) { + b.append(" noreply"); + } + + str = b.toString(); + return str; + } + + public String getCommand() { + return command; + } +} diff --git a/src/main/java/net/spy/memcached/collection/MapGet.java b/src/main/java/net/spy/memcached/collection/MapGet.java new file mode 100644 index 00000000..b44fb2a2 --- /dev/null +++ b/src/main/java/net/spy/memcached/collection/MapGet.java @@ -0,0 +1,99 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.collection; + +import java.util.List; + +public class MapGet extends CollectionGet { + + private static final String command = "mop get"; + + protected List mkeyList; + protected byte[] data; + private String commaSeparatedKeys; + protected byte[] additionalArgs; + + public MapGet(List mkeyList, boolean delete) { + this.headerCount = 2; + this.mkeyList = mkeyList; + this.delete = delete; + if (mkeyList.size() == 0) { + this.additionalArgs = null; + } else { + this.additionalArgs = getCommaSeparatedMkeys().getBytes(); + } + } + + public MapGet(List mkeyList, boolean delete, boolean dropIfEmpty) { + this(mkeyList, delete); + this.dropIfEmpty = dropIfEmpty; + } + + public String getCommaSeparatedMkeys() { + if (commaSeparatedKeys != null) { + return commaSeparatedKeys; + } + + StringBuilder sb = new StringBuilder(); + int numkeys = mkeyList.size(); + for (int i = 0; i < numkeys; i++) { + sb.append(mkeyList.get(i)); + if ((i + 1) < numkeys) { + sb.append(","); + } + } + commaSeparatedKeys = sb.toString(); + return commaSeparatedKeys; + } + + @Override + public byte[] getAddtionalArgs() { + return additionalArgs; + } + + public String stringify() { + if (str != null) return str; + + StringBuilder b = new StringBuilder(); + if (additionalArgs == null) { + b.append("0"); + } else { + b.append(additionalArgs.length); + } + b.append(" ").append(mkeyList.size()); + + if (delete && dropIfEmpty) { + b.append(" drop"); + } + if (delete && !dropIfEmpty) { + b.append(" delete"); + } + + str = b.toString(); + return str; + } + + public String getCommand() { + return command; + } + + public void decodeItemHeader(String itemHeader) { + String[] splited = itemHeader.split(" "); + this.subkey = splited[0]; + this.dataLength = Integer.parseInt(splited[1]); + } +} diff --git a/src/main/java/net/spy/memcached/collection/MapStore.java b/src/main/java/net/spy/memcached/collection/MapStore.java new file mode 100644 index 00000000..ed5d19e9 --- /dev/null +++ b/src/main/java/net/spy/memcached/collection/MapStore.java @@ -0,0 +1,31 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.collection; + +public class MapStore extends CollectionStore { + + private static final String command = "mop insert"; + + public MapStore(T value, boolean createKeyIfNotExists, RequestMode requestMode, CollectionAttributes attr) { + super(value, null, createKeyIfNotExists, requestMode, attr); + } + + public String getCommand() { + return command; + } + +} \ No newline at end of file diff --git a/src/main/java/net/spy/memcached/collection/MapUpdate.java b/src/main/java/net/spy/memcached/collection/MapUpdate.java new file mode 100644 index 00000000..afb6084f --- /dev/null +++ b/src/main/java/net/spy/memcached/collection/MapUpdate.java @@ -0,0 +1,31 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.collection; + +public class MapUpdate extends CollectionUpdate { + + private static final String command = "mop update"; + + public MapUpdate(T newValue, boolean noreply) { + super(newValue, null, noreply); + } + + public String getCommand() { + return command; + } + +} diff --git a/src/main/java/net/spy/memcached/ops/APIType.java b/src/main/java/net/spy/memcached/ops/APIType.java index 9f50bef5..8d59d435 100644 --- a/src/main/java/net/spy/memcached/ops/APIType.java +++ b/src/main/java/net/spy/memcached/ops/APIType.java @@ -38,7 +38,14 @@ public enum APIType { SOP_DELETE(OperationType.WRITE), SOP_EXIST(OperationType.READ), SOP_GET(OperationType.RW), - + + // Map API Type + MOP_CREATE(OperationType.WRITE), + MOP_INSERT(OperationType.WRITE), + MOP_UPDATE(OperationType.WRITE), + MOP_DELETE(OperationType.WRITE), + MOP_GET(OperationType.RW), + // B+Tree API Type BOP_CREATE(OperationType.WRITE), BOP_INSERT(OperationType.WRITE), diff --git a/src/main/java/net/spy/memcached/protocol/ascii/CollectionBulkStoreOperationImpl.java b/src/main/java/net/spy/memcached/protocol/ascii/CollectionBulkStoreOperationImpl.java index 73329943..0772a11e 100644 --- a/src/main/java/net/spy/memcached/protocol/ascii/CollectionBulkStoreOperationImpl.java +++ b/src/main/java/net/spy/memcached/protocol/ascii/CollectionBulkStoreOperationImpl.java @@ -80,6 +80,8 @@ public CollectionBulkStoreOperationImpl(List keyList, setAPIType(APIType.LOP_INSERT); else if (this.store instanceof CollectionBulkStore.SetBulkStore) setAPIType(APIType.SOP_INSERT); + else if (this.store instanceof CollectionBulkStore.MapBulkStore) + setAPIType(APIType.MOP_INSERT); else if (this.store instanceof CollectionBulkStore.BTreeBulkStore) setAPIType(APIType.BOP_INSERT); setOperationType(OperationType.WRITE); diff --git a/src/main/java/net/spy/memcached/protocol/ascii/CollectionCreateOperationImpl.java b/src/main/java/net/spy/memcached/protocol/ascii/CollectionCreateOperationImpl.java index a23b15ec..c9e0b343 100644 --- a/src/main/java/net/spy/memcached/protocol/ascii/CollectionCreateOperationImpl.java +++ b/src/main/java/net/spy/memcached/protocol/ascii/CollectionCreateOperationImpl.java @@ -26,6 +26,7 @@ import net.spy.memcached.collection.CollectionResponse; import net.spy.memcached.collection.ListCreate; import net.spy.memcached.collection.SetCreate; +import net.spy.memcached.collection.MapCreate; import net.spy.memcached.ops.APIType; import net.spy.memcached.ops.CollectionCreateOperation; import net.spy.memcached.ops.CollectionOperationStatus; @@ -66,6 +67,8 @@ else if (this.collectionCreate instanceof SetCreate) setAPIType(APIType.SOP_CREATE); else if (this.collectionCreate instanceof BTreeCreate) setAPIType(APIType.BOP_CREATE); + else if (this.collectionCreate instanceof MapCreate) + setAPIType(APIType.MOP_CREATE); setOperationType(OperationType.WRITE); } diff --git a/src/main/java/net/spy/memcached/protocol/ascii/CollectionDeleteOperationImpl.java b/src/main/java/net/spy/memcached/protocol/ascii/CollectionDeleteOperationImpl.java index 9b54b9bb..fa76b914 100644 --- a/src/main/java/net/spy/memcached/protocol/ascii/CollectionDeleteOperationImpl.java +++ b/src/main/java/net/spy/memcached/protocol/ascii/CollectionDeleteOperationImpl.java @@ -26,6 +26,7 @@ import net.spy.memcached.collection.CollectionResponse; import net.spy.memcached.collection.ListDelete; import net.spy.memcached.collection.SetDelete; +import net.spy.memcached.collection.MapDelete; import net.spy.memcached.ops.APIType; import net.spy.memcached.ops.CollectionDeleteOperation; import net.spy.memcached.ops.CollectionOperationStatus; @@ -70,6 +71,8 @@ public CollectionDeleteOperationImpl(String key, setAPIType(APIType.LOP_DELETE); else if (this.collectionDelete instanceof SetDelete) setAPIType(APIType.SOP_DELETE); + else if (this.collectionDelete instanceof MapDelete) + setAPIType(APIType.MOP_DELETE); else if (this.collectionDelete instanceof BTreeDelete) setAPIType(APIType.BOP_DELETE); setOperationType(OperationType.WRITE); diff --git a/src/main/java/net/spy/memcached/protocol/ascii/CollectionGetOperationImpl.java b/src/main/java/net/spy/memcached/protocol/ascii/CollectionGetOperationImpl.java index ce6bb833..ac392ef7 100644 --- a/src/main/java/net/spy/memcached/protocol/ascii/CollectionGetOperationImpl.java +++ b/src/main/java/net/spy/memcached/protocol/ascii/CollectionGetOperationImpl.java @@ -27,6 +27,7 @@ import net.spy.memcached.collection.CollectionResponse; import net.spy.memcached.collection.ListGet; import net.spy.memcached.collection.SetGet; +import net.spy.memcached.collection.MapGet; import net.spy.memcached.ops.APIType; import net.spy.memcached.ops.CollectionGetOperation; import net.spy.memcached.ops.CollectionOperationStatus; @@ -86,6 +87,8 @@ public CollectionGetOperationImpl(String key, CollectionGet collectionGet, setAPIType(APIType.LOP_GET); else if (this.collectionGet instanceof SetGet) setAPIType(APIType.SOP_GET); + else if (this.collectionGet instanceof MapGet) + setAPIType(APIType.MOP_GET); else if (this.collectionGet instanceof BTreeGet) setAPIType(APIType.BOP_GET); if (collectionGet.isDelete()) diff --git a/src/main/java/net/spy/memcached/protocol/ascii/CollectionPipedStoreOperationImpl.java b/src/main/java/net/spy/memcached/protocol/ascii/CollectionPipedStoreOperationImpl.java index 36190871..3361fd85 100644 --- a/src/main/java/net/spy/memcached/protocol/ascii/CollectionPipedStoreOperationImpl.java +++ b/src/main/java/net/spy/memcached/protocol/ascii/CollectionPipedStoreOperationImpl.java @@ -79,6 +79,8 @@ public CollectionPipedStoreOperationImpl(String key, setAPIType(APIType.LOP_INSERT); else if (this.store instanceof CollectionPipedStore.SetPipedStore) setAPIType(APIType.SOP_INSERT); + else if (this.store instanceof CollectionPipedStore.MapPipedStore) + setAPIType(APIType.MOP_INSERT); else if (this.store instanceof CollectionPipedStore.BTreePipedStore) setAPIType(APIType.BOP_INSERT); else if (this.store instanceof CollectionPipedStore.ByteArraysBTreePipedStore) diff --git a/src/main/java/net/spy/memcached/protocol/ascii/CollectionPipedUpdateOperationImpl.java b/src/main/java/net/spy/memcached/protocol/ascii/CollectionPipedUpdateOperationImpl.java index 9a294c94..ff532508 100644 --- a/src/main/java/net/spy/memcached/protocol/ascii/CollectionPipedUpdateOperationImpl.java +++ b/src/main/java/net/spy/memcached/protocol/ascii/CollectionPipedUpdateOperationImpl.java @@ -22,6 +22,7 @@ import net.spy.memcached.collection.CollectionPipedUpdate; import net.spy.memcached.collection.CollectionPipedUpdate.BTreePipedUpdate; +import net.spy.memcached.collection.CollectionPipedUpdate.MapPipedUpdate; import net.spy.memcached.collection.CollectionResponse; import net.spy.memcached.ops.APIType; import net.spy.memcached.ops.CollectionOperationStatus; @@ -78,6 +79,8 @@ public CollectionPipedUpdateOperationImpl(String key, this.cb = (Callback) cb; if (this.update instanceof BTreePipedUpdate) setAPIType(APIType.BOP_UPDATE); + else if (this.update instanceof MapPipedUpdate) + setAPIType(APIType.MOP_UPDATE); setOperationType(OperationType.WRITE); } diff --git a/src/main/java/net/spy/memcached/protocol/ascii/CollectionStoreOperationImpl.java b/src/main/java/net/spy/memcached/protocol/ascii/CollectionStoreOperationImpl.java index f24a9f1d..4f6de688 100644 --- a/src/main/java/net/spy/memcached/protocol/ascii/CollectionStoreOperationImpl.java +++ b/src/main/java/net/spy/memcached/protocol/ascii/CollectionStoreOperationImpl.java @@ -26,6 +26,7 @@ import net.spy.memcached.collection.CollectionStore; import net.spy.memcached.collection.ListStore; import net.spy.memcached.collection.SetStore; +import net.spy.memcached.collection.MapStore; import net.spy.memcached.ops.APIType; import net.spy.memcached.ops.CollectionOperationStatus; import net.spy.memcached.ops.CollectionStoreOperation; @@ -78,6 +79,8 @@ public CollectionStoreOperationImpl(String key, String subkey, setAPIType(APIType.LOP_INSERT); else if (this.collectionStore instanceof SetStore) setAPIType(APIType.SOP_INSERT); + else if (this.collectionStore instanceof MapStore) + setAPIType(APIType.MOP_INSERT); else if (this.collectionStore instanceof BTreeStore) setAPIType(APIType.BOP_INSERT); setOperationType(OperationType.WRITE); diff --git a/src/main/java/net/spy/memcached/protocol/ascii/CollectionUpdateOperationImpl.java b/src/main/java/net/spy/memcached/protocol/ascii/CollectionUpdateOperationImpl.java index 914134aa..4f07f1de 100644 --- a/src/main/java/net/spy/memcached/protocol/ascii/CollectionUpdateOperationImpl.java +++ b/src/main/java/net/spy/memcached/protocol/ascii/CollectionUpdateOperationImpl.java @@ -22,6 +22,7 @@ import net.spy.memcached.KeyUtil; import net.spy.memcached.collection.BTreeUpdate; +import net.spy.memcached.collection.MapUpdate; import net.spy.memcached.collection.CollectionResponse; import net.spy.memcached.collection.CollectionUpdate; import net.spy.memcached.collection.ElementFlagUpdate; @@ -76,6 +77,8 @@ public CollectionUpdateOperationImpl(String key, String subkey, this.data = data; if (this.collectionUpdate instanceof BTreeUpdate) setAPIType(APIType.BOP_UPDATE); + else if (this.collectionUpdate instanceof MapUpdate) + setAPIType(APIType.MOP_UPDATE); setOperationType(OperationType.WRITE); } diff --git a/src/test/java/net/spy/memcached/ArcusTimeoutTest.java b/src/test/java/net/spy/memcached/ArcusTimeoutTest.java index 4d5d7970..ea950ba2 100644 --- a/src/test/java/net/spy/memcached/ArcusTimeoutTest.java +++ b/src/test/java/net/spy/memcached/ArcusTimeoutTest.java @@ -298,4 +298,39 @@ public void testFlushByPrefixTimeout() OperationFuture flushFuture = mc.flush("prefix"); flushFuture.get(1L, TimeUnit.MILLISECONDS); } + + @Test(expected = TimeoutException.class) + public void testMopInsertBulkMultipleTimeout() + throws InterruptedException, ExecutionException, TimeoutException { + String key = "MyMopKey"; + String value = "MyValue"; + + int elementSize = mc.getMaxPipedItemCount(); + Map elements = new TreeMap(); + for (int i = 0; i < elementSize; i++) { + elements.put(String.valueOf(i), value); + } + + Future> future = mc.asyncMopPipedInsertBulk( + key, elements, new CollectionAttributes()); + future.get(1L, TimeUnit.NANOSECONDS); + future.cancel(true); + } + + public void testMopInsertBulkTimeout() + throws InterruptedException, ExecutionException, TimeoutException { + String mkey = "MyMopKey"; + String value = "MyValue"; + int keySize = 250000; + + String[] keys = new String[keySize]; + for (int i = 0; i < keys.length; i++) { + keys[i] = "MyMopKey" + i; + } + + Future> future = mc.asyncMopInsertBulk( + Arrays.asList(keys), mkey, value, new CollectionAttributes()); + future.get(1L, TimeUnit.MILLISECONDS); + future.cancel(true); + } } diff --git a/src/test/manual/net/spy/memcached/bulkoperation/MopInsertBulkMultipleTest.java b/src/test/manual/net/spy/memcached/bulkoperation/MopInsertBulkMultipleTest.java new file mode 100644 index 00000000..2cb9babb --- /dev/null +++ b/src/test/manual/net/spy/memcached/bulkoperation/MopInsertBulkMultipleTest.java @@ -0,0 +1,118 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.bulkoperation; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import junit.framework.Assert; +import net.spy.memcached.collection.BaseIntegrationTest; +import net.spy.memcached.collection.CollectionAttributes; +import net.spy.memcached.ops.CollectionOperationStatus; + +public class MopInsertBulkMultipleTest extends BaseIntegrationTest { + + public void testInsertAndGet() { + String key = "MyMopKey32"; + String value = "MyValue"; + + int elementSize = 500; + Map elements = new TreeMap(); + for (int i = 0; i < elementSize; i++) { + elements.put(String.valueOf(i), value); + } + + try { + // REMOVE + mc.asyncMopDelete(key, true); + + // SET + Future> future = mc + .asyncMopPipedInsertBulk(key, elements, + new CollectionAttributes()); + try { + Map errorList = future.get( + 20000L, TimeUnit.MILLISECONDS); + + Assert.assertTrue("Error list is not empty.", + errorList.isEmpty()); + } catch (TimeoutException e) { + future.cancel(true); + e.printStackTrace(); + } + + // GET + int errorCount = 0; + for (Entry entry : elements.entrySet()) { + Future> f = mc.asyncMopGet(key, + entry.getKey(), false, false); + Map map = null; + try { + map = f.get(); + } catch (Exception e) { + f.cancel(true); + e.printStackTrace(); + } + Object value2 = map.entrySet().iterator().next().getValue(); + if (!value.equals(value2)) { + errorCount++; + } + } + Assert.assertEquals("Error count is greater than 0.", 0, errorCount); + + // REMOVE + for (Entry entry : elements.entrySet()) { + mc.asyncMopDelete(key, entry.getKey(), true).get(); + } + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + } + + public void testErrorCount() { + String key = "MyMopKeyErrorCount"; + String value = "MyValue"; + + int elementSize = 1200; + Map elements = new TreeMap(); + for (int i = 0; i < elementSize; i++) { + elements.put(String.valueOf(i), value); + } + + try { + mc.delete(key).get(); + + // SET + Future> future = mc + .asyncMopPipedInsertBulk(key, elements, null); + + Map map = future.get(2000L, + TimeUnit.MILLISECONDS); + assertEquals(elementSize, map.size()); + + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + } + +} diff --git a/src/test/manual/net/spy/memcached/bulkoperation/MopInsertBulkTest.java b/src/test/manual/net/spy/memcached/bulkoperation/MopInsertBulkTest.java new file mode 100644 index 00000000..01307a22 --- /dev/null +++ b/src/test/manual/net/spy/memcached/bulkoperation/MopInsertBulkTest.java @@ -0,0 +1,116 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.bulkoperation; + +import java.util.Arrays; +import java.util.Map; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import junit.framework.Assert; +import net.spy.memcached.collection.BaseIntegrationTest; +import net.spy.memcached.collection.CollectionAttributes; +import net.spy.memcached.ops.CollectionOperationStatus; + +public class MopInsertBulkTest extends BaseIntegrationTest { + + private final String MKEY = "mkey"; + + public void testInsertAndGet() { + String value = "MyValue"; + int keySize = 500; + + String[] keys = new String[keySize]; + for (int i = 0; i < keys.length; i++) { + keys[i] = "MyMopKey" + i; + } + + try { + // REMOVE + for (String key : keys) { + mc.delete(key).get(); + } + + // SET + Future> future = mc + .asyncMopInsertBulk(Arrays.asList(keys), MKEY, value, + new CollectionAttributes()); + try { + Map errorList = future.get( + 100L, TimeUnit.MILLISECONDS); + Assert.assertTrue("Error list is not empty.", + errorList.isEmpty()); + } catch (TimeoutException e) { + future.cancel(true); + } + + // GET + int errorCount = 0; + for (String key : keys) { + Future> f = mc.asyncMopGet(key, MKEY, false, false); + Map cachedMap = null; + try { + cachedMap = f.get(); + } catch (Exception e) { + f.cancel(true); + } + Object value2 = cachedMap.get(MKEY); + if (!value.equals(value2)) { + errorCount++; + } + } + Assert.assertEquals("Error count is greater than 0.", 0, errorCount); + + // REMOVE + for (String key : keys) { + mc.asyncMopDelete(key, true).get(); + } + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + } + + public void testCountError() { + String value = "MyValue"; + + int keySize = 1200; + + String[] keys = new String[keySize]; + + try { + for (int i = 0; i < keys.length; i++) { + keys[i] = "MyMopKey" + i; + mc.delete(keys[i]).get(); + } + + // SET + Future> future = mc + .asyncMopInsertBulk(Arrays.asList(keys), MKEY, value, null); + + Map map = future.get(1000L, + TimeUnit.MILLISECONDS); + assertEquals(keySize, map.size()); + + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + } + +} diff --git a/src/test/manual/net/spy/memcached/bulkoperation/PipeInsertTest.java b/src/test/manual/net/spy/memcached/bulkoperation/PipeInsertTest.java index b751e9b4..02fa827a 100644 --- a/src/test/manual/net/spy/memcached/bulkoperation/PipeInsertTest.java +++ b/src/test/manual/net/spy/memcached/bulkoperation/PipeInsertTest.java @@ -58,8 +58,6 @@ public void testBopPipeInsert() { } try { - long start = System.currentTimeMillis(); - CollectionAttributes attr = new CollectionAttributes(); CollectionFuture> future = mc @@ -68,8 +66,6 @@ public void testBopPipeInsert() { Map map = future.get(5000L, TimeUnit.MILLISECONDS); - // System.out.println(System.currentTimeMillis() - start + "ms"); - Assert.assertTrue(map.isEmpty()); Map> map3 = mc.asyncBopGet(KEY, 0, 9999, @@ -150,4 +146,34 @@ public void testLopPipeInsert() { } } + public void testMopPipeInsert() { + int elementCount = 5000; + + Map elements = new TreeMap(); + + for (int i = 0; i < elementCount; i++) { + elements.put(String.valueOf(i), "value" + i); + } + + try { + CollectionAttributes attr = new CollectionAttributes(); + + CollectionFuture> future = mc + .asyncMopPipedInsertBulk(KEY, elements, attr); + + Map map = future.get(5000L, + TimeUnit.MILLISECONDS); + + Assert.assertEquals(1000, map.size()); + + Map rmap = mc.asyncMopGet(KEY, false, false) + .get(); + + Assert.assertEquals(4000, rmap.size()); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } + } diff --git a/src/test/manual/net/spy/memcached/collection/BaseIntegrationTest.java b/src/test/manual/net/spy/memcached/collection/BaseIntegrationTest.java index 5912f9a2..d16ccb12 100644 --- a/src/test/manual/net/spy/memcached/collection/BaseIntegrationTest.java +++ b/src/test/manual/net/spy/memcached/collection/BaseIntegrationTest.java @@ -148,6 +148,14 @@ protected void addToBTree(String key, Object[] items) throws Exception { } } + protected void addToMap(String key, Object[] items) throws Exception { + for (int i = 0; i < items.length; i++) { + assertTrue(mc.asyncMopInsert(key, String.valueOf(i), items[i], + new CollectionAttributes()) + .get(1000, TimeUnit.MILLISECONDS)); + } + } + protected void deleteList(String key, int size) throws Exception { mc.asyncLopDelete(key, 0, size, true).get(1000, TimeUnit.MILLISECONDS); } @@ -164,4 +172,8 @@ protected void deleteBTree(String key, Object[] values) throws Exception { .get(1000, TimeUnit.MILLISECONDS); } } + + protected void deleteMap(String key) throws Exception { + mc.asyncMopDelete(key, true).get(1000, TimeUnit.MILLISECONDS); + } } diff --git a/src/test/manual/net/spy/memcached/collection/attribute/UnReadableMapTest.java b/src/test/manual/net/spy/memcached/collection/attribute/UnReadableMapTest.java new file mode 100644 index 00000000..f63ab989 --- /dev/null +++ b/src/test/manual/net/spy/memcached/collection/attribute/UnReadableMapTest.java @@ -0,0 +1,127 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.collection.attribute; + +import java.util.Map; + +import junit.framework.Assert; +import net.spy.memcached.collection.BaseIntegrationTest; +import net.spy.memcached.collection.CollectionAttributes; +import net.spy.memcached.collection.ElementValueType; +import net.spy.memcached.internal.CollectionFuture; + +public class UnReadableMapTest extends BaseIntegrationTest { + + private final String KEY = this.getClass().getSimpleName(); + private final String MKEY = "MKEY"; + private final String VALUE = "VALUE"; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mc.delete(KEY).get(); + Assert.assertNull(mc.asyncGetAttr(KEY).get()); + } + + @Override + protected void tearDown() throws Exception { + mc.delete(KEY).get(); + super.tearDown(); + } + + public void testCreateUnreadableMapTest() { + try { + // create unreadable empty + CollectionAttributes attribute = new CollectionAttributes(); + attribute.setReadable(false); + + Boolean insertResult = mc.asyncMopCreate(KEY, + ElementValueType.STRING, attribute).get(); + Assert.assertTrue(insertResult); + + // check attribute + CollectionAttributes attr = mc.asyncGetAttr(KEY).get(); + + Assert.assertEquals(new Long(0), attr.getCount()); + Assert.assertEquals(new Long(4000), attr.getMaxCount()); + Assert.assertEquals(new Integer(0), attr.getExpireTime()); + Assert.assertFalse(attr.getReadable()); + + // insert an item + Assert.assertTrue(mc.asyncMopInsert(KEY, MKEY, VALUE, null) + .get()); + + // get an item + CollectionFuture> f = mc.asyncMopGet( + KEY, MKEY, false, false); + Assert.assertNull(f.get()); + Assert.assertEquals("UNREADABLE", f.getOperationStatus() + .getMessage()); + + // set readable + attribute.setReadable(true); + Assert.assertTrue(mc.asyncSetAttr(KEY, attribute).get()); + + // get an item again + f = mc.asyncMopGet(KEY, MKEY, false, false); + Map map = f.get(); + + Assert.assertNotNull(map); + Assert.assertEquals(VALUE, map.get(MKEY)); + Assert.assertEquals("END", f.getOperationStatus().getMessage()); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } + + public void testCreateReadableMapTest() { + try { + // create readable empty + CollectionAttributes attribute = new CollectionAttributes(); + attribute.setReadable(true); + + Boolean insertResult = mc.asyncMopCreate(KEY, + ElementValueType.STRING, attribute).get(); + Assert.assertTrue(insertResult); + + // check attribute + CollectionAttributes attr = mc.asyncGetAttr(KEY).get(); + + Assert.assertEquals(new Long(0), attr.getCount()); + Assert.assertEquals(new Long(4000), attr.getMaxCount()); + Assert.assertEquals(new Integer(0), attr.getExpireTime()); + Assert.assertTrue(attr.getReadable()); + + // insert an item + Assert.assertTrue(mc.asyncMopInsert(KEY, MKEY, VALUE, null) + .get()); + + // get an item + CollectionFuture> f = mc.asyncMopGet( + KEY, MKEY, false, false); + + Map map = f.get(); + Assert.assertNotNull(map); + Assert.assertEquals(VALUE, map.get(MKEY)); + Assert.assertEquals("END", f.getOperationStatus().getMessage()); + } catch (Exception e) { + Assert.fail(e.getMessage()); + } + } + +} diff --git a/src/test/manual/net/spy/memcached/collection/map/MopBulkAPITest.java b/src/test/manual/net/spy/memcached/collection/map/MopBulkAPITest.java new file mode 100644 index 00000000..9ea4f81f --- /dev/null +++ b/src/test/manual/net/spy/memcached/collection/map/MopBulkAPITest.java @@ -0,0 +1,153 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.collection.map; + +import junit.framework.Assert; +import net.spy.memcached.collection.BaseIntegrationTest; +import net.spy.memcached.collection.CollectionAttributes; +import net.spy.memcached.collection.CollectionOverflowAction; +import net.spy.memcached.internal.CollectionFuture; +import net.spy.memcached.ops.CollectionOperationStatus; + +import java.util.Map; +import java.util.HashMap; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +public class MopBulkAPITest extends BaseIntegrationTest { + + private String key = "MopBulkAPITest33"; + Map elements = new HashMap(); + Map updateMap = new HashMap(); + + + private int getValueCount() { + return mc.getMaxPipedItemCount(); + } + + protected void setUp() throws Exception { + super.setUp(); + for (long i = 0; i < getValueCount(); i++) { + elements.put("mkey" + String.valueOf(i), + "value" + String.valueOf(i)); + updateMap.put("mkey" + String.valueOf(i), + "newvalue" + String.valueOf(i)); + } + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + public void testBulk() throws Exception { + for (int i = 0; i < 10; i++) { + mc.delete(key).get(); + bulk(); + } + } + + public void bulk() { + try { + Future> future = mc + .asyncMopPipedInsertBulk(key, elements, + new CollectionAttributes()); + + Map map = future.get(10000, + TimeUnit.MILLISECONDS); + + Map rmap = mc.asyncMopGet(key, false, + false).get(); + assertEquals(getValueCount(), rmap.size()); + assertEquals(0, map.size()); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } + + public void testBulkFailed() { + try { + mc.asyncMopDelete(key, true).get(1000, + TimeUnit.MILLISECONDS); + + mc.asyncMopInsert(key, "mkey1", "value1", new CollectionAttributes()) + .get(); + + mc.asyncSetAttr(key, new CollectionAttributes(0, 1L, CollectionOverflowAction.error)).get(); + + CollectionFuture> future = mc + .asyncMopPipedInsertBulk(key, elements, + new CollectionAttributes()); + + Map map = future.get(10000, + TimeUnit.MILLISECONDS); + + assertEquals(getValueCount(), map.size()); + assertFalse(future.getOperationStatus().isSuccess()); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } + + public void testBulkEmptyElements() { + try { + CollectionFuture> future = mc + .asyncMopPipedInsertBulk(key, new HashMap(), + new CollectionAttributes()); + + future.get(10000, TimeUnit.MILLISECONDS); + Assert.fail(); + } catch (IllegalArgumentException e) { + return; + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + Assert.fail(); + } + + public void testUpdateBulk() { + try { + mc.asyncMopDelete(key, true).get(1000, + TimeUnit.MILLISECONDS); + + Future> future = mc + .asyncMopPipedInsertBulk(key, elements, + new CollectionAttributes()); + + Map map = future.get(10000, + TimeUnit.MILLISECONDS); + + CollectionFuture> future2 = mc + .asyncMopPipedUpdateBulk(key, updateMap); + + Map map2 = future2.get(10000, + TimeUnit.MILLISECONDS); + + Map rmap = mc.asyncMopGet(key, false, false).get(); + assertEquals(getValueCount(), rmap.size()); + assertEquals(0, map.size()); + assertEquals(0, map2.size()); + + assertEquals("newvalue1", rmap.get("mkey1")); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } +} diff --git a/src/test/manual/net/spy/memcached/collection/map/MopDeleteTest.java b/src/test/manual/net/spy/memcached/collection/map/MopDeleteTest.java new file mode 100644 index 00000000..971c876b --- /dev/null +++ b/src/test/manual/net/spy/memcached/collection/map/MopDeleteTest.java @@ -0,0 +1,87 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.collection.map; + +import net.spy.memcached.collection.BaseIntegrationTest; +import net.spy.memcached.collection.CollectionAttributes; +import net.spy.memcached.transcoders.LongTranscoder; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class MopDeleteTest extends BaseIntegrationTest { + + private String key = "MopDeleteTest"; + + private Long[] items9 = { 0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L }; + + protected void setUp() throws Exception { + super.setUp(); + + deleteMap(key); + addToMap(key, items9); + + CollectionAttributes attrs = new CollectionAttributes(); + attrs.setMaxCount(10); + assertTrue(mc.asyncSetAttr(key, attrs).get(1000, TimeUnit.MILLISECONDS)); + } + + protected void tearDown() throws Exception { + try { + deleteMap(key); + super.tearDown(); + } catch (Exception e) { + } + } + + public void testMopDelete_NoKey() throws Exception { + assertFalse(mc.asyncMopDelete("no_key", false).get(1000, TimeUnit.MILLISECONDS)); + } + + public void testMopDelete_NoMkey() throws Exception { + assertFalse(mc.asyncMopDelete(key, "11", false).get(1000, TimeUnit.MILLISECONDS)); + } + + public void testMopDelete_DeleteByBestEffort() throws Exception { + // Delete items(2..11) in the map + for (int i=2; i<12; i++) { + mc.asyncMopDelete(key, String.valueOf(i), false).get(1000, + TimeUnit.MILLISECONDS); + } + + // Check that item is inserted + Map rmap = mc.asyncMopGet(key, false, false, + new LongTranscoder()).get(1000, TimeUnit.MILLISECONDS); + + // By rule of 'best effort', + // items(2..9) should be deleted + assertEquals(2, rmap.size()); + assertEquals((Long) 0L, rmap.get("0")); + assertEquals((Long) 1L, rmap.get("1")); + } + + public void testMopDelete_DeletedDropped() throws Exception { + // Delete all items in the list + assertTrue(mc.asyncMopDelete(key, true).get(1000, TimeUnit.MILLISECONDS)); + + CollectionAttributes attrs = mc.asyncGetAttr(key).get(1000, + TimeUnit.MILLISECONDS); + assertNull(attrs); + } +} diff --git a/src/test/manual/net/spy/memcached/collection/map/MopGetTest.java b/src/test/manual/net/spy/memcached/collection/map/MopGetTest.java new file mode 100644 index 00000000..72ba7dd8 --- /dev/null +++ b/src/test/manual/net/spy/memcached/collection/map/MopGetTest.java @@ -0,0 +1,118 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.collection.map; + +import net.spy.memcached.collection.BaseIntegrationTest; +import net.spy.memcached.collection.CollectionAttributes; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class MopGetTest extends BaseIntegrationTest { + + private String key = "MopGetTest"; + + private Long[] items9 = { 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L }; + + protected void setUp() throws Exception { + super.setUp(); + + deleteMap(key); + addToMap(key, items9); + + CollectionAttributes attrs = new CollectionAttributes(); + attrs.setMaxCount(10); + assertTrue(mc.asyncSetAttr(key, attrs).get(1000, TimeUnit.MILLISECONDS)); + } + + protected void tearDown() throws Exception { + try { + deleteMap(key); + super.tearDown(); + } catch (Exception e) { + } + } + + public void testMopGet_NoKey() throws Exception { + Map rmap = mc.asyncMopGet("no_key", false, false).get( + 1000, TimeUnit.MILLISECONDS); + + // We've got an empty list + assertNull(rmap); + } + + public void testMopGet_NoMkey() throws Exception { + Map map = mc.asyncMopGet(key, "20", false, false).get(1000, + TimeUnit.MILLISECONDS); + assertNotNull(map); + assertTrue(map.isEmpty()); + } + + public void testMopGet_GetByBestEffort() throws Exception { + // Retrieve items(2..11) in the list + List mkeyList = new ArrayList(); + for (int i = 2; i < 12; i++) { + mkeyList.add(String.valueOf(i)); + } + Map rmap = mc.asyncMopGet(key, mkeyList, false, false).get(1000, + TimeUnit.MILLISECONDS); + + // By rule of 'best effort', + // items(2..9) should be retrieved + assertEquals(7, rmap.size()); + for (int i = 0; i < rmap.size(); i++) { + assertTrue(rmap.containsValue(items9[i + 2])); + } + } + + + public void testMopGet_GetWithDeletion() throws Exception { + CollectionAttributes attrs = null; + Map rmap = null; + List mkeyList = new ArrayList(); + + // Retrieve items(0..5) in the list with delete option + for (int i = 0; i < 6; i++) { + mkeyList.add(String.valueOf(i)); + } + rmap = mc.asyncMopGet(key, mkeyList, true, false).get(1000, + TimeUnit.MILLISECONDS); + + assertEquals(6, rmap.size()); + mkeyList.clear(); + + // Check the remaining item count in the list + attrs = mc.asyncGetAttr(key).get(1000, TimeUnit.MILLISECONDS); + assertEquals(3, attrs.getCount().intValue()); + + // Retrieve items(6..8) in the list with delete option + for (int i = 6; i < 9; i++) { + mkeyList.add(String.valueOf(i)); + } + rmap = mc.asyncMopGet(key, mkeyList, true, true).get(1000, + TimeUnit.MILLISECONDS); + + assertEquals(3, rmap.size()); + + // Now our list has no items and would be deleted + rmap = mc.asyncMopGet(key, true, false).get(1000, + TimeUnit.MILLISECONDS); + assertNull(rmap); + } +} \ No newline at end of file diff --git a/src/test/manual/net/spy/memcached/collection/map/MopInsertWhenKeyExists.java b/src/test/manual/net/spy/memcached/collection/map/MopInsertWhenKeyExists.java new file mode 100644 index 00000000..faab3778 --- /dev/null +++ b/src/test/manual/net/spy/memcached/collection/map/MopInsertWhenKeyExists.java @@ -0,0 +1,88 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.collection.map; + +import net.spy.memcached.collection.BaseIntegrationTest; +import net.spy.memcached.collection.CollectionAttributes; +import net.spy.memcached.transcoders.LongTranscoder; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class MopInsertWhenKeyExists extends BaseIntegrationTest { + + private String key = "MopInsertWhenKeyExists"; + + private Long[] items9 = { 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L }; + + protected void tearDown() { + try { + mc.asyncMopDelete(key, true).get(1000, TimeUnit.MILLISECONDS); + mc.delete(key).get(); + super.tearDown(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void testMopInsert_Normal() throws Exception { + // Create a list and add it 9 items + addToMap(key, items9); + + // Set maxcount to 10 + CollectionAttributes attrs = new CollectionAttributes(); + attrs.setMaxCount(10); + assertTrue(mc.asyncSetAttr(key, attrs).get(1000, TimeUnit.MILLISECONDS)); + + // Insert one item + assertTrue(mc.asyncMopInsert(key, "10", 10L, + new CollectionAttributes()).get(1000, TimeUnit.MILLISECONDS)); + + // Check inserted item + Map rmap = mc.asyncMopGet(key, false, false, + new LongTranscoder()).get(1000, TimeUnit.MILLISECONDS); + assertEquals(10, rmap.size()); + + Long comp = rmap.get("10"); + assertEquals((Long) 10L, comp); + + // Check list attributes + CollectionAttributes rattrs = mc.asyncGetAttr(key).get(1000, + TimeUnit.MILLISECONDS); + assertEquals(10, rattrs.getCount().intValue()); + } + + public void testMopInsert_SameField() throws Exception { + // Create a list and add it 9 items + addToMap(key, items9); + + // Set maxcount to 10 + CollectionAttributes attrs = new CollectionAttributes(); + attrs.setMaxCount(10); + assertTrue(mc.asyncSetAttr(key, attrs).get(1000, TimeUnit.MILLISECONDS)); + + // Insert an item same to the last item + mc.asyncMopInsert(key, "8", 10L, new CollectionAttributes()).get( + 1000, TimeUnit.MILLISECONDS); + + // Check that item is inserted + Map rmap = mc.asyncMopGet(key, false, false, + new LongTranscoder()).get(1000, TimeUnit.MILLISECONDS); + + assertEquals(9, rmap.size()); + } +} diff --git a/src/test/manual/net/spy/memcached/collection/map/MopInsertWhenKeyNotExist.java b/src/test/manual/net/spy/memcached/collection/map/MopInsertWhenKeyNotExist.java new file mode 100644 index 00000000..c8078fae --- /dev/null +++ b/src/test/manual/net/spy/memcached/collection/map/MopInsertWhenKeyNotExist.java @@ -0,0 +1,113 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.collection.map; + +import net.spy.memcached.collection.BaseIntegrationTest; +import net.spy.memcached.collection.CollectionAttributes; + +import java.util.concurrent.TimeUnit; + +public class MopInsertWhenKeyNotExist extends BaseIntegrationTest { + + private String key = "MopInsertWhenKeyNotExist"; + + private String[] items9 = { "value0", "value1", "value2", "value3", + "value4", "value5", "value6", "value7", "value8", }; + + protected void tearDown() { + try { + deleteMap(key); + super.tearDown(); + } catch (Exception e) { + } + } + + /** + *
+	 * CREATE	FIXED	VALUE
+	 * true	false	null
+	 * 
+ */ + public void testMopInsert_nokey_01() throws Exception { + insertToFail(key, true, null); + } + + /** + *
+	 * CREATE	FIXED	VALUE
+	 * false	true	not null
+	 * 
+ */ + public void testMopInsert_nokey_02() throws Exception { + assertFalse(insertToSucceed(key, false, items9[0])); + } + + /** + *
+	 * CREATE	FIXED	VALUE
+	 * false	false	not null
+	 * 
+ */ + public void testMopInsert_nokey_04() throws Exception { + assertFalse(insertToSucceed(key, false, items9[0])); + } + + /** + *
+	 * CREATE	FIXED	VALUE
+	 * true	true	not null
+	 * 
+ */ + public void testMopInsert_nokey_05() throws Exception { + assertTrue(insertToSucceed(key, true, items9[0])); + } + + boolean insertToFail(String key, boolean createKeyIfNotExists, Object value) { + boolean result = false; + try { + result = mc + .asyncMopInsert( + key, + "0", + value, + ((createKeyIfNotExists) ? new CollectionAttributes() + : null)).get(1000, TimeUnit.MILLISECONDS); + fail("should be failed"); + } catch (Exception e) { + } + return result; + } + + boolean insertToSucceed(String key, boolean createKeyIfNotExists, + Object value) { + boolean result = false; + try { + result = mc + .asyncMopInsert( + key, + "0", + value, + ((createKeyIfNotExists) ? new CollectionAttributes() + : null)).get(1000, TimeUnit.MILLISECONDS); + } catch (Exception e) { + e.printStackTrace(); + fail("should not be failed"); + } + return result; + } + +} \ No newline at end of file diff --git a/src/test/manual/net/spy/memcached/collection/map/MopOverflowActionTest.java b/src/test/manual/net/spy/memcached/collection/map/MopOverflowActionTest.java new file mode 100644 index 00000000..28b66fc6 --- /dev/null +++ b/src/test/manual/net/spy/memcached/collection/map/MopOverflowActionTest.java @@ -0,0 +1,341 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.collection.map; + +import junit.framework.Assert; +import net.spy.memcached.collection.BaseIntegrationTest; +import net.spy.memcached.collection.CollectionAttributes; +import net.spy.memcached.collection.CollectionOverflowAction; + +import java.util.ArrayList; +import java.util.Map; +import java.util.List; +import java.util.TreeMap; +import java.util.concurrent.TimeUnit; + +public class MopOverflowActionTest extends BaseIntegrationTest { + + private String key = "MopOverflowActionTest"; + private List keyList = new ArrayList(); + + protected void setUp() { + keyList.add(key); + try { + super.setUp(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void testMopGet_Maxcount() throws Exception { + // Test + for (int maxcount = 100; maxcount <= 200; maxcount += 100) { + // Create a map + mc.asyncMopInsert(key, "0", "item0", new CollectionAttributes()); + + // Set maxcount + CollectionAttributes attrs = new CollectionAttributes(); + attrs.setMaxCount(maxcount); + assertTrue(mc.asyncSetAttr(key, attrs).get(1000, + TimeUnit.MILLISECONDS)); + + for (int i = 1; i < maxcount; i++) { + assertTrue(mc.asyncMopInsert(key, String.valueOf(i), "item" + i, null).get( + 1000, TimeUnit.MILLISECONDS)); + } + + Map result = mc.asyncMopGet(key, false, + false).get(10000, TimeUnit.MILLISECONDS); + assertEquals(maxcount, result.size()); + assertTrue(mc.asyncMopDelete(key, true).get(1000, + TimeUnit.MILLISECONDS)); + } + } + + public void testMopGet_Overflow() throws Exception { + // Create a map + mc.asyncMopInsert(key, "0", "item0", new CollectionAttributes()); + + int maxcount = 100; + + // Set maxcount to 100 + CollectionAttributes attrs = new CollectionAttributes(); + attrs.setMaxCount(maxcount); + attrs.setOverflowAction(CollectionOverflowAction.error); + assertTrue(mc.asyncSetAttr(key, attrs).get(1000, TimeUnit.MILLISECONDS)); + + // Insert more than maxcount + for (int i = 1; i <= maxcount + 10; i++) { + mc.asyncMopInsert(key, String.valueOf(i), "item" + i, null).get(1000, + TimeUnit.MILLISECONDS); + + } + + Map result = mc.asyncMopGet(key, false, + false).get(10000, TimeUnit.MILLISECONDS); + + // result size should be maxsize(10000) + assertEquals(maxcount, result.size()); + assertEquals("item0", result.get("0")); + assertEquals("item99", result.get(String.valueOf(result.size() - 1))); + assertTrue(mc.asyncMopDelete(key, true).get(1000, + TimeUnit.MILLISECONDS)); + } + + public void testMopGet_AvailableOverflowAction() throws Exception { + // Create a set + mc.asyncMopInsert(key, "0", "item0", new CollectionAttributes()); + + // Set OverflowAction + // error + assertTrue(mc.asyncSetAttr(key, + new CollectionAttributes(null, null, CollectionOverflowAction.error)) + .get(1000, TimeUnit.MILLISECONDS)); + + // head_trim + assertFalse(mc.asyncSetAttr(key, + new CollectionAttributes(null, null, CollectionOverflowAction.head_trim)).get(1000, + TimeUnit.MILLISECONDS)); + + // tail_trim + assertFalse(mc.asyncSetAttr(key, + new CollectionAttributes(null, null, CollectionOverflowAction.tail_trim)).get(1000, + TimeUnit.MILLISECONDS)); + + // smallest_trim + assertFalse(mc.asyncSetAttr(key, + new CollectionAttributes(null, null, CollectionOverflowAction.smallest_trim)).get(1000, + TimeUnit.MILLISECONDS)); + + // largest_trim + assertFalse(mc.asyncSetAttr(key, + new CollectionAttributes(null, null, CollectionOverflowAction.largest_trim)).get(1000, + TimeUnit.MILLISECONDS)); + + mc.asyncMopDelete(key, true).get(1000, TimeUnit.MILLISECONDS); + } + + public void testMopGet_notAvailableOverflowAction() { + CollectionAttributes attributesForCreate = new CollectionAttributes(); + Map elem = new TreeMap(); + elem.put("0", "item0"); + + // insert + try { + attributesForCreate.setOverflowAction(CollectionOverflowAction.head_trim); + mc.asyncMopInsert(key, "0", "item0", attributesForCreate).get(); + Assert.fail(); + } catch (IllegalArgumentException e) { + // test success + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + + // pipe insert + try { + mc.asyncMopPipedInsertBulk(key, elem, attributesForCreate).get(); + Assert.fail(); + } catch (IllegalArgumentException e) { + // test success + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + + // bulk insert + try { + mc.asyncMopInsertBulk(keyList, "0", "item0", attributesForCreate).get(); + Assert.fail(); + } catch (IllegalArgumentException e) { + // test success + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + + // insert + try { + attributesForCreate.setOverflowAction(CollectionOverflowAction.tail_trim); + mc.asyncMopInsert(key, "0", "item0", attributesForCreate).get(); + Assert.fail(); + } catch (IllegalArgumentException e) { + // test success + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + + // pipe insert + try { + mc.asyncMopPipedInsertBulk(key, elem, attributesForCreate).get(); + Assert.fail(); + } catch (IllegalArgumentException e) { + // test success + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + + // bulk insert + try { + mc.asyncMopInsertBulk(keyList, "0", "item0", attributesForCreate).get(); + Assert.fail(); + } catch (IllegalArgumentException e) { + // test success + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + + // insert + try { + attributesForCreate.setOverflowAction(CollectionOverflowAction.smallest_trim); + mc.asyncMopInsert(key, "0", "item0", attributesForCreate).get(); + Assert.fail(); + } catch (IllegalArgumentException e) { + // test success + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + + // pipe insert + try { + mc.asyncMopPipedInsertBulk(key, elem, attributesForCreate).get(); + Assert.fail(); + } catch (IllegalArgumentException e) { + // test success + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + + // bulk insert + try { + mc.asyncMopInsertBulk(keyList, "0", "item0", attributesForCreate).get(); + Assert.fail(); + } catch (IllegalArgumentException e) { + // test success + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + + // insert + try { + attributesForCreate.setOverflowAction(CollectionOverflowAction.smallest_silent_trim); + mc.asyncMopInsert(key, "0", "item0", attributesForCreate).get(); + Assert.fail(); + } catch (IllegalArgumentException e) { + // test success + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + + // pipe insert + try { + mc.asyncMopPipedInsertBulk(key, elem, attributesForCreate).get(); + Assert.fail(); + } catch (IllegalArgumentException e) { + // test success + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + + // bulk insert + try { + mc.asyncMopInsertBulk(keyList, "0", "item0", attributesForCreate).get(); + Assert.fail(); + } catch (IllegalArgumentException e) { + // test success + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + + // insert + try { + attributesForCreate.setOverflowAction(CollectionOverflowAction.largest_trim); + mc.asyncMopInsert(key, "0", "item0", attributesForCreate).get(); + Assert.fail(); + } catch (IllegalArgumentException e) { + // test success + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + + // pipe insert + try { + mc.asyncMopPipedInsertBulk(key, elem, attributesForCreate).get(); + Assert.fail(); + } catch (IllegalArgumentException e) { + // test success + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + + // bulk insert + try { + mc.asyncMopInsertBulk(keyList, "0", "item0", attributesForCreate).get(); + Assert.fail(); + } catch (IllegalArgumentException e) { + // test success + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + + // insert + try { + attributesForCreate.setOverflowAction(CollectionOverflowAction.largest_silent_trim); + mc.asyncMopInsert(key, "0", "item0", attributesForCreate).get(); + Assert.fail(); + } catch (IllegalArgumentException e) { + // test success + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + + // pipe insert + try { + mc.asyncMopPipedInsertBulk(key, elem, attributesForCreate).get(); + Assert.fail(); + } catch (IllegalArgumentException e) { + // test success + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + + // bulk insert + try { + mc.asyncMopInsertBulk(keyList, "0", "item0", attributesForCreate).get(); + Assert.fail(); + } catch (IllegalArgumentException e) { + // test success + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + } +} diff --git a/src/test/manual/net/spy/memcached/collection/map/MopServerMessageTest.java b/src/test/manual/net/spy/memcached/collection/map/MopServerMessageTest.java new file mode 100644 index 00000000..eeed522a --- /dev/null +++ b/src/test/manual/net/spy/memcached/collection/map/MopServerMessageTest.java @@ -0,0 +1,172 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.collection.map; + +import net.spy.memcached.collection.BaseIntegrationTest; +import net.spy.memcached.collection.CollectionAttributes; +import net.spy.memcached.collection.CollectionOverflowAction; +import net.spy.memcached.internal.CollectionFuture; +import net.spy.memcached.ops.OperationStatus; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class MopServerMessageTest extends BaseIntegrationTest { + + private String key = "MopServerMessageTest"; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mc.delete(key).get(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + public void testNotFound() throws Exception { + CollectionFuture> future = (CollectionFuture>) mc + .asyncMopGet(key, false, false); + assertNull(future.get(1000, TimeUnit.MILLISECONDS)); + + OperationStatus status = future.getOperationStatus(); + assertNotNull(status); + assertEquals("NOT_FOUND", status.getMessage()); + } + + public void testCreatedStored() throws Exception { + CollectionFuture future = (CollectionFuture) mc + .asyncMopInsert(key, "0", 0, new CollectionAttributes()); + assertTrue(future.get(1000, TimeUnit.MILLISECONDS)); + + OperationStatus status = future.getOperationStatus(); + assertNotNull(status); + assertEquals("CREATED_STORED", status.getMessage()); + } + + public void testStored() throws Exception { + CollectionFuture future = (CollectionFuture) mc + .asyncMopInsert(key, "0", 0, new CollectionAttributes()); + assertTrue(future.get(1000, TimeUnit.MILLISECONDS)); + + future = (CollectionFuture) mc.asyncMopInsert(key, "1", 1, + new CollectionAttributes()); + assertTrue(future.get(1000, TimeUnit.MILLISECONDS)); + + OperationStatus status = future.getOperationStatus(); + assertNotNull(status); + assertEquals("STORED", status.getMessage()); + } + + public void testOverflowed() throws Exception { + CollectionFuture future = (CollectionFuture) mc + .asyncMopInsert(key, "0", 0, new CollectionAttributes()); + assertTrue(future.get(1000, TimeUnit.MILLISECONDS)); + + assertTrue(mc.asyncSetAttr(key, + new CollectionAttributes(null, 2L, CollectionOverflowAction.error)) + .get(1000, TimeUnit.MILLISECONDS)); + + future = (CollectionFuture) mc.asyncMopInsert(key, "1", 1, + new CollectionAttributes()); + assertTrue(future.get(1000, TimeUnit.MILLISECONDS)); + + future = (CollectionFuture) mc.asyncMopInsert(key, "2", 1, + new CollectionAttributes()); + assertFalse(future.get(1000, TimeUnit.MILLISECONDS)); + + OperationStatus status = future.getOperationStatus(); + assertNotNull(status); + assertEquals("OVERFLOWED", status.getMessage()); + } + + public void testDeletedDropped() throws Exception { + // create + CollectionFuture future = (CollectionFuture) mc + .asyncMopInsert(key, "0", "aaa", new CollectionAttributes()); + assertTrue(future.get(1000, TimeUnit.MILLISECONDS)); + + // delete + future = (CollectionFuture) mc.asyncMopDelete(key, true); + assertTrue(future.get(1000, TimeUnit.MILLISECONDS)); + + OperationStatus status = future.getOperationStatus(); + assertNotNull(status); + assertEquals("DELETED_DROPPED", status.getMessage()); + } + + public void testDeleted() throws Exception { + // create + CollectionFuture future = (CollectionFuture) mc + .asyncMopInsert(key, "0", "aaa", new CollectionAttributes()); + assertTrue(future.get(1000, TimeUnit.MILLISECONDS)); + + // insert + future = (CollectionFuture) mc.asyncMopInsert(key, "1", "bbb", + new CollectionAttributes()); + assertTrue(future.get(1000, TimeUnit.MILLISECONDS)); + + // delete + future = (CollectionFuture) mc.asyncMopDelete(key, "0", false); + assertTrue(future.get(1000, TimeUnit.MILLISECONDS)); + + OperationStatus status = future.getOperationStatus(); + assertNotNull(status); + assertEquals("DELETED", status.getMessage()); + } + + public void testDeletedDroppedAfterRetrieval() throws Exception { + // create + CollectionFuture future = (CollectionFuture) mc + .asyncMopInsert(key, "0", "aaa", new CollectionAttributes()); + assertTrue(future.get(1000, TimeUnit.MILLISECONDS)); + + // get + CollectionFuture> future2 = (CollectionFuture>) mc + .asyncMopGet(key, true, true); + assertNotNull(future2.get(1000, TimeUnit.MILLISECONDS)); + + OperationStatus status = future2.getOperationStatus(); + assertNotNull(status); + assertEquals("DELETED_DROPPED", status.getMessage()); + } + + public void testDeletedAfterRetrieval() throws Exception { + // create + CollectionFuture future = (CollectionFuture) mc + .asyncMopInsert(key, "0", "aaa", new CollectionAttributes()); + assertTrue(future.get(1000, TimeUnit.MILLISECONDS)); + + // insert + future = (CollectionFuture) mc.asyncMopInsert(key, "1", "bbb", + new CollectionAttributes()); + assertTrue(future.get(1000, TimeUnit.MILLISECONDS)); + + // get + CollectionFuture> future2 = (CollectionFuture>) mc + .asyncMopGet(key, true, false); + assertNotNull(future2.get(1000, TimeUnit.MILLISECONDS)); + + OperationStatus status = future2.getOperationStatus(); + assertNotNull(status); + assertEquals("DELETED", status.getMessage()); + } +} diff --git a/src/test/manual/net/spy/memcached/collection/map/MopUpdateTest.java b/src/test/manual/net/spy/memcached/collection/map/MopUpdateTest.java new file mode 100644 index 00000000..b6cfdce8 --- /dev/null +++ b/src/test/manual/net/spy/memcached/collection/map/MopUpdateTest.java @@ -0,0 +1,79 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.collection.map; + +import junit.framework.Assert; +import net.spy.memcached.collection.BaseIntegrationTest; +import net.spy.memcached.collection.CollectionAttributes; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class MopUpdateTest extends BaseIntegrationTest { + + private final String KEY = this.getClass().getSimpleName(); + + private final String mkey = "updateTestMkey"; + + private final String VALUE = "VALUE"; + private final String NEW_VALUE = "NEWVALUE"; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mc.delete(KEY).get(); + Assert.assertNull(mc.asyncGetAttr(KEY).get()); + } + + @Override + protected void tearDown() throws Exception { + mc.delete(KEY).get(); + super.tearDown(); + } + + public void testUpdateNotExistsKey() { + try { + // update value + Assert.assertFalse(mc.asyncMopUpdate(KEY, mkey, VALUE).get()); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } + + public void testExistsKey() { + try { + // insert one + Assert.assertTrue(mc.asyncMopInsert(KEY, mkey, VALUE, + new CollectionAttributes()).get()); + + // update value only + Map rmap = mc.asyncMopGet(KEY, false, false) + .get(1000, TimeUnit.MILLISECONDS); + + Assert.assertEquals(VALUE, rmap.get(mkey)); + + Assert.assertTrue(mc.asyncMopUpdate(KEY, mkey, NEW_VALUE).get()); + + Map urmap = mc.asyncMopGet(KEY, false, false) + .get(1000, TimeUnit.MILLISECONDS); + Assert.assertEquals(NEW_VALUE, urmap.get(mkey)); + } catch (Exception e) { + Assert.fail(e.getMessage()); + } + } +} diff --git a/src/test/manual/net/spy/memcached/emptycollection/CreateEmptyMapTest.java b/src/test/manual/net/spy/memcached/emptycollection/CreateEmptyMapTest.java new file mode 100644 index 00000000..0de79894 --- /dev/null +++ b/src/test/manual/net/spy/memcached/emptycollection/CreateEmptyMapTest.java @@ -0,0 +1,87 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.emptycollection; + +import junit.framework.Assert; +import net.spy.memcached.collection.BaseIntegrationTest; +import net.spy.memcached.collection.CollectionAttributes; +import net.spy.memcached.collection.ElementValueType; +import net.spy.memcached.collection.CollectionOverflowAction; + +public class CreateEmptyMapTest extends BaseIntegrationTest { + + private final String KEY = this.getClass().getSimpleName(); + + @Override + protected void setUp() throws Exception { + super.setUp(); + mc.delete(KEY).get(); + Assert.assertNull(mc.asyncGetAttr(KEY).get()); + } + + @Override + protected void tearDown() throws Exception { + mc.delete(KEY).get(); + super.tearDown(); + } + + public void testCreateEmptyWithDefaultAttribute() { + try { + // create empty + CollectionAttributes attribute = new CollectionAttributes(); + Boolean insertResult = mc.asyncMopCreate(KEY, + ElementValueType.OTHERS, attribute).get(); + Assert.assertTrue(insertResult); + + // check attribute + CollectionAttributes attr = mc.asyncGetAttr(KEY).get(); + + Assert.assertEquals(new Long(0), attr.getCount()); + Assert.assertEquals(new Long(4000), attr.getMaxCount()); + Assert.assertEquals(new Integer(0), attr.getExpireTime()); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } + + public void testCreateEmptyWithSpecifiedAttribute() { + try { + // create empty + CollectionAttributes attribute = new CollectionAttributes(); + attribute.setMaxCount(10000); + attribute.setExpireTime(9999); + attribute.setOverflowAction(CollectionOverflowAction.error); + Boolean insertResult = mc.asyncMopCreate(KEY, + ElementValueType.OTHERS, attribute).get(); + + Assert.assertTrue(insertResult); + + // check attribute + CollectionAttributes attr = mc.asyncGetAttr(KEY).get(); + + Assert.assertEquals(new Long(0), attr.getCount()); + Assert.assertEquals(new Long(10000), attr.getMaxCount()); + Assert.assertEquals(CollectionOverflowAction.error, + attr.getOverflowAction()); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } + +} diff --git a/src/test/manual/net/spy/memcached/emptycollection/GetWithDropMapTest.java b/src/test/manual/net/spy/memcached/emptycollection/GetWithDropMapTest.java new file mode 100644 index 00000000..8ac8bdf0 --- /dev/null +++ b/src/test/manual/net/spy/memcached/emptycollection/GetWithDropMapTest.java @@ -0,0 +1,113 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.emptycollection; + +import java.util.Map; + +import junit.framework.Assert; +import net.spy.memcached.collection.BaseIntegrationTest; +import net.spy.memcached.collection.CollectionAttributes; + +public class GetWithDropMapTest extends BaseIntegrationTest { + + private final String KEY = this.getClass().getSimpleName(); + private final String MKEY = "mkey"; + private final int VALUE = 1234567890; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mc.delete(KEY).get(); + + boolean insertResult = mc.asyncMopInsert(KEY, MKEY, VALUE, + new CollectionAttributes()).get(); + Assert.assertTrue(insertResult); + } + + public void testGetWithoutDeleteAndDrop() { + try { + // check attr + Assert.assertEquals(new Long(1), mc.asyncGetAttr(KEY).get() + .getCount()); + + // get value delete=false, drop=false + Assert.assertEquals( + VALUE, + mc.asyncMopGet(KEY, MKEY, false, false).get().get(MKEY)); + + // check exists + Assert.assertEquals(new Long(1), mc.asyncGetAttr(KEY).get() + .getCount()); + + // get value again + Assert.assertEquals( + VALUE, + mc.asyncMopGet(KEY, MKEY, false, false).get().get(MKEY)); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } + + public void testGetWithtDeleteAndWithoutDrop() { + try { + // check attr + Assert.assertEquals(new Long(1), mc.asyncGetAttr(KEY).get() + .getCount()); + + // get value delete=true, drop=false + Assert.assertEquals( + VALUE, + mc.asyncMopGet(KEY, MKEY, true, false).get().get(MKEY)); + + // check exists empty map + CollectionAttributes attr = mc.asyncGetAttr(KEY).get(); + Assert.assertNotNull(attr); + Assert.assertEquals(new Long(0), attr.getCount()); + + Map map = mc.asyncMopGet(KEY, MKEY, false, false).get(); + Assert.assertNotNull(map); + Assert.assertTrue(map.isEmpty()); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } + + public void testGetWithtDeleteAndWithDrop() { + try { + // check attr + Assert.assertEquals(new Long(1), mc.asyncGetAttr(KEY).get() + .getCount()); + + // get value delete=true, drop=true + Assert.assertEquals( + VALUE, + mc.asyncMopGet(KEY, MKEY, true, true).get().get(MKEY)); + + // check map + CollectionAttributes attr = mc.asyncGetAttr(KEY).get(); + Assert.assertNull(attr); + + Map map = mc.asyncMopGet(KEY, MKEY, false, false).get(); + Assert.assertNull(map); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } +} diff --git a/src/test/manual/net/spy/memcached/emptycollection/InsertMapWithAttrTest.java b/src/test/manual/net/spy/memcached/emptycollection/InsertMapWithAttrTest.java new file mode 100644 index 00000000..d2fd1620 --- /dev/null +++ b/src/test/manual/net/spy/memcached/emptycollection/InsertMapWithAttrTest.java @@ -0,0 +1,96 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.emptycollection; + +import java.util.Map; + +import junit.framework.Assert; +import net.spy.memcached.collection.BaseIntegrationTest; +import net.spy.memcached.collection.CollectionAttributes; + +public class InsertMapWithAttrTest extends BaseIntegrationTest { + + private final String KEY = this.getClass().getSimpleName(); + private final String MKEY = "mkey"; + private final int EXPIRE_TIME_IN_SEC = 1; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mc.delete(KEY).get(); + Assert.assertNull(mc.asyncGetAttr(KEY).get()); + } + + @Override + protected void tearDown() throws Exception { + mc.delete(KEY).get(); + super.tearDown(); + } + + public void testInsertWithAttribute() { + try { + // check not exists + Assert.assertNull(mc.asyncGetAttr(KEY).get()); + + // insert with create option + CollectionAttributes attr = new CollectionAttributes(); + attr.setExpireTime(EXPIRE_TIME_IN_SEC); + attr.setMaxCount(3333); + + Boolean insertResult = mc.asyncMopInsert(KEY, MKEY, "value", attr) + .get(); + Assert.assertTrue(insertResult); + + // check attribute + CollectionAttributes collectionAttributes = mc.asyncGetAttr(KEY) + .get(); + Assert.assertEquals(new Long(3333), + collectionAttributes.getMaxCount()); + + // check expire time + Thread.sleep(EXPIRE_TIME_IN_SEC * 1000L); + Map map = mc.asyncMopGet(KEY, MKEY, false, false).get(); + Assert.assertNull(map); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } + + public void testInsertWithDefaultAttribute() { + try { + // check not exists + Assert.assertNull(mc.asyncGetAttr(KEY).get()); + + // insert with create option + CollectionAttributes attr = new CollectionAttributes(); + + Boolean insertResult = mc.asyncMopInsert(KEY, MKEY, "value", attr) + .get(); + Assert.assertTrue(insertResult); + + // check attribute + CollectionAttributes collectionAttributes = mc.asyncGetAttr(KEY) + .get(); + Assert.assertEquals(new Long(4000), + collectionAttributes.getMaxCount()); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } +} diff --git a/src/test/manual/net/spy/memcached/emptycollection/PipedBulkInsertMapWithAttrTest.java b/src/test/manual/net/spy/memcached/emptycollection/PipedBulkInsertMapWithAttrTest.java new file mode 100644 index 00000000..5fb6fe56 --- /dev/null +++ b/src/test/manual/net/spy/memcached/emptycollection/PipedBulkInsertMapWithAttrTest.java @@ -0,0 +1,152 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.emptycollection; + +import java.util.HashMap; +import java.util.Map; + +import junit.framework.Assert; +import net.spy.memcached.collection.BaseIntegrationTest; +import net.spy.memcached.collection.CollectionAttributes; +import net.spy.memcached.ops.CollectionOperationStatus; + +public class PipedBulkInsertMapWithAttrTest extends BaseIntegrationTest { + + private final String KEY = this.getClass().getSimpleName(); + private final String MKEY = "10"; + private final int EXPIRE_TIME_IN_SEC = 1; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mc.delete(KEY).get(); + Assert.assertNull(mc.asyncGetAttr(KEY).get()); + } + + @Override + protected void tearDown() throws Exception { + mc.delete(KEY).get(); + super.tearDown(); + } + + public void testInsertWithAttribute() { + try { + // check not exists + Assert.assertNull(mc.asyncGetAttr(KEY).get()); + + // insert with create option + CollectionAttributes attr = new CollectionAttributes(); + attr.setExpireTime(EXPIRE_TIME_IN_SEC); + attr.setMaxCount(3333); + + Map elements = new HashMap(); + for (long i = 1; i < 11; i++) + elements.put(String.valueOf(i), 1); + Map insertResult = mc + .asyncMopPipedInsertBulk(KEY, elements, attr).get(); + Assert.assertTrue(insertResult.isEmpty()); + + // check attribute + CollectionAttributes collectionAttributes = mc.asyncGetAttr(KEY) + .get(); + Assert.assertEquals(new Long(3333), + collectionAttributes.getMaxCount()); + + // check expire time + Thread.sleep(EXPIRE_TIME_IN_SEC * 1000L); + Map map = mc.asyncMopGet(KEY, MKEY, + false, false).get(); + Assert.assertNull(map); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } + + public void testInsertWithDefaultAttribute() { + try { + // check not exists + Assert.assertNull(mc.asyncGetAttr(KEY).get()); + + // insert with create option + CollectionAttributes attr = new CollectionAttributes(); + + Map elements = new HashMap(); + for (long i = 1; i < 11; i++) + elements.put(String.valueOf(i), 1); + Map insertResult = mc + .asyncMopPipedInsertBulk(KEY, elements, attr).get(); + Assert.assertTrue(insertResult.isEmpty()); + + // check attribute + CollectionAttributes collectionAttributes = mc.asyncGetAttr(KEY) + .get(); + Assert.assertEquals(new Long(4000), + collectionAttributes.getMaxCount()); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } + + public void testInsertWithoutAttributeCreate() { + try { + // check not exists + Assert.assertNull(mc.asyncGetAttr(KEY).get()); + + Map elements = new HashMap(); + for (long i = 1; i < 11; i++) + elements.put(String.valueOf(i), 1); + Map insertResult = mc + .asyncMopPipedInsertBulk(KEY, elements, + new CollectionAttributes()).get(); + Assert.assertTrue(insertResult.isEmpty()); + + // check attribute + CollectionAttributes collectionAttributes = mc.asyncGetAttr(KEY) + .get(); + Assert.assertEquals(new Long(4000), + collectionAttributes.getMaxCount()); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } + + public void testInsertWithoutAttributeDoNotCreate() { + try { + // check not exists + Assert.assertNull(mc.asyncGetAttr(KEY).get()); + + Map elements = new HashMap(); + for (long i = 1; i < 11; i++) + elements.put(String.valueOf(i), 1); + Map insertResult = mc + .asyncMopPipedInsertBulk(KEY, elements, null).get(); + Assert.assertEquals(10, insertResult.size()); + + // check attribute + CollectionAttributes collectionAttributes = mc.asyncGetAttr(KEY) + .get(); + assertNull(collectionAttributes); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } + +} diff --git a/src/test/manual/net/spy/memcached/emptycollection/ProtocolMapDeleteTest.java b/src/test/manual/net/spy/memcached/emptycollection/ProtocolMapDeleteTest.java new file mode 100644 index 00000000..eb5bdc56 --- /dev/null +++ b/src/test/manual/net/spy/memcached/emptycollection/ProtocolMapDeleteTest.java @@ -0,0 +1,63 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.emptycollection; + +import junit.framework.Assert; +import junit.framework.TestCase; +import net.spy.memcached.collection.MapDelete; + +import java.util.List; +import java.util.ArrayList; + +public class ProtocolMapDeleteTest extends TestCase { + + public void testStringfy() { + List mkeyList = new ArrayList(); + mkeyList.add("mkey"); + + List mkeyList2 = new ArrayList(); + mkeyList2.add("mkey1"); + mkeyList2.add("mkey2"); + // default setting : dropIfEmpty = true + + Assert.assertEquals("4 1 drop", + (new MapDelete(mkeyList, false)).stringify()); + + Assert.assertEquals("4 1", + (new MapDelete(mkeyList, false, false)).stringify()); + Assert.assertEquals("4 1 drop", + (new MapDelete(mkeyList, false, true)).stringify()); + + Assert.assertEquals("11 2", (new MapDelete(mkeyList2, false, + false)).stringify()); + Assert.assertEquals("11 2 drop", (new MapDelete(mkeyList2, + false, true)).stringify()); + + Assert.assertEquals("4 1 drop noreply", + (new MapDelete(mkeyList, true)).stringify()); + + Assert.assertEquals("4 1 noreply", (new MapDelete(mkeyList, true, + false)).stringify()); + Assert.assertEquals("4 1 drop noreply", (new MapDelete(mkeyList, + true, true)).stringify()); + + Assert.assertEquals("11 2 noreply", (new MapDelete(mkeyList2, + true, false)).stringify()); + Assert.assertEquals("11 2 drop noreply", (new MapDelete(mkeyList2, + true, true)).stringify()); + } +} \ No newline at end of file diff --git a/src/test/manual/net/spy/memcached/emptycollection/ProtocolMapGetTest.java b/src/test/manual/net/spy/memcached/emptycollection/ProtocolMapGetTest.java new file mode 100644 index 00000000..5ac02cc1 --- /dev/null +++ b/src/test/manual/net/spy/memcached/emptycollection/ProtocolMapGetTest.java @@ -0,0 +1,48 @@ +/* + * arcus-java-client : Arcus Java client + * Copyright 2016 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.spy.memcached.emptycollection; + +import junit.framework.Assert; +import junit.framework.TestCase; +import net.spy.memcached.collection.MapGet; + +import java.util.ArrayList; +import java.util.List; + +public class ProtocolMapGetTest extends TestCase { + + private final String MKEY = "mkey"; + + public void testStringfy() { + // default setting : dropIfEmpty = true + + List mkeyList = new ArrayList(); + mkeyList.add(MKEY); + Assert.assertEquals("4 1 drop", + (new MapGet(mkeyList, true)).stringify()); + Assert.assertEquals("4 1", + (new MapGet(mkeyList, false)).stringify()); + Assert.assertEquals("4 1 drop", + (new MapGet(mkeyList, true, true)).stringify()); + Assert.assertEquals("4 1 delete", + (new MapGet(mkeyList, true, false)).stringify()); + Assert.assertEquals("4 1", + (new MapGet(mkeyList, false, true)).stringify()); + Assert.assertEquals("4 1", + (new MapGet(mkeyList, false, false)).stringify()); + } +}