Esempio n. 1
0
/*
 * 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 */
    }
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
/*
 * 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;
}
Esempio n. 4
0
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;
  }
}
Esempio n. 5
0
/*
 * 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;
}
Esempio n. 6
0
/*
 * 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);
}
Esempio n. 7
0
/*
 * 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;
}
Esempio n. 8
0
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;
    }
}
Esempio n. 9
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;
}