/** * 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; }
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; }
LIBCOUCHBASE_API lcb_int32_t lcb_get_num_replicas(lcb_t instance) { if (LCBT_VBCONFIG(instance)) { return LCBT_NREPLICAS(instance); } else { return -1; } }
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; }
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; }
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; }