/* * Shrinks a connection's buffers if they're too big. This prevents * periodic large "get" requests from permanently chewing lots of server * memory. * * This should only be called in between requests since it can wipe output * buffers! */ void conn_shrink(struct conn *c) { ASSERT(c != NULL); if (c->udp) { return; } if (c->rsize > RSIZE_HIGHWAT && c->rbytes < TCP_BUFFER_SIZE) { char *newbuf; if (c->rcurr != c->rbuf) { memmove(c->rbuf, c->rcurr, (size_t)c->rbytes); } newbuf = mc_realloc(c->rbuf, TCP_BUFFER_SIZE); if (newbuf != NULL) { c->rbuf = newbuf; c->rsize = TCP_BUFFER_SIZE; } /* TODO check other branch... */ c->rcurr = c->rbuf; } if (c->isize > ILIST_HIGHWAT) { struct item **newbuf; newbuf = mc_realloc(c->ilist, ILIST_SIZE * sizeof(c->ilist[0])); if (newbuf != NULL) { c->ilist = newbuf; c->isize = ILIST_SIZE; } /* TODO check error condition? */ } if (c->msg_size > MSG_HIGHWAT) { struct msghdr *newbuf; newbuf = mc_realloc(c->msg, MSG_SIZE * sizeof(c->msg[0])); if (newbuf != NULL) { c->msg = newbuf; c->msg_size = MSG_SIZE; } /* TODO check error condition? */ } if (c->iov_size > IOV_HIGHWAT) { struct iovec *newbuf; newbuf = mc_realloc(c->iov, IOV_SIZE * sizeof(c->iov[0])); if (newbuf != NULL) { c->iov = newbuf; c->iov_size = IOV_SIZE; } /* TODO check return value */ } }
static rstatus_t asc_create_cas_suffix(struct conn *c, unsigned valid_key_iter, char **cas_suffix) { if (valid_key_iter >= c->ssize) { char **new_suffix_list; new_suffix_list = mc_realloc(c->slist, sizeof(char *) * c->ssize * 2); if (new_suffix_list == NULL) { return MC_ENOMEM; } c->ssize *= 2; c->slist = new_suffix_list; } *cas_suffix = cache_alloc(c->thread->suffix_cache); if (*cas_suffix == NULL) { log_warn("server error on c %d for req of type %d with enomem on " "suffix cache", c->sd, c->req_type); asc_write_server_error(c); return MC_ENOMEM; } *(c->slist + valid_key_iter) = *cas_suffix; return MC_OK; }
/* * Ensures that there is room for another struct iovec in a connection's * iov list. * * Returns 0 on success, -1 on out-of-memory. */ static rstatus_t conn_ensure_iov_space(struct conn *c) { ASSERT(c != NULL); if (c->iov_used >= c->iov_size) { int i, iovnum; struct iovec *new_iov; new_iov = mc_realloc(c->iov, (c->iov_size * 2) * sizeof(*c->iov)); if (new_iov == NULL) { return MC_ENOMEM; } c->iov = new_iov; c->iov_size *= 2; /* point all the msghdr structures at the new list */ for (i = 0, iovnum = 0; i < c->msg_used; i++) { c->msg[i].msg_iov = &c->iov[iovnum]; iovnum += c->msg[i].msg_iovlen; } } return MC_OK; }
static char *readline(FILE * f) { char *line = mystrdup(""); char buf[10240]; int readsome = 0; while (fgets(buf, 10240, f) != NULL) { readsome = 1; { int i, ret = 0; for (i = 0; buf[i] != '\0' && buf[i] != '\n'; i++) ; if (buf[i] == '\n') { buf[i] = '\0'; ret = 1; } line = (char *)mc_realloc(line, strlen(line) + 1 + i + 1); strcat(line, buf); if (ret) { return line; } } } if (readsome) { return line; } else { mc_free(line); return NULL; } }
/* * Constructs a set of UDP headers and attaches them to the outgoing * messages. */ rstatus_t conn_build_udp_headers(struct conn *c) { int i; unsigned char *hdr; ASSERT(c != NULL); if (c->msg_used > c->udp_hsize) { void *new_udp_hbuf; if (c->udp_hbuf != NULL) { new_udp_hbuf = mc_realloc(c->udp_hbuf, c->msg_used * 2 * UDP_HEADER_SIZE); } else { new_udp_hbuf = mc_alloc(c->msg_used * 2 * UDP_HEADER_SIZE); } if (new_udp_hbuf == NULL) { return MC_ENOMEM; } c->udp_hbuf = (unsigned char *)new_udp_hbuf; c->udp_hsize = c->msg_used * 2; } hdr = c->udp_hbuf; for (i = 0; i < c->msg_used; i++) { c->msg[i].msg_iov[0].iov_base = (void*)hdr; c->msg[i].msg_iov[0].iov_len = UDP_HEADER_SIZE; *hdr++ = c->udp_rid / 256; *hdr++ = c->udp_rid % 256; *hdr++ = i / 256; *hdr++ = i % 256; *hdr++ = c->msg_used / 256; *hdr++ = c->msg_used % 256; *hdr++ = 0; *hdr++ = 0; ASSERT((void *) hdr == (caddr_t)c->msg[i].msg_iov[0].iov_base + UDP_HEADER_SIZE); } return MC_OK; }
/* * Return an object back to the cache. * * The caller should return the object in an initialized state so that * the object may be returned in an expected state from cache_alloc. * * @param handle handle to the object cache to return the object to * @param ptr pointer to the object to return. */ void cache_free(cache_t *cache, void *ptr) { pthread_mutex_lock(&cache->mutex); if (cache->freecurr < cache->freetotal) { cache->ptr[cache->freecurr++] = ptr; } else { /* try to enlarge free connections array */ size_t newtotal = cache->freetotal * 2; void **new_free = mc_realloc(cache->ptr, sizeof(char *) * newtotal); if (new_free != NULL) { cache->freetotal = newtotal; cache->ptr = new_free; cache->ptr[cache->freecurr++] = ptr; } else { mc_free(ptr); } } pthread_mutex_unlock(&cache->mutex); }
/* * Adds a message header to a connection. * * Returns 0 on success, -1 on out-of-memory. */ rstatus_t conn_add_msghdr(struct conn *c) { struct msghdr *msg; ASSERT(c != NULL); if (c->msg_size == c->msg_used) { msg = mc_realloc(c->msg, c->msg_size * 2 * sizeof(*c->msg)); if (msg == NULL) { return MC_ENOMEM; } c->msg = msg; c->msg_size *= 2; } msg = c->msg + c->msg_used; memset(msg, 0, sizeof(*msg)); msg->msg_iov = &c->iov[c->iov_used]; if (c->udp) { msg->msg_name = &c->udp_raddr; msg->msg_namelen = c->udp_raddr_size; } c->msg_bytes = 0; c->msg_used++; if (c->udp) { /* leave room for the UDP header, which we'll fill in later */ return conn_add_iov(c, NULL, UDP_HEADER_SIZE); } return MC_OK; }
static inline void asc_process_read(struct conn *c, struct token *token, int ntoken) { rstatus_t status; char *key; size_t nkey; unsigned valid_key_iter = 0; struct item *it; struct token *key_token; bool return_cas; if (!asc_ntoken_valid(c, ntoken)) { log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for " "req of type %d with %d invalid tokens", c->sd, c->req_type, ntoken); asc_write_client_error(c); return; } return_cas = (c->req_type == REQ_GETS) ? true : false; key_token = &token[TOKEN_KEY]; do { while (key_token->len != 0) { key = key_token->val; nkey = key_token->len; if (nkey > KEY_MAX_LEN) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d " "and %d length key", c->sd, c->req_type, nkey); asc_write_client_error(c); return; } if (return_cas) { stats_thread_incr(gets); } else { stats_thread_incr(get); } it = item_get(key, nkey); if (it != NULL) { /* item found */ if (return_cas) { stats_slab_incr(it->id, gets_hit); } else { stats_slab_incr(it->id, get_hit); } if (valid_key_iter >= c->isize) { struct item **new_list; new_list = mc_realloc(c->ilist, sizeof(struct item *) * c->isize * 2); if (new_list != NULL) { c->isize *= 2; c->ilist = new_list; } else { item_remove(it); break; } } status = asc_respond_get(c, valid_key_iter, it, return_cas); if (status != MC_OK) { log_debug(LOG_NOTICE, "client error on c %d for req of type " "%d with %d tokens", c->sd, c->req_type, ntoken); stats_thread_incr(cmd_error); item_remove(it); break; } log_debug(LOG_VVERB, ">%d sending key %.*s", c->sd, it->nkey, item_key(it)); item_touch(it); *(c->ilist + valid_key_iter) = it; valid_key_iter++; } else { /* item not found */ if (return_cas) { stats_thread_incr(gets_miss); } else { stats_thread_incr(get_miss); } klog_write(c->peer, c->req_type, key, nkey, 1, 0); } key_token++; } /* * If the command string hasn't been fully processed, get the next set * of token. */ if (key_token->val != NULL) { ntoken = asc_tokenize(key_token->val, token, TOKEN_MAX); /* ntoken is unused */ key_token = token; } } while (key_token->val != NULL); c->icurr = c->ilist; c->ileft = valid_key_iter; if (return_cas) { c->scurr = c->slist; c->sleft = valid_key_iter; } log_debug(LOG_VVERB, ">%d END", c->sd); /* * If the loop was terminated because of out-of-memory, it is not * reliable to add END\r\n to the buffer, because it might not end * in \r\n. So we send SERVER_ERROR instead. */ if (key_token->val != NULL || conn_add_iov(c, "END\r\n", 5) != MC_OK || (c->udp && conn_build_udp_headers(c) != MC_OK)) { log_warn("server error on c %d for req of type %d with enomem", c->sd, c->req_type); asc_write_server_error(c); } else { conn_set_state(c, CONN_MWRITE); c->msg_curr = 0; } }
static void addEntry(cue_t * r, cue_entry_t * entry) { r->count += 1; r->entries = (cue_entry_t **) mc_realloc(r->entries, sizeof(cue_entry_t *) * r->count); r->entries[r->count - 1] = entry; }