int mdb_t::put ( const char * key, size_t key_len, const char * val, size_t val_len, uint32_t ttl ) { if ( unlikely ( ! m_ok ) ) { return EINVAL; } int r = process_update_command ( ( char * ) key, key_len, 0, ( char * ) val, val_len, ttl, 2 ); if ( unlikely ( ! r ) ) { return EINVAL; } return 0; }
void cproxy_process_upstream_ascii(conn *c, char *line) { assert(c != NULL); assert(c->next == NULL); assert(c->extra != NULL); assert(c->cmd == -1); assert(c->item == NULL); assert(line != NULL); assert(line == c->rcurr); assert(IS_ASCII(c->protocol)); assert(IS_PROXY(c->protocol)); if (settings.verbose > 2) { moxi_log_write("<%d cproxy_process_upstream_ascii %s\n", c->sfd, line); } // Snapshot rcurr, because the caller, try_read_command(), changes it. // c->cmd_curr = -1; c->cmd_start = c->rcurr; c->cmd_start_time = msec_current_time; c->cmd_retries = 0; proxy_td *ptd = c->extra; assert(ptd != NULL); /* For commands set/add/replace, we build an item and read the data * directly into it, then continue in nread_complete(). */ if (!cproxy_prep_conn_for_write(c)) { ptd->stats.stats.err_upstream_write_prep++; conn_set_state(c, conn_closing); return; } bool mcmux_command = false; bool self_command = false; /* Check for proxy pattern - A:host:port or B:host:port */ if (true == settings.enable_mcmux_mode && ((*line == 'A' || *line == 'B') && *(line + 1) == ':')) { mcmux_command = true; } else if (true == settings.enable_mcmux_mode) { self_command = true; } c->peer_protocol = 0; c->peer_host = NULL; c->peer_port = 0; if (mcmux_command) { char *peer_port = NULL; int i = 0; c->peer_protocol = (*line == 'A') ? proxy_downstream_ascii_prot : proxy_downstream_binary_prot; line += 2; c->peer_host = line; while (*line != ' ' && *line != '\0' && *line != ':' && ++i < MAX_HOSTNAME_LEN) { line++; } if (*line == '\0' || line - c->peer_host <= 0) { out_string(c, "ERROR"); moxi_log_write("Malformed request line"); return; } *line = '\0'; line++; peer_port = line; i = 0; while (*line != ' ' && *line != '\0' && ++i <= MAX_PORT_LEN) { line++; } if (*line == '\0' || line - peer_port <= 0) { out_string(c, "ERROR"); moxi_log_write("Malformed request line"); return; } c->peer_port = atoi(peer_port); *line++ = '\0'; c->cmd_start = line; } int cmd_len = 0; token_t tokens[MAX_TOKENS]; size_t ntokens = scan_tokens(line, tokens, MAX_TOKENS, &cmd_len); char *cmd = tokens[COMMAND_TOKEN].value; int cmdx = -1; int cmd_st = STATS_CMD_TYPE_REGULAR; int comm; #define SEEN(cmd_id, is_cas, cmd_len) \ cmd_st = c->noreply ? \ STATS_CMD_TYPE_QUIET : STATS_CMD_TYPE_REGULAR; \ ptd->stats.stats_cmd[cmd_st][cmd_id].seen++; \ ptd->stats.stats_cmd[cmd_st][cmd_id].read_bytes += cmd_len; \ if (is_cas) { \ ptd->stats.stats_cmd[cmd_st][cmd_id].cas++; \ } if (ntokens >= 3 && (false == self_command) && (strncmp(cmd, "get", 3) == 0)) { if (cmd[3] == 'l') { c->cmd_curr = PROTOCOL_BINARY_CMD_GETL; } else if (ntokens == 3) { // Single-key get/gets optimization. // c->cmd_curr = PROTOCOL_BINARY_CMD_GETK; } else { c->cmd_curr = PROTOCOL_BINARY_CMD_GETKQ; } // Handles get and gets. // cproxy_pause_upstream_for_downstream(ptd, c); // The cmd_len from scan_tokens might not include // all the keys, so cmd_len might not == strlen(command). // Handle read_bytes during multiget broadcast. // if (cmd[3] == 'l') { SEEN(STATS_CMD_GETL, true, 0); } else { SEEN(STATS_CMD_GET, cmd[3] == 's', 0); } } else if ((ntokens == 6 || ntokens == 7) && (false == self_command) && ((strncmp(cmd, "add", 3) == 0 && (comm = NREAD_ADD) && (cmdx = STATS_CMD_ADD) && (c->cmd_curr = PROTOCOL_BINARY_CMD_ADD)) || (strncmp(cmd, "set", 3) == 0 && (comm = NREAD_SET) && (cmdx = STATS_CMD_SET) && (c->cmd_curr = PROTOCOL_BINARY_CMD_SET)) || (strncmp(cmd, "replace", 7) == 0 && (comm = NREAD_REPLACE) && (cmdx = STATS_CMD_REPLACE) && (c->cmd_curr = PROTOCOL_BINARY_CMD_REPLACE)) || (strncmp(cmd, "prepend", 7) == 0 && (comm = NREAD_PREPEND) && (cmdx = STATS_CMD_PREPEND) && (c->cmd_curr = PROTOCOL_BINARY_CMD_PREPEND)) || (strncmp(cmd, "append", 6) == 0 && (comm = NREAD_APPEND) && (cmdx = STATS_CMD_APPEND) && (c->cmd_curr = PROTOCOL_BINARY_CMD_APPEND)))) { assert(c->item == NULL); c->item = NULL; process_update_command(c, tokens, ntokens, comm, false); if (cmdx >= 0) { item *it = c->item; if (it != NULL) { SEEN(cmdx, false, cmd_len + it->nbytes); } else { SEEN(cmdx, false, cmd_len); ptd->stats.stats_cmd[cmd_st][cmdx].misses++; } } } else if ((ntokens == 7 || ntokens == 8) && (false == self_command) && (strncmp(cmd, "cas", 3) == 0 && (comm = NREAD_CAS) && (c->cmd_curr = PROTOCOL_BINARY_CMD_SET))) { assert(c->item == NULL); c->item = NULL; process_update_command(c, tokens, ntokens, comm, true); item *it = c->item; if (it != NULL) { SEEN(STATS_CMD_CAS, true, cmd_len + it->nbytes); } else { SEEN(STATS_CMD_CAS, true, cmd_len); ptd->stats.stats_cmd[cmd_st][STATS_CMD_CAS].misses++; } } else if ((ntokens == 4 || ntokens == 5) && (false == self_command) && (strncmp(cmd, "incr", 4) == 0) && (c->cmd_curr = PROTOCOL_BINARY_CMD_INCREMENT)) { set_noreply_maybe(c, tokens, ntokens); cproxy_pause_upstream_for_downstream(ptd, c); SEEN(STATS_CMD_INCR, false, cmd_len); } else if ((ntokens == 4 || ntokens == 5) && (false == self_command) && (strncmp(cmd, "decr", 4) == 0) && (c->cmd_curr = PROTOCOL_BINARY_CMD_DECREMENT)) { set_noreply_maybe(c, tokens, ntokens); cproxy_pause_upstream_for_downstream(ptd, c); SEEN(STATS_CMD_DECR, false, cmd_len); } else if (ntokens >= 3 && ntokens <= 4 && (false == self_command) && (strncmp(cmd, "delete", 6) == 0) && (c->cmd_curr = PROTOCOL_BINARY_CMD_DELETE)) { set_noreply_maybe(c, tokens, ntokens); cproxy_pause_upstream_for_downstream(ptd, c); SEEN(STATS_CMD_DELETE, false, cmd_len); } else if (ntokens >= 2 && ntokens <= 4 && (false == self_command) && (strncmp(cmd, "flush_all", 9) == 0) && (c->cmd_curr = PROTOCOL_BINARY_CMD_FLUSH)) { set_noreply_maybe(c, tokens, ntokens); cproxy_pause_upstream_for_downstream(ptd, c); SEEN(STATS_CMD_FLUSH_ALL, false, cmd_len); } else if (ntokens >= 3 && ntokens <= 4 && (strncmp(cmd, "stats proxy", 10) == 0)) { process_stats_proxy_command(c, tokens, ntokens); SEEN(STATS_CMD_STATS, false, cmd_len); } else if (ntokens == 3 && (false == self_command) && (strcmp(cmd, "stats reset") == 0) && (c->cmd_curr = PROTOCOL_BINARY_CMD_STAT)) { cproxy_pause_upstream_for_downstream(ptd, c); SEEN(STATS_CMD_STATS_RESET, false, cmd_len); } else if (ntokens == 2 && (false == self_command) && (strcmp(cmd, "stats") == 0) && (c->cmd_curr = PROTOCOL_BINARY_CMD_STAT)) { // Even though we've coded to handle advanced stats // like stats cachedump, prevent those here to avoid // locking downstream servers. // cproxy_pause_upstream_for_downstream(ptd, c); SEEN(STATS_CMD_STATS, false, cmd_len); } else if (ntokens == 2 && (true == mcmux_command) && (strncmp(cmd, "version", 7) == 0) && (c->cmd_curr = PROTOCOL_BINARY_CMD_VERSION)) { /* downstream version command */ cproxy_pause_upstream_for_downstream(ptd, c); SEEN(STATS_CMD_VERSION, false, cmd_len); } else if (ntokens == 2 && (strncmp(cmd, "version", 7) == 0)) { out_string(c, "VERSION " VERSION); SEEN(STATS_CMD_VERSION, false, cmd_len); } else if ((ntokens == 3 || ntokens == 4) && (strncmp(cmd, "verbosity", 9) == 0)) { process_verbosity_command(c, tokens, ntokens); SEEN(STATS_CMD_VERBOSITY, false, cmd_len); } else if (ntokens == 2 && (strncmp(cmd, "quit", 4) == 0)) { conn_set_state(c, conn_closing); SEEN(STATS_CMD_QUIT, false, cmd_len); } else if (ntokens == 4 && (strncmp(cmd, "unl", 3) == 0) && (false == self_command) && (c->cmd_curr = PROTOCOL_BINARY_CMD_UNL)) { cproxy_pause_upstream_for_downstream(ptd, c); SEEN(STATS_CMD_UNL, false, cmd_len); } else { out_string(c, "ERROR"); SEEN(STATS_CMD_ERROR, false, cmd_len); } }
// parse a single memcached request. bool parse_command(conn *c, char *command) { token_t tokens[MAX_TOKENS]; size_t ntokens; int comm; assert(c != NULL); ntokens = tokenize_command(command, tokens, MAX_TOKENS); if (ntokens >= 3 && ((strcmp(tokens[COMMAND_TOKEN].value, "get") == 0) || (strcmp(tokens[COMMAND_TOKEN].value, "bget") == 0))) { process_get_command(c, tokens, ntokens, false); } else if (ntokens >= 3 && (strcmp(tokens[COMMAND_TOKEN].value, "gets") == 0)) { process_get_command(c, tokens, ntokens, true); } else if ((ntokens == 6 || ntokens == 7) && ((strcmp(tokens[COMMAND_TOKEN].value, "add") == 0 && (comm = NREAD_ADD)) || (strcmp(tokens[COMMAND_TOKEN].value, "set") == 0 && (comm = NREAD_SET)) || (strcmp(tokens[COMMAND_TOKEN].value, "replace") == 0 && (comm = NREAD_REPLACE)) || (strcmp(tokens[COMMAND_TOKEN].value, "prepend") == 0 && (comm = NREAD_PREPEND)) || (strcmp(tokens[COMMAND_TOKEN].value, "append") == 0 && (comm = NREAD_APPEND)) )) { process_update_command(c, tokens, ntokens, comm, false); } else if ((ntokens == 7 || ntokens == 8) && (strcmp(tokens[COMMAND_TOKEN].value, "cas") == 0 && (comm = NREAD_CAS))) { process_update_command(c, tokens, ntokens, comm, true); /* } else if ((ntokens == 4 || ntokens == 5) && */ /* (strcmp(tokens[COMMAND_TOKEN].value, "incr") == 0)) { */ /* process_arithmetic_command(c, tokens, ntokens, 1); */ /* } else if ((ntokens == 4 || ntokens == 5) && */ /* (strcmp(tokens[COMMAND_TOKEN].value, "decr") == 0)) { */ /* process_arithmetic_command(c, tokens, ntokens, 0); */ /* } else if (ntokens >= 3 && ntokens <= 5 && */ /* (strcmp(tokens[COMMAND_TOKEN].value, "delete") == 0)) { */ /* process_delete_command(c, tokens, ntokens); */ /* } else if ((ntokens == 4 || ntokens == 5) && */ /* (strcmp(tokens[COMMAND_TOKEN].value, "touch") == 0)) { */ /* process_touch_command(c, tokens, ntokens); */ } else if (ntokens >= 2 && (strcmp(tokens[COMMAND_TOKEN].value, "stats") == 0)) { process_stat_command(c, tokens, ntokens); /* } else if (ntokens >= 2 && ntokens <= 4 && */ /* (strcmp(tokens[COMMAND_TOKEN].value, "flush_all") == 0)) { */ /* process_flush_cmd(c, tokens, ntokens); */ /* } else if (ntokens == 2 && */ /* (strcmp(tokens[COMMAND_TOKEN].value, "version") == 0)) { */ /* process_version_cmd(c, tokens, ntokens); */ /* } else if (ntokens == 2 && */ /* (strcmp(tokens[COMMAND_TOKEN].value, "quit") == 0)) { */ /* process_quite_cmd(c, tokens, ntokens); */ /* } else if (ntokens == 2 && */ /* (strcmp(tokens[COMMAND_TOKEN].value, "shutdown") == 0)) { */ /* process_shutdown_cmd(c, tokens, ntokens); */ /* } else if (ntokens > 1 && */ /* (strcmp(tokens[COMMAND_TOKEN].value, "slabs") == 0)) { */ /* process_slab_cmd(c, tokens, ntokens); */ /* } else if ((ntokens == 3 || ntokens == 4) && */ /* (strcmp(tokens[COMMAND_TOKEN].value, "verbosity") == 0)) { */ /* process_verbosity_command(c, tokens, ntokens); */ } else { return false; } // NOTE: No refcnt needed here as not changing pointer structure. mutex_lock(&c->stats->lock); c->stats->requests++; mutex_unlock(&c->stats->lock); return true; }