Beispiel #1
0
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);
}