PHP_COUCHBASE_LOCAL void pcbc_ht_storeb(zval *assoc, const char *key, int nkey, zend_bool value) { pcbc_ht_key hk; pcbc_ht_key_create(key, nkey, &hk); pcbc_ht_hkstoreb(assoc, &hk, value); pcbc_ht_key_cleanup(&hk); }
PHP_COUCHBASE_LOCAL void pcbc_ht_key_free(pcbc_ht_key *info) { if (!info) { return; } pcbc_ht_key_cleanup(info); efree(info); }
PHP_COUCHBASE_LOCAL zval *pcbc_ht_find(zval *assoc, const char *key, int key_len) { zval *ret; pcbc_ht_key hk = { NULL }; pcbc_ht_key_create(key, key_len, &hk); ret = pcbc_ht_hkfind(assoc, &hk); pcbc_ht_key_cleanup(&hk); return ret; }
PHP_COUCHBASE_LOCAL void pcbc_ht_del(zval *assoc, const char *key, unsigned int key_len) { pcbc_ht_key hk = { NULL }; ISARRAY_SANITY(assoc); pcbc_ht_key_create(key, key_len, &hk); zend_hash_del(Z_ARRVAL_P(assoc), hk.key, hk.key_len + 1); pcbc_ht_key_cleanup(&hk); }
/** * Populate the snapshot results from the observe operations * @param res the couchbase object * @param ocoll the observe collection * @param abools an array (or single) boolean * @param adetails an array of details to be indexed by key * @param multi boolean param - this determines whether abools is a scalar or * an array */ static void oks_populate_results(php_couchbase_res *res, struct observe_collection *ocoll, zval *abools, zval *adetails, int multi) { int ii; if (multi && IS_ARRAY != Z_TYPE_P(abools)) { array_init(abools); } for (ii = 0; ii < ocoll->nks; ii++) { /* get the key */ pcbc_ht_key reski; zval *tmpary; struct observe_keystate *oks = ocoll->ks + ii; pcbc_ht_key_create( oks->ocmd.v.v0.key, oks->ocmd.v.v0.nkey, &reski); if (multi) { pcbc_ht_hkstoreb(abools, &reski, oks_get_boolval(oks)); } else { if (oks_get_boolval(oks)) { ZVAL_TRUE(abools); } else { ZVAL_FALSE(abools); } } if (adetails != NULL) { ALLOC_INIT_ZVAL(tmpary); array_init(tmpary); oks_to_zvarray(oks, tmpary); pcbc_ht_hkstorez(adetails, &reski, tmpary); } pcbc_ht_key_cleanup(&reski); } }
PHP_COUCHBASE_LOCAL int pcbc_ht_exists(zval *assoc, const char *key, int key_len) { pcbc_ht_key hk = { NULL }; const char *zh_key; int zh_nkey; int ret; ISARRAY_SANITY(assoc); pcbc_ht_key_create(key, key_len, &hk); HK_STRING(&hk, zh_key, zh_nkey); ret = zend_hash_exists(Z_ARRVAL_P(assoc), zh_key, zh_nkey); pcbc_ht_key_cleanup(&hk); return ret; }
PHP_COUCHBASE_LOCAL void php_couchbase_observe_impl(INTERNAL_FUNCTION_PARAMETERS, int multi, int oo, int poll) { zval *adurability = NULL, *adetails = NULL; /* zval passed by ref, will be stuffed with details if given */ php_couchbase_res *couchbase_res; struct observe_collection ocoll = { 0 }; struct observe_expectation expect = { 0 }; struct observe_pollprefs pollprefs; int argflags = oo ? PHP_COUCHBASE_ARG_F_OO : PHP_COUCHBASE_ARG_F_FUNCTIONAL; /* param handling, return value setup */ if (multi) { zval *akey_to_cas; if (poll) { PHP_COUCHBASE_GET_PARAMS(couchbase_res, argflags, "aa", &akey_to_cas, &adurability); } else { PHP_COUCHBASE_GET_PARAMS(couchbase_res, argflags, "a|z", &akey_to_cas, &adetails); } array_init(return_value); if (poll) { if (-1 == oks_extract_durability(couchbase_res, &expect, &pollprefs, adurability)) { RETURN_FALSE; } } if (-1 == oks_build_context(couchbase_res, &ocoll, &expect, akey_to_cas, 1)) { RETURN_FALSE; } } else { /* single */ char *key = NULL; long nkey = 0; zval *cas; zval *akc_dummy = NULL; pcbc_ht_key dummy_hk; lcb_cas_t tmpcas = 0; ZVAL_FALSE(return_value); if (poll) { PHP_COUCHBASE_GET_PARAMS(couchbase_res, argflags, "sza", &key, &nkey, &cas, &adurability); } else { PHP_COUCHBASE_GET_PARAMS(couchbase_res, argflags, "sz|z", &key, &nkey, &cas, &adetails); } if (adetails && IS_ARRAY != Z_TYPE_P(adetails)) { array_init(adetails); } if (key == NULL || nkey == 0) { /* empty key */ RETURN_FALSE; } make_prefixed_hk(couchbase_res, key, nkey, &dummy_hk); tmpcas = cas_from_zval(cas); if (tmpcas == -1) { pcbc_ht_key_cleanup(&dummy_hk); RETURN_FALSE; } ALLOC_INIT_ZVAL(akc_dummy); array_init(akc_dummy); if (tmpcas) { pcbc_ht_hkstores(akc_dummy, &dummy_hk, Z_STRVAL_P(cas), Z_STRLEN_P(cas)); } else { pcbc_ht_hkstoreb(akc_dummy, &dummy_hk, 0); } /* Weird block right here to sanely free the structures allocated */ { int have_failure = 0; do { if (poll) { if (-1 == oks_extract_durability(couchbase_res, &expect, &pollprefs, adurability)) { have_failure = 1; break; } } if (-1 == oks_build_context( couchbase_res, &ocoll, &expect, akc_dummy, 0)) { have_failure = 1; break; } } while (0); /** >> CLEANUP HERE */ zval_ptr_dtor(&akc_dummy); pcbc_ht_key_cleanup(&dummy_hk); if (have_failure) { RETURN_FALSE; } } } if (adetails && Z_TYPE_P(adetails) != IS_ARRAY) { array_init(adetails); } if (poll) { observe_poll(couchbase_res, &ocoll, &pollprefs); } else { observe_iterate(couchbase_res, &ocoll); } oks_populate_results(couchbase_res, &ocoll, return_value, adetails, multi); oks_cleanup_context(&ocoll); }
/** * Populate an observe collection with the appropriate key contexts * @param res the couchbase object * @param ocoll an already allocated collection object * @param akc a zend array mapping keys to their expected CAS values * @param expectation an array of durability requirements * @param append_prefix - whether the keys should be appended with the * couchbase-level prefix */ static int oks_build_context(php_couchbase_res *res, struct observe_collection *ocoll, struct observe_expectation *expectation, zval *akc, int append_prefix) { int nks, ix; struct observe_keystate *ks; nks = pcbc_ht_len(akc); ks = ecalloc(sizeof(*ks), nks); for (ix = 0, pcbc_ht_iter_init(akc); pcbc_ht_iter_remaining(akc); pcbc_ht_iter_next(akc), ix++) { pcbc_ht_entry *kv = pcbc_ht_iter_entry(akc); struct observe_keystate *oks = ks + ix; if (kv->key_info->key_len == 0) { ix--; continue; } oks->parent = ocoll; if (expectation) { oks->expected = *expectation; } if ((oks->expected.cas = cas_from_zval(kv->data)) == -1) { pcbc_ht_entry_free(kv); goto GT_CLEANUP; } if (append_prefix && res->prefix_key_len && ocoll->prefix_appended == 0) { pcbc_ht_key prefixed_ki; make_prefixed_hk(res, kv->key_info->key, kv->key_info->key_len, &prefixed_ki); oks->ocmd.v.v0.nkey = prefixed_ki.key_len; oks->ocmd.v.v0.key = emalloc(prefixed_ki.key_len); memcpy((char *)oks->ocmd.v.v0.key, prefixed_ki.key, prefixed_ki.key_len); pcbc_ht_key_cleanup(&prefixed_ki); } else { oks->ocmd.v.v0.key = emalloc(kv->key_info->key_len); oks->ocmd.v.v0.nkey = kv->key_info->key_len; memcpy((char *)oks->ocmd.v.v0.key, kv->key_info->key, oks->ocmd.v.v0.nkey); } pcbc_ht_entry_free(kv); if (append_prefix && res->prefix_key_len) { ocoll->prefix_appended = 1; } } ocoll->ks = ks; ocoll->nks = ix; ocoll->remaining = ocoll->nks; ocoll->res = res; return 0; GT_CLEANUP: for (ix = 0; ix < nks; ix++) { struct observe_keystate *oks = ks + ix; if (oks->ocmd.v.v0.key) { efree((void *) oks->ocmd.v.v0.key); } } efree(ks); return -1; }