Beispiel #1
0
/**
 * Ensure that the user-specified criteria is possible; i.e. we have enough
 * servers and replicas. If the user requested capping, we do that here too.
 */
static int verify_critera(lcb_t instance, lcb_DURSET *dset)
{
    lcb_durability_opts_t *options = &dset->opts;

    int replica_max = LCBT_NREPLICAS(instance);
    int persist_max = replica_max + 1;

    /* persist_max is always one more than replica_max */
    if ((int)OPTFLD(options, persist_to) > persist_max) {
        if (OPTFLD(options, cap_max)) {
            OPTFLD(options, persist_to) = persist_max;

        } else {
            return -1;
        }
    }

    if (OPTFLD(options, replicate_to) == 0) {
        return 0;
    }

    if (replica_max < 0) {
        replica_max = 0;
    }
    /* now, we need at least as many nodes as we have replicas */
    if ((int)OPTFLD(options, replicate_to) > replica_max) {
        if (OPTFLD(options, cap_max)) {
            OPTFLD(options, replicate_to) = replica_max;
        } else {
            return -1;
        }
    }

    return 0;
}
Beispiel #2
0
void
lcbdur_prepare_item(lcb_DURITEM *ent, lcb_U16 *ixarray, size_t *nitems)
{
    size_t ii, oix = 0, maxix = 0;
    lcb_DURSET *dset = ent->parent;
    lcb_t instance = dset->instance;
    lcbvb_CONFIG *vbc = LCBT_VBCONFIG(instance);

    RESFLD(ent, persisted_master) = 0;
    RESFLD(ent, exists_master) = 0;
    RESFLD(ent, npersisted) = 0;
    RESFLD(ent, nreplicated) = 0;
    RESFLD(ent, cas) = 0;
    RESFLD(ent, rc) = LCB_SUCCESS;

    if (DSET_OPTFLD(dset, persist_to) == 1 &&
            DSET_OPTFLD(dset, replicate_to) == 0) {
        maxix = 1; /* Only master! */
    } else {
        maxix = LCBT_NREPLICAS(instance) + 1;
    }

    for (ii = 0; ii < maxix; ii++) {
        int cur_ix;
        lcbdur_SERVINFO *info = &ent->sinfo[ii];
        const mc_SERVER *s_exp;

        cur_ix = lcbvb_vbserver(vbc, ent->vbid, ii);
        if (cur_ix < 0) {
            memset(info, 0, sizeof(*info));
            continue;
        }

        s_exp = LCBT_GET_SERVER(instance, cur_ix);
        if (s_exp != info->server) {
            memset(info, 0, sizeof(*info));

        } else if (server_criteria_satisfied(ent, info, ii==0)) {
            /* Update counters as required */
            if (ii == 0) {
                RESFLD(ent, exists_master) = 1;
            } else {
                RESFLD(ent, nreplicated)++;
            }

            if (info->persisted) {
                RESFLD(ent, npersisted)++;
                if (ii == 0) {
                    RESFLD(ent, persisted_master) = 1;
                }
            }
            continue;
        }

        /* Otherwise, write the expected server out */
        ixarray[oix++] = s_exp->pipeline.index;
    }
    *nitems = oix;
}
Beispiel #3
0
LIBCOUCHBASE_API
lcb_int32_t lcb_get_num_replicas(lcb_t instance)
{
    if (LCBT_VBCONFIG(instance)) {
        return LCBT_NREPLICAS(instance);
    } else {
        return -1;
    }
}
Beispiel #4
0
lcbdur_SERVINFO *
lcbdur_ent_getinfo(lcb_DURITEM *item, int srvix)
{
    size_t ii;
    lcb_t instance = item->parent->instance;

    for (ii = 0; ii < LCBT_NREPLICAS(instance)+1; ii++) {
        int ix = lcbvb_vbserver(LCBT_VBCONFIG(instance), item->vbid, ii);
        if (ix > -1 && ix == srvix) {
            return &item->sinfo[ii];
        }
    }
    return NULL;
}
Beispiel #5
0
LIBCOUCHBASE_API
lcb_error_t
lcb_durability_validate(lcb_t instance,
    lcb_U16 *persist_to, lcb_U16 *replicate_to, int options)
{
    int replica_max = DUR_MIN(
        LCBT_NREPLICAS(instance),
        LCBT_NDATASERVERS(instance)-1);
    int persist_max = replica_max + 1;

    if (*persist_to == 0 && *replicate_to == 0) {
        /* Empty values! */
        return LCB_EINVAL;
    }

    /* persist_max is always one more than replica_max */
    if ((int)*persist_to > persist_max) {
        if (options & LCB_DURABILITY_VALIDATE_CAPMAX) {
            *persist_to = persist_max;
        } else {
            return LCB_DURABILITY_ETOOMANY;
        }
    }

    if (*replicate_to == 0) {
        return LCB_SUCCESS;
    }

    if (replica_max < 0) {
        replica_max = 0;
    }

    /* now, we need at least as many nodes as we have replicas */
    if ((int)*replicate_to > replica_max) {
        if (options & LCB_DURABILITY_VALIDATE_CAPMAX) {
            *replicate_to = replica_max;
        } else {
            return LCB_DURABILITY_ETOOMANY;
        }
    }
    return LCB_SUCCESS;

}
Beispiel #6
0
LIBCOUCHBASE_API
lcb_error_t
lcb_rget3(lcb_t instance, const void *cookie, const lcb_CMDGETREPLICA *cmd)
{
    /**
     * Because we need to direct these commands to specific servers, we can't
     * just use the 'basic_packet()' function.
     */
    mc_CMDQUEUE *cq = &instance->cmdq;
    int vbid, ixtmp;
    protocol_binary_request_header req;
    unsigned r0, r1 = 0;
    rget_cookie *rck = NULL;

    if (LCB_KEYBUF_IS_EMPTY(&cmd->key)) {
        return LCB_EMPTY_KEY;
    }
    if (!cq->config) {
        return LCB_CLIENT_ETMPFAIL;
    }
    if (!LCBT_NREPLICAS(instance)) {
        return LCB_NO_MATCHING_SERVER;
    }

    mcreq_map_key(cq, &cmd->key, &cmd->_hashkey, MCREQ_PKT_BASESIZE,
        &vbid, &ixtmp);

    /* The following blocks will also validate that the entire index range is
     * valid. This is in order to ensure that we don't allocate the cookie
     * if there aren't enough replicas online to satisfy the requirements */

    if (cmd->strategy == LCB_REPLICA_SELECT) {
        r0 = r1 = cmd->index;
        if ((ixtmp = lcbvb_vbreplica(cq->config, vbid, r0)) < 0) {
            return LCB_NO_MATCHING_SERVER;
        }

    } else if (cmd->strategy == LCB_REPLICA_ALL) {
        unsigned ii;
        r0 = 0;
        r1 = LCBT_NREPLICAS(instance);
        /* Make sure they're all online */
        for (ii = 0; ii < LCBT_NREPLICAS(instance); ii++) {
            if ((ixtmp = lcbvb_vbreplica(cq->config, vbid, ii)) < 0) {
                return LCB_NO_MATCHING_SERVER;
            }
        }
    } else {
        for (r0 = 0; r0 < LCBT_NREPLICAS(instance); r0++) {
            if ((ixtmp = lcbvb_vbreplica(cq->config, vbid, r0)) > -1) {
                r1 = r0;
                break;
            }
        }
        if (r0 == LCBT_NREPLICAS(instance)) {
            return LCB_NO_MATCHING_SERVER;
        }
    }

    if (r1 < r0 || r1 >= cq->npipelines) {
        return LCB_NO_MATCHING_SERVER;
    }

    /* Initialize the cookie */
    rck = calloc(1, sizeof(*rck));
    rck->base.cookie = cookie;
    rck->base.start = gethrtime();
    rck->base.procs = &rget_procs;
    rck->strategy = cmd->strategy;
    rck->r_cur = r0;
    rck->r_max = LCBT_NREPLICAS(instance);
    rck->instance = instance;
    rck->vbucket = vbid;

    /* Initialize the packet */
    req.request.magic = PROTOCOL_BINARY_REQ;
    req.request.opcode = PROTOCOL_BINARY_CMD_GET_REPLICA;
    req.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
    req.request.vbucket = htons((lcb_uint16_t)vbid);
    req.request.cas = 0;
    req.request.extlen = 0;
    req.request.keylen = htons((lcb_uint16_t)cmd->key.contig.nbytes);
    req.request.bodylen = htonl((lcb_uint32_t)cmd->key.contig.nbytes);

    do {
        int curix;
        mc_PIPELINE *pl;
        mc_PACKET *pkt;

        curix = lcbvb_vbreplica(cq->config, vbid, r0);
        /* XXX: this is always expected to be in range. For the FIRST mode
         * it will seek to the first valid index (checked above), and for the
         * ALL mode, it will fail if not all replicas are already online
         * (also checked above) */
        pl = cq->pipelines[curix];
        pkt = mcreq_allocate_packet(pl);
        if (!pkt) {
            return LCB_CLIENT_ENOMEM;
        }

        pkt->u_rdata.exdata = &rck->base;
        pkt->flags |= MCREQ_F_REQEXT;

        mcreq_reserve_key(pl, pkt, sizeof(req.bytes), &cmd->key);

        req.request.opaque = pkt->opaque;
        rck->remaining++;
        mcreq_write_hdr(pkt, &req);
        mcreq_sched_add(pl, pkt);
    } while (++r0 < r1);

    return LCB_SUCCESS;
}