From acecdd12b9a689d15cd77926e827194cea61f4f7 Mon Sep 17 00:00:00 2001 From: MinWooJin Date: Thu, 25 Feb 2016 17:37:30 +0900 Subject: [PATCH 1/3] MAP_COLLECTION --- docs/01-arcus-cloud-basics.md | 1 + docs/07-map-API.md | 469 ++++++++++++++++++ ...7-attribute-API.md => 08-attribute-API.md} | 0 docs/{08-other-API.md => 09-other-API.md} | 0 docs/{09-log-message.md => 10-log-message.md} | 0 ...{10-client-notes.md => 11-client-notes.md} | 0 docs/arcus-java-client-user-guide.md | 22 +- install-arcus-memcached.sh | 8 + .../java/net/spy/memcached/ArcusClient.java | 413 ++++++++++++++- .../java/net/spy/memcached/ArcusClientIF.java | 315 +++++++++++- .../net/spy/memcached/ArcusClientPool.java | 142 ++++++ .../collection/CollectionBulkStore.java | 82 +++ .../collection/CollectionCreate.java | 5 + .../collection/CollectionPipedStore.java | 163 +++++- .../collection/CollectionPipedUpdate.java | 78 +++ .../memcached/collection/CollectionStore.java | 3 + .../memcached/collection/CollectionType.java | 4 + .../collection/CollectionUpdate.java | 10 + .../spy/memcached/collection/MapCreate.java | 34 ++ .../spy/memcached/collection/MapDelete.java | 89 ++++ .../spy/memcached/collection/MapElement.java | 71 +++ .../net/spy/memcached/collection/MapGet.java | 99 ++++ .../spy/memcached/collection/MapStore.java | 31 ++ .../spy/memcached/collection/MapUpdate.java | 31 ++ .../java/net/spy/memcached/ops/APIType.java | 9 +- .../CollectionBulkStoreOperationImpl.java | 2 + .../ascii/CollectionCreateOperationImpl.java | 3 + .../ascii/CollectionDeleteOperationImpl.java | 3 + .../ascii/CollectionGetOperationImpl.java | 3 + .../CollectionPipedStoreOperationImpl.java | 2 + .../CollectionPipedUpdateOperationImpl.java | 3 + .../ascii/CollectionStoreOperationImpl.java | 3 + .../ascii/CollectionUpdateOperationImpl.java | 3 + .../MopInsertBulkMultipleTest.java | 246 +++++++++ .../bulkoperation/MopInsertBulkTest.java | 145 ++++++ .../bulkoperation/PipeInsertTest.java | 34 ++ .../collection/BaseIntegrationTest.java | 12 + .../attribute/UnReadableMapTest.java | 127 +++++ .../collection/map/MopBulkAPITest.java | 158 ++++++ .../collection/map/MopDeleteTest.java | 87 ++++ .../memcached/collection/map/MopGetTest.java | 118 +++++ .../map/MopInsertWhenKeyExists.java | 88 ++++ .../map/MopInsertWhenKeyNotExist.java | 113 +++++ .../collection/map/MopOverflowActionTest.java | 341 +++++++++++++ .../collection/map/MopServerMessageTest.java | 172 +++++++ .../collection/map/MopUpdateTest.java | 79 +++ .../emptycollection/CreateEmptyMapTest.java | 87 ++++ .../emptycollection/GetWithDropMapTest.java | 113 +++++ .../InsertMapWithAttrTest.java | 96 ++++ .../PipedBulkInsertMapWithAttrTest.java | 152 ++++++ .../ProtocolMapDeleteTest.java | 63 +++ .../emptycollection/ProtocolMapGetTest.java | 48 ++ 52 files changed, 4367 insertions(+), 13 deletions(-) create mode 100644 docs/07-map-API.md rename docs/{07-attribute-API.md => 08-attribute-API.md} (100%) rename docs/{08-other-API.md => 09-other-API.md} (100%) rename docs/{09-log-message.md => 10-log-message.md} (100%) rename docs/{10-client-notes.md => 11-client-notes.md} (100%) create mode 100644 src/main/java/net/spy/memcached/collection/MapCreate.java create mode 100644 src/main/java/net/spy/memcached/collection/MapDelete.java create mode 100644 src/main/java/net/spy/memcached/collection/MapElement.java create mode 100644 src/main/java/net/spy/memcached/collection/MapGet.java create mode 100644 src/main/java/net/spy/memcached/collection/MapStore.java create mode 100644 src/main/java/net/spy/memcached/collection/MapUpdate.java create mode 100644 src/test/manual/net/spy/memcached/bulkoperation/MopInsertBulkMultipleTest.java create mode 100644 src/test/manual/net/spy/memcached/bulkoperation/MopInsertBulkTest.java create mode 100644 src/test/manual/net/spy/memcached/collection/attribute/UnReadableMapTest.java create mode 100644 src/test/manual/net/spy/memcached/collection/map/MopBulkAPITest.java create mode 100644 src/test/manual/net/spy/memcached/collection/map/MopDeleteTest.java create mode 100644 src/test/manual/net/spy/memcached/collection/map/MopGetTest.java create mode 100644 src/test/manual/net/spy/memcached/collection/map/MopInsertWhenKeyExists.java create mode 100644 src/test/manual/net/spy/memcached/collection/map/MopInsertWhenKeyNotExist.java create mode 100644 src/test/manual/net/spy/memcached/collection/map/MopOverflowActionTest.java create mode 100644 src/test/manual/net/spy/memcached/collection/map/MopServerMessageTest.java create mode 100644 src/test/manual/net/spy/memcached/collection/map/MopUpdateTest.java create mode 100644 src/test/manual/net/spy/memcached/emptycollection/CreateEmptyMapTest.java create mode 100644 src/test/manual/net/spy/memcached/emptycollection/GetWithDropMapTest.java create mode 100644 src/test/manual/net/spy/memcached/emptycollection/InsertMapWithAttrTest.java create mode 100644 src/test/manual/net/spy/memcached/emptycollection/PipedBulkInsertMapWithAttrTest.java create mode 100644 src/test/manual/net/spy/memcached/emptycollection/ProtocolMapDeleteTest.java create mode 100644 src/test/manual/net/spy/memcached/emptycollection/ProtocolMapGetTest.java 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..f77063e8 --- /dev/null +++ b/docs/07-map-API.md @@ -0,0 +1,469 @@ +## 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 최대 길이는 key의 최대 길이와 같고, 하나의 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) +CollectionFuture> +asyncMopPipedInsertBulk(String key, List 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, List> mapElements) +``` +- key: 변경 대상 map의 key +- mapElements: 변경 대상 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 index 0b77707f..ddc54015 100644 --- a/install-arcus-memcached.sh +++ b/install-arcus-memcached.sh @@ -12,6 +12,14 @@ else echo "Using cached arcus installation" fi +# checkout develop in arcus-memcached +cd $HOME/arcus/server +git checkout develop +./config/autorun.sh +./configure --prefix=$HOME/arcus --enable-zk-integration --with-libevent=$HOME/arcus --with-zookeeper=$HOME/arcus +make +make install + rm -rf $HOME/arcus/zookeeper/data cp $CWD/mvnTestConf.json $HOME/arcus/scripts/conf/ cd $HOME/arcus/scripts && diff --git a/src/main/java/net/spy/memcached/ArcusClient.java b/src/main/java/net/spy/memcached/ArcusClient.java index 37d2a893..ba8ca26d 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,12 @@ 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.MapElement; import net.spy.memcached.collection.SetCreate; import net.spy.memcached.collection.SetDelete; import net.spy.memcached.collection.SetExist; @@ -730,7 +738,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 +1289,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 +1433,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 +1606,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 +1756,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 +1807,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 +1855,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 +1917,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 +2915,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 +3035,42 @@ public CollectionFuture> asyncBopPip } } + /* + * (non-Javadoc) + * + * @see net.spy.memcached.ArcusClientIF#asyncMopUpdate(java.lang.String, + * net.spy.memcached.collection.MapElement, net.spy.memcached.transcoders.Transcoder) + */ + @Override + public CollectionFuture> asyncMopPipedUpdateBulk( + String key, List> mapElements) { + return asyncMopPipedUpdateBulk(key, mapElements, collectionTranscoder); + } + + @Override + public CollectionFuture> asyncMopPipedUpdateBulk( + String key, List> mapElements, Transcoder tc) { + + if (mapElements.size() <= CollectionPipedUpdate.MAX_PIPED_ITEM_COUNT) { + CollectionPipedUpdate collectionPipedUpdate = new MapPipedUpdate( + key, mapElements, tc); + return asyncCollectionPipedUpdate(key, collectionPipedUpdate); + } else { + PartitionedList> list = new PartitionedList>( + mapElements, 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) @@ -3594,6 +3928,48 @@ public void gotStatus(Integer index, OperationStatus status) { return rv; } + /* + * (non-Javadoc) + * @see net.spy.memcached.ArcusClientIF#asyncMopPipedInsertBulk(java.lang.String, java.util.List, boolean, net.spy.memcached.collection.CollectionAttributes) + */ + @Override + public CollectionFuture> asyncMopPipedInsertBulk( + String key, List> mapElements, + CollectionAttributes attributesForCreate) { + return asyncMopPipedInsertBulk(key, mapElements, attributesForCreate, + collectionTranscoder); + } + + /* + * (non-Javadoc) + * @see net.spy.memcached.ArcusClientIF#asyncMopPipedInsertBulk(java.lang.String, java.util.List, boolean, net.spy.memcached.collection.CollectionAttributes, net.spy.memcached.transcoders.Transcoder) + */ + @Override + public CollectionFuture> asyncMopPipedInsertBulk( + String key, List> mapElements, + CollectionAttributes attributesForCreate, Transcoder tc) { + if (mapElements.size() <= CollectionPipedStore.MAX_PIPED_ITEM_COUNT) { + CollectionPipedStore store = new CollectionPipedStore.MapElementsPipedStore( + key, mapElements, (attributesForCreate != null), + attributesForCreate, tc); + return asyncCollectionPipedStore(key, store); + } else { + PartitionedList> list = new PartitionedList>( + mapElements, CollectionPipedStore.MAX_PIPED_ITEM_COUNT); + + List> storeList = new ArrayList>( + list.size()); + + for (int i = 0; i < list.size(); i++) { + storeList.add(new CollectionPipedStore.MapElementsPipedStore(key, + list.get(i), (attributesForCreate != null), + attributesForCreate, tc)); + } + + return asyncCollectionPipedStore(key, storeList); + } + } + /* * (non-Javadoc) * @see net.spy.memcached.ArcusClientIF#asyncBopPipedInsertBulk(java.lang.String, java.util.List, boolean, net.spy.memcached.collection.CollectionAttributes) @@ -3890,6 +4266,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 2b34d0c7..2bc6805d 100644 --- a/src/main/java/net/spy/memcached/ArcusClientIF.java +++ b/src/main/java/net/spy/memcached/ArcusClientIF.java @@ -33,6 +33,7 @@ import net.spy.memcached.collection.ElementValueType; import net.spy.memcached.collection.SMGetElement; import net.spy.memcached.collection.SMGetMode; +import net.spy.memcached.collection.MapElement; import net.spy.memcached.internal.BTreeStoreAndGetFuture; import net.spy.memcached.internal.CollectionFuture; import net.spy.memcached.internal.CollectionGetBulkFuture; @@ -199,7 +200,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 b+tree 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 b+tree 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 +380,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 +504,89 @@ public CollectionFuture>> asyncBopGet(String key, long from, long to, ElementFlagFilter eFlagFilter, int offset, int count, boolean withDelete, boolean dropIfEmpty, Transcoder tc); + /** + * Retrieves count all items of random in the map + * + * @param key key of a map + * @param withDelete true to remove the returned item in the map + * @param dropIfEmpty false to remove the key when all elements are removed. true 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 count all items in given mkey + * The returned map from the future should be sorted by the given range. + * + * @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 false to remove the key when all elements are removed. true 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 an item on given mkeyList in the map. + * + * @param key + * key of a map + * @param mkeyList + * mkeyList + * @param withDelete + * true to remove the returned item in the b+tree + * @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 a future that will hold the return value map of the fetch. + */ + public CollectionFuture> asyncMopGet(String key, + List mkeyList, boolean withDelete, boolean dropIfEmpty); + + /** + * Retrieves count all items of random in the map + * + * @param + * @param key key of a map + * @param withDelete true to remove the returned item in the b+tree + * @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 + * @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 count of all items in given mkey + * The returned map from the future should be sorted by the given range. + * + * @param + * @param key key of a map + * @param mkey mkey of a map + * @param withDelete true to remove the returned item in the b+tree + * @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 + * @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 an item on given mkeyList in the map + * + * @param + * @param key key of a map + * @param mkeyList mkeyList + * @param withDelete true to remove the returned item in the b+tree + * @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 + * @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 +719,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 +823,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 +886,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 +944,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 +998,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 +1196,38 @@ 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. + * do not update the value if this argument is null. + * @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. + * do not update the value if this argument is null. + * @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 +1254,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 mapElements + * list of map element + * @return a future indicating success + */ + public CollectionFuture> asyncMopPipedUpdateBulk( + String key, List> mapElements); + + /** + * Update elements from the map + * + * @param key + * key of a map + * @param mapElements + * list of map element + * @param tc + * a transcoder to encode the value of element + * @return a future indicating success + */ + public CollectionFuture> asyncMopPipedUpdateBulk( + String key, List> mapElements, Transcoder tc); + /** * Insert an item into the b+tree * @@ -1236,7 +1508,44 @@ public CollectionFuture> asyncSopPipedExistBulk( */ public CollectionFuture> asyncSopPipedExistBulk( String key, List values, Transcoder tc); - + + /** + * Insert elements into a map + * + * @param key + * a key list of map + * @param mapElements + * mapElement list which insert into map + * @param attributesForCreate + * create a b+tree with this attributes, if given key is not + * exists. + * @return a future that will hold the index of iteration sequence which + * failed elements and result code. + * + */ + public CollectionFuture> asyncMopPipedInsertBulk( + String key, List> mapElements, + CollectionAttributes attributesForCreate); + + /** + * Insert elements into a map + * + * @param key + * a key list of map + * @param mapElements + * MapElement list which insert into map + * @param attributesForCreate + * create a b+tree with this attributes, if given key is not exists. + * @param tc + * transcoder to decode value + * @return a future that will hold the index of iteration sequence which + * failed elements and result code. + * + */ + public CollectionFuture> asyncMopPipedInsertBulk( + String key, List> mapElements, + CollectionAttributes attributesForCreate, 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..6f9a202f 100644 --- a/src/main/java/net/spy/memcached/ArcusClientPool.java +++ b/src/main/java/net/spy/memcached/ArcusClientPool.java @@ -39,6 +39,7 @@ import net.spy.memcached.collection.ElementValueType; import net.spy.memcached.collection.SMGetElement; import net.spy.memcached.collection.SMGetMode; +import net.spy.memcached.collection.MapElement; import net.spy.memcached.internal.BTreeStoreAndGetFuture; import net.spy.memcached.internal.BulkFuture; import net.spy.memcached.internal.CollectionFuture; @@ -373,6 +374,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 +433,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 +483,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 +576,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 +626,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 +654,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 +684,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 +716,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 +879,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 +903,18 @@ public CollectionFuture> asyncBopPip return this.getClient().asyncBopPipedUpdateBulk(key, elements, tc); } + @Override + public CollectionFuture> asyncMopPipedUpdateBulk( + String key, List> mapElements) { + return this.getClient().asyncMopPipedUpdateBulk(key, mapElements); + } + + @Override + public CollectionFuture> asyncMopPipedUpdateBulk( + String key, List> mapElements, Transcoder tc) { + return this.getClient().asyncMopPipedUpdateBulk(key, mapElements, tc); + } + @Override public CollectionFuture> asyncSopPipedExistBulk( String key, List values) { @@ -801,6 +927,22 @@ public CollectionFuture> asyncSopPipedExistBulk( return this.getClient().asyncSopPipedExistBulk(key, values, tc); } + @Override + public CollectionFuture> asyncMopPipedInsertBulk( + String key, List> mapElements, + CollectionAttributes attributesForCreate) { + return this.getClient().asyncMopPipedInsertBulk(key, mapElements, + attributesForCreate); + } + + @Override + public CollectionFuture> asyncMopPipedInsertBulk( + String key, List> mapElements, + CollectionAttributes attributesForCreate, Transcoder tc) { + return this.getClient().asyncMopPipedInsertBulk(key, mapElements, + attributesForCreate, tc); + } + @Override public CollectionFuture> asyncBopPipedInsertBulk( String key, List> elements, 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..6dae78dc 100644 --- a/src/main/java/net/spy/memcached/collection/CollectionCreate.java +++ b/src/main/java/net/spy/memcached/collection/CollectionCreate.java @@ -16,6 +16,8 @@ */ package net.spy.memcached.collection; +import java.util.IllegalFormatCodePointException; + public abstract class CollectionCreate { protected int flags; protected int expTime; @@ -36,6 +38,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..e36b5d38 100644 --- a/src/main/java/net/spy/memcached/collection/CollectionPipedStore.java +++ b/src/main/java/net/spy/memcached/collection/CollectionPipedStore.java @@ -368,7 +368,168 @@ 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; + + // decode 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 keySize = map.keySet().size(); + List keyList = new ArrayList(map.keySet()); + for(i = this.nextOpIndex; i < keySize; 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 < keySize - 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 MapElementsPipedStore extends CollectionPipedStore { + + private static final String COMMAND = "mop insert"; + private List> mapElements; + + public MapElementsPipedStore(String key, List> mapElements, + 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.mapElements = mapElements; + this.createKeyIfNotExists = createKeyIfNotExists; + this.attribute = attr; + this.tc = tc; + this.itemCount = mapElements.size(); + } + + public ByteBuffer getAsciiCommand() { + int capacity = 0; + + // decode values + List encodedList = new ArrayList(mapElements.size()); + CachedData cd = null; + for (MapElement each : mapElements) { + cd = tc.encode(each.getValue()); + encodedList.add(cd.getData()); + } + + // estimate the buffer capacity + int i = 0; + for (MapElement eachMkey : mapElements) { + capacity += KeyUtil.getKeyBytes(key).length; + capacity += KeyUtil.getKeyBytes(eachMkey.getMkey()).length; + capacity += encodedList.get(i++).length; + capacity += 64; + } + + // allocate the buffer + ByteBuffer bb = ByteBuffer.allocate(capacity); + + // create ascii operation string + int fSize = mapElements.size(); + for(i = this.nextOpIndex; i < fSize; i++) { + MapElement mapMkey = mapElements.get(i); + byte[] value = encodedList.get(i); + + setArguments(bb, COMMAND, key, mapMkey.getMkey(), 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().toString() + : "" : "", + (createKeyIfNotExists) ? (attribute != null && attribute + .getReadable() != null && !attribute.getReadable()) ? + "unreadable" : "" : "", + (i < fSize - 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..e7494a00 100644 --- a/src/main/java/net/spy/memcached/collection/CollectionPipedUpdate.java +++ b/src/main/java/net/spy/memcached/collection/CollectionPipedUpdate.java @@ -141,6 +141,84 @@ public ByteBuffer getBinaryCommand() { } } + + public static class MapPipedUpdate extends CollectionPipedUpdate { + + private static final String COMMAND = "mop update"; + private List> mapElements; + + public MapPipedUpdate(String key, List> mapElements, + Transcoder tc) { + this.key = key; + this.mapElements = mapElements; + this.tc = tc; + this.itemCount = mapElements.size(); + } + + public ByteBuffer getAsciiCommand() { + int capacity = 0; + + // decode parameters + List encodedList = new ArrayList(mapElements.size()); + CachedData cd = null; + for (MapElement each : mapElements) { + if (each.getValue() != null) { + cd = tc.encode(each.getValue()); + encodedList.add(cd.getData()); + } else { + encodedList.add(null); + } + } + + // estimate the buffer capacity + int i = 0; + byte[] value; + StringBuilder b; + + for (MapElement each : mapElements) { + capacity += KeyUtil.getKeyBytes(key).length; + capacity += KeyUtil.getKeyBytes(each.getMkey()).length; + if (encodedList.get(i) != null) { + capacity += encodedList.get(i++).length; + } + capacity += 64; + } + + // allocate the buffer + ByteBuffer bb = ByteBuffer.allocate(capacity); + + // create ascii operation string + i = 0; + + Iterator> iterator = mapElements.iterator(); + while (iterator.hasNext()) { + MapElement mapElement = iterator.next(); + value = encodedList.get(i++); + b = new StringBuilder(); + + setArguments(bb, COMMAND, key, + String.valueOf(mapElement.getMkey()), + b.toString(), (value == null ? -1 : value.length), + (iterator.hasNext()) ? 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/CollectionUpdate.java b/src/main/java/net/spy/memcached/collection/CollectionUpdate.java index 89b3e888..403d1edb 100644 --- a/src/main/java/net/spy/memcached/collection/CollectionUpdate.java +++ b/src/main/java/net/spy/memcached/collection/CollectionUpdate.java @@ -42,6 +42,16 @@ public CollectionUpdate(T newValue, ElementFlagUpdate eflagUpdate, boolean norep this.noreply = noreply; } + public CollectionUpdate(T newValue, boolean noreply) { + if (newValue == null) { + throw new IllegalArgumentException( + "newValue must not be null."); + } + + this.newValue = newValue; + this.noreply = noreply; + } + public String stringify() { if (str != null) return str; 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..5475e562 --- /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/MapElement.java b/src/main/java/net/spy/memcached/collection/MapElement.java new file mode 100644 index 00000000..bd431be7 --- /dev/null +++ b/src/main/java/net/spy/memcached/collection/MapElement.java @@ -0,0 +1,71 @@ +/* + * 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; + +/** + * Collection MapElement + * + * @param + */ +public class MapElement { + private final String mkey; + private final T value; + + /** + * Create an element + * + * @param mkey mkey of mapElement + * @param value value of mapElement + */ + public MapElement(String mkey, T value) { + this.mkey = mkey; + this.value = value; + } + + /** + * get mkey in map op. + * + * @return mkey + */ + public String getMkey() { + return mkey; + } + + /** + * get value + * + * @return value + */ + public T getValue() { + return value; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("{ \""); + sb.append(getMkey()); + + sb.append("\" : { "); + + sb.append(" \"value\" : \"").append(value.toString()).append("\""); + sb.append(" }"); + + return sb.toString(); + } + +} 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..9e41643f --- /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, 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/manual/net/spy/memcached/bulkoperation/MopInsertBulkMultipleTest.java b/src/test/manual/net/spy/memcached/bulkoperation/MopInsertBulkMultipleTest.java new file mode 100644 index 00000000..7d760caf --- /dev/null +++ b/src/test/manual/net/spy/memcached/bulkoperation/MopInsertBulkMultipleTest.java @@ -0,0 +1,246 @@ +/* + * 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 mkeySize = 500; + Map mkeys = new TreeMap(); + for (int i = 0; i < mkeySize; i++) { + mkeys.put(String.valueOf(i), value); + } + + try { + // REMOVE + mc.asyncMopDelete(key, true); + + // SET + Future> future = mc + .asyncMopPipedInsertBulk(key, mkeys, + 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 : mkeys.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 : mkeys.entrySet()) { + mc.asyncMopDelete(key, entry.getKey(), true).get(); + } + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + } + + public void testTimeout() { + String key = "MyMopKey"; + String value = "MyValue"; + + int mkeySize = mc.getMaxPipedItemCount(); + Map mkeys = new TreeMap(); + for (int i = 0; i < mkeySize; i++) { + mkeys.put(String.valueOf(i), value); + } + + try { + // SET + Future> future = mc + .asyncMopPipedInsertBulk(key, mkeys, + new CollectionAttributes()); + try { + Map errorList = future.get( + 1L, TimeUnit.NANOSECONDS); + + Assert.assertTrue("Error list is not empty." + errorList, + errorList.isEmpty()); + } catch (TimeoutException e) { + future.cancel(true); + return; + } catch (Exception e) { + future.cancel(true); + Assert.fail(); + } + Assert.fail(); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + } + + public void testInsertAndGetUsingSingleClient() { + String key = "MyMopKey333"; + String value = "MyValue"; + + int mkeySize = 500; + Map mkeys = new TreeMap(); + for (int i = 0; i < mkeySize; i++) { + mkeys.put(String.valueOf(i), value); + } + + try { + // REMOVE + mc.asyncMopDelete(key, true); + + // SET + Future> future = mc + .asyncMopPipedInsertBulk(key, mkeys, + 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 : mkeys.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 : mkeys.entrySet()) { + mc.asyncMopDelete(key, entry.getKey(), true).get(); + } + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + } + + public void testTimeoutUsingSingleClient() { + String key = "MyMopKey"; + String value = "MyValue"; + + int mkeySize = mc.getMaxPipedItemCount(); + Map mkeys = new TreeMap(); + for (int i = 0; i < mkeySize; i++) { + mkeys.put(String.valueOf(i), value); + } + + try { + // SET + Future> future = mc + .asyncMopPipedInsertBulk(key, mkeys, + new CollectionAttributes()); + try { + Map errorList = future.get( + 1L, TimeUnit.NANOSECONDS); + + Assert.assertTrue("Error list is not empty." + errorList, + errorList.isEmpty()); + } catch (TimeoutException e) { + future.cancel(true); + return; + } catch (Exception e) { + future.cancel(true); + Assert.fail(); + } + Assert.fail(); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } + } + + public void testErrorCount() { + String key = "MyMopKeyErrorCount"; + String value = "MyValue"; + + int mkeySize = 1200; + Map mkeys = new TreeMap(); + for (int i = 0; i < mkeySize; i++) { + mkeys.put(String.valueOf(i), value); + } + + try { + mc.delete(key).get(); + + // SET + Future> future = mc + .asyncMopPipedInsertBulk(key, mkeys, null); + + Map map = future.get(2000L, + TimeUnit.MILLISECONDS); + assertEquals(mkeySize, 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..905567b0 --- /dev/null +++ b/src/test/manual/net/spy/memcached/bulkoperation/MopInsertBulkTest.java @@ -0,0 +1,145 @@ +/* + * 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 testTimeout() { + String value = "MyValue"; + int keySize = 250000; + + String[] keys = new String[keySize]; + for (int i = 0; i < keys.length; i++) { + keys[i] = "MyMopKey" + i; + } + + try { + // SET + Future> future = mc + .asyncMopInsertBulk(Arrays.asList(keys), MKEY, value, + new CollectionAttributes()); + try { + future.get(1L, TimeUnit.MILLISECONDS); + Assert.fail("There is no timeout"); + } catch (TimeoutException e) { + future.cancel(true); + return; + } catch (Exception e) { + future.cancel(true); + } + } 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..eee375cd 100644 --- a/src/test/manual/net/spy/memcached/bulkoperation/PipeInsertTest.java +++ b/src/test/manual/net/spy/memcached/bulkoperation/PipeInsertTest.java @@ -150,4 +150,38 @@ 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 { + long start = System.currentTimeMillis(); + + CollectionAttributes attr = new CollectionAttributes(); + + CollectionFuture> future = mc + .asyncMopPipedInsertBulk(KEY, elements, attr); + + Map map = future.get(5000L, + TimeUnit.MILLISECONDS); + + // System.out.println(System.currentTimeMillis() - start + "ms"); + + 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..9616da2b --- /dev/null +++ b/src/test/manual/net/spy/memcached/collection/map/MopBulkAPITest.java @@ -0,0 +1,158 @@ +/* + * 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.collection.MapElement; +import net.spy.memcached.internal.CollectionFuture; +import net.spy.memcached.ops.CollectionOperationStatus; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +public class MopBulkAPITest extends BaseIntegrationTest { + + private String key = "MopBulkAPITest33"; + Map elements = new HashMap(); + List> updateMap = new ArrayList>(); + + + 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)); + MapElement temp = + new MapElement("mkey" + String.valueOf(i), + "newvalue" + String.valueOf(i)); + updateMap.add(temp); + } + } + + 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()); + } +} From 936ddf634b91ac67d4ad0c713b5a8bb89d27d725 Mon Sep 17 00:00:00 2001 From: Wooseok Son Date: Mon, 22 Aug 2016 14:11:53 +0900 Subject: [PATCH 2/3] Fix testTimeouts for map collection features moved timeout related tests of map collection to ArcusTimeoutTest.java --- .../net/spy/memcached/ArcusTimeoutTest.java | 35 ++++++++++ .../MopInsertBulkMultipleTest.java | 70 ------------------- .../bulkoperation/MopInsertBulkTest.java | 29 -------- 3 files changed, 35 insertions(+), 99 deletions(-) diff --git a/src/test/java/net/spy/memcached/ArcusTimeoutTest.java b/src/test/java/net/spy/memcached/ArcusTimeoutTest.java index b954aa24..64b1d8de 100644 --- a/src/test/java/net/spy/memcached/ArcusTimeoutTest.java +++ b/src/test/java/net/spy/memcached/ArcusTimeoutTest.java @@ -342,4 +342,39 @@ public void testFlushByPrefixTimeout() flushFuture.get(1L, TimeUnit.MILLISECONDS); flushFuture.cancel(true); } + + @Test(expected = TimeoutException.class) + public void testMopInsertBulkMultipleTimeout() + throws InterruptedException, ExecutionException, TimeoutException { + String key = "MyMopKey"; + String value = "MyValue"; + + int mkeySize = mc.getMaxPipedItemCount(); + Map mkeys = new TreeMap(); + for (int i = 0; i < mkeySize; i++) { + mkeys.put(String.valueOf(i), value); + } + + Future> future = mc.asyncMopPipedInsertBulk( + key, mkeys, new CollectionAttributes()); + future.get(1L, TimeUnit.NANOSECONDS); + future.cancel(true); + } + + public void testMopInsertBulkTimeout() + throws InterruptedException, ExecutionException, TimeoutException { + String key = "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), key, 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 index 7d760caf..9644894e 100644 --- a/src/test/manual/net/spy/memcached/bulkoperation/MopInsertBulkMultipleTest.java +++ b/src/test/manual/net/spy/memcached/bulkoperation/MopInsertBulkMultipleTest.java @@ -88,41 +88,6 @@ public void testInsertAndGet() { } } - public void testTimeout() { - String key = "MyMopKey"; - String value = "MyValue"; - - int mkeySize = mc.getMaxPipedItemCount(); - Map mkeys = new TreeMap(); - for (int i = 0; i < mkeySize; i++) { - mkeys.put(String.valueOf(i), value); - } - - try { - // SET - Future> future = mc - .asyncMopPipedInsertBulk(key, mkeys, - new CollectionAttributes()); - try { - Map errorList = future.get( - 1L, TimeUnit.NANOSECONDS); - - Assert.assertTrue("Error list is not empty." + errorList, - errorList.isEmpty()); - } catch (TimeoutException e) { - future.cancel(true); - return; - } catch (Exception e) { - future.cancel(true); - Assert.fail(); - } - Assert.fail(); - } catch (Exception e) { - e.printStackTrace(); - Assert.fail(); - } - } - public void testInsertAndGetUsingSingleClient() { String key = "MyMopKey333"; String value = "MyValue"; @@ -181,41 +146,6 @@ public void testInsertAndGetUsingSingleClient() { } } - public void testTimeoutUsingSingleClient() { - String key = "MyMopKey"; - String value = "MyValue"; - - int mkeySize = mc.getMaxPipedItemCount(); - Map mkeys = new TreeMap(); - for (int i = 0; i < mkeySize; i++) { - mkeys.put(String.valueOf(i), value); - } - - try { - // SET - Future> future = mc - .asyncMopPipedInsertBulk(key, mkeys, - new CollectionAttributes()); - try { - Map errorList = future.get( - 1L, TimeUnit.NANOSECONDS); - - Assert.assertTrue("Error list is not empty." + errorList, - errorList.isEmpty()); - } catch (TimeoutException e) { - future.cancel(true); - return; - } catch (Exception e) { - future.cancel(true); - Assert.fail(); - } - Assert.fail(); - } catch (Exception e) { - e.printStackTrace(); - Assert.fail(); - } - } - public void testErrorCount() { String key = "MyMopKeyErrorCount"; String value = "MyValue"; diff --git a/src/test/manual/net/spy/memcached/bulkoperation/MopInsertBulkTest.java b/src/test/manual/net/spy/memcached/bulkoperation/MopInsertBulkTest.java index 905567b0..01307a22 100644 --- a/src/test/manual/net/spy/memcached/bulkoperation/MopInsertBulkTest.java +++ b/src/test/manual/net/spy/memcached/bulkoperation/MopInsertBulkTest.java @@ -86,35 +86,6 @@ public void testInsertAndGet() { } } - public void testTimeout() { - String value = "MyValue"; - int keySize = 250000; - - String[] keys = new String[keySize]; - for (int i = 0; i < keys.length; i++) { - keys[i] = "MyMopKey" + i; - } - - try { - // SET - Future> future = mc - .asyncMopInsertBulk(Arrays.asList(keys), MKEY, value, - new CollectionAttributes()); - try { - future.get(1L, TimeUnit.MILLISECONDS); - Assert.fail("There is no timeout"); - } catch (TimeoutException e) { - future.cancel(true); - return; - } catch (Exception e) { - future.cancel(true); - } - } catch (Exception e) { - e.printStackTrace(); - Assert.fail(); - } - } - public void testCountError() { String value = "MyValue"; From 5b4864ba421580084247afc26addfe584bb6c2aa Mon Sep 17 00:00:00 2001 From: MinWooJin Date: Tue, 27 Sep 2016 11:05:22 +0900 Subject: [PATCH 3/3] MAP_COLLECTION: refactor map collection, remove MapElement... --- docs/07-map-API.md | 12 +- install-arcus-memcached.sh | 28 ----- .../java/net/spy/memcached/ArcusClient.java | 59 ++-------- .../java/net/spy/memcached/ArcusClientIF.java | 111 +++++------------- .../net/spy/memcached/ArcusClientPool.java | 25 +--- .../collection/CollectionCreate.java | 2 - .../collection/CollectionPipedStore.java | 93 +-------------- .../collection/CollectionPipedUpdate.java | 48 ++++---- .../collection/CollectionUpdate.java | 10 -- .../spy/memcached/collection/MapDelete.java | 2 +- .../spy/memcached/collection/MapElement.java | 71 ----------- .../spy/memcached/collection/MapUpdate.java | 2 +- .../net/spy/memcached/ArcusTimeoutTest.java | 14 +-- .../MopInsertBulkMultipleTest.java | 84 ++----------- .../bulkoperation/PipeInsertTest.java | 8 -- .../collection/map/MopBulkAPITest.java | 13 +- 16 files changed, 100 insertions(+), 482 deletions(-) delete mode 100644 install-arcus-memcached.sh delete mode 100644 src/main/java/net/spy/memcached/collection/MapElement.java diff --git a/docs/07-map-API.md b/docs/07-map-API.md index f77063e8..e8beaf23 100644 --- a/docs/07-map-API.md +++ b/docs/07-map-API.md @@ -6,7 +6,7 @@ Map을 Java의 Map 자료형을 저장하는 용도로 사용하길 권장한다 **제약 조건** - 저장 가능한 최대 element 개수 : 디폴트 4,000개 (attribute 설정으로 최대 50,000개 확장 가능) - 각 element에서 value 최대 크기 : 4KB -- mkey의 입력, Java map type에서 key는 string type만 가능하다. mkey 최대 길이는 key의 최대 길이와 같고, 하나의 map 내에서 mkey간의 중복은 허용하지 않는다. +- mkey의 입력, Java map type에서 key는 string type만 가능하다. mkey 최대 길이는 250 바이트 이고, 하나의 map에 중복된 mkey는 허용하지 않는다. Map item에 대해 수행가능한 기본 연산은 다음과 같다. @@ -269,14 +269,14 @@ Map element를 조회하는 함수는 세 유형이 있다. ```java CollectionFuture> -asyncMopGet(String key, boolean withDelete, Boolean dropIfEmpty) +asyncMopGet(String key, boolean withDelete, boolean dropIfEmpty) ``` 둘째, 해당 Map에서 주어진 mkey 하나의 element를 조회한다. ```java CollectionFuture> -asyncMopGet(String key, String mkey, boolean withDelete, Boolean dropIfEmpty) +asyncMopGet(String key, String mkey, boolean withDelete, boolean dropIfEmpty) ``` 셋째, Map에서 주어진 mkeyList의 element를 조회한다. @@ -364,8 +364,6 @@ Map에 여러 element를 한번에 삽입하는 함수는 두 유형이 있다. ```java CollectionFuture> asyncMopPipedInsertBulk(String key, Map elements, CollectionAttributes attributesForCreate) -CollectionFuture> -asyncMopPipedInsertBulk(String key, List elements, CollectionAttributes attributesForCreate) ``` - key: 삽입 대상 map의 key @@ -463,7 +461,7 @@ Map에서 주어진 elements에 해당하는 모든 element의 value를 일괄 ```java CollectionFuture> -asyncMopPipedUpdateBulk(String key, List> mapElements) +asyncMopPipedUpdateBulk(String key, Map> elements) ``` - key: 변경 대상 map의 key -- mapElements: 변경 대상 map에 대해 mkey, new value를 가진다. +- elements: 변경 대상 map에 대해 mkey, new value를 가진다. diff --git a/install-arcus-memcached.sh b/install-arcus-memcached.sh deleted file mode 100644 index ddc54015..00000000 --- a/install-arcus-memcached.sh +++ /dev/null @@ -1,28 +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 - -# checkout develop in arcus-memcached -cd $HOME/arcus/server -git checkout develop -./config/autorun.sh -./configure --prefix=$HOME/arcus --enable-zk-integration --with-libevent=$HOME/arcus --with-zookeeper=$HOME/arcus -make -make install - -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 ba8ca26d..5c4e8920 100644 --- a/src/main/java/net/spy/memcached/ArcusClient.java +++ b/src/main/java/net/spy/memcached/ArcusClient.java @@ -108,7 +108,6 @@ import net.spy.memcached.collection.MapGet; import net.spy.memcached.collection.MapStore; import net.spy.memcached.collection.MapUpdate; -import net.spy.memcached.collection.MapElement; import net.spy.memcached.collection.SetCreate; import net.spy.memcached.collection.SetDelete; import net.spy.memcached.collection.SetExist; @@ -3039,25 +3038,25 @@ public CollectionFuture> asyncBopPip * (non-Javadoc) * * @see net.spy.memcached.ArcusClientIF#asyncMopUpdate(java.lang.String, - * net.spy.memcached.collection.MapElement, net.spy.memcached.transcoders.Transcoder) + * java.util.Map, net.spy.memcached.transcoders.Transcoder) */ @Override public CollectionFuture> asyncMopPipedUpdateBulk( - String key, List> mapElements) { - return asyncMopPipedUpdateBulk(key, mapElements, collectionTranscoder); + String key, Map elements) { + return asyncMopPipedUpdateBulk(key, elements, collectionTranscoder); } @Override public CollectionFuture> asyncMopPipedUpdateBulk( - String key, List> mapElements, Transcoder tc) { + String key, Map elements, Transcoder tc) { - if (mapElements.size() <= CollectionPipedUpdate.MAX_PIPED_ITEM_COUNT) { + if (elements.size() <= CollectionPipedUpdate.MAX_PIPED_ITEM_COUNT) { CollectionPipedUpdate collectionPipedUpdate = new MapPipedUpdate( - key, mapElements, tc); + key, elements, tc); return asyncCollectionPipedUpdate(key, collectionPipedUpdate); } else { - PartitionedList> list = new PartitionedList>( - mapElements, CollectionPipedUpdate.MAX_PIPED_ITEM_COUNT); + PartitionedMap list = new PartitionedMap( + elements, CollectionPipedUpdate.MAX_PIPED_ITEM_COUNT); List> collectionPipedUpdateList = new ArrayList>( list.size()); @@ -3928,48 +3927,6 @@ public void gotStatus(Integer index, OperationStatus status) { return rv; } - /* - * (non-Javadoc) - * @see net.spy.memcached.ArcusClientIF#asyncMopPipedInsertBulk(java.lang.String, java.util.List, boolean, net.spy.memcached.collection.CollectionAttributes) - */ - @Override - public CollectionFuture> asyncMopPipedInsertBulk( - String key, List> mapElements, - CollectionAttributes attributesForCreate) { - return asyncMopPipedInsertBulk(key, mapElements, attributesForCreate, - collectionTranscoder); - } - - /* - * (non-Javadoc) - * @see net.spy.memcached.ArcusClientIF#asyncMopPipedInsertBulk(java.lang.String, java.util.List, boolean, net.spy.memcached.collection.CollectionAttributes, net.spy.memcached.transcoders.Transcoder) - */ - @Override - public CollectionFuture> asyncMopPipedInsertBulk( - String key, List> mapElements, - CollectionAttributes attributesForCreate, Transcoder tc) { - if (mapElements.size() <= CollectionPipedStore.MAX_PIPED_ITEM_COUNT) { - CollectionPipedStore store = new CollectionPipedStore.MapElementsPipedStore( - key, mapElements, (attributesForCreate != null), - attributesForCreate, tc); - return asyncCollectionPipedStore(key, store); - } else { - PartitionedList> list = new PartitionedList>( - mapElements, CollectionPipedStore.MAX_PIPED_ITEM_COUNT); - - List> storeList = new ArrayList>( - list.size()); - - for (int i = 0; i < list.size(); i++) { - storeList.add(new CollectionPipedStore.MapElementsPipedStore(key, - list.get(i), (attributesForCreate != null), - attributesForCreate, tc)); - } - - return asyncCollectionPipedStore(key, storeList); - } - } - /* * (non-Javadoc) * @see net.spy.memcached.ArcusClientIF#asyncBopPipedInsertBulk(java.lang.String, java.util.List, boolean, 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 2bc6805d..d2653eeb 100644 --- a/src/main/java/net/spy/memcached/ArcusClientIF.java +++ b/src/main/java/net/spy/memcached/ArcusClientIF.java @@ -33,7 +33,6 @@ import net.spy.memcached.collection.ElementValueType; import net.spy.memcached.collection.SMGetElement; import net.spy.memcached.collection.SMGetMode; -import net.spy.memcached.collection.MapElement; import net.spy.memcached.internal.BTreeStoreAndGetFuture; import net.spy.memcached.internal.CollectionFuture; import net.spy.memcached.internal.CollectionGetBulkFuture; @@ -49,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 */ @@ -60,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( @@ -209,9 +208,9 @@ public abstract Future> asyncBopInsertBul * @param mkey * mkey of map. * @param value - * value of map + * value of map * @param attributesForCreate - * create a b+tree with this attributes, if given key is not + * create a map with this attributes, if given key is not * exists. * @param tc * transcoder to encode value @@ -229,9 +228,9 @@ public abstract Future> asyncMopInser * @param mkey * mkey of map. * @param value - * value of map + * value of map * @param attributesForCreate - * create a b+tree with this attributes, if given key is not + * create a map with this attributes, if given key is not * exists. * @return a future indicating success */ @@ -505,53 +504,47 @@ public CollectionFuture>> asyncBopGet(String key, boolean withDelete, boolean dropIfEmpty, Transcoder tc); /** - * Retrieves count all items of random in the map + * 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 false to remove the key when all elements are removed. true map will remain empty even if all the elements are removed + * @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 count all items in given mkey - * The returned map from the future should be sorted by the given range. + * 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 false to remove the key when all elements are removed. true map will remain empty even if all the elements are removed + * @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 an item on given mkeyList in the map. + * 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 b+tree - * @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 + * @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 count all items of random in the map + * Retrieves all items from the map * * @param * @param key key of a map - * @param withDelete true to remove the returned item in the b+tree - * @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 + * @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 */ @@ -559,14 +552,13 @@ public CollectionFuture> asyncMopGet(String key, boolean withDelete, boolean dropIfEmpty, Transcoder tc); /** - * Retrieves count of all items in given mkey - * The returned map from the future should be sorted by the given range. + * 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 b+tree - * @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 + * @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 */ @@ -574,13 +566,13 @@ public CollectionFuture> asyncMopGet(String key, String mkey, boolean withDelete, boolean dropIfEmpty, Transcoder tc); /** - * Retrieves an item on given mkeyList in the map + * 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 b+tree - * @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 + * @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. */ @@ -1205,7 +1197,6 @@ public CollectionFuture asyncBopUpdate(String key, long bkey, * key of a map element * @param value * new value of element. - * do not update the value if this argument is null. * @return a future indicating success */ public CollectionFuture asyncMopUpdate (String key, String mkey, @@ -1220,7 +1211,6 @@ public CollectionFuture asyncMopUpdate (String key, String mkey, * key of a map element * @param value * new value of element. - * do not update the value if this argument is null. * @param tc * a transcoder to encode the value of element * @return a future indicating success @@ -1259,26 +1249,26 @@ public CollectionFuture> asyncBopPip * * @param key * key of a map - * @param mapElements - * list of map element + * @param elements + * Map of map element * @return a future indicating success */ public CollectionFuture> asyncMopPipedUpdateBulk( - String key, List> mapElements); + String key, Map elements); /** * Update elements from the map * * @param key * key of a map - * @param mapElements - * list of map element + * @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, List> mapElements, Transcoder tc); + String key, Map elements, Transcoder tc); /** * Insert an item into the b+tree @@ -1509,43 +1499,6 @@ public CollectionFuture> asyncSopPipedExistBulk( public CollectionFuture> asyncSopPipedExistBulk( String key, List values, Transcoder tc); - /** - * Insert elements into a map - * - * @param key - * a key list of map - * @param mapElements - * mapElement list which insert into map - * @param attributesForCreate - * create a b+tree with this attributes, if given key is not - * exists. - * @return a future that will hold the index of iteration sequence which - * failed elements and result code. - * - */ - public CollectionFuture> asyncMopPipedInsertBulk( - String key, List> mapElements, - CollectionAttributes attributesForCreate); - - /** - * Insert elements into a map - * - * @param key - * a key list of map - * @param mapElements - * MapElement list which insert into map - * @param attributesForCreate - * create a b+tree with this attributes, if given key is not exists. - * @param tc - * transcoder to decode value - * @return a future that will hold the index of iteration sequence which - * failed elements and result code. - * - */ - public CollectionFuture> asyncMopPipedInsertBulk( - String key, List> mapElements, - CollectionAttributes attributesForCreate, 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 6f9a202f..bc5ff558 100644 --- a/src/main/java/net/spy/memcached/ArcusClientPool.java +++ b/src/main/java/net/spy/memcached/ArcusClientPool.java @@ -39,7 +39,6 @@ import net.spy.memcached.collection.ElementValueType; import net.spy.memcached.collection.SMGetElement; import net.spy.memcached.collection.SMGetMode; -import net.spy.memcached.collection.MapElement; import net.spy.memcached.internal.BTreeStoreAndGetFuture; import net.spy.memcached.internal.BulkFuture; import net.spy.memcached.internal.CollectionFuture; @@ -905,14 +904,14 @@ public CollectionFuture> asyncBopPip @Override public CollectionFuture> asyncMopPipedUpdateBulk( - String key, List> mapElements) { - return this.getClient().asyncMopPipedUpdateBulk(key, mapElements); + String key, Map elements) { + return this.getClient().asyncMopPipedUpdateBulk(key, elements); } @Override public CollectionFuture> asyncMopPipedUpdateBulk( - String key, List> mapElements, Transcoder tc) { - return this.getClient().asyncMopPipedUpdateBulk(key, mapElements, tc); + String key, Map elements, Transcoder tc) { + return this.getClient().asyncMopPipedUpdateBulk(key, elements, tc); } @Override @@ -927,22 +926,6 @@ public CollectionFuture> asyncSopPipedExistBulk( return this.getClient().asyncSopPipedExistBulk(key, values, tc); } - @Override - public CollectionFuture> asyncMopPipedInsertBulk( - String key, List> mapElements, - CollectionAttributes attributesForCreate) { - return this.getClient().asyncMopPipedInsertBulk(key, mapElements, - attributesForCreate); - } - - @Override - public CollectionFuture> asyncMopPipedInsertBulk( - String key, List> mapElements, - CollectionAttributes attributesForCreate, Transcoder tc) { - return this.getClient().asyncMopPipedInsertBulk(key, mapElements, - attributesForCreate, tc); - } - @Override public CollectionFuture> asyncBopPipedInsertBulk( String key, List> elements, diff --git a/src/main/java/net/spy/memcached/collection/CollectionCreate.java b/src/main/java/net/spy/memcached/collection/CollectionCreate.java index 6dae78dc..186a39e7 100644 --- a/src/main/java/net/spy/memcached/collection/CollectionCreate.java +++ b/src/main/java/net/spy/memcached/collection/CollectionCreate.java @@ -16,8 +16,6 @@ */ package net.spy.memcached.collection; -import java.util.IllegalFormatCodePointException; - public abstract class CollectionCreate { protected int flags; protected int expTime; diff --git a/src/main/java/net/spy/memcached/collection/CollectionPipedStore.java b/src/main/java/net/spy/memcached/collection/CollectionPipedStore.java index e36b5d38..8fd82c9d 100644 --- a/src/main/java/net/spy/memcached/collection/CollectionPipedStore.java +++ b/src/main/java/net/spy/memcached/collection/CollectionPipedStore.java @@ -396,7 +396,7 @@ public MapPipedStore(String key, Map map, public ByteBuffer getAsciiCommand() { int capacity = 0; - // decode values + // encode values List encodedList = new ArrayList(map.size()); CachedData cd = null; for (T each : map.values()) { @@ -417,9 +417,9 @@ public ByteBuffer getAsciiCommand() { ByteBuffer bb = ByteBuffer.allocate(capacity); // create ascii operation string - int keySize = map.keySet().size(); + int mkeySize = map.keySet().size(); List keyList = new ArrayList(map.keySet()); - for(i = this.nextOpIndex; i < keySize; i++) { + for(i = this.nextOpIndex; i < mkeySize; i++) { String mkey = keyList.get(i); byte[] value = encodedList.get(i); @@ -429,92 +429,7 @@ public ByteBuffer getAsciiCommand() { (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 < keySize - 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 MapElementsPipedStore extends CollectionPipedStore { - - private static final String COMMAND = "mop insert"; - private List> mapElements; - - public MapElementsPipedStore(String key, List> mapElements, - 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.mapElements = mapElements; - this.createKeyIfNotExists = createKeyIfNotExists; - this.attribute = attr; - this.tc = tc; - this.itemCount = mapElements.size(); - } - - public ByteBuffer getAsciiCommand() { - int capacity = 0; - - // decode values - List encodedList = new ArrayList(mapElements.size()); - CachedData cd = null; - for (MapElement each : mapElements) { - cd = tc.encode(each.getValue()); - encodedList.add(cd.getData()); - } - - // estimate the buffer capacity - int i = 0; - for (MapElement eachMkey : mapElements) { - capacity += KeyUtil.getKeyBytes(key).length; - capacity += KeyUtil.getKeyBytes(eachMkey.getMkey()).length; - capacity += encodedList.get(i++).length; - capacity += 64; - } - - // allocate the buffer - ByteBuffer bb = ByteBuffer.allocate(capacity); - - // create ascii operation string - int fSize = mapElements.size(); - for(i = this.nextOpIndex; i < fSize; i++) { - MapElement mapMkey = mapElements.get(i); - byte[] value = encodedList.get(i); - - setArguments(bb, COMMAND, key, mapMkey.getMkey(), 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().toString() - : "" : "", - (createKeyIfNotExists) ? (attribute != null && attribute - .getReadable() != null && !attribute.getReadable()) ? - "unreadable" : "" : "", - (i < fSize - 1) ? PIPE : ""); + (i < mkeySize - 1) ? PIPE : ""); bb.put(value); bb.put(CRLF); } diff --git a/src/main/java/net/spy/memcached/collection/CollectionPipedUpdate.java b/src/main/java/net/spy/memcached/collection/CollectionPipedUpdate.java index e7494a00..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(); @@ -145,29 +147,25 @@ public ByteBuffer getBinaryCommand() { public static class MapPipedUpdate extends CollectionPipedUpdate { private static final String COMMAND = "mop update"; - private List> mapElements; + private Map elements; - public MapPipedUpdate(String key, List> mapElements, + public MapPipedUpdate(String key, Map elements, Transcoder tc) { this.key = key; - this.mapElements = mapElements; + this.elements = elements; this.tc = tc; - this.itemCount = mapElements.size(); + this.itemCount = elements.size(); } public ByteBuffer getAsciiCommand() { int capacity = 0; - // decode parameters - List encodedList = new ArrayList(mapElements.size()); + // encode parameters + List encodedList = new ArrayList(elements.size()); CachedData cd = null; - for (MapElement each : mapElements) { - if (each.getValue() != null) { - cd = tc.encode(each.getValue()); - encodedList.add(cd.getData()); - } else { - encodedList.add(null); - } + for (T each : elements.values()) { + cd = tc.encode(each); + encodedList.add(cd.getData()); } // estimate the buffer capacity @@ -175,12 +173,10 @@ public ByteBuffer getAsciiCommand() { byte[] value; StringBuilder b; - for (MapElement each : mapElements) { + for (String eachMkey : elements.keySet()) { capacity += KeyUtil.getKeyBytes(key).length; - capacity += KeyUtil.getKeyBytes(each.getMkey()).length; - if (encodedList.get(i) != null) { - capacity += encodedList.get(i++).length; - } + capacity += KeyUtil.getKeyBytes(eachMkey).length; + capacity += encodedList.get(i++).length; capacity += 64; } @@ -188,18 +184,16 @@ public ByteBuffer getAsciiCommand() { ByteBuffer bb = ByteBuffer.allocate(capacity); // create ascii operation string - i = 0; - - Iterator> iterator = mapElements.iterator(); - while (iterator.hasNext()) { - MapElement mapElement = iterator.next(); - value = encodedList.get(i++); + 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, - String.valueOf(mapElement.getMkey()), + setArguments(bb, COMMAND, key, mkey, b.toString(), (value == null ? -1 : value.length), - (iterator.hasNext()) ? PIPE : ""); + (i < mkeySize - 1) ? PIPE : ""); if (value != null) { if (value.length > 0) { bb.put(value); diff --git a/src/main/java/net/spy/memcached/collection/CollectionUpdate.java b/src/main/java/net/spy/memcached/collection/CollectionUpdate.java index 403d1edb..89b3e888 100644 --- a/src/main/java/net/spy/memcached/collection/CollectionUpdate.java +++ b/src/main/java/net/spy/memcached/collection/CollectionUpdate.java @@ -42,16 +42,6 @@ public CollectionUpdate(T newValue, ElementFlagUpdate eflagUpdate, boolean norep this.noreply = noreply; } - public CollectionUpdate(T newValue, boolean noreply) { - if (newValue == null) { - throw new IllegalArgumentException( - "newValue must not be null."); - } - - this.newValue = newValue; - this.noreply = noreply; - } - public String stringify() { if (str != null) return str; diff --git a/src/main/java/net/spy/memcached/collection/MapDelete.java b/src/main/java/net/spy/memcached/collection/MapDelete.java index 5475e562..48b32b09 100644 --- a/src/main/java/net/spy/memcached/collection/MapDelete.java +++ b/src/main/java/net/spy/memcached/collection/MapDelete.java @@ -18,7 +18,7 @@ import java.util.List; -public class MapDelete extends CollectionDelete{ +public class MapDelete extends CollectionDelete { private static final String command = "mop delete"; protected List mkeyList; diff --git a/src/main/java/net/spy/memcached/collection/MapElement.java b/src/main/java/net/spy/memcached/collection/MapElement.java deleted file mode 100644 index bd431be7..00000000 --- a/src/main/java/net/spy/memcached/collection/MapElement.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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; - -/** - * Collection MapElement - * - * @param - */ -public class MapElement { - private final String mkey; - private final T value; - - /** - * Create an element - * - * @param mkey mkey of mapElement - * @param value value of mapElement - */ - public MapElement(String mkey, T value) { - this.mkey = mkey; - this.value = value; - } - - /** - * get mkey in map op. - * - * @return mkey - */ - public String getMkey() { - return mkey; - } - - /** - * get value - * - * @return value - */ - public T getValue() { - return value; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("{ \""); - sb.append(getMkey()); - - sb.append("\" : { "); - - sb.append(" \"value\" : \"").append(value.toString()).append("\""); - sb.append(" }"); - - return sb.toString(); - } - -} diff --git a/src/main/java/net/spy/memcached/collection/MapUpdate.java b/src/main/java/net/spy/memcached/collection/MapUpdate.java index 9e41643f..afb6084f 100644 --- a/src/main/java/net/spy/memcached/collection/MapUpdate.java +++ b/src/main/java/net/spy/memcached/collection/MapUpdate.java @@ -21,7 +21,7 @@ public class MapUpdate extends CollectionUpdate { private static final String command = "mop update"; public MapUpdate(T newValue, boolean noreply) { - super(newValue, noreply); + super(newValue, null, noreply); } public String getCommand() { diff --git a/src/test/java/net/spy/memcached/ArcusTimeoutTest.java b/src/test/java/net/spy/memcached/ArcusTimeoutTest.java index 64b1d8de..744b79a8 100644 --- a/src/test/java/net/spy/memcached/ArcusTimeoutTest.java +++ b/src/test/java/net/spy/memcached/ArcusTimeoutTest.java @@ -349,21 +349,21 @@ public void testMopInsertBulkMultipleTimeout() String key = "MyMopKey"; String value = "MyValue"; - int mkeySize = mc.getMaxPipedItemCount(); - Map mkeys = new TreeMap(); - for (int i = 0; i < mkeySize; i++) { - mkeys.put(String.valueOf(i), value); + 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, mkeys, new CollectionAttributes()); + key, elements, new CollectionAttributes()); future.get(1L, TimeUnit.NANOSECONDS); future.cancel(true); } public void testMopInsertBulkTimeout() throws InterruptedException, ExecutionException, TimeoutException { - String key = "MyMopKey"; + String mkey = "MyMopKey"; String value = "MyValue"; int keySize = 250000; @@ -373,7 +373,7 @@ public void testMopInsertBulkTimeout() } Future> future = mc.asyncMopInsertBulk( - Arrays.asList(keys), key, value, new CollectionAttributes()); + 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 index 9644894e..2cb9babb 100644 --- a/src/test/manual/net/spy/memcached/bulkoperation/MopInsertBulkMultipleTest.java +++ b/src/test/manual/net/spy/memcached/bulkoperation/MopInsertBulkMultipleTest.java @@ -34,10 +34,10 @@ public void testInsertAndGet() { String key = "MyMopKey32"; String value = "MyValue"; - int mkeySize = 500; - Map mkeys = new TreeMap(); - for (int i = 0; i < mkeySize; i++) { - mkeys.put(String.valueOf(i), value); + int elementSize = 500; + Map elements = new TreeMap(); + for (int i = 0; i < elementSize; i++) { + elements.put(String.valueOf(i), value); } try { @@ -46,7 +46,7 @@ public void testInsertAndGet() { // SET Future> future = mc - .asyncMopPipedInsertBulk(key, mkeys, + .asyncMopPipedInsertBulk(key, elements, new CollectionAttributes()); try { Map errorList = future.get( @@ -61,7 +61,7 @@ public void testInsertAndGet() { // GET int errorCount = 0; - for (Entry entry : mkeys.entrySet()) { + for (Entry entry : elements.entrySet()) { Future> f = mc.asyncMopGet(key, entry.getKey(), false, false); Map map = null; @@ -79,65 +79,7 @@ public void testInsertAndGet() { Assert.assertEquals("Error count is greater than 0.", 0, errorCount); // REMOVE - for (Entry entry : mkeys.entrySet()) { - mc.asyncMopDelete(key, entry.getKey(), true).get(); - } - } catch (Exception e) { - e.printStackTrace(); - Assert.fail(); - } - } - - public void testInsertAndGetUsingSingleClient() { - String key = "MyMopKey333"; - String value = "MyValue"; - - int mkeySize = 500; - Map mkeys = new TreeMap(); - for (int i = 0; i < mkeySize; i++) { - mkeys.put(String.valueOf(i), value); - } - - try { - // REMOVE - mc.asyncMopDelete(key, true); - - // SET - Future> future = mc - .asyncMopPipedInsertBulk(key, mkeys, - 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 : mkeys.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 : mkeys.entrySet()) { + for (Entry entry : elements.entrySet()) { mc.asyncMopDelete(key, entry.getKey(), true).get(); } } catch (Exception e) { @@ -150,10 +92,10 @@ public void testErrorCount() { String key = "MyMopKeyErrorCount"; String value = "MyValue"; - int mkeySize = 1200; - Map mkeys = new TreeMap(); - for (int i = 0; i < mkeySize; i++) { - mkeys.put(String.valueOf(i), value); + int elementSize = 1200; + Map elements = new TreeMap(); + for (int i = 0; i < elementSize; i++) { + elements.put(String.valueOf(i), value); } try { @@ -161,11 +103,11 @@ public void testErrorCount() { // SET Future> future = mc - .asyncMopPipedInsertBulk(key, mkeys, null); + .asyncMopPipedInsertBulk(key, elements, null); Map map = future.get(2000L, TimeUnit.MILLISECONDS); - assertEquals(mkeySize, map.size()); + assertEquals(elementSize, map.size()); } catch (Exception e) { e.printStackTrace(); diff --git a/src/test/manual/net/spy/memcached/bulkoperation/PipeInsertTest.java b/src/test/manual/net/spy/memcached/bulkoperation/PipeInsertTest.java index eee375cd..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, @@ -160,8 +156,6 @@ public void testMopPipeInsert() { } try { - long start = System.currentTimeMillis(); - CollectionAttributes attr = new CollectionAttributes(); CollectionFuture> future = mc @@ -170,8 +164,6 @@ public void testMopPipeInsert() { Map map = future.get(5000L, TimeUnit.MILLISECONDS); - // System.out.println(System.currentTimeMillis() - start + "ms"); - Assert.assertEquals(1000, map.size()); Map rmap = mc.asyncMopGet(KEY, false, false) diff --git a/src/test/manual/net/spy/memcached/collection/map/MopBulkAPITest.java b/src/test/manual/net/spy/memcached/collection/map/MopBulkAPITest.java index 9616da2b..9ea4f81f 100644 --- a/src/test/manual/net/spy/memcached/collection/map/MopBulkAPITest.java +++ b/src/test/manual/net/spy/memcached/collection/map/MopBulkAPITest.java @@ -20,14 +20,11 @@ import net.spy.memcached.collection.BaseIntegrationTest; import net.spy.memcached.collection.CollectionAttributes; import net.spy.memcached.collection.CollectionOverflowAction; -import net.spy.memcached.collection.MapElement; import net.spy.memcached.internal.CollectionFuture; import net.spy.memcached.ops.CollectionOperationStatus; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; import java.util.Map; +import java.util.HashMap; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -35,7 +32,7 @@ public class MopBulkAPITest extends BaseIntegrationTest { private String key = "MopBulkAPITest33"; Map elements = new HashMap(); - List> updateMap = new ArrayList>(); + Map updateMap = new HashMap(); private int getValueCount() { @@ -47,10 +44,8 @@ protected void setUp() throws Exception { for (long i = 0; i < getValueCount(); i++) { elements.put("mkey" + String.valueOf(i), "value" + String.valueOf(i)); - MapElement temp = - new MapElement("mkey" + String.valueOf(i), - "newvalue" + String.valueOf(i)); - updateMap.add(temp); + updateMap.put("mkey" + String.valueOf(i), + "newvalue" + String.valueOf(i)); } }