From def986413525de8c2fd8b794f3c62637ca515690 Mon Sep 17 00:00:00 2001 From: yeoncheol-kim Date: Thu, 12 Dec 2024 09:29:00 +0900 Subject: [PATCH] DOC: Modify examples for the btree document --- docs/07-btree-API.md | 1417 ++++++++++++++++++++++-------------------- 1 file changed, 740 insertions(+), 677 deletions(-) diff --git a/docs/07-btree-API.md b/docs/07-btree-API.md index 432a1cae..686d8407 100644 --- a/docs/07-btree-API.md +++ b/docs/07-btree-API.md @@ -54,7 +54,6 @@ B+tree item에서 사용 가능한 bkey 데이터 타입은 아래 두 가지이 eflag는 현재 b+tree element에만 존재하는 필드이다. eflag 데이터 타입은 최대 31 크기의 byte array 타입만 가능하다. - ## Element Flag Filter 구조체 B+tree의 element flag에 대한 filtering을 지정하기 위해선, `eflag_filter` 구조체를 사용해야 한다. @@ -102,7 +101,7 @@ memcached_coll_eflags_filter_init(memcached_coll_eflag_filter_st *ptr, - MEMCACHED_COLL_COMP_EQ - MEMCACHED_COLL_COMP_NE -eflag의 전체/부분 값에 대해 어떤 operand로 bitwise 연산을 취함으로써 eflag의 특정 bit들만을 골라내어 compare할 수 있다. +eflag의 전체/부분 값에 대해 bitwise 연산을 취함으로써 eflag의 특정 bit들만을 골라내어 compare할 수 있다. 이와 같이 `eflag_filter`에 bitwise 연산을 추가할 경우에는 아래의 API를 이용할 수 있다. ```c @@ -113,7 +112,7 @@ memcached_coll_eflag_filter_set_bitwise(memcached_coll_eflag_filter_st *ptr, memcached_coll_bitwise_t bitwise_op) ``` -- value, value_length: eflag에서 bitwise 연산을 취할 operand를 지정한다. +- value, value_length: eflag에서 bitwise 연산을 취할 값을 지정한다. - bitwise_op: bitwise 연산을 지정한다. - MEMCACHED_COLL_BITWISE_AND - MEMCACHED_COLL_BITWISE_OR @@ -150,53 +149,53 @@ memcached_coll_eflag_update_set_bitwise(memcached_coll_eflag_update_st *ptr, - MEMCACHED_COLL_BITWISE_OR - MEMCACHED_COLL_BITWISE_XOR - ## B+Tree Query 구조체 memcached_bop_query_st 구조체는 B+tree 조회 조건을 추상화하고 있으며 다양한 API에 사용될 수 있다. 먼저, 아래 함수는 하나의 bkey의 element를 조회하는 query 구조체를 생성한다. -``` c +```c memcached_return_t memcached_bop_query_init(memcached_bop_query_st *ptr, const uint64_t bkey, memcached_bop_eflag_filter_st *eflag_filter) + memcached_return_t memcached_bop_ext_query_init(memcached_bop_query_st *ptr, - const unsigned char *bkey, const size_t bkey_length, - memcached_bop_eflag_filter_st *eflag_filter) + const unsigned char *bkey, const size_t bkey_length, + memcached_bop_eflag_filter_st *eflag_filter) ``` 아래 함수는 bkey range, element flag filter, offset과 count를 함께 명시하여 query 구조체를 생성한다. -``` c +```c memcached_return_t memcached_bop_range_query_init(memcached_bop_query_st *ptr, const uint64_t bkey_from, const uint64_t bkey_to, memcached_bop_eflag_filter_st *eflag_filter, - const size_t offset, const size_t count) + size_t offset, size_t count) + memcached_return_t memcached_bop_ext_range_query_init (memcached_bop_query_st *ptr, - const unsigned char *bkey_from, const size_t bkey_from_length, - const unsigned char *bkey_to, const size_t bkey_to_length, - memcached_bop_eflag_filter_st *eflag_filter, - const size_t offset, const size_t count) + const unsigned char *bkey_from, const size_t bkey_from_length, + const unsigned char *bkey_to, const size_t bkey_to_length, + memcached_bop_eflag_filter_st *eflag_filter, + size_t offset, size_t count) ``` - ## B+Tree Item 생성 새로운 empty b+tree item을 생성한다. -``` c +```c memcached_return_t memcached_bop_create(memcached_st *ptr, const char *key, size_t key_length, memcached_coll_create_attrs_st *attributes) ``` -- key: b+tree item의 key +- key, key_length: b+tree item의 key - attributes: b+tree item의 속성 정보 [(링크)](08-attribute-API.md#attribute-생성) Response code는 아래와 같다. @@ -206,31 +205,30 @@ Response code는 아래와 같다. - not MEMCACHED_SUCCESS - MEMCACHED_EXISTS: 동일한 key를 가진 b+tree가 이미 존재함. -B+tree item을 생성하는 예제는 아래와 같다. +B+tree item을 생성하는 예시는 아래와 같다. -``` c -void arcus_btree_item_create(memcached_st *memc) +```c +int arcus_btree_item_create(memcached_st *memc) { - uint32_t flags= 10; - uint32_t exptime= 600; - uint32_t maxcount= 1000; - - memcached_coll_create_attrs_st attributes; - memcached_coll_create_attrs_init(&attributes, flags, exptime, maxcount); - - memcached_return_t rc - - // 비어 있는 B+tree를 생성한다. - rc= memcached_bop_create(memc, "btree:an_empty_btree", strlen("btree:an_empty_btree"), - &attributes); - assert(MEMCACHED_SUCCESS == rc); - assert(MEMCACHED_CREATED == memcached_get_last_response_code(memc)); - - // 이미 존재하는 key를 갖는 B+tree를 생성하려 하면 오류를 반환한다. - rc= memcached_bop_create(memc, "btree:an_empty_btree", strlen("btree:an_empty_btree"), - &attributes); - assert(MEMCACHED_SUCCESS != rc); - assert(MEMCACHED_EXISTS == memcached_get_last_response_code(memc)); + const char *key= "btree:a_key"; + uint32_t flags= 0; + uint32_t exptime= 600; + uint32_t maxcount= 1000; + memcached_return_t rc; + + memcached_coll_create_attrs_st attributes; + memcached_coll_create_attrs_init(&attributes, flags, exptime, maxcount); + + rc= memcached_bop_create(memc, key, strlen(key), &attributes); + if (memcached_failed(rc)) { + fprintf(stderr, "Failed to memcached_bop_create: %d(%s)\n", + rc, memcached_strerror(memc, rc)); + return -1; + } + + assert(rc == MEMCACHED_SUCCESS); + assert(memcached_get_last_response_code(memc) == MEMCACHED_CREATED); + return 0; } ``` @@ -239,7 +237,7 @@ void arcus_btree_item_create(memcached_st *memc) B+Tree에 하나의 element를 삽입한다. 전자는 8바이트 unsigned integer 타입의 bkey를, 후자는 최대 31 크기의 byte array 타입의 bkey를 사용한다. -``` c +```c memcached_return_t memcached_bop_insert(memcached_st *ptr, const char *key, size_t key_length, @@ -250,11 +248,11 @@ memcached_bop_insert(memcached_st *ptr, memcached_return_t memcached_bop_ext_insert(memcached_st *ptr, - const char *key, size_t key_length, - const unsigned char *bkey, size_t bkey_length, // bkey of byte array type - const unsigned char *eflag, size_t eflag_length, - const char *value, size_t value_length, - memcached_coll_create_attrs_st *attributes) + const char *key, size_t key_length, + const unsigned char *bkey, size_t bkey_length, // bkey of byte array type + const unsigned char *eflag, size_t eflag_length, + const char *value, size_t value_length, + memcached_coll_create_attrs_st *attributes) ``` - key, key_length: b+tree item의 key @@ -276,40 +274,39 @@ Response code는 아래와 같다. - MEMCACHED_OVERFLOWED: Overflow 상태임. (overflowaction=error, maxcount=count) - MEMCACHED_OUT_OF_RANGE: 주어진 bkey가 maxcount 또는 maxbkeyrange를 위배하여 overflowaction에 따라 trim됨. +B+tree element를 삽입하는 예시는 아래와 같다. -B+tree element를 삽입하는 예제는 아래와 같다. - -``` c -void arcus_btree_element_insert(memcached_st *memc) +```c +int arcus_btree_element_insert(memcached_st *memc) { - uint32_t flags= 10; - uint32_t exptime= 600; - uint32_t maxcount= 1; - - memcached_coll_create_attrs_st attributes; - memcached_coll_create_attrs_init(&attributes, flags, exptime, maxcount); - - memcached_return_t rc; - - // 입력할 때 B+Tree가 존재하지 않으면 새로 생성한 뒤 입력한다. - rc= memcached_bop_insert(memc, "btree:a_btree", strlen("btree:a_btree"), 1, - NULL, 0, "value", strlen("value"), &attributes); - assert(MEMCACHED_SUCCESS == rc); - assert(MEMCACHED_CREATED_STORED == memcached_get_last_response_code(memc)); - - // 이미 존재하는 bkey를 가지는 element는 입력할 수 없다. - rc= memcached_bop_insert(memc, "btree:a_btree", strlen("btree:a_btree"), 1, - NULL, 0, "value", strlen("value"), &attributes); - assert(MEMCACHED_SUCCESS == rc); - assert(MEMCACHED_ELEMENT_EXISTS == memcached_get_last_response_code(memc)); - - // B+tree에 설정된 overflow action에 따라 입력 불가능한 bkey가 결정된다. - // B+tree는 smallest_trim 정책이 기본값으로 설정되어 있으며, - // B+tree의 smallest bkey 보다 더 작은 bkey를 입력하면 OUT_OF_RANGE 오류가 발생한다. - rc= memcached_bop_insert(memc, "btree:a_btree", strlen("btree:a_btree"), 0, - NULL, 0, "value", strlen("value"), &attributes); - assert(MEMCACHED_SUCCESS != rc); - assert(MEMCACHED_OUT_OF_RANGE == memcached_get_last_response_code(memc)); + const char *key= "btree:a_key"; + const char *value= "value"; + const uint64_t bkey= 0; + // const unsigned char bkey[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH]= {0, }; + const unsigned char eflag[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH]= {0, }; + memcached_return_t rc; + + uint32_t flags= 0; + uint32_t exptime= 600; + uint32_t maxcount= 1000; + + memcached_coll_create_attrs_st attributes; + memcached_coll_create_attrs_init(&attributes, flags, exptime, maxcount); + + rc= memcached_bop_insert(memc, key, strlen(key), bkey, eflag, sizeof(eflag), + value, strlen(value), &attributes); + /* rc= memcached_bop_ext_insert(memc, key, strlen(key), bkey, sizeof(bkey), + eflag, sizeof(eflag), value, strlen(value), &attributes); */ + if (memcached_failed(rc)) { + fprintf(stderr, "Failed to memcached_bop_insert: %d(%s)\n", + rc, memcached_strerror(memc, rc)); + return -1; + } + + memcached_return_t last_response= memcached_get_last_response_code(memc); + assert(rc == MEMCACHED_SUCCESS); + assert(last_response == MEMCACHED_STORED || last_response == MEMCACHED_CREATED_STORED); + return 0; } ``` @@ -317,14 +314,13 @@ void arcus_btree_element_insert(memcached_st *memc) 하지만, C client에서는 이 기능을 아직 제공하지 않고 있다. - ## B+Tree Element Upsert B+Tree에 하나의 element를 upsert하는 함수들이다. Upsert 연산은 해당 element가 없으면 insert하고, 있으면 update하는 연산이다. 전자는 8바이트 unsigned integer 타입의 bkey를, 후자는 최대 31 크기의 byte array 타입의 bkey를 사용한다. -``` c +```c memcached_return_t memcached_bop_upsert(memcached_st *ptr, const char *key, size_t key_length, @@ -335,11 +331,11 @@ memcached_bop_upsert(memcached_st *ptr, memcached_return_t memcached_bop_ext_upsert(memcached_st *ptr, - const char *key, size_t key_length, - const unsigned char *bkey, size_t bkey_length, // bkey of byte array type - const unsigned char *eflag, size_t eflag_length, - const char *value, size_t value_length, - memcached_coll_create_attrs_st *attributes) + const char *key, size_t key_length, + const unsigned char *bkey, size_t bkey_length, // bkey of byte array type + const unsigned char *eflag, size_t eflag_length, + const char *value, size_t value_length, + memcached_coll_create_attrs_st *attributes) ``` - key, key_length: b+tree item의 key @@ -361,32 +357,41 @@ Response code는 아래와 같다. - MEMCACHED_OVERFLOWED: Overflow 상태임. (overflowaction=error, maxcount=count) - MEMCACHED_OUT_OF_RANGE: 삽입 위치가 b+tree의 element bkey 범위를 넘어섬. +B+tree element를 upsert하는 예시는 아래와 같다. -B+tree element를 upsert하는 예제는 아래와 같다. - -``` c -void arcus_btree_element_upsert(memcached_st *memc) +```c +int arcus_btree_element_upsert(memcached_st *memc) { - uint32_t flags= 10; - uint32_t exptime= 600; - uint32_t maxcount= 1; - - memcached_coll_create_attrs_st attributes; - memcached_coll_create_attrs_init(&attributes, flags, exptime, maxcount); - - memcached_return_t rc; - - // 입력할 때 B+Tree가 존재하지 않으면 새로 생성한 뒤 입력한다. - rc= memcached_bop_upsert(memc, "btree:a_btree", strlen("btree:a_btree"), 1, - NULL, 0, "value", strlen("value"), &attributes); - assert(MEMCACHED_SUCCESS == rc); - assert(MEMCACHED_CREATED_STORED == memcached_get_last_response_code(memc)); - - // 이미 존재하는 bkey를 가지는 element를 새로운 element로 대체한다. - rc= memcached_bop_upsert(memc, "btree:a_btree", strlen("btree:a_btree"), 1, - NULL, 0, "new value", strlen("new value"), &attributes); - assert(MEMCACHED_SUCCESS == rc); - assert(MEMCACHED_REPLACED == memcached_get_last_response_code(memc)); + const char *key= "btree:a_key"; + const char *value= "value"; + const uint64_t bkey= 0; + // const unsigned char bkey[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH]= {0, }; + const unsigned char eflag[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH]= {0, }; + memcached_return_t rc; + + uint32_t flags= 0; + uint32_t exptime= 600; + uint32_t maxcount= 1000; + + memcached_coll_create_attrs_st attributes; + memcached_coll_create_attrs_init(&attributes, flags, exptime, maxcount); + + rc= memcached_bop_upsert(memc, key, strlen(key), bkey, eflag, sizeof(eflag), + value, strlen(value), &attributes); + /* rc= memcached_bop_ext_upsert(memc, key, strlen(key), bkey, sizeof(bkey), + eflag, sizeof(eflag), value, strlen(value), &attributes); */ + if (memcached_failed(rc)) { + fprintf(stderr, "Failed to memcached_bop_upsert: %d(%s)\n", + rc, memcached_strerror(memc, rc)); + return -1; + } + + memcached_return_t last_response= memcached_get_last_response_code(memc); + assert(rc == MEMCACHED_SUCCESS); + assert(last_response == MEMCACHED_STORED || + last_response == MEMCACHED_CREATED_STORED || + last_response == MEMCACHED_REPLACED); + return 0; } ``` @@ -395,7 +400,7 @@ void arcus_btree_element_upsert(memcached_st *memc) B+Tree에서 하나의 element를 변경하는 함수이다. Element의 eflag 그리고/또는 value를 변경한다. 전자는 8바이트 unsigned integer 타입의 bkey를, 후자는 최대 31 크기의 byte array 타입의 bkey를 사용한다. -``` c +```c memcached_return_t memcached_bop_update(memcached_st *ptr, const char *key, size_t key_length, @@ -405,10 +410,10 @@ memcached_bop_update(memcached_st *ptr, memcached_return_t memcached_bop_ext_update(memcached_st *ptr, - const char *key, size_t key_length, - const unsigned char *bkey, size_t bkey_length, // bkey of byte array type - memcached_coll_eflag_update_st *eflag_update, - const char *value, size_t value_length) + const char *key, size_t key_length, + const unsigned char *bkey, size_t bkey_length, // bkey of byte array type + memcached_coll_eflag_update_st *eflag_update, + const char *value, size_t value_length) ``` - key, key_length: b+tree item의 key @@ -428,13 +433,36 @@ Response code는 아래와 같다. - MEMCACHED_BKEY_MISMATCH: 주어진 bkey 유형과 해당 B+tree의 bkey 유형이 다름. - MEMCACHED_EFLAG_MISMATCH: eflag_update에 명시된 eflag 데이터가 존재하지 않음. +B+tree element를 변경하는 예시는 아래와 같다. -B+tree element를 변경하는 예제는 아래와 같다. - -``` c -void arcus_btree_element_update(memcached_st *memc) +```c +int arcus_btree_element_update(memcached_st *memc) { - /* TODO : example code */ + const char *key= "btree:a_key"; + const char *value= "value"; + const uint64_t bkey= 0; + // const unsigned char bkey[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH]= {0, }; + memcached_return_t rc; + + const unsigned char new_eflag[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH]= {0, }; + + memcached_coll_eflag_update_st eflag_update; + memcached_coll_eflag_update_init(&eflag_update, new_eflag, sizeof(new_eflag)); + + rc= memcached_bop_update(memc, key, strlen(key), bkey, + &eflag_update, value, strlen(value)); + /* rc= memcached_bop_ext_update(memc, key, strlen(key), bkey, sizeof(bkey), + &eflag_update, value, strlen(value)); */ + if (memcached_failed(rc)) { + fprintf(stderr, "Failed to memcached_bop_update: %d(%s)\n", rc, memcached_strerror(memc, rc)); + return -1; + } + + memcached_return_t last_response= memcached_get_last_response_code(memc); + assert(rc == MEMCACHED_SUCCESS); + assert(last_response == MEMCACHED_UPDATED); + + return 0; } ``` @@ -444,7 +472,7 @@ B+tree에서 element를 삭제하는 함수들은 두 유형이 있다. 첫째, b+tree에서 특정 bkey를 가진 element에 대해 eflag filter 조건을 만족하면 삭제하는 함수이다. -``` c +```c memcached_return_t memcached_bop_delete(memcached_st *ptr, const char *key, size_t key_length, @@ -454,16 +482,16 @@ memcached_bop_delete(memcached_st *ptr, memcached_return_t memcached_bop_ext_delete(memcached_st *ptr, - const char *key, size_t key_length, - const unsigned char *bkey, size_t bkey_length, // bkey of byte array type - memcached_coll_eflag_filter_st *eflag_filter, - bool drop_if_empty) + const char *key, size_t key_length, + const unsigned char *bkey, size_t bkey_length, // bkey of byte array type + memcached_coll_eflag_filter_st *eflag_filter, + bool drop_if_empty) ``` 둘째, b+tree에서 bkey range에 해당하는 element들을 스캔하면서 eflag filter 조건을 만족하는 N개의 element들을 삭제하는 함수이다. -``` c +```c memcached_return_t memcached_bop_delete_by_range(memcached_st *ptr, const char *key, size_t key_length, @@ -497,49 +525,43 @@ Response code는 아래와 같다. - MEMCACHED_TYPE_MISMATCH: 주어진 key에 해당하는 자료구조가 B+tree가 아님. - MEMCACHED_BKEY_MISMATCH: 주어진 bkey 유형과 해당 B+tree의 bkey 유형이 다름. -B+tree element를 삭제하는 예제는 아래와 같다. +대표적으로 b+tree에서 bkey range에 해당하는 element들을 스캔하면서 +eflag filter 조건을 만족하는 N개의 element들을 삭제하는 예시는 아래와 같다. -``` c -void arcus_btree_element_delete(memcached_st *memc) +```c +int arcus_btree_element_delete_by_range(memcached_st *memc) { - - uint32_t flags= 10; - uint32_t exptime= 600; - uint32_t maxcount= 1000; - - memcached_coll_create_attrs_st attributes; - memcached_coll_create_attrs_init(&attributes, flags, exptime, maxcount); - memcached_return_t rc; - - - // 테스트 데이터를 입력한다. - rc= memcached_bop_insert(memc, "btree:a_btree", strlen("btree:a_btree"), 0, - NULL, 0, "value", strlen("value"), &attributes); - - assert(MEMCACHED_SUCCESS == rc); - assert(MEMCACHED_CREATED_STORED == memcached_get_last_response_code(memc)); - - - rc= memcached_bop_insert(memc, "btree:a_btree", strlen("btree:a_btree"), 1, - NULL, 0, "value", strlen("value"), &attributes); - - assert(MEMCACHED_SUCCESS == rc); - assert(MEMCACHED_STORED == memcached_get_last_response_code(memc)); - - - // 삭제를 요청한 bkey가 B+tree에 존재하지 않으면 오류가 발생한다. - rc= memcached_bop_delete(memc, "btree:a_btree", strlen("btree:a_btree"), 2, NULL, true); - - assert(MEMCACHED_SUCCESS != rc); - assert(MEMCACHED_NOTFOUND_ELEMENT == memcached_get_last_response_code(memc)); - - - // bkey 범위가 0~10 사이인 element를 모두 삭제한다. - rc= memcached_bop_delete_by_range(memc, "btree:a_btree", strlen("btree:a_btree"), - 0, 10, NULL, 0, true); - - assert(MEMCACHED_SUCCESS == rc); - assert(MEMCACHED_DELETED_DROPPED == memcached_get_last_response_code(memc)); + const char *key= "btree:a_key"; + const uint64_t from= 0, to= UINT64_MAX; + /* const unsigned char from[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH]= {0, }; + const unsigned char to[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH] + = {[0 ... MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH - 1] = 0xff}; */ + size_t count= 0; + bool drop_if_empty= false; + memcached_return_t rc; + + const size_t comp_offset= 0; + const unsigned char comp_value[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH]= {0, }; + memcached_coll_comp_t comp_op= MEMCACHED_COLL_COMP_EQ; + + memcached_coll_eflag_filter_st eflag_filter; + memcached_coll_eflag_filter_init(&eflag_filter, comp_offset, comp_value, sizeof(comp_value), comp_op); + + rc= memcached_bop_delete_by_range(memc, key, strlen(key), + from, to, &eflag_filter, count, drop_if_empty); + /* rc= memcached_bop_ext_delete_by_range(memc, key, strlen(key), + from, sizeof(from), to, sizeof(to), + &eflag_filter, count, drop_if_empty); */ + if (memcached_failed(rc)) { + fprintf(stderr, "Failed to memcached_bop_delete_by_range: %d(%s)\n", + rc, memcached_strerror(memc, rc)); + return -1; + } + + memcached_return_t last_response= memcached_get_last_response_code(memc); + assert(rc == MEMCACHED_SUCCESS); + assert(last_response == MEMCACHED_DELETED || last_response == MEMCACHED_DELETED_DROPPED); + return 0; } ``` @@ -550,7 +572,7 @@ Element의 값은 숫자형 값이어야 한다. 전자는 8바이트 unsigned integer 타입의 bkey를, 후자는 최대 31 크기의 byte array 타입의 bkey를 사용한다. -``` c +```c memcached_return_t memcached_bop_incr(memcached_st *ptr, const char *key, size_t key_length, @@ -569,9 +591,9 @@ memcached_bop_ext_incr(memcached_st *ptr, const uint64_t delta, uint64_t *value) memcached_return_t memcached_bop_ext_decr(memcached_st *ptr, - const char *key, size_t key_length, - const unsigned char *bkey, size_t bkey_length, - const uint64_t delta, uint64_t *value) + const char *key, size_t key_length, + const unsigned char *bkey, size_t bkey_length, + const uint64_t delta, uint64_t *value) ``` - key, key_length: b+tree item의 key @@ -592,64 +614,28 @@ Response code는 아래와 같다. - MEMCACHED_OUT_OF_RANGE : 주어진 조회 범위에 해당하는 element가 없으나, 조회 범위가 overflow 정책에 의해 삭제되는 영역에 걸쳐 있음. 즉, B+tree 크기 제한으로 인해 삭제되어 조회되지 않은 element가 어딘가(DB)에 존재할 수도 있음을 뜻함. -B+tree element 값의 증감을 수행하는 예제는 아래와 같다. +대표적으로 B+tree element의 값을 증가시키는 예시는 다음과 같다. -``` c -void arcus_btree_element_incr(memcached_st *memc) -{ - uint64_t value; uint32_t flags= 10; - int32_t exptime= 600; - uint32_t maxcount= 1000; - uint64_t value; - - memcached_coll_create_attrs_st attributes; - memcached_coll_create_attrs_init(&attributes, flags, exptime, maxcount); - memcached_return_t rc; - - memcached_coll_result_st result_obj; - memcached_coll_result_st *result= memcached_coll_result_create(memc, &result_obj); - - // element 추가 - rc= memcached_bop_insert(memc, "btree:a_btree_incr", 19, 1, - NULL, 0, "2", 1, &attributes); - assert(rc == MEMCACHED_SUCCESS); - - // element increment - rc= memcached_bop_incr(memc, "btree:a_btree_incr", 19, 1, 1, &value); - assert(rc == MEMCACHED_SUCCESS); - assert(uint64_t(3), value); - -} - -void arcus_btree_element_decr(memcached_st *memc) +```c +int arcus_btree_element_arithmetic(memcached_st *memc) { - uint64_t value; uint32_t flags= 10; - int32_t exptime= 600; - uint32_t maxcount= 1000; - uint64_t value; - - memcached_coll_create_attrs_st attributes; - memcached_coll_create_attrs_init(&attributes, flags, exptime, maxcount); - memcached_return_t rc; - - memcached_coll_result_st result_obj; - memcached_coll_result_st *result= memcached_coll_result_create(memc, &result_obj); - - // element 추가 - rc= memcached_bop_insert(memc, "btree:a_btree_incr", 19, 1, - NULL, 0, "2", 1, &attributes); - assert(rc == MEMCACHED_SUCCESS); - - // element decrement 1 - rc= memcached_bop_decr(memc, "btree:a_btree_incr", 19, 1, 1, &value); - assert(rc == MEMCACHED_SUCCESS); - assert(uint64_t(1), value); - - // element decrement 2 - rc= memcached_bop_decr(memc, "btree:a_btree_incr", 19, 1, 2, &value); - assert(rc == MEMCACHED_SUCCESS); - assert(uint64_t(0), value); - + const char *key= "btree:a_key"; + const uint64_t bkey= 0; + // const unsigned char bkey[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH]= {0, }; + uint64_t value= 0; + uint64_t delta= 10; + memcached_return_t rc; + + rc= memcached_bop_incr(memc, key, strlen(key), bkey, delta, &value); + // rc= memcached_bop_ext_incr(memc, key, strlen(key), bkey, sizeof(bkey), delta, &value); + if (memcached_failed(rc)) { + fprintf(stderr, "Failed to memcached_bop_incr: %d(%s)\n", rc, memcached_strerror(memc, rc)); + return -1; + } + + assert(rc == MEMCACHED_SUCCESS); + fprintf(stdout, "incremented value: %llu\n", value); + return 0; } ``` @@ -659,7 +645,7 @@ B+tree element 개수를 확인하는 함수는 두 유형이 있다. 첫째, b+tree에서 특정 bkey를 가진 element에 대해 eflag filter 조건을 만족하는지를 확인하는 함수이다. -``` c +```c memcached_return_t memcached_bop_count(memcached_st *ptr, const char *key, size_t key_length, @@ -669,15 +655,15 @@ memcached_bop_count(memcached_st *ptr, memcached_return_t memcached_bop_ext_count(memcached_st *ptr, - const char *key, size_t key_length, - const unsigned char *bkey, size_t bkey_length, - memcached_coll_eflag_filter_st *eflag_filter, - size_t *count) + const char *key, size_t key_length, + const unsigned char *bkey, size_t bkey_length, + memcached_coll_eflag_filter_st *eflag_filter, + size_t *count) ``` 둘째, b+tree에서 bkey range에 해당하는 element들 중 eflag filter 조건을 만족하는 element 개수를 확인하는 함수이다. -``` c +```c memcached_return_t memcached_bop_count_by_range(memcached_st *ptr, const char *key, size_t key_length, @@ -687,11 +673,11 @@ memcached_bop_count_by_range(memcached_st *ptr, memcached_return_t memcached_bop_ext_count_by_range(memcached_st *ptr, - const char *key, size_t key_length, - const unsigned char *from, size_t from_length, - const unsigned char *to, size_t to_length, - memcached_coll_eflag_filter_st *eflag_filter, - size_t *count) + const char *key, size_t key_length, + const unsigned char *from, size_t from_length, + const unsigned char *to, size_t to_length, + memcached_coll_eflag_filter_st *eflag_filter, + size_t *count) ``` - key, key_length: b+tree item의 key @@ -699,7 +685,6 @@ memcached_bop_ext_count_by_range(memcached_st *ptr, - eflag_filter: element의 eflag에 대한 filter 조건 - count: element 개수가 반환되는 인자 - Response code는 아래와 같다. - MEMCACHED_SUCCESS @@ -709,43 +694,39 @@ Response code는 아래와 같다. - MEMCACHED_TYPE_MISMATCH: 주어진 key에 해당하는 자료구조가 B+tree가 아님. - MEMCACHED_BKEY_MISMATCH: 주어진 bkey 유형과 해당 B+tree의 bkey 유형이 다름. -B+tree element 개수를 확인하는 예제는 아래와 같다. +대표적으로 b+tree에서 bkey range에 해당하는 element들 중 eflag filter 조건을 만족하는 element 개수를 확인하는 예시는 다음과 같다. -``` c -void arcus_btree_element_count(memcached_st *memc) +```c +int arcus_btree_element_count_by_range(memcached_st *memc) { - uint32_t flags= 10; - uint32_t exptime= 600; - uint32_t maxcount= 1000; - - memcached_coll_create_attrs_st attributes; - memcached_coll_create_attrs_init(&attributes, flags, exptime, maxcount); - - memcached_return_t rc; - - // 테스트 데이터를 입력한다. - rc= memcached_bop_insert(memc, "btree:a_btree", strlen("btree:a_btree"), 0, - NULL, 0, "value", strlen("value"), &attributes); - assert(MEMCACHED_SUCCESS == rc); - assert(MEMCACHED_CREATED_STORED == memcached_get_last_response_code(memc)); - - rc= memcached_bop_insert(memc, "btree:a_btree", strlen("btree:a_btree"), 1, - NULL, 0, "value", strlen("value"), &attributes); - assert(MEMCACHED_SUCCESS == rc); - assert(MEMCACHED_STORED == memcached_get_last_response_code(memc)); - - uint32_t bkey_from = 0; - uint32_t bkey_to = 10000; - - memcached_coll_query_st query; - memcached_bop_count_range_query_create(memc, &query, bkey_from, bkey_to, NULL); - - // 범위 안의 element 개수를 요청한다. - size_t count = 0; - rc= memcached_bop_count(memc, "btree:a_btree", strlen("btree:a_btree"), - &query, &count); - assert(MEMCACHED_SUCCESS == rc); - assert(2 == count); + const char *key= "btree:a_key"; + const uint64_t from= 0, to= UINT64_MAX; + /* const unsigned char from[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH]= {0, }; + const unsigned char to[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH] + = {[0 ... MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH - 1] = 0xff}; */ + size_t count= 0; + memcached_return_t rc; + + const size_t comp_offset= 0; + const unsigned char comp_value[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH]= {0, }; + memcached_coll_comp_t comp_op= MEMCACHED_COLL_COMP_EQ; + + memcached_coll_eflag_filter_st eflag_filter; + memcached_coll_eflag_filter_init(&eflag_filter, comp_offset, comp_value, sizeof(comp_value), comp_op); + + rc= memcached_bop_count_by_range(memc, key, strlen(key), from, to, &eflag_filter, &count); + /* rc= memcached_bop_ext_count_by_range(memc, key, strlen(key), + from, sizeof(from), to, sizeof(to), + &eflag_filter, &count); */ + if (memcached_failed(rc)) { + fprintf(stderr, "Failed to memcached_bop_count_by_range: %d(%s)\n", + rc, memcached_strerror(memc, rc)); + return -1; + } + + assert(rc == MEMCACHED_SUCCESS); + fprintf(stdout, "count: %lu\n", count); + return 0; } ``` @@ -755,7 +736,7 @@ B+tree element를 조회하는 함수는 세 유형이 있다. 첫째, b+tree에서 특정 bkey를 가진 element에 대해 eflag filter 조건을 만족하면 조회하는 함수이다. -``` c +```c memcached_return_t memcached_bop_get(memcached_st *ptr, const char *key, size_t key_length, @@ -776,7 +757,7 @@ memcached_bop_ext_get(memcached_st *ptr, 둘째, b+tree에서 bkey range에 해당하는 element들을 스캔하면서 eflag filter 조건을 만족하는 element들 중 offset 개를 skip한 후 count 개의 element를 조회하는 함수이다. -``` c +```c memcached_return_t memcached_bop_get_by_range(memcached_st *ptr, const char *key, size_t key_length, @@ -799,7 +780,7 @@ memcached_bop_ext_get_by_range(memcached_st *ptr, 셋째, query 구조체를 이용하여 b+tree element를 조회하는 함수이다. -``` c +```c memcached_return_t memcached_bop_get_by_query(memcached_st *ptr, const char *key, size_t key_length, @@ -838,8 +819,7 @@ Response code는 아래와 같다. 조회 결과는 memcached_coll_result_t 구조체에 저장된다. 조회 결과에 접근하기 위한 API는 다음과 같다. - -``` c +```c memcached_coll_result_st * memcached_coll_result_create(const memcached_st *ptr, memcached_coll_result_st *result) void @@ -857,57 +837,124 @@ size_t memcached_coll_result_get_value_length(memcached_coll_result_st *result, size_t index) ``` -B+tree element를 조회하는 예제는 아래와 같다. +대표적으로 b+tree에서 bkey range에 해당하는 element들 중 eflag filter 조건을 만족하는 element를 조회하는 예시는 다음과 같다. + +첫째, 각 인자를 직접 API에 전달하는 예시이다. -``` c -void arcus_btree_element_get(memcached_st *memc) +```c +int arcus_btree_element_get_by_range(memcached_st *memc) { - uint32_t flags= 10; - uint32_t exptime= 600; - uint32_t maxcount= 1000; - - memcached_coll_create_attrs_st attributes; - memcached_coll_create_attrs_init(&attributes, flags, exptime, maxcount); - - memcached_return_t rc; - - for (uint32_t i=0; i %s\n", key, bkey, value); + // fprintf(stdout, "memcached_bop_get_by_range: %s : %s => %s\n", key, str_bkey, value); + } + } while(0); - memcached_coll_result_free(result); + memcached_coll_result_free(&result); + return (rc == MEMCACHED_SUCCESS) ? 0 : -1; +} +``` - // 조회와 동시에 조회된 element를 삭제한다. Empty 상태가 된 B+tree는 삭제된다. - result = memcached_coll_result_create(memc, NULL); +둘째, query 구조체를 이용하는 예시이다. - rc= memcached_bop_get_by_range(memc, "btree:a_btree", strlen("btree:a_btree"), - 0, maxcount, - NULL, 0, maxcount, true, false, result); - assert(MEMCACHED_SUCCESS == rc); - assert(MEMCACHED_DELETED_DROPPED == memcached_get_last_response_code(memc)); +```c +int arcus_btree_element_get_by_query(memcached_st *memc) +{ + const char *key= "btree:a_key"; + const uint64_t from= UINT64_MAX, to= 0; + /* const unsigned char from[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH] + = {[0 ... MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH - 1] = 0xff}; + const unsigned char to[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH]= {0, }; */ + const size_t offset= 0; + const size_t count= 0; + bool with_delete= false; + bool drop_if_empty= false; + memcached_coll_result_st result; + memcached_return_t rc; + + const size_t comp_offset= 0; + const unsigned char comp_value[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH]= {0, }; + memcached_coll_comp_t comp_op= MEMCACHED_COLL_COMP_EQ; + + memcached_coll_eflag_filter_st eflag_filter; + memcached_coll_eflag_filter_init(&eflag_filter, comp_offset, comp_value, sizeof(comp_value), comp_op); + + memcached_coll_query_st query; + memcached_bop_range_query_init(&query, from, to, &eflag_filter, offset, count); + // memcached_bop_ext_range_query_init(&query, from, sizeof(from), to, sizeof(to), &eflag_filter, offset, count); + + memcached_coll_result_create(memc, &result); + + do { + rc= memcached_bop_get_by_query(memc, key, strlen(key), &query, + with_delete, drop_if_empty, &result); + if (memcached_failed(rc)) { + fprintf(stderr, "Failed to memcached_bop_get_by_query: %d(%s)\n", rc, memcached_strerror(memc, rc)); + break; + } - for (size_t i=0; i %s\n", key, bkey, value); + // fprintf(stdout, "memcached_bop_get_by_query: %s : %s => %s\n", key, str_bkey, value); } + } while(0); - // 조회 결과를 삭제한다. - memcached_coll_result_free(result); + memcached_coll_result_free(&result); + return (rc == MEMCACHED_SUCCESS) ? 0 : -1; } ``` @@ -918,7 +965,7 @@ B+tree에 여러 element를 한번에 삽입하는 함수는 두 유형이 있 첫째, 하나의 key가 가리키는 b+tree에 다수의 element들을 삽입하는 함수이다. 전자는 8바이트 unsigned integer 타입의 bkey를, 후자는 최대 31 크기의 byte array 타입의 bkey를 사용한다. -``` c +```c memcached_return_t memcached_bop_piped_insert(memcached_st *ptr, const char *key, const size_t key_length, @@ -932,14 +979,14 @@ memcached_bop_piped_insert(memcached_st *ptr, memcached_return_t memcached_bop_ext_piped_insert(memcached_st *ptr, - const char *key, const size_t key_length, - const size_t number_of_piped_items, - const unsigned char * const *bkeys, const size_t *bkeys_length, - const unsigned char * const *eflags, const size_t *eflags_length, - const char * const *values, const size_t *values_length, - memcached_coll_create_attrs_st *attributes, - memcached_return_t *results, - memcached_return_t *piped_rc) + const char *key, const size_t key_length, + const size_t number_of_piped_items, + const unsigned char * const *bkeys, const size_t *bkeys_length, + const unsigned char * const *eflags, const size_t *eflags_length, + const char * const *values, const size_t *values_length, + memcached_coll_create_attrs_st *attributes, + memcached_return_t *results, + memcached_return_t *piped_rc) ``` - key, key_length: b+tree item의 key @@ -952,7 +999,7 @@ memcached_bop_ext_piped_insert(memcached_st *ptr, 둘째, 여러 key들이 가리키는 b+tree들에 각각 하나의 element를 삽입하는 함수이다. 전자는 8바이트 unsigned integer 타입의 bkey를, 후자는 최대 31 크기의 byte array 타입의 bkey를 사용한다. -``` c +```c memcached_return_t memcached_bop_piped_insert_bulk(memcached_st *ptr, const char * const *keys, @@ -995,57 +1042,139 @@ B+tree element 일괄 삽입의 결과는 아래의 인자를 통해 받는다. - MEMCACHED_SOME_SUCCESS: 일부 element가 저장됨. - MEMCACHED_ALL_FAILURE: 전체 element가 저장되지 않음. -B+tree element 일괄 삽입의 예제는 아래와 같다. +B+tree에 여러 element를 한번에 삽입하는 예시는 다음과 같다. + +첫째, 하나의 key가 가리키는 b+tree에 다수의 element들을 삽입하는 예시이다. -``` c -void arcus_btree_element_piped_insert(memcached_st *memc) +```c +int arcus_btree_element_piped_insert(memcached_st *memc) { - uint32_t flags= 10; - uint32_t exptime= 600; - uint32_t maxcount= 500; - - memcached_coll_create_attrs_st attributes; - memcached_coll_create_attrs_init(&attributes, flags, exptime, maxcount); - - memcached_return_t rc; - memcached_return_t piped_rc; - memcached_return_t results[MEMCACHED_COLL_MAX_PIPED_CMD_SIZE]; - - uint64_t bkeys[100]; - unsigned char **eflags = (unsigned char **)malloc(sizeof(unsigned char *) * 100); - size_t eflaglengths[100]; - char **values = (char **)malloc(sizeof(char *) * 100); - size_t valuelengths[100]; - - uint32_t eflag = 0; - int i; - - // pipe 연산에 필요한 argument를 생성한다. - for (i=0; i<100; i++) - { - bkeys[i] = i; - eflags[i] = (unsigned char *)&eflag; - eflaglengths[i] = sizeof(eflag); - values[i] = (char *)malloc(sizeof(char)*15); - valuelengths[i] = snprintf(values[i], 15, "value%llu", (unsigned long long)i); + const char *key= "btree:a_key"; + const char * const values[]= { "value1", "value2", "value3" }; + const uint64_t bkeys[]= { 0, 1, 2 }; + /* unsigned char bkeys[][MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH]= { {0,}, {1, }, {2, } }; + unsigned char *bkeys_ptr[]= { bkeys[0], bkeys[1], bkeys[2] }; */ + unsigned char eflags[3][MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH]= { {0,} }; + unsigned char *eflags_ptr[3]= { eflags[0], eflags[1], eflags[2] }; + size_t number_of_piped_items= 3; + size_t bkeys_len[3]; + size_t values_len[3]; + size_t eflags_len[3]; + memcached_return_t rc; + memcached_return_t piped_rc; + memcached_return_t results[3]; + + uint32_t flags= 0; + uint32_t exptime= 600; + uint32_t maxcount= 1000; + + memcached_coll_create_attrs_st attributes; + memcached_coll_create_attrs_init(&attributes, flags, exptime, maxcount); + + for(size_t i=0; i %s %d(%s)\n", + key, bkeys[i], values[i], results[i], memcached_strerror(memc, results[i])); + /* memcached_hexadecimal_st hex_bkey= { (unsigned char *)bkeys[i], + sizeof(bkeys[i]), { 0 } }; + char str_bkey[MEMCACHED_COLL_MAX_BYTE_STRING_LENGTH]; + memcached_hexadecimal_to_str(&hex_bkey, str_bkey, sizeof(str_bkey)); + fprintf(stderr, "Failed to memcached_bop_piped_insert: %s : %s => %s %d(%s)\n", + key, str_bkey, values[i], results[i], memcached_strerror(memc, results[i])); */ } + } - // 입력할 때 B+Tree가 존재하지 않으면 새로 생성한 뒤 입력한다. - rc= memcached_bop_piped_insert(memc, "btree:a_btree", strlen("btree:a_btree"), - 100, bkeys, eflags, eflaglengths, values, valuelengths, - &attributes, results, &piped_rc); - assert(MEMCACHED_SUCCESS == rc); - assert(MEMCACHED_ALL_SUCCESS == piped_rc); - for (i=0; i<100; i++) - { - assert(MEMCACHED_STORED == results[i] || MEMCACHED_CREATED_STORED == results[i]); - } - for (i=0; i<100; i++) - { - free((void*)values[i]); + assert(rc == MEMCACHED_SUCCESS); + return 0; +} +``` + +둘째, 여러 key들이 가리키는 b+tree들에 각각 하나의 element를 삽입하는 예시이다. + +```c +int arcus_btree_element_piped_insert_bulk(memcached_st *memc) +{ + const char * const keys[]= { "btree:a_key1", "btree:a_key2", "btree:a_key3" }; + const uint64_t bkey= 0; + // const unsigned char bkey[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH]= {0, }; + const char *value= "value"; + const unsigned char eflag[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH]= {0, }; + size_t keys_len[3]; + size_t number_of_keys= 3; + memcached_return_t rc; + memcached_return_t piped_rc; + memcached_return_t results[3]; + + uint32_t flags= 0; + uint32_t exptime= 600; + uint32_t maxcount= 1000; + + memcached_coll_create_attrs_st attributes; + memcached_coll_create_attrs_init(&attributes, flags, exptime, maxcount); + + for (size_t i=0; i %s %d(%s)\n", + keys[i], bkey, value, results[i], memcached_strerror(memc, results[i])); + /* fprintf(stderr, "Failed to memcached_bop_piped_insert_bulk: %s : %s => %s %d(%s)\n", + keys[i], str_bkey, value, results[i], memcached_strerror(memc, results[i])); */ } - free((void*)eflags); - free((void*)values); + } + + assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_SOME_ERRORS); + return 0; } ``` @@ -1059,7 +1188,7 @@ void arcus_btree_element_piped_insert(memcached_st *memc) 첫째 단계로, 다수 b+tree들에 대한 element 조회 요청을 보내는 함수는 아래와 같다. B+tree element 조회 조건는 query 구조체를 이용하여 명시한다. -``` c +```c memcached_return_t memcached_bop_mget(memcached_st *ptr, const char * const *keys, @@ -1082,7 +1211,7 @@ Response code는 아래와 같다. 둘째 단계로, element 조회 결과를 iteration 방식으로 하나씩 가져오기 위한 함수는 아래와 같다. -``` c +```c memcached_coll_result_st * memcached_coll_fetch_result(memcached_st *ptr, memcached_coll_result_st *result, @@ -1104,65 +1233,70 @@ memcached_coll_fetch_result(memcached_st *ptr, - MEMCACHED_TYPE_MISMATCH: 주어진 key에 해당하는 자료구조가 B+tree가 아님. - MEMCACHED_BKEY_MISMATCH: 주어진 bkey 유형과 해당 B+tree의 bkey 유형이 다름. +B+tree element 일괄 조회하는 예시는 아래와 같다. -B+tree element 일괄 조회하는 예제는 아래와 같다. - -``` c -static void arcus_btree_element_mget(memcached_st *memc) +```c +int arcus_btree_element_mget(memcached_st *memc) { - uint32_t flags= 10; - uint32_t exptime= 600; - uint32_t maxcount= 50; - - memcached_coll_create_attrs_st attributes; - memcached_coll_create_attrs_init(&attributes, flags, exptime, maxcount); - - memcached_return_t rc; - - // test data - const char *keys[]= { "btree:a_btree1", "btree:a_btree2", "btree:a_btree3", - "btree:a_btree4", "btree:a_btree5" }; - size_t key_length[] = { 14, 14, 14, 14, 14 }; - - for (size_t i=0; i<3; i++) - { - for (size_t j=0; j %s\n", key, bkey, value); + // fprintf(stderr, "memcached_coll_fetch_result: %s : %s => %s\n", key, str_bkey, value); + } } + memcached_coll_result_free(&result); + } - // query - memcached_bop_query_st query_obj; - memcached_bop_range_query_init(&query_obj, 0, 10000, NULL, 0, maxcount); - - rc= memcached_bop_mget(memc, keys, key_length, 5, &query_obj); - // result - memcached_coll_result_st result_obj; - memcached_coll_result_st *result= memcached_coll_result_create(memc, &result_obj); - - while ((result= memcached_coll_fetch_result(memc, &result_obj, &rc))) - { - if (rc == MEMCACHED_SUCCESS or - rc == MEMCACHED_TRIMMED ) - { - for (size_t i=0; i Hexadecimal 변환을 Big-endian에 맞추기로 하자. - bkeys[i] = htonl(rand()); - } - - memcached_coll_create_attrs_st attributes; - memcached_coll_create_attrs_init(&attributes, 0, 600, 1000); - - // 테스트 데이터를 입력한다. - for (int i=0; i<100; i++) { - uint32_t bkey = bkeys[i]; - uint32_t eflag = 0; - char value[64]; - size_t value_length = snprintf(value, 64, "value_id%d_bkey%u", i, bkey); - - // 여기서는 bkey와 eflag를 uint32_t 타입의 정수(big-endian)로 - // 캐스팅하여 넘겨 주고 있음을 참고하자. - rc = memcached_bop_ext_insert(memc, keys[i], key_length[i], - (unsigned char *)&bkey, sizeof(uint32_t), - (unsigned char *)&eflag, sizeof(eflag), - value, value_length, &attributes); - } - - memcached_coll_smget_result_st smget_result_object; - memcached_coll_smget_result_st *smget_result; - smget_result = memcached_coll_smget_result_create(memc, &smget_result_object); - - uint32_t bkey_from = 0; - uint32_t bkey_to = htonl(UINT32_MAX); - - // byte array bkey에 대해 중복 bkey 허용한 범위 검색 쿼리를 생성한다. - memcached_bop_query_st query; - memcached_bop_ext_smget_query_init(&query, - (unsigned char *)&bkey_from, sizeof(uint32_t), - (unsigned char *)&bkey_to, sizeof(uint32_t), - NULL, 100, false); - - // smget을 수행한다. - rc = memcached_bop_smget(memc, keys, key_length, 100, &query, smget_result); - assert(MEMCACHED_END == memcached_get_last_response_code(memc)); - aseert(100 == memcached_coll_smget_result_get_count(smget_result)); - aseert(0 == memcached_coll_smget_result_get_missed_key_count(smget_result)); - aseert(0 == memcached_coll_smget_result_get_trimmed_key_count(smget_result)); - - if (rc == MEMCACHED_SUCCESS) { - uint32_t last_bkey = bkey_from; - for (uint32_t i=0; isub_keys[i].bkey_ext; - char bkey_buf[64]; - memcached_hexadecimal_to_str(&bkey, bkey_buf, 64); - char eflag_buf[64]; - memcached_hexadecimal_to_str(&smget_result->eflags[i], eflag_buf, 64); - char *rvalue = smget_result->values[i].string; - fprintf(stderr, "key[%s], bkey[%s], eflag[%s] = %s\n", - smget_result->keys[i].string, bkey_buf, eflag_buf, rvalue); - } - } else { - fprintf(stderr, "memcached_bop_smget() failed, reason=%s\n", memcached_strerror(NULL, rc)); - return; - } - - memcached_coll_smget_result_free(smget_result); - - for (int i=0; i<100; i++) { - free((void*)keys[i]); - } + const char * const keys[]= { "btree:a_key1", "btree:a_key2", "btree:a_key3" }; + const uint64_t from= UINT64_MAX, to= 0; + /* const unsigned char from[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH] + = {[0 ... MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH - 1] = 0xff}; + const unsigned char to[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH]= {0, }; */ + size_t number_of_keys= 3; + size_t keys_len[3]; + size_t count= 50; + bool unique= false; + memcached_coll_smget_result_st result; + memcached_return_t rc; + + const size_t comp_offset= 0; + const unsigned char comp_value[MEMCACHED_COLL_MAX_BYTE_ARRAY_LENGTH]= {0, }; + memcached_coll_comp_t comp_op= MEMCACHED_COLL_COMP_EQ; + + memcached_coll_eflag_filter_st eflag_filter; + memcached_coll_eflag_filter_init(&eflag_filter, comp_offset, comp_value, sizeof(comp_value), comp_op); + + memcached_bop_query_st query; + memcached_bop_smget_query_init(&query, from, to, &eflag_filter, count, unique); + /* memcached_bop_ext_smget_query_init(&query, from, sizeof(from), to, sizeof(to), + &eflag_filter, count, unique); */ + + memcached_coll_smget_result_create(memc, &result); + + for(size_t i=0; i %s\n", key, bkey, value); + // fprintf(stdout, "memcached_bop_smget: %s : %s => %s\n", key, str_bkey, value); + } + + for(size_t i=0; i %s\n", key, bkey, value); + } else { + memcached_hexadecimal_st *hex_bkey= memcached_coll_result_get_bkey_ext(&result, i); + char str_bkey[MEMCACHED_COLL_MAX_BYTE_STRING_LENGTH]; + memcached_hexadecimal_to_str(hex_bkey, str_bkey, sizeof(str_bkey)); + fprintf(stdout, "memcached_bop_get_by_position: %s : %s => %s\n", key, str_bkey, value); + } } - memcached_coll_result_free(result); + } while(0); + + memcached_coll_result_free(&result); + return (rc == MEMCACHED_SUCCESS) ? 0 : -1; } ``` @@ -1659,77 +1748,51 @@ Response code는 아래와 같다. - result에 보관된 element들에서 주어진 bkey의 element 위치 - memcached_coll_result_get_result_position(result) API를 통해 조회한다. - B+Tree에서 특정 bkey에 대한 순위 및 element 조회와 함께 -앞뒤 양방향으로 N개 element들을 조회하는 예제는 아래와 같다. +앞뒤 양방향으로 N개 element들을 조회하는 예시는 아래와 같다. ```c -void arcus_btree_find_position_with_get(memcached_st *memc) +int arcus_btree_find_position_with_get(memcached_st *memc) { - uint32_t flags= 10; - uint32_t exptime= 600; - uint32_t maxcount= 1000; - char buffer[16]; - size_t buffer_len; - - memcached_return_t rc; - memcached_coll_result_st *result; - memcached_coll_create_attrs_st attributes; - memcached_coll_create_attrs_init(&attributes, flags, exptime, maxcount); - - // bkey 범위가 0 ~ 999인 1000개 element를 가진 b+tree 생성. - for (uint32_t bkey=0; bkey %s\n", key, bkey, value); + /* fprintf(stdout, "memcached_bop_find_position_with_get: " + "%s : %s => %s\n", key, str_bkey, value); */ } - memcached_coll_result_free(result); + } while(0); + + memcached_coll_result_free(&result); + return (rc == MEMCACHED_SUCCESS) ? 0 : -1; } ```