Exemplo n.º 1
0
/*
 * Adds data to the list of pending data that will be written out to a
 * connection.
 *
 * Returns 0 on success, -1 on out-of-memory.
 */
rstatus_t
conn_add_iov(struct conn *c, const void *buf, int len)
{
    struct msghdr *m;
    int leftover;
    bool limit_to_mtu;

    ASSERT(c != NULL);

    do {
        rstatus_t status;

        ASSERT(c->msg_used >= 1);

        m = &c->msg[c->msg_used - 1];

        /*
         * Limit UDP packets, and the first payloads of TCP replies, to
         * UDP_MAX_PAYLOAD_SIZE bytes.
         */
        limit_to_mtu = c->udp || (1 == c->msg_used);

        /* We may need to start a new msghdr if this one is full. */
        if (m->msg_iovlen == IOV_MAX ||
            (limit_to_mtu && c->msg_bytes >= UDP_MAX_PAYLOAD_SIZE)) {
            status = conn_add_msghdr(c);
            if (status != MC_OK) {
                return status;
            }
        }

        status = conn_ensure_iov_space(c);
        if (status != MC_OK) {
            return status;
        }

        /* if the fragment is too big to fit in the datagram, split it up */
        if (limit_to_mtu && len + c->msg_bytes > UDP_MAX_PAYLOAD_SIZE) {
            leftover = len + c->msg_bytes - UDP_MAX_PAYLOAD_SIZE;
            len -= leftover;
        } else {
            leftover = 0;
        }

        ASSERT(c->msg_used >= 1);

        m = &c->msg[c->msg_used - 1];
        m->msg_iov[m->msg_iovlen].iov_base = (void *)buf;
        m->msg_iov[m->msg_iovlen].iov_len = len;

        c->msg_bytes += len;
        c->iov_used++;
        m->msg_iovlen++;

        buf = ((char *)buf) + len;
        len = leftover;
    } while (leftover > 0);

    return MC_OK;
}
Exemplo n.º 2
0
// Adds data to the list of pending data that will be written out to a
// connection.
//
// @return true on success, false on out-of-memory.
bool conn_add_iov(conn *c, const void *buf, int len) {
	assert(c != NULL);

	int leftover;
	do {
		struct msghdr *m = &c->msglist[c->msgused - 1];

		// Limit the first payloads of TCP replies, to MAX_PAYLOAD_SIZE bytes.
		bool limit_to_mtu = 1 == c->msgused;

		// We may need to start a new msghdr if this one is full.
		if (m->msg_iovlen == IOV_MAX ||
		    (limit_to_mtu && c->msgbytes >= MAX_PAYLOAD_SIZE)) {
			conn_add_msghdr(c);
			m = &c->msglist[c->msgused - 1];
		}

		if (!ensure_iov_space(c)) return false;

		// If the fragment is too big to fit in the datagram, split it up.
		if (limit_to_mtu && len + c->msgbytes > MAX_PAYLOAD_SIZE) {
			leftover = len + c->msgbytes - MAX_PAYLOAD_SIZE;
			len -= leftover;
		} else {
			leftover = 0;
		}

		m = &c->msglist[c->msgused - 1];
		m->msg_iov[m->msg_iovlen].iov_base = (void *)buf;
		m->msg_iov[m->msg_iovlen].iov_len = len;

		c->msgbytes += len;
		c->iovused++;
		m->msg_iovlen++;

		buf = ((char *)buf) + len;
		len = leftover;
	} while (leftover > 0);

	return true;
}
Exemplo n.º 3
0
static void
asc_dispatch(struct conn *c)
{
    rstatus_t status;
    struct token token[TOKEN_MAX];
    int ntoken;

    /*
     * For commands set, add, or replace, we build an item and read the data
     * directly into it, then continue in asc_complete_nread().
     */

    c->msg_curr = 0;
    c->msg_used = 0;
    c->iov_used = 0;
    status = conn_add_msghdr(c);
    if (status != MC_OK) {
        log_warn("server error on c %d for req of type %d because of oom in "
                 "preparing response", c->sd, c->req_type);

        asc_write_server_error(c);
        return;
    }

    ntoken = asc_tokenize(c->req, token, TOKEN_MAX);

    c->req_type = asc_parse_type(c, token, ntoken);
    switch (c->req_type) {
    case REQ_GET:
    case REQ_GETS:
        /* we do not update stats metrics here because of multi-get */
        asc_process_read(c, token, ntoken);
        break;

    case REQ_SET:
        stats_thread_incr(set);
        asc_process_update(c, token, ntoken);
        break;

    case REQ_ADD:
        stats_thread_incr(add);
        asc_process_update(c, token, ntoken);
        break;

    case REQ_REPLACE:
        stats_thread_incr(replace);
        asc_process_update(c, token, ntoken);
        break;

    case REQ_APPEND:
        stats_thread_incr(append);
        asc_process_update(c, token, ntoken);
        break;

    case REQ_PREPEND:
        stats_thread_incr(prepend);
        asc_process_update(c, token, ntoken);
        break;

    case REQ_CAS:
        stats_thread_incr(cas);
        asc_process_update(c, token, ntoken);
        break;

    case REQ_INCR:
        stats_thread_incr(incr);
        asc_process_arithmetic(c, token, ntoken);
        break;

    case REQ_DECR:
        stats_thread_incr(decr);
        asc_process_arithmetic(c, token, ntoken);
        break;

    case REQ_DELETE:
        stats_thread_incr(delete);
        asc_process_delete(c, token, ntoken);
        break;

    case REQ_STATS:
        stats_thread_incr(stats);
        asc_process_stats(c, token, ntoken);
        break;

    case REQ_FLUSHALL:
        stats_thread_incr(flush);
        asc_process_flushall(c, token, ntoken);
        break;

    case REQ_VERSION:
        asc_write_version(c);
        break;

    case REQ_QUIT:
        conn_set_state(c, CONN_CLOSE);
        break;

    case REQ_VERBOSITY:
        asc_process_verbosity(c, token, ntoken);
        break;

    case REQ_CONFIG:
        asc_process_config(c, token, ntoken);
        break;

    case REQ_UNKNOWN:
    default:
        log_hexdump(LOG_INFO, c->req, c->req_len, "req on c %d with %d "
                    "invalid tokens", c->sd, ntoken);
        asc_write_client_error(c);
        break;
    }
}