static lcb_error_t dset_ctx_add(lcb_MULTICMD_CTX *mctx, const lcb_CMDBASE *cmd) { lcb_DURSET *dset = CTX_FROM_MULTI(mctx); lcb_DURITEM *ent; if (LCB_KEYBUF_IS_EMPTY(&cmd->key)) { return LCB_EMPTY_KEY; } /* ensure we have enough space first */ if (dset->nentries == 0) { /* First entry. Optimize */ ent = &dset->single.ent; dset->entries = &dset->single.ent; } else if (dset->nentries == 1) { /* More than a single entry */ dset->ents_alloced = 2; dset->entries = malloc(2 * sizeof(*dset->entries)); if (!dset->entries) { return LCB_CLIENT_ENOMEM; } dset->entries[0] = dset->single.ent; ent = &dset->entries[1]; dset->ht = lcb_hashtable_nc_new(16); if (!dset->ht) { return LCB_CLIENT_ENOMEM; } } else if (dset->nentries < dset->ents_alloced) { ent = &dset->entries[dset->nentries]; } else { lcb_DURITEM *newarr; lcb_SIZE newsize = dset->ents_alloced * 1.5; newarr = realloc(dset->entries, sizeof(*ent) * newsize); if (!newarr) { return LCB_CLIENT_ENOMEM; } dset->entries = newarr; dset->ents_alloced = newsize; ent = &dset->entries[dset->nentries]; } /* ok. now let's initialize the entry..*/ memset(ent, 0, sizeof (*ent)); RESFLD(ent, nkey) = cmd->key.contig.nbytes; ent->hashkey = cmd->hashkey; ent->reqcas = cmd->cas; ent->parent = dset; lcb_string_append(&dset->kvbufs, cmd->key.contig.bytes, cmd->key.contig.nbytes); if (cmd->hashkey.contig.nbytes) { lcb_string_append(&dset->kvbufs, cmd->hashkey.contig.bytes, cmd->hashkey.contig.nbytes); } dset->nentries++; return LCB_SUCCESS; }
LIBCOUCHBASE_API lcb_error_t lcb_durability_poll(lcb_t instance, const void *cookie, const lcb_durability_opts_t *options, lcb_size_t ncmds, const lcb_durability_cmd_t *const *cmds) { hrtime_t now = gethrtime(); lcb_durability_set_t *dset; lcb_size_t ii; lcb_io_opt_t io = instance->settings.io; if (!ncmds) { return LCB_EINVAL; } dset = calloc(1, sizeof(*dset)); if (!dset) { return LCB_CLIENT_ENOMEM; } dset->opts = *options; dset->instance = instance; if (!DSET_OPTFLD(dset, timeout)) { DSET_OPTFLD(dset, timeout) = instance->settings.durability_timeout; } if (-1 == verify_critera(instance, dset)) { free(dset); return LCB_DURABILITY_ETOOMANY; } /* set our timeouts now */ dset->us_timeout = (lcb_uint32_t)(now / 1000) + DSET_OPTFLD(dset, timeout); dset->timer = io->v.v0.create_timer(io); dset->cookie = cookie; dset->nentries = ncmds; dset->nremaining = ncmds; /** Get the timings */ if (!DSET_OPTFLD(dset, interval)) { DSET_OPTFLD(dset, interval) = LCB_DEFAULT_DURABILITY_INTERVAL; } /* list of observe commands to schedule */ if (dset->nentries == 1) { dset->entries = &dset->single.ent; dset->valid_entries = &dset->single.entp; } else { dset->ht = lcb_hashtable_nc_new(dset->nentries); dset->entries = calloc(dset->nentries, sizeof(*dset->entries)); dset->valid_entries = malloc(dset->nentries * sizeof(*dset->valid_entries)); if (dset->entries == NULL || dset->valid_entries == NULL) { lcb_durability_dset_destroy(dset); return LCB_CLIENT_ENOMEM; } } /* set up the observe commands */ for (ii = 0; ii < dset->nentries; ii++) { lcb_durability_entry_t *ent = dset->entries + ii; ent_init(cmds[ii], ent); ent->parent = dset; if (dset->nentries > 1) { int mt = genhash_update(dset->ht, REQFLD(ent, key), REQFLD(ent, nkey), ent, 0); if (mt != NEW) { lcb_durability_dset_destroy(dset); return LCB_DUPLICATE_COMMANDS; } } } /** * Increase the refcount by one. This will be decremented * when the remaining_total count hits 0 */ dset_ref(dset); hashset_add(instance->durability_polls, dset); timer_schedule(dset, 0, STATE_OBSPOLL); return lcb_synchandler_return(instance, LCB_SUCCESS); }