lcb_error_t lcb_n1p_mutation_token(lcb_N1QLPARAMS *params, const lcb_MUTATION_TOKEN *sv) { size_t np; if (params->scanvec_type == SCANVEC_FULL) { return LCB_OPTIONS_CONFLICT; } params->consist_type = LCB_N1P_CONSISTENCY_RYOW; /* Reserve data: */ if (-1 == lcb_string_reserve(¶ms->scanvec, SCANVEC_BASE_SIZE)) { return LCB_CLIENT_ENOMEM; } if (!params->scanvec.nused) { lcb_string_append(¶ms->scanvec, "{", 1); } else { lcb_string_append(¶ms->scanvec, ",", 1); } np = sprintf(params->scanvec.base + params->scanvec.nused, SCANVEC_BASEFMT, sv->vbid_, (unsigned long long)sv->uuid_, (unsigned long long)sv->seqno_); lcb_string_added(¶ms->scanvec, np); params->scanvec_type = SCANVEC_PARTIAL; return LCB_SUCCESS; }
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; }
static void sanitize_config( const lcb_string *src, const char *host, lcb_string *dst) { char *cur = src->base, *last = src->base; while ((cur = strstr(cur, HOST_TOKEN))) { lcb_string_append(dst, last, cur-last); lcb_string_appendz(dst, host); cur += sizeof(HOST_TOKEN)-1; last = cur; } lcb_string_append(dst, last, src->base + src->nalloc - last); }
lcb_error_t lcb_n1p_posparam(lcb_N1QLPARAMS *params, const char *value, size_t nvalue) { nvalue = get_strlen(value, nvalue); if (-1 == lcb_string_reserve(¶ms->posargs, nvalue+3)) { return LCB_CLIENT_ENOMEM; } if (!params->posargs.nused) { lcb_string_append(¶ms->posargs, "[", 1); } else { lcb_string_append(¶ms->posargs, ",", 1); } lcb_string_append(¶ms->posargs, value, nvalue); return LCB_SUCCESS; }
void lcb_cccp_update2(const void *cookie, lcb_error_t err, const void *bytes, lcb_size_t nbytes, const lcb_host_t *origin) { cccp_cookie *ck = (cccp_cookie *)cookie; cccp_provider *cccp = ck->parent; if (err == LCB_SUCCESS) { lcb_string ss; lcb_string_init(&ss); lcb_string_append(&ss, bytes, nbytes); err = lcb_cccp_update(&cccp->base, origin->host, &ss); lcb_string_release(&ss); if (err != LCB_SUCCESS && ck->ignore_errors == 0) { mcio_error(cccp, err); } } else if (!ck->ignore_errors) { mcio_error(cccp, err); } if (ck == cccp->cmdcookie) { cccp->cmdcookie = NULL; } free(ck); }
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; int vbid, srvix; if (LCB_KEYBUF_IS_EMPTY(&cmd->key)) { return LCB_EMPTY_KEY; } LCB_SSOBUF_ALLOC(&ent, &dset->entries_, lcb_DURITEM); if (!ent) { return LCB_CLIENT_ENOMEM; } mcreq_map_key(&dset->instance->cmdq, &cmd->key, &cmd->_hashkey, MCREQ_PKT_BASESIZE, &vbid, &srvix); /* ok. now let's initialize the entry..*/ memset(ent, 0, sizeof (*ent)); RESFLD(ent, nkey) = cmd->key.contig.nbytes; ent->reqcas = cmd->cas; ent->parent = dset; ent->vbid = vbid; lcb_string_append(&dset->kvbufs, cmd->key.contig.bytes, cmd->key.contig.nbytes); if (DSET_PROCS(dset)->ent_add) { return DSET_PROCS(dset)->ent_add(dset, ent, (lcb_CMDENDURE*)cmd); } else { return LCB_SUCCESS; } }
/** * Invoked when get a NOT_MY_VBUCKET response. If the response contains a JSON * payload then we refresh the configuration with it. * * This function returns 1 if the operation was successfully rescheduled; * otherwise it returns 0. If it returns 0 then we give the error back to the * user. */ static int handle_nmv(mc_SERVER *oldsrv, packet_info *resinfo, mc_PACKET *oldpkt) { mc_PACKET *newpkt; protocol_binary_request_header hdr; lcb_error_t err = LCB_ERROR; lcb_t instance = oldsrv->instance; lcb_U16 vbid; clconfig_provider *cccp = lcb_confmon_get_provider(instance->confmon, LCB_CLCONFIG_CCCP); mcreq_read_hdr(oldpkt, &hdr); vbid = ntohs(hdr.request.vbucket); lcb_log(LOGARGS(oldsrv, WARN), LOGFMT "NOT_MY_VBUCKET. Packet=%p (S=%u). VBID=%u", LOGID(oldsrv), (void*)oldpkt, oldpkt->opaque, vbid); /* Notify of new map */ lcb_vbguess_remap(instance, vbid, oldsrv->pipeline.index); if (PACKET_NBODY(resinfo) && cccp->enabled) { lcb_string s; lcb_string_init(&s); lcb_string_append(&s, PACKET_VALUE(resinfo), PACKET_NVALUE(resinfo)); err = lcb_cccp_update(cccp, mcserver_get_host(oldsrv), &s); lcb_string_release(&s); } if (err != LCB_SUCCESS) { int bs_options; if (instance->cur_configinfo->origin == LCB_CLCONFIG_CCCP) { /** * XXX: Not enough to see if cccp was enabled, since cccp might * be requested by a user, but would still not actually be active * for clusters < 2.5 If our current config is from CCCP * then we can be fairly certain that CCCP is indeed working. * * For this reason, we don't use if (cccp->enabled) {...} */ bs_options = LCB_BS_REFRESH_THROTTLE; } else { bs_options = LCB_BS_REFRESH_ALWAYS; } lcb_bootstrap_common(instance, bs_options); } if (!lcb_should_retry(oldsrv->settings, oldpkt, LCB_NOT_MY_VBUCKET)) { return 0; } /** Reschedule the packet again .. */ newpkt = mcreq_renew_packet(oldpkt); newpkt->flags &= ~MCREQ_STATE_FLAGS; lcb_retryq_nmvadd(instance->retryq, (mc_EXPACKET*)newpkt); return 1; }
static lcb_error_t finalize_field(lcb_N1QLPARAMS *params, lcb_string *ss, const char *field, const char *term) { if (ss->nused == 0) { return LCB_SUCCESS; } if (-1 == lcb_string_append(ss, term, 1)) { return LCB_CLIENT_ENOMEM; } return lcb_n1p_setopt(params, field, -1, ss->base, ss->nused); }
static lcb_error_t parse_body(struct htvb_st *vbs, int *done) { lcb_error_t err = LCB_BUSY; char *term; if ((err = parse_chunk(vbs)) != LCB_SUCCESS) { *done = 1; /* no data */ lcb_assert(err == LCB_BUSY); return err; } if (lcb_string_append(&vbs->input, vbs->chunk.base, vbs->chunk_size)) { return LCB_CLIENT_ENOMEM; } lcb_string_erase_end(&vbs->input, 2); lcb_string_erase_beginning(&vbs->chunk, vbs->chunk_size); vbs->chunk_size = (lcb_size_t) - 1; if (vbs->chunk.nused > 0) { *done = 0; } term = strstr(vbs->input.base, "\n\n\n\n"); if (term != NULL) { lcb_string tmp; lcb_error_t ret; /** Next input */ lcb_string_init(&tmp); lcb_string_appendz(&tmp, term + 4); *term = '\0'; ret = set_next_config(vbs); /** Now, erase everything until the end of the 'term' */ if (vbs->input.base) { lcb_string_release(&vbs->input); } lcb_string_transfer(&tmp, &vbs->input); return ret; } return err; }
static lcb_error_t setopt(lcb_N1QLPARAMS *params, const char *k, size_t nk, const char *v, size_t nv, lcb_string *target) { nv = get_strlen(v, nv); nk = get_strlen(k, nk); /* Do we need the '&'? */ if (params->form.nused) { if (-1 == lcb_string_append(target, "&", 1)) { return LCB_CLIENT_ENOMEM; } } if (-1 == add_encstr(target, k, nk)) { return LCB_CLIENT_ENOMEM; } if (-1 == lcb_string_append(target, "=", 1)) { return LCB_CLIENT_ENOMEM; } if (-1 == add_encstr(target, v, nv)) { return LCB_CLIENT_ENOMEM; } return LCB_SUCCESS; }
/** * Invoked when get a NOT_MY_VBUCKET response. If the response contains a JSON * payload then we refresh the configuration with it. * * This function returns 1 if the operation was successfully rescheduled; * otherwise it returns 0. If it returns 0 then we give the error back to the * user. */ static int handle_nmv(mc_SERVER *oldsrv, packet_info *resinfo, mc_PACKET *oldpkt) { mc_PACKET *newpkt; protocol_binary_request_header hdr; lcb_error_t err = LCB_ERROR; lcb_t instance = oldsrv->instance; lcb_U16 vbid; int tmpix; clconfig_provider *cccp = lcb_confmon_get_provider(instance->confmon, LCB_CLCONFIG_CCCP); mcreq_read_hdr(oldpkt, &hdr); vbid = ntohs(hdr.request.vbucket); lcb_log(LOGARGS(oldsrv, WARN), LOGFMT "NOT_MY_VBUCKET. Packet=%p (S=%u). VBID=%u", LOGID(oldsrv), (void*)oldpkt, oldpkt->opaque, vbid); /* Notify of new map */ tmpix = lcb_vbguess_remap(LCBT_VBCONFIG(instance), instance->vbguess, vbid, oldsrv->pipeline.index); if (tmpix > -1 && tmpix != oldsrv->pipeline.index) { lcb_log(LOGARGS(oldsrv, TRACE), LOGFMT "Heuristically set IX=%d as master for VBID=%u", LOGID(oldsrv), tmpix, vbid); } if (PACKET_NBODY(resinfo) && cccp->enabled) { lcb_string s; lcb_string_init(&s); lcb_string_append(&s, PACKET_VALUE(resinfo), PACKET_NVALUE(resinfo)); err = lcb_cccp_update(cccp, mcserver_get_host(oldsrv), &s); lcb_string_release(&s); } if (err != LCB_SUCCESS) { lcb_bootstrap_common(instance, LCB_BS_REFRESH_ALWAYS); } if (!lcb_should_retry(oldsrv->settings, oldpkt, LCB_NOT_MY_VBUCKET)) { return 0; } /** Reschedule the packet again .. */ newpkt = mcreq_renew_packet(oldpkt); newpkt->flags &= ~MCREQ_STATE_FLAGS; lcb_retryq_add(instance->retryq, (mc_EXPACKET*)newpkt, LCB_NOT_MY_VBUCKET); return 1; }
static lcb_error_t obs_ctxadd(lcb_MULTICMD_CTX *mctx, const lcb_CMDOBSERVE *cmd) { const void *hk; lcb_SIZE nhk; int vbid; unsigned maxix; int ii; OBSERVECTX *ctx = CTX_FROM_MULTI(mctx); lcb_t instance = ctx->instance; mc_CMDQUEUE *cq = &instance->cmdq; if (LCB_KEYBUF_IS_EMPTY(&cmd->key)) { return LCB_EMPTY_KEY; } if (cq->config == NULL) { return LCB_CLIENT_ETMPFAIL; } if (LCBVB_DISTTYPE(LCBT_VBCONFIG(instance)) != LCBVB_DIST_VBUCKET) { return LCB_NOT_SUPPORTED; } mcreq_extract_hashkey(&cmd->key, &cmd->_hashkey, 24, &hk, &nhk); vbid = lcbvb_k2vb(cq->config, hk, nhk); maxix = LCBVB_NREPLICAS(cq->config); for (ii = -1; ii < (int)maxix; ++ii) { struct observe_st *rr; lcb_U16 vb16, klen16; int ix; if (ii == -1) { ix = lcbvb_vbmaster(cq->config, vbid); if (ix < 0) { return LCB_NO_MATCHING_SERVER; } } else { ix = lcbvb_vbreplica(cq->config, vbid, ii); if (ix < 0) { continue; } } lcb_assert(ix < (int)ctx->nrequests); rr = ctx->requests + ix; if (!rr->allocated) { if (!init_request(rr)) { return LCB_CLIENT_ENOMEM; } } vb16 = htons((lcb_U16)vbid); klen16 = htons((lcb_U16)cmd->key.contig.nbytes); lcb_string_append(&rr->body, &vb16, sizeof vb16); lcb_string_append(&rr->body, &klen16, sizeof klen16); lcb_string_append(&rr->body, cmd->key.contig.bytes, cmd->key.contig.nbytes); ctx->remaining++; if (cmd->cmdflags & LCB_CMDOBSERVE_F_MASTER_ONLY) { break; } } return LCB_SUCCESS; }
static int load_cache(file_provider *provider) { lcb_string str; char line[1024]; lcb_ssize_t nr; int fail; FILE *fp = NULL; lcbvb_CONFIG *config = NULL; char *end; struct stat st; int status = -1; lcb_string_init(&str); if (provider->filename == NULL) { return -1; } fp = fopen(provider->filename, "r"); if (fp == NULL) { int save_errno = errno; lcb_log(LOGARGS(provider, ERROR), LOGFMT "Couldn't open for reading: %s", LOGID(provider), strerror(save_errno)); return -1; } if (fstat(fileno(fp), &st)) { provider->last_errno = errno; goto GT_DONE; } if (provider->last_mtime == st.st_mtime) { lcb_log(LOGARGS(provider, WARN), LOGFMT "Modification time too old", LOGID(provider)); goto GT_DONE; } config = lcbvb_create(); if (config == NULL) { goto GT_DONE; } lcb_string_init(&str); while ((nr = fread(line, 1, sizeof(line), fp)) > 0) { if (lcb_string_append(&str, line, nr)) { goto GT_DONE; } } if (ferror(fp)) { goto GT_DONE; } fclose(fp); fp = NULL; if (!str.nused) { status = -1; goto GT_DONE; } end = strstr(str.base, CONFIG_CACHE_MAGIC); if (end == NULL) { lcb_log(LOGARGS(provider, ERROR), LOGFMT "Couldn't find magic", LOGID(provider)); if (!provider->ro_mode) { remove(provider->filename); } status = -1; goto GT_DONE; } fail = lcbvb_load_json(config, str.base); if (fail) { status = -1; lcb_log(LOGARGS(provider, ERROR), LOGFMT "Couldn't parse configuration", LOGID(provider)); lcb_log_badconfig(LOGARGS(provider, ERROR), config, str.base); if (!provider->ro_mode) { remove(provider->filename); } goto GT_DONE; } if (lcbvb_get_distmode(config) != LCBVB_DIST_VBUCKET) { status = -1; lcb_log(LOGARGS(provider, ERROR), LOGFMT "Not applying cached memcached config", LOGID(provider)); goto GT_DONE; } if (strcmp(config->bname, PROVIDER_SETTING(&provider->base, bucket)) != 0) { status = -1; lcb_log(LOGARGS(provider, ERROR), LOGFMT "Bucket name in file is different from the one requested", LOGID(provider)); } if (provider->config) { lcb_clconfig_decref(provider->config); } provider->config = lcb_clconfig_create(config, LCB_CLCONFIG_FILE); provider->config->cmpclock = gethrtime(); provider->config->origin = provider->base.type; provider->last_mtime = st.st_mtime; status = 0; config = NULL; GT_DONE: if (fp != NULL) { fclose(fp); } if (config != NULL) { lcbvb_destroy(config); } lcb_string_release(&str); return status; }
/** * It's assumed the server buffers will be reset upon close(), so we must make * sure to _not_ release the ringbuffer if that happens. */ static void handle_read(lcbio_CTX *ioctx, unsigned nb) { mc_pSESSREQ sreq = lcbio_ctx_data(ioctx); packet_info info; unsigned required; uint16_t status; sreq_STATE state = SREQ_S_WAIT; int rc; GT_NEXT_PACKET: memset(&info, 0, sizeof(info)); rc = lcb_pktinfo_ectx_get(&info, ioctx, &required); if (rc == 0) { LCBIO_CTX_RSCHEDULE(ioctx, required); return; } else if (rc < 0) { state = SREQ_S_ERROR; } status = PACKET_STATUS(&info); switch (PACKET_OPCODE(&info)) { case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS: { lcb_string str; int saslrc; const char *mechlist_data; unsigned int nmechlist_data; if (lcb_string_init(&str)) { set_error_ex(sreq, LCB_CLIENT_ENOMEM, NULL); state = SREQ_S_ERROR; break; } if (lcb_string_append(&str, info.payload, PACKET_NBODY(&info))) { lcb_string_release(&str); set_error_ex(sreq, LCB_CLIENT_ENOMEM, NULL); state = SREQ_S_ERROR; break; } saslrc = set_chosen_mech(sreq, &str, &mechlist_data, &nmechlist_data); if (saslrc == 0) { if (0 == send_sasl_auth(sreq, mechlist_data, nmechlist_data)) { state = SREQ_S_WAIT; } else { state = SREQ_S_ERROR; } } else if (saslrc < 0) { state = SREQ_S_ERROR; } else { state = SREQ_S_HELLODONE; } lcb_string_release(&str); break; } case PROTOCOL_BINARY_CMD_SASL_AUTH: { if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) { send_hello(sreq); state = SREQ_S_AUTHDONE; break; } if (status != PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE) { set_error_ex(sreq, LCB_AUTH_ERROR, "SASL AUTH failed"); state = SREQ_S_ERROR; break; } if (send_sasl_step(sreq, &info) == 0 && send_hello(sreq) == 0) { state = SREQ_S_WAIT; } else { state = SREQ_S_ERROR; } break; } case PROTOCOL_BINARY_CMD_SASL_STEP: { if (status != PROTOCOL_BINARY_RESPONSE_SUCCESS) { lcb_log(LOGARGS(sreq, WARN), SESSREQ_LOGFMT "SASL auth failed with STATUS=0x%x", SESSREQ_LOGID(sreq), status); set_error_ex(sreq, LCB_AUTH_ERROR, "SASL Step Failed"); state = SREQ_S_ERROR; } else { /* Wait for pipelined HELLO response */ state = SREQ_S_AUTHDONE; } break; } case PROTOCOL_BINARY_CMD_HELLO: { state = SREQ_S_HELLODONE; if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) { parse_hello(sreq, &info); } else if (status == PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND || status == PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED) { lcb_log(LOGARGS(sreq, DEBUG), SESSREQ_LOGFMT "Server does not support HELLO", SESSREQ_LOGID(sreq)); /* nothing */ } else { set_error_ex(sreq, LCB_PROTOCOL_ERROR, "Hello response unexpected"); state = SREQ_S_ERROR; } break; } default: { state = SREQ_S_ERROR; lcb_log(LOGARGS(sreq, ERROR), SESSREQ_LOGFMT "Received unknown response. OP=0x%x. RC=0x%x", SESSREQ_LOGID(sreq), PACKET_OPCODE(&info), PACKET_STATUS(&info)); set_error_ex(sreq, LCB_NOT_SUPPORTED, "Received unknown response"); break; } } lcb_pktinfo_ectx_done(&info, ioctx); if (sreq->err != LCB_SUCCESS) { bail_pending(sreq); } else if (state == SREQ_S_ERROR) { set_error_ex(sreq, LCB_ERROR, "FIXME: Error code set without description"); } else if (state == SREQ_S_HELLODONE) { negotiation_success(sreq); } else { goto GT_NEXT_PACKET; } (void)nb; }
lcb_error_t lcb_host_parse(lcb_host_t *host, const char *spec, int speclen, int deflport) { lcb_string zspec; char *host_s; char *port_s; char *delim; /** Parse the host properly */ if (speclen < 0) { speclen = strlen(spec); } else if (speclen == 0) { return LCB_INVALID_HOST_FORMAT; } if (deflport < 1) { return LCB_INVALID_HOST_FORMAT; } if (lcb_string_init(&zspec)) { return LCB_CLIENT_ENOMEM; } if (lcb_string_append(&zspec, spec, speclen)) { lcb_string_release(&zspec); return LCB_CLIENT_ENOMEM; } host_s = zspec.base; if (*host_s == ':') { lcb_string_release(&zspec); return LCB_INVALID_HOST_FORMAT; } if ( (delim = strstr(host_s, "://"))) { host_s = delim + 3; } if ((delim = strstr(host_s, "/"))) { *delim = '\0'; } port_s = strstr(host_s, ":"); if (port_s != NULL) { char *endp; long ll; *port_s = '\0'; port_s++; if (! *port_s) { lcb_string_release(&zspec); return LCB_INVALID_HOST_FORMAT; } ll = strtol(port_s, &endp, 10); if (ll == LONG_MIN || ll == LONG_MAX) { lcb_string_release(&zspec); return LCB_INVALID_HOST_FORMAT; } if (*endp) { lcb_string_release(&zspec); return LCB_INVALID_HOST_FORMAT; } } else { port_s = ""; } if (strlen(host_s) > sizeof(host->host)-1 || strlen(port_s) > sizeof(host->port)-1 || *host_s == '\0') { lcb_string_release(&zspec); return LCB_INVALID_HOST_FORMAT; } { lcb_size_t ii, hostlen = strlen(host_s); for (ii = 0; ii < hostlen; ii++) { if (isalnum(host_s[ii])) { continue; } switch (host_s[ii]) { case '.': case '-': case '_': break; default: lcb_string_release(&zspec); return LCB_INVALID_HOST_FORMAT; } } } strcpy(host->host, host_s); if (*port_s) { strcpy(host->port, port_s); } else { sprintf(host->port, "%d", deflport); } lcb_string_release(&zspec); return LCB_SUCCESS; }
lcb_error_t hostlist_add_string(hostlist_t hostlist, const char *spec, int speclen, int deflport) { lcb_error_t err = LCB_SUCCESS; lcb_string str; char *delim; char *curstart; if (speclen < 0) { speclen = strlen(spec); } if (lcb_string_init(&str)) { return LCB_CLIENT_ENOMEM; } if (lcb_string_append(&str, spec, speclen)) { lcb_string_release(&str); return LCB_CLIENT_ENOMEM; } if (!str.nused) { lcb_string_release(&str); return LCB_SUCCESS; } if (str.base[str.nused-1] != ';') { if (lcb_string_appendz(&str, ";")) { lcb_string_release(&str); return LCB_CLIENT_ENOMEM; } } curstart = str.base; while ( (delim = strstr(curstart, ";"))) { lcb_host_t curhost; lcb_size_t curlen; if (delim == curstart) { curstart++; continue; } /** { 'f', 'o', 'o', ';' } */ curlen = delim - curstart; err = lcb_host_parse(&curhost, curstart, curlen, deflport); if (err != LCB_SUCCESS) { break; } err = hostlist_add_host(hostlist, &curhost); if (err != LCB_SUCCESS) { break; } curstart = delim + 1; } lcb_string_release(&str); return err; }
static void io_read_handler(lcb_connection_t conn) { packet_info pi; cccp_provider *cccp = conn->data; lcb_string jsonstr; lcb_error_t err; int rv; lcb_host_t curhost; memset(&pi, 0, sizeof(pi)); rv = lcb_packet_read_ringbuffer(&pi, conn->input); if (rv < 0) { LOG(cccp, ERR, "Couldn't parse packet!?"); mcio_error(cccp, LCB_EINTERNAL); return; } else if (rv == 0) { lcb_sockrw_set_want(conn, LCB_READ_EVENT, 1); lcb_sockrw_apply_want(conn); return; } if (PACKET_STATUS(&pi) != PROTOCOL_BINARY_RESPONSE_SUCCESS) { lcb_log(LOGARGS(cccp, ERR), "CCCP Packet responded with 0x%x; nkey=%d, nbytes=%lu, cmd=0x%x, seq=0x%x", PACKET_STATUS(&pi), PACKET_NKEY(&pi), PACKET_NBODY(&pi), PACKET_OPCODE(&pi), PACKET_OPAQUE(&pi)); switch (PACKET_STATUS(&pi)) { case PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED: case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND: mcio_error(cccp, LCB_NOT_SUPPORTED); break; default: mcio_error(cccp, LCB_PROTOCOL_ERROR); break; } return; } if (!PACKET_NBODY(&pi)) { mcio_error(cccp, LCB_PROTOCOL_ERROR); return; } if (lcb_string_init(&jsonstr)) { mcio_error(cccp, LCB_CLIENT_ENOMEM); return; } if (lcb_string_append(&jsonstr, PACKET_BODY(&pi), PACKET_NBODY(&pi))) { mcio_error(cccp, LCB_CLIENT_ENOMEM); return; } curhost = *lcb_connection_get_host(&cccp->connection); lcb_packet_release_ringbuffer(&pi, conn->input); release_socket(cccp, 1); err = lcb_cccp_update(&cccp->base, curhost.host, &jsonstr); lcb_string_release(&jsonstr); if (err == LCB_SUCCESS) { lcb_timer_disarm(cccp->timer); cccp->server_active = 0; } else { schedule_next_request(cccp, LCB_PROTOCOL_ERROR, 0); } }
/** * Returns 1 if retried, 0 if the command should fail, -1 for an internal * error */ static int handle_not_my_vbucket(lcb_server_t *c, packet_info *resinfo, protocol_binary_request_header *oldreq, struct lcb_command_data_st *oldct) { int idx; char *body; lcb_size_t nbody, nr; lcb_server_t *new_srv; struct lcb_command_data_st ct; protocol_binary_request_header req; hrtime_t now; lcb_string config_string; lcb_error_t err = LCB_ERROR; lcb_log(LOGARGS(c, WARN), "NOT_MY_VBUCKET; Server=%p,ix=%d,real_start=%lu,vb=%d", (void *)c, c->index, (unsigned long)oldct->real_start, (int)ntohs(oldreq->request.vbucket)); lcb_string_init(&config_string); if (PACKET_NBODY(resinfo)) { lcb_string_append(&config_string, PACKET_VALUE(resinfo), PACKET_NVALUE(resinfo)); err = lcb_cccp_update(lcb_confmon_get_provider(c->instance->confmon, LCB_CLCONFIG_CCCP), c->curhost.host, &config_string); } lcb_string_release(&config_string); if (err != LCB_SUCCESS) { lcb_bootstrap_refresh(c->instance); } /* re-schedule command to new server */ if (!c->instance->settings.vb_noguess) { idx = vbucket_found_incorrect_master(c->instance->vbucket_config, ntohs(oldreq->request.vbucket), (int)c->index); } else { idx = c->index; } if (idx == -1) { lcb_log(LOGARGS(c, ERR), "no alternate server"); return 0; } lcb_log(LOGARGS(c, INFO), "Mapped key to new server %d -> %d", c->index, idx); now = gethrtime(); if (oldct->real_start) { hrtime_t min_ok = now - MCSERVER_TIMEOUT(c) * 1000; if (oldct->real_start < min_ok) { /** Timed out in a 'natural' manner */ return 0; } } req = *oldreq; lcb_assert((lcb_size_t)idx < c->instance->nservers); new_srv = c->instance->servers + idx; nr = ringbuffer_read(&c->cmd_log, req.bytes, sizeof(req)); lcb_assert(nr == sizeof(req)); req.request.opaque = ++c->instance->seqno; nbody = ntohl(req.request.bodylen); body = malloc(nbody); if (body == NULL) { lcb_error_handler(c->instance, LCB_CLIENT_ENOMEM, NULL); return -1; } nr = ringbuffer_read(&c->cmd_log, body, nbody); lcb_assert(nr == nbody); nr = ringbuffer_read(&c->output_cookies, &ct, sizeof(ct)); lcb_assert(nr == sizeof(ct)); /* Preserve the cookie and reset timestamp for the command. This * means that the library will retry the command until it will * get code different from LCB_NOT_MY_VBUCKET */ if (!ct.real_start) { ct.real_start = ct.start; } ct.start = now; lcb_server_retry_packet(new_srv, &ct, &req, sizeof(req)); /* FIXME dtrace instrumentation */ lcb_server_write_packet(new_srv, body, nbody); lcb_server_end_packet(new_srv); lcb_server_send_packets(new_srv); free(body); return 1; }
static int load_cache(file_provider *provider) { lcb_string str; char line[1024]; lcb_ssize_t nr; int fail; FILE *fp = NULL; VBUCKET_CONFIG_HANDLE config = NULL; char *end; struct stat st; int status = -1; lcb_string_init(&str); if (provider->filename == NULL) { return -1; } fp = fopen(provider->filename, "r"); if (fp == NULL) { LOG(provider, ERROR, "Couldn't open filename"); return -1; } if (fstat(fileno(fp), &st)) { provider->last_errno = errno; goto GT_DONE; } if (provider->last_mtime == st.st_mtime) { LOG(provider, INFO, "Rejecting file. Modification time too old"); goto GT_DONE; } config = vbucket_config_create(); if (config == NULL) { goto GT_DONE; } lcb_string_init(&str); while ((nr = fread(line, 1, sizeof(line), fp)) > 0) { if (lcb_string_append(&str, line, nr)) { goto GT_DONE; } } if (ferror(fp)) { goto GT_DONE; } fclose(fp); fp = NULL; if (!str.nused) { status = -1; goto GT_DONE; } end = strstr(str.base, CONFIG_CACHE_MAGIC); if (end == NULL) { LOG(provider, ERROR, "Couldn't find magic in file"); remove(provider->filename); status = -1; goto GT_DONE; } fail = vbucket_config_parse(config, LIBVBUCKET_SOURCE_MEMORY, str.base); if (fail) { status = -1; LOG(provider, ERROR, "Couldn't parse configuration"); remove(provider->filename); goto GT_DONE; } if (vbucket_config_get_distribution_type(config) != VBUCKET_DISTRIBUTION_VBUCKET) { status = -1; LOG(provider, ERROR, "Not applying cached memcached config"); goto GT_DONE; } if (provider->config) { lcb_clconfig_decref(provider->config); } provider->config = lcb_clconfig_create(config, &str, LCB_CLCONFIG_FILE); provider->config->cmpclock = gethrtime(); provider->config->origin = provider->base.type; provider->last_mtime = st.st_mtime; status = 0; config = NULL; GT_DONE: if (fp != NULL) { fclose(fp); } if (config != NULL) { vbucket_config_destroy(config); } lcb_string_release(&str); return status; }
static lcb_error_t obs_ctxadd(lcb_MULTICMD_CTX *mctx, const lcb_CMDBASE *cmdbase) { int vbid, srvix_dummy; unsigned ii; const lcb_CMDOBSERVE *cmd = (const lcb_CMDOBSERVE *)cmdbase; OBSERVECTX *ctx = CTX_FROM_MULTI(mctx); lcb_t instance = ctx->instance; mc_CMDQUEUE *cq = &instance->cmdq; lcb_U16 servers_s[4]; const lcb_U16 *servers; size_t nservers; if (LCB_KEYBUF_IS_EMPTY(&cmd->key)) { return LCB_EMPTY_KEY; } if (cq->config == NULL) { return LCB_CLIENT_ETMPFAIL; } if (LCBVB_DISTTYPE(LCBT_VBCONFIG(instance)) != LCBVB_DIST_VBUCKET) { return LCB_NOT_SUPPORTED; } mcreq_map_key(cq, &cmd->key, &cmd->_hashkey, 24, &vbid, &srvix_dummy); if (cmd->servers_) { servers = cmd->servers_; nservers = cmd->nservers_; } else { nservers = 0; servers = servers_s; /* Replicas are always < 4 */ for (ii = 0; ii < LCBVB_NREPLICAS(cq->config) + 1; ii++) { int ix = lcbvb_vbserver(cq->config, vbid, ii); if (ix < 0) { if (ii == 0) { return LCB_NO_MATCHING_SERVER; } else { continue; } } servers_s[nservers++] = ix; if (cmd->cmdflags & LCB_CMDOBSERVE_F_MASTER_ONLY) { break; /* Only a single server! */ } } } if (nservers == 0) { return LCB_NO_MATCHING_SERVER; } for (ii = 0; ii < nservers; ii++) { lcb_string *rr; lcb_U16 vb16, klen16; lcb_U16 ix = servers[ii]; lcb_assert(ix < ctx->nrequests); rr = ctx->requests + ix; if (0 != lcb_string_reserve(rr, 4 + cmd->key.contig.nbytes)) { return LCB_CLIENT_ENOMEM; } vb16 = htons((lcb_U16)vbid); klen16 = htons((lcb_U16)cmd->key.contig.nbytes); lcb_string_append(rr, &vb16, sizeof vb16); lcb_string_append(rr, &klen16, sizeof klen16); lcb_string_append(rr, cmd->key.contig.bytes, cmd->key.contig.nbytes); ctx->remaining++; } return LCB_SUCCESS; }
LIBCOUCHBASE_API const char * lcb_n1p_encode(lcb_N1QLPARAMS *params, lcb_error_t *err) { lcb_error_t err_s = LCB_SUCCESS; if (!err) { err = &err_s; } /* Build the query */ lcb_string_clear(¶ms->reqbuf); if (!params->form.nused) { *err = LCB_EINVAL; return NULL; } if (-1 == lcb_string_append( ¶ms->reqbuf, params->form.base, params->form.nused)) { *err = LCB_CLIENT_ENOMEM; return NULL; } if ((*err = finalize_field(params, ¶ms->posargs, "args", "]")) != LCB_SUCCESS) { return NULL; } if (params->scanvec.nused) { if (params->consist_type != LCB_N1P_CONSISTENCY_RYOW) { *err = LCB_OPTIONS_CONFLICT; return NULL; } if ((*err = finalize_field(params, ¶ms->scanvec, "scan_vector", "}")) != LCB_SUCCESS) { return NULL; } } if (params->consist_type) { if (-1 == lcb_string_reserve(¶ms->reqbuf, 15)) { *err = LCB_CLIENT_ENOMEM; return NULL; } } if (params->consist_type == LCB_N1P_CONSISTENCY_RYOW) { if (!params->scanvec.nused) { *err = LCB_OPTIONS_CONFLICT; return NULL; } else { set_reqbuf_optz(params, PARAM_CONSISTENT, "at_plus"); } } else if (params->consist_type == LCB_N1P_CONSISTENCY_REQUEST) { set_reqbuf_optz(params, PARAM_CONSISTENT, "request_plus"); } else if (params->consist_type == LCB_N1P_CONSISTENCY_STATEMENT) { set_reqbuf_optz(params, PARAM_CONSISTENT, "statement_plus"); } else if (params->consist_type == LCB_N1P_CONSISTENCY_NONE) { /* Nothing */ } else { *err = LCB_EINVAL; return NULL; } return params->reqbuf.base; }