Skip to content

Commit c7f426e

Browse files
committed
PCBC-799: implement {get,upsert,remove}Multi
Change-Id: Iab9372024c899698baef8df8469bd33e00dbd4e1 Reviewed-on: https://review.couchbase.org/c/php-couchbase/+/167017 Tested-by: Build Bot <[email protected]> Reviewed-by: Sergey Avseyev <[email protected]>
1 parent 7d197e8 commit c7f426e

File tree

12 files changed

+990
-6
lines changed

12 files changed

+990
-6
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
*.dep
12
*.core
23
*.lo
34
*.loT

api/couchbase.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1824,6 +1824,35 @@ public function lookupIn(string $id, array $specs, LookupInOptions $options = nu
18241824
*/
18251825
public function mutateIn(string $id, array $specs, MutateInOptions $options = null): MutateInResult {}
18261826

1827+
/**
1828+
* Retrieves a group of documents. If the document does not exist, it will not raise an exception, but rather fill
1829+
* non-null value in error() property of the corresponding result object.
1830+
*
1831+
* @param array $ids array of IDs, organized like this ["key1", "key2", ...]
1832+
* @param GetOptions $options the options to use for the operation
1833+
* @return array array of GetResult, one for each of the entries
1834+
*/
1835+
public function getMulti(array $ids, RemoveOptions $options = null): array {}
1836+
1837+
/**
1838+
* Removes a group of documents. If second element of the entry (CAS) is null, then the operation will
1839+
* remove the document unconditionally.
1840+
*
1841+
* @param array $entries array of arrays, organized like this [["key1", "encodedCas1"], ["key2", , "encodedCas2"], ...] or ["key1", "key2", ...]
1842+
* @param RemoveOptions $options the options to use for the operation
1843+
* @return array array of MutationResult, one for each of the entries
1844+
*/
1845+
public function removeMulti(array $entries, RemoveOptions $options = null): array {}
1846+
1847+
/**
1848+
* Creates a group of documents if they don't exist, otherwise updates them.
1849+
*
1850+
* @param array $entries array of arrays, organized like this [["key1", $value1], ["key2", $value2], ...]
1851+
* @param UpsertOptions $options the options to use for the operation
1852+
* @return array array of MutationResult, one for each of the entries
1853+
*/
1854+
public function upsertMulti(array $entries, UpsertOptions $options = null): array {}
1855+
18271856
/**
18281857
* Creates and returns a BinaryCollection object for use with binary type documents.
18291858
*

config.m4

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,15 +87,18 @@ COUCHBASE_FILES=" \
8787
src/couchbase/bucket/exists.c \
8888
src/couchbase/bucket/expiry_util.c \
8989
src/couchbase/bucket/get.c \
90+
src/couchbase/bucket/get_multi.c \
9091
src/couchbase/bucket/get_replica.c \
9192
src/couchbase/bucket/health.c \
9293
src/couchbase/bucket/http.c \
9394
src/couchbase/bucket/n1ql.c \
9495
src/couchbase/bucket/remove.c \
96+
src/couchbase/bucket/remove_multi.c \
9597
src/couchbase/bucket/store.c \
9698
src/couchbase/bucket/subdoc.c \
9799
src/couchbase/bucket/touch.c \
98100
src/couchbase/bucket/unlock.c \
101+
src/couchbase/bucket/upsert_multi.c \
99102
src/couchbase/bucket/view.c \
100103
src/couchbase/cert_authenticator.c \
101104
src/couchbase/cluster.c \

config.w32

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,18 @@ if (PHP_COUCHBASE != "no") {
4343
"exists.c " +
4444
"expiry_util.c " +
4545
"get.c " +
46+
"get_multi.c " +
4647
"get_replica.c " +
4748
"health.c " +
4849
"http.c " +
4950
"n1ql.c " +
5051
"remove.c " +
52+
"remove_multi.c " +
5153
"store.c " +
5254
"subdoc.c " +
5355
"touch.c " +
5456
"unlock.c " +
57+
"upsert_multi.c " +
5558
"view.c ";
5659
src_couchbase_managers_sources =
5760
"bucket_manager.c " +

couchbase.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,9 @@ PHP_MINIT_FUNCTION(CollectionTouch);
246246
PHP_MINIT_FUNCTION(CollectionCounter);
247247
PHP_MINIT_FUNCTION(CollectionRemove);
248248
PHP_MINIT_FUNCTION(CollectionSubdoc);
249+
PHP_MINIT_FUNCTION(CollectionGetMulti);
250+
PHP_MINIT_FUNCTION(CollectionRemoveMulti);
251+
PHP_MINIT_FUNCTION(CollectionUpsertMulti);
249252
PHP_MINIT_FUNCTION(BucketView);
250253
PHP_MINIT_FUNCTION(N1qlQuery);
251254
PHP_MINIT_FUNCTION(ViewIndexManager);
@@ -329,6 +332,9 @@ PHP_MINIT_FUNCTION(couchbase)
329332
PHP_MINIT(CollectionCounter)(INIT_FUNC_ARGS_PASSTHRU);
330333
PHP_MINIT(CollectionRemove)(INIT_FUNC_ARGS_PASSTHRU);
331334
PHP_MINIT(CollectionSubdoc)(INIT_FUNC_ARGS_PASSTHRU);
335+
PHP_MINIT(CollectionGetMulti)(INIT_FUNC_ARGS_PASSTHRU);
336+
PHP_MINIT(CollectionRemoveMulti)(INIT_FUNC_ARGS_PASSTHRU);
337+
PHP_MINIT(CollectionUpsertMulti)(INIT_FUNC_ARGS_PASSTHRU);
332338
PHP_MINIT(BucketView)(INIT_FUNC_ARGS_PASSTHRU);
333339
PHP_MINIT(N1qlQuery)(INIT_FUNC_ARGS_PASSTHRU);
334340
PHP_MINIT(ViewIndexManager)(INIT_FUNC_ARGS_PASSTHRU);
@@ -367,8 +373,7 @@ PHP_MINIT_FUNCTION(couchbase)
367373
#define X(name, value, cls, f, s) \
368374
{ \
369375
ap_php_snprintf(buf, sizeof(buf), "COUCHBASE_%s", #name + 4); \
370-
zend_register_long_constant(buf, PCBC_CONST_LENGTH(buf), value, CONST_CS | CONST_PERSISTENT, \
371-
module_number); \
376+
zend_register_long_constant(buf, PCBC_CONST_LENGTH(buf), value, CONST_CS | CONST_PERSISTENT, module_number); \
372377
}
373378

374379
LCB_XERROR(X)
@@ -942,8 +947,7 @@ PHP_FUNCTION(zlibCompress)
942947
ZVAL_STRINGL(return_value, dataOut, 4 + dataOutSize);
943948
efree(dataOut);
944949
#else
945-
zend_throw_exception(NULL, "The zlib library was not available when the couchbase extension was built.",
946-
0);
950+
zend_throw_exception(NULL, "The zlib library was not available when the couchbase extension was built.", 0);
947951
#endif
948952
}
949953

@@ -967,8 +971,7 @@ PHP_FUNCTION(zlibDecompress)
967971
ZVAL_STRINGL(return_value, dataOut, dataOutSize);
968972
efree(dataOut);
969973
#else
970-
zend_throw_exception(NULL, "The zlib library was not available when the couchbase extension was built.",
971-
0);
974+
zend_throw_exception(NULL, "The zlib library was not available when the couchbase extension was built.", 0);
972975
#endif
973976
}
974977

package.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,16 +78,19 @@
7878
<file role="src" name="src/couchbase/bucket/expiry_util.c" />
7979
<file role="src" name="src/couchbase/bucket/expiry_util.h" />
8080
<file role="src" name="src/couchbase/bucket/get.c" />
81+
<file role="src" name="src/couchbase/bucket/get_multi.c" />
8182
<file role="src" name="src/couchbase/bucket/get_replica.c" />
8283
<file role="src" name="src/couchbase/bucket/health.c" />
8384
<file role="src" name="src/couchbase/bucket/http.c" />
8485
<file role="src" name="src/couchbase/bucket/n1ql.c" />
8586
<file role="src" name="src/couchbase/bucket/remove.c" />
87+
<file role="src" name="src/couchbase/bucket/remove_multi.c" />
8688
<file role="src" name="src/couchbase/bucket/store.c" />
8789
<file role="src" name="src/couchbase/bucket/subdoc.c" />
8890
<file role="src" name="src/couchbase/bucket/subdoc_cookie.h" />
8991
<file role="src" name="src/couchbase/bucket/touch.c" />
9092
<file role="src" name="src/couchbase/bucket/unlock.c" />
93+
<file role="src" name="src/couchbase/bucket/upsert_multi.c" />
9194
<file role="src" name="src/couchbase/bucket/view.c" />
9295
<file role="src" name="src/couchbase/cert_authenticator.c" />
9396
<file role="src" name="src/couchbase/cluster.c" />

src/couchbase/bucket/get_multi.c

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/**
2+
* Copyright 2021 Couchbase, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "couchbase.h"
18+
19+
#define LOGARGS(instance, lvl) LCB_LOG_##lvl, instance, "pcbc/get_multi", __FILE__, __LINE__
20+
21+
extern zend_class_entry *pcbc_get_result_impl_ce;
22+
extern zend_class_entry *pcbc_get_options_ce;
23+
24+
struct get_multi_cookie {
25+
lcb_STATUS rc;
26+
zval *return_value;
27+
size_t index;
28+
};
29+
30+
void get_multi_callback(lcb_INSTANCE *instance, int cbtype, const lcb_RESPGET *resp)
31+
{
32+
struct get_multi_cookie *cookie = NULL;
33+
const lcb_KEY_VALUE_ERROR_CONTEXT *ectx = NULL;
34+
lcb_respget_cookie(resp, (void **)&cookie);
35+
zval *return_value = zend_hash_index_find(HASH_OF(cookie->return_value), cookie->index);
36+
if (return_value == NULL) {
37+
cookie->rc = LCB_ERR_INVALID_RANGE;
38+
return;
39+
}
40+
cookie->rc = lcb_respget_status(resp);
41+
pcbc_update_property_long(pcbc_get_result_impl_ce, return_value, ("status"), cookie->rc);
42+
lcb_respget_error_context(resp, &ectx);
43+
44+
set_property_str(ectx, lcb_errctx_kv_context, pcbc_get_result_impl_ce, "err_ctx");
45+
set_property_str(ectx, lcb_errctx_kv_ref, pcbc_get_result_impl_ce, "err_ref");
46+
set_property_str(ectx, lcb_errctx_kv_key, pcbc_get_result_impl_ce, "key");
47+
if (cookie->rc == LCB_SUCCESS) {
48+
set_property_num(uint32_t, lcb_respget_flags, pcbc_get_result_impl_ce, "flags");
49+
set_property_num(uint8_t, lcb_respget_datatype, pcbc_get_result_impl_ce, "datatype");
50+
set_property_str(resp, lcb_respget_value, pcbc_get_result_impl_ce, "data");
51+
{
52+
uint64_t data;
53+
lcb_respget_cas(resp, &data);
54+
zend_string *b64;
55+
b64 = php_base64_encode((unsigned char *)&data, sizeof(data));
56+
pcbc_update_property_str(pcbc_get_result_impl_ce, return_value, ("cas"), b64);
57+
zend_string_release(b64);
58+
}
59+
}
60+
(void)instance;
61+
(void)cbtype;
62+
}
63+
64+
PHP_METHOD(Collection, getMulti)
65+
{
66+
zval *ids = NULL;
67+
zval *options = NULL;
68+
69+
int rv = zend_parse_parameters_throw(ZEND_NUM_ARGS(), "A|O!", &ids, &options, pcbc_get_options_ce);
70+
if (rv == FAILURE) {
71+
RETURN_NULL();
72+
}
73+
PCBC_RESOLVE_COLLECTION;
74+
75+
zval decoder = {0};
76+
ZVAL_NULL(&decoder);
77+
zend_long timeout = 0;
78+
if (options) {
79+
zval ret;
80+
const zval *prop;
81+
prop = pcbc_read_property(pcbc_get_options_ce, options, ("timeout"), 0, &ret);
82+
if (Z_TYPE_P(prop) == IS_LONG) {
83+
timeout = Z_LVAL_P(prop);
84+
}
85+
prop = pcbc_read_property(pcbc_get_options_ce, options, ("decoder"), 0, &ret);
86+
if (Z_TYPE_P(prop) != IS_NULL) {
87+
ZVAL_COPY(&decoder, prop);
88+
}
89+
}
90+
91+
lcbtrace_SPAN *span = NULL;
92+
lcbtrace_TRACER *tracer = lcb_get_tracer(bucket->conn->lcb);
93+
if (tracer) {
94+
span = lcbtrace_span_start(tracer, "php/" LCBTRACE_OP_GET "_multi", 0, NULL);
95+
lcbtrace_span_add_tag_str(span, LCBTRACE_TAG_COMPONENT, pcbc_client_string);
96+
lcbtrace_span_add_tag_str(span, LCBTRACE_TAG_SERVICE, LCBTRACE_TAG_SERVICE_KV);
97+
}
98+
99+
size_t num_of_ids = zend_hash_num_elements(Z_ARRVAL_P(ids));
100+
struct get_multi_cookie *cookies = calloc(num_of_ids, sizeof(struct get_multi_cookie));
101+
array_init_size(return_value, num_of_ids);
102+
lcb_sched_enter(bucket->conn->lcb);
103+
const zval *id;
104+
lcb_STATUS err = LCB_SUCCESS;
105+
size_t index = 0;
106+
ZEND_HASH_FOREACH_VAL(HASH_OF(ids), id)
107+
{
108+
if (Z_TYPE_P(id) != IS_STRING) {
109+
err = LCB_ERR_INVALID_ARGUMENT;
110+
lcb_sched_fail(bucket->conn->lcb);
111+
break;
112+
}
113+
zval result;
114+
object_init_ex(&result, pcbc_get_result_impl_ce);
115+
add_next_index_zval(return_value, &result);
116+
cookies[index].rc = LCB_SUCCESS;
117+
cookies[index].return_value = return_value;
118+
cookies[index].index = index;
119+
pcbc_update_property(pcbc_get_result_impl_ce, &result, ("decoder"),
120+
Z_TYPE(decoder) == IS_NULL ? &bucket->decoder : &decoder);
121+
122+
lcb_CMDGET *cmd;
123+
lcb_cmdget_create(&cmd);
124+
lcb_cmdget_collection(cmd, scope_str, scope_len, collection_str, collection_len);
125+
lcb_cmdget_key(cmd, Z_STRVAL_P(id), Z_STRLEN_P(id));
126+
if (timeout > 0) {
127+
lcb_cmdget_timeout(cmd, timeout);
128+
}
129+
if (span) {
130+
lcb_cmdget_parent_span(cmd, span);
131+
}
132+
err = lcb_get(bucket->conn->lcb, &cookies[index], cmd);
133+
lcb_cmdget_destroy(cmd);
134+
if (err != LCB_SUCCESS) {
135+
lcb_sched_fail(bucket->conn->lcb);
136+
break;
137+
}
138+
++index;
139+
}
140+
ZEND_HASH_FOREACH_END();
141+
lcb_sched_leave(bucket->conn->lcb);
142+
143+
if (err == LCB_SUCCESS) {
144+
lcb_RESPCALLBACK prev_cb =
145+
lcb_install_callback(bucket->conn->lcb, LCB_CALLBACK_GET, (lcb_RESPCALLBACK)get_multi_callback);
146+
lcb_wait(bucket->conn->lcb, LCB_WAIT_DEFAULT);
147+
lcb_install_callback(bucket->conn->lcb, LCB_CALLBACK_GET, prev_cb);
148+
}
149+
free(cookies);
150+
151+
if (span) {
152+
lcbtrace_span_finish(span, LCBTRACE_NOW);
153+
}
154+
if (err != LCB_SUCCESS) {
155+
throw_lcb_exception(err, NULL);
156+
}
157+
}
158+
159+
PHP_MINIT_FUNCTION(CollectionGetMulti)
160+
{
161+
return SUCCESS;
162+
}
163+
164+
/*
165+
* vim: et ts=4 sw=4 sts=4
166+
*/

0 commit comments

Comments
 (0)