static memcached_return binary_stats_fetch(memcached_st *ptr,
                                           memcached_stat_st *stat,
                                           char *args,
                                           unsigned int server_key)
{
  memcached_return rc;

  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
  protocol_binary_request_stats request= {0};
  request.message.header.request.magic= PROTOCOL_BINARY_REQ;
  request.message.header.request.opcode= PROTOCOL_BINARY_CMD_STAT;
  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;

  if (args != NULL) 
  {
    int len= strlen(args);

    rc= memcached_validate_key_length(len, true);
    unlikely (rc != MEMCACHED_SUCCESS)
      return rc;

    request.message.header.request.keylen= htons((uint16_t)len);
    request.message.header.request.bodylen= htonl(len);
      
    if ((memcached_do(&ptr->hosts[server_key], request.bytes, 
                      sizeof(request.bytes), 0) != MEMCACHED_SUCCESS) ||
        (memcached_io_write(&ptr->hosts[server_key], args, len, 1) == -1)) 
    {
      memcached_io_reset(&ptr->hosts[server_key]);
      return MEMCACHED_WRITE_FAILURE;
    }
  }
static memcached_return binary_incr_decr(memcached_st *ptr, uint8_t cmd,
                                         const char *key, size_t key_length,
                                         uint32_t offset, uint64_t *value) 
{
  unsigned int server_key;
#ifndef _MSC_VER
  protocol_binary_request_incr request= {.bytes= {0}};
#else
  protocol_binary_request_incr request= {0};
#endif

  unlikely (ptr->hosts == NULL || ptr->number_of_hosts == 0)
    return MEMCACHED_NO_SERVERS;

  server_key= memcached_generate_hash(ptr, key, key_length);

  request.message.header.request.magic= PROTOCOL_BINARY_REQ;
  request.message.header.request.opcode= cmd;
  request.message.header.request.keylen= htons((uint16_t)key_length);
  request.message.header.request.extlen= 20;
  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
  request.message.header.request.bodylen= htonl(key_length + request.message.header.request.extlen);  
  request.message.body.delta= htonll(offset);
  
  /* TODO: The binary protocol allows you to specify initial and expiry time */
  if ((memcached_do(&ptr->hosts[server_key], request.bytes,
                    sizeof(request.bytes), 0)!=MEMCACHED_SUCCESS) ||
      (memcached_io_write(&ptr->hosts[server_key], key, key_length, 1) == -1)) 
  {
    memcached_io_reset(&ptr->hosts[server_key]);
    return MEMCACHED_WRITE_FAILURE;
  }
 
  return memcached_response(&ptr->hosts[server_key], (char*)value, sizeof(*value), NULL);
}
示例#3
0
memcached_return_t memcached_read_one_response(memcached_server_write_instance_st ptr,
                                               char *buffer, size_t buffer_length,
                                               memcached_result_st *result)
{
  if (result == NULL)
  {
    memcached_st *root= (memcached_st *)ptr->root;
    result = &root->result;
  }

  memcached_return_t rc;
  if (ptr->root->flags.binary_protocol)
    rc= binary_read_one_response(ptr, buffer, buffer_length, result);
  else
    rc= textual_read_one_response(ptr, buffer, buffer_length, result);

  unlikely(rc == MEMCACHED_UNKNOWN_READ_FAILURE ||
           rc == MEMCACHED_PROTOCOL_ERROR ||
           rc == MEMCACHED_CLIENT_ERROR ||
           rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
    memcached_io_reset(ptr);

  return rc;
}
示例#4
0
static inline memcached_return_t memcached_send(memcached_st *ptr,
                                                const char *master_key, size_t master_key_length,
                                                const char *key, size_t key_length,
                                                const char *value, size_t value_length,
                                                time_t expiration,
                                                uint32_t flags,
                                                uint64_t cas,
                                                memcached_storage_action_t verb)
{
  bool to_write;
  size_t write_length;
  memcached_return_t rc;
  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
  uint32_t server_key;
  memcached_server_instance_st *instance;

  WATCHPOINT_ASSERT(!(value == NULL && value_length > 0));

  rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
  unlikely (rc != MEMCACHED_SUCCESS)
    return rc;

  unlikely (memcached_server_count(ptr) == 0)
    return MEMCACHED_NO_SERVERS;

  if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
    return MEMCACHED_BAD_KEY_PROVIDED;

  if (ptr->flags.binary_protocol)
  {
    return memcached_send_binary(ptr, master_key, master_key_length,
                                 key, key_length,
                                 value, value_length, expiration,
                                 flags, cas, verb);
  }

  server_key= memcached_generate_hash(ptr, master_key, master_key_length);
  instance= memcached_server_instance_fetch(ptr, server_key);

  if (cas)
  {
    write_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
                                    "%s %.*s%.*s %u %llu %zu %llu%s\r\n",
                                    storage_op_string(verb),
                                    (int)ptr->prefix_key_length,
                                    ptr->prefix_key,
                                    (int)key_length, key, flags,
                                    (unsigned long long)expiration, value_length,
                                    (unsigned long long)cas,
                                    (ptr->flags.no_reply) ? " noreply" : "");
  }
  else
  {
    char *buffer_ptr= buffer;
    const char *command= storage_op_string(verb);

    /* Copy in the command, no space needed, we handle that in the command function*/
    memcpy(buffer_ptr, command, strlen(command));

    /* Copy in the key prefix, switch to the buffer_ptr */
    buffer_ptr= memcpy((buffer_ptr + strlen(command)), ptr->prefix_key, ptr->prefix_key_length);

    /* Copy in the key, adjust point if a key prefix was used. */
    buffer_ptr= memcpy(buffer_ptr + (ptr->prefix_key_length ? ptr->prefix_key_length : 0),
                       key, key_length);
    buffer_ptr+= key_length;
    buffer_ptr[0]=  ' ';
    buffer_ptr++;

    write_length= (size_t)(buffer_ptr - buffer);
    write_length+= (size_t) snprintf(buffer_ptr, MEMCACHED_DEFAULT_COMMAND_SIZE,
                                     "%u %llu %zu%s\r\n",
                                     flags,
                                     (unsigned long long)expiration, value_length,
                                     ptr->flags.no_reply ? " noreply" : "");
  }

  if (ptr->flags.use_udp && ptr->flags.buffer_requests)
  {
    size_t cmd_size= write_length + value_length + 2;
    if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
      return MEMCACHED_WRITE_FAILURE;
    if (cmd_size + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
      memcached_io_write(instance, NULL, 0, true);
  }

  if (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
  {
    rc= MEMCACHED_WRITE_FAILURE;
    goto error;
  }

  /* Send command header */
  rc=  memcached_do(instance, buffer, write_length, false);
  if (rc != MEMCACHED_SUCCESS)
    goto error;

  /* Send command body */
  if (memcached_io_write(instance, value, value_length, false) == -1)
  {
    rc= MEMCACHED_WRITE_FAILURE;
    goto error;
  }

  if (ptr->flags.buffer_requests && verb == SET_OP)
  {
    to_write= false;
  }
  else
  {
    to_write= true;
  }

  if (memcached_io_write(instance, "\r\n", 2, to_write) == -1)
  {
    rc= MEMCACHED_WRITE_FAILURE;
    goto error;
  }

  if (ptr->flags.no_reply)
    return (to_write == false) ? MEMCACHED_BUFFERED : MEMCACHED_SUCCESS;

  if (to_write == false)
    return MEMCACHED_BUFFERED;

  rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);

  if (rc == MEMCACHED_STORED)
    return MEMCACHED_SUCCESS;
  else
    return rc;

error:
  memcached_io_reset(instance);

  return rc;
}
memcached_return value_fetch(memcached_server_st *ptr,
                             char *buffer,
                             memcached_result_st *result)
{
  memcached_return rc= MEMCACHED_SUCCESS;
  char *string_ptr;
  char *end_ptr;
  char *next_ptr;
  size_t value_length;
  size_t read_length;
  size_t to_read;
  char *value_ptr;

  WATCHPOINT_ASSERT(ptr->root);
  end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;

  memcached_result_reset(result);

  string_ptr= buffer;
  string_ptr+= 6; /* "VALUE " */


  /* We load the key */
  {
    char *key;
    size_t prefix_length;

    key= result->key;
    result->key_length= 0;

    for (prefix_length= ptr->root->prefix_key_length; !(iscntrl(*string_ptr) || isspace(*string_ptr)) ; string_ptr++)
    {
      if (prefix_length == 0)
      {
        *key= *string_ptr;
        key++;
        result->key_length++;
      }
      else
        prefix_length--;
    }
    result->key[result->key_length]= 0;
  }

  if (end_ptr == string_ptr)
    goto read_error;

  /* Flags fetch move past space */
  string_ptr++;
  if (end_ptr == string_ptr)
    goto read_error;
  for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
  result->flags= strtoul(next_ptr, &string_ptr, 10);

  if (end_ptr == string_ptr)
    goto read_error;

  /* Length fetch move past space*/
  string_ptr++;
  if (end_ptr == string_ptr)
    goto read_error;

  for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
  value_length= (size_t)strtoull(next_ptr, &string_ptr, 10);

  if (end_ptr == string_ptr)
    goto read_error;

  /* Skip spaces */
  if (*string_ptr == '\r')
  {
    /* Skip past the \r\n */
    string_ptr+= 2;
  }
  else
  {
    string_ptr++;
    for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
    result->cas= strtoull(next_ptr, &string_ptr, 10);
  }

  if (end_ptr < string_ptr)
    goto read_error;

  /* We add two bytes so that we can walk the \r\n */
  rc= memcached_string_check(&result->value, value_length+2);
  if (rc != MEMCACHED_SUCCESS)
  {
    value_length= 0;
    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
  }

  value_ptr= memcached_string_value(&result->value);
  read_length= 0;
  /* 
    We read the \r\n into the string since not doing so is more 
    cycles then the waster of memory to do so.

    We are null terminating through, which will most likely make
    some people lazy about using the return length.
  */
  to_read= (value_length) + 2;
  read_length= memcached_io_read(ptr, value_ptr, to_read);
  if (read_length != (size_t)(value_length + 2))
  {
    goto read_error;
  }

/* This next bit blows the API, but this is internal....*/
  {
    char *char_ptr;
    char_ptr= memcached_string_value(&result->value);;
    char_ptr[value_length]= 0;
    char_ptr[value_length + 1]= 0;
    memcached_string_set_length(&result->value, value_length);
  }

  return MEMCACHED_SUCCESS;

read_error:
  memcached_io_reset(ptr);

  return MEMCACHED_PARTIAL_READ;
}
示例#6
0
memcached_return_t memcached_purge(memcached_server_write_instance_st ptr)
{
  uint32_t x;
  memcached_return_t ret= MEMCACHED_SUCCESS;
  memcached_st *root= (memcached_st *)ptr->root;
  uint32_t no_msg;

  if (memcached_is_purging(ptr->root) || /* already purging */
      (memcached_server_response_count(ptr) < ptr->root->io_msg_watermark &&
       ptr->io_bytes_sent < ptr->root->io_bytes_watermark) ||
      (ptr->io_bytes_sent >= ptr->root->io_bytes_watermark &&
       memcached_server_response_count(ptr) < 2))
  {
    return MEMCACHED_SUCCESS;
  }

  /* memcached_io_write and memcached_response may call memcached_purge
    so we need to be able stop any recursion.. */
  memcached_set_purging(root, true);

  WATCHPOINT_ASSERT(ptr->fd != -1);
  /* Force a flush of the buffer to ensure that we don't have the n-1 pending
    requests buffered up.. */
  if (memcached_io_write(ptr, NULL, 0, true) == -1)
  {
    memcached_set_purging(root, true);

    return MEMCACHED_WRITE_FAILURE;
  }
  WATCHPOINT_ASSERT(ptr->fd != -1);

  no_msg= memcached_server_response_count(ptr) - 1;
  if (no_msg > 0)
  {
    memcached_result_st result;
    memcached_result_st *result_ptr;
    char buffer[SMALL_STRING_LEN];

    /*
     * We need to increase the timeout, because we might be waiting for
     * data to be sent from the server (the commands was in the output buffer
     * and just flushed
   */
    const int32_t timeo= ptr->root->poll_timeout;
    root->poll_timeout= 2000;

    result_ptr= memcached_result_create(root, &result);
    WATCHPOINT_ASSERT(result_ptr);

    for (x= 0; x < no_msg; x++)
    {
      memcached_return_t rc;
      memcached_result_reset(result_ptr);
      rc= memcached_read_one_response(ptr, buffer,
                                                         sizeof (buffer),
                                                         result_ptr);
      /*
       * Purge doesn't care for what kind of command results that is received.
       * The only kind of errors I care about if is I'm out of sync with the
       * protocol or have problems reading data from the network..
     */
      if (rc== MEMCACHED_PROTOCOL_ERROR || rc == MEMCACHED_UNKNOWN_READ_FAILURE)
      {
        WATCHPOINT_ERROR(rc);
        ret = rc;
        memcached_io_reset(ptr);
      }

      if (ptr->root->callbacks != NULL)
      {
        memcached_callback_st cb = *ptr->root->callbacks;
        if (rc == MEMCACHED_SUCCESS)
        {
          uint32_t y;
          for (y= 0; y < cb.number_of_callback; y++)
          {
            rc = (*cb.callback[y])(ptr->root, result_ptr, cb.context);
            if (rc != MEMCACHED_SUCCESS)
              break;
          }
        }
      }
    }

    memcached_result_free(result_ptr);
    root->poll_timeout= timeo;
  }
  memcached_set_purging(root, false);

  return ret;
}
示例#7
0
static inline memcached_return_t memcached_send(memcached_st *ptr,
                                                const char *master_key, size_t master_key_length,
                                                const char *key, size_t key_length,
                                                const char *value, size_t value_length,
                                                time_t expiration,
                                                uint32_t flags,
                                                uint64_t cas,
                                                uint16_t vbucketid,
                                                memcached_storage_action_t verb)
{
  bool to_write;
  size_t write_length;
  memcached_return_t rc;
  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
  uint32_t server_key;
  memcached_server_write_instance_st instance;

  WATCHPOINT_ASSERT(!(value == NULL && value_length > 0));

  rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
  unlikely (rc != MEMCACHED_SUCCESS)
    return rc;

  unlikely (memcached_server_count(ptr) == 0)
    return MEMCACHED_NO_SERVERS;

  if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
    return MEMCACHED_BAD_KEY_PROVIDED;

  server_key= memcached_generate_hash_with_redistribution(ptr, master_key, master_key_length);
  instance= memcached_server_instance_fetch(ptr, server_key);
  instance->read_buffer_length = 0;

  WATCHPOINT_SET(instance->io_wait_count.read= 0);
  WATCHPOINT_SET(instance->io_wait_count.write= 0);

  if (ptr->flags.binary_protocol)
  {
    rc= memcached_send_binary(ptr, instance, server_key,
                              key, key_length,
                              value, value_length, expiration,
                              flags, cas, vbucketid, verb);
    WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.read > 2, "read IO_WAIT", instance->io_wait_count.read);
    WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.write > 2, "write_IO_WAIT", instance->io_wait_count.write);
  }
  else
  {

    if (cas)
    {
      int check_length;
      check_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
                                    "%s %.*s%.*s %u %llu %lu %llu%s\r\n",
                                    storage_op_string(verb),
                                    (int)ptr->prefix_key_length,
                                    ptr->prefix_key,
                                    (int)key_length, key, flags,
                                    (unsigned long long)expiration, (unsigned long)value_length,
                                    (unsigned long long)cas,
                                    (ptr->flags.no_reply) ? " noreply" : "");
      if (check_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || check_length < 0)
      {
        rc= MEMCACHED_WRITE_FAILURE;
        memcached_io_reset(instance);

        return rc;
      }
      write_length= check_length;
    }
    else
    {
      char *buffer_ptr= buffer;
      const char *command= storage_op_string(verb);

      /* Copy in the command, no space needed, we handle that in the command function*/
      memcpy(buffer_ptr, command, strlen(command));

      /* Copy in the key prefix, switch to the buffer_ptr */
      buffer_ptr= memcpy((buffer_ptr + strlen(command)), ptr->prefix_key, ptr->prefix_key_length);

      /* Copy in the key, adjust point if a key prefix was used. */
      buffer_ptr= memcpy(buffer_ptr + (ptr->prefix_key_length ? ptr->prefix_key_length : 0),
                         key, key_length);
      buffer_ptr+= key_length;
      buffer_ptr[0]=  ' ';
      buffer_ptr++;

      write_length= (size_t)(buffer_ptr - buffer);
      int check_length;
      check_length= snprintf(buffer_ptr, MEMCACHED_DEFAULT_COMMAND_SIZE -(size_t)(buffer_ptr - buffer),
                                    "%u %llu %lu%s\r\n",
                                    flags,
                                    (unsigned long long)expiration, (unsigned long)value_length,
                                    ptr->flags.no_reply ? " noreply" : "");
      if ((size_t)check_length >= MEMCACHED_DEFAULT_COMMAND_SIZE -(size_t)(buffer_ptr - buffer) || check_length < 0)
      {
        rc= MEMCACHED_WRITE_FAILURE;
        memcached_io_reset(instance);

        return rc;
      }

      write_length+= (size_t)check_length;
      WATCHPOINT_ASSERT(write_length < MEMCACHED_DEFAULT_COMMAND_SIZE);
    }

    if (ptr->flags.use_udp && ptr->flags.buffer_requests)
    {
      size_t cmd_size= write_length + value_length + 2;
      if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
        return MEMCACHED_WRITE_FAILURE;
      if (cmd_size + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
        memcached_io_write(instance, NULL, 0, true);
    }

    if (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
    {
      rc= MEMCACHED_WRITE_FAILURE;
    }
    else
    {
      struct libmemcached_io_vector_st vector[]=
      {
        { .length= write_length, .buffer= buffer },
        { .length= value_length, .buffer= value },
        { .length= 2, .buffer= "\r\n" }
      };
示例#8
0
static inline memcached_return memcached_send(memcached_st *ptr,
                                              const char *master_key, size_t master_key_length,
                                              const char *key, size_t key_length,
                                              const char *value, size_t value_length,
                                              time_t expiration,
                                              uint32_t flags,
                                              uint64_t cas,
                                              memcached_storage_action verb)
{
  char to_write;
  size_t write_length;
  ssize_t sent_length;
  memcached_return rc;
  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
  unsigned int server_key;

  WATCHPOINT_ASSERT(!(value == NULL && value_length > 0));

  rc= memcached_validate_key_length(key_length, ptr->flags & MEM_BINARY_PROTOCOL);
  unlikely (rc != MEMCACHED_SUCCESS)
    return rc;

  unlikely (ptr->number_of_hosts == 0)
    return MEMCACHED_NO_SERVERS;

  if ((ptr->flags & MEM_VERIFY_KEY) && (memcached_key_test((char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
    return MEMCACHED_BAD_KEY_PROVIDED;

  server_key= memcached_generate_hash(ptr, master_key, master_key_length);

  if (ptr->flags & MEM_BINARY_PROTOCOL)
    return memcached_send_binary(&ptr->hosts[server_key], key, key_length,
                                 value, value_length, expiration,
                                 flags, cas, verb);

  if (cas)
    write_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
                           "%s %s%.*s %u %llu %zu %llu%s\r\n",
                           storage_op_string(verb),
                           ptr->prefix_key,
                           (int)key_length, key, flags,
                           (unsigned long long)expiration, value_length,
                           (unsigned long long)cas,
                           (ptr->flags & MEM_NOREPLY) ? " noreply" : "");
  else
  {
    char *buffer_ptr= buffer;
    const char *command= storage_op_string(verb);

    /* Copy in the command, no space needed, we handle that in the command function*/
    memcpy(buffer_ptr, command, strlen(command));

    /* Copy in the key prefix, switch to the buffer_ptr */
    buffer_ptr= memcpy(buffer_ptr + strlen(command) , ptr->prefix_key, strlen(ptr->prefix_key));

    /* Copy in the key, adjust point if a key prefix was used. */
    buffer_ptr= memcpy(buffer_ptr + (ptr->prefix_key ? strlen(ptr->prefix_key) : 0),
                       key, key_length);
    buffer_ptr+= key_length;
    buffer_ptr[0]=  ' ';
    buffer_ptr++;

    write_length= (size_t)(buffer_ptr - buffer);
    write_length+= snprintf(buffer_ptr, MEMCACHED_DEFAULT_COMMAND_SIZE,
                           "%u %llu %zu%s\r\n",
                           flags,
                           (unsigned long long)expiration, value_length,
                           (ptr->flags & MEM_NOREPLY) ? " noreply" : "");
  }

  if (ptr->flags & MEM_USE_UDP && ptr->flags & MEM_BUFFER_REQUESTS)
  {
    size_t cmd_size= write_length + value_length + 2;
    if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
      return MEMCACHED_WRITE_FAILURE;
    if (cmd_size + ptr->hosts[server_key].write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
      memcached_io_write(&ptr->hosts[server_key], NULL, 0, 1);
  }

  if (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
  {
    rc= MEMCACHED_WRITE_FAILURE;
    goto error;
  }

  /* Send command header */
  rc=  memcached_do(&ptr->hosts[server_key], buffer, write_length, 0);
  if (rc != MEMCACHED_SUCCESS)
    goto error;

  /* Send command body */
  if ((sent_length= memcached_io_write(&ptr->hosts[server_key], value, value_length, 0)) == -1)
  {
    rc= MEMCACHED_WRITE_FAILURE;
    goto error;
  }

  if ((ptr->flags & MEM_BUFFER_REQUESTS) && verb == SET_OP)
    to_write= 0;
  else
    to_write= 1;

  if ((sent_length= memcached_io_write(&ptr->hosts[server_key], "\r\n", 2, to_write)) == -1)
  {
    rc= MEMCACHED_WRITE_FAILURE;
    goto error;
  }

  if (ptr->flags & MEM_NOREPLY)
    return (to_write == 0) ? MEMCACHED_BUFFERED : MEMCACHED_SUCCESS;

  if (to_write == 0)
    return MEMCACHED_BUFFERED;

  rc= memcached_response(&ptr->hosts[server_key], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);

  if (rc == MEMCACHED_STORED)
    return MEMCACHED_SUCCESS;
  else
    return rc;

error:
  memcached_io_reset(&ptr->hosts[server_key]);

  return rc;
}
static inline memcached_return memcached_send(memcached_st *ptr, 
                                              const char *master_key, size_t master_key_length, 
                                              const char *key, size_t key_length, 
                                              const char *value, size_t value_length, 
                                              time_t expiration,
                                              uint32_t flags,
                                              uint64_t cas,
                                              memcached_storage_action verb)
{
  char to_write;
  size_t write_length;
  ssize_t sent_length;
  memcached_return rc;
  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
  unsigned int server_key;

  WATCHPOINT_ASSERT(!(value == NULL && value_length > 0));

  rc= memcached_validate_key_length(key_length, ptr->flags & MEM_BINARY_PROTOCOL);
  unlikely (rc != MEMCACHED_SUCCESS)
    return rc;
  
  unlikely (ptr->number_of_hosts == 0)
    return MEMCACHED_NO_SERVERS;

  if ((ptr->flags & MEM_VERIFY_KEY) && (memcachd_key_test((char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
    return MEMCACHED_BAD_KEY_PROVIDED;

  server_key= memcached_generate_hash(ptr, master_key, master_key_length);

  if (ptr->flags & MEM_BINARY_PROTOCOL)
    return memcached_send_binary(&ptr->hosts[server_key], key, key_length, 
                                 value, value_length, expiration, 
                                 flags, cas, verb);

#ifndef _WIN32
  if (cas)
    write_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 
                           "%s %s%.*s %u %llu %zu %llu%s\r\n", 
                           storage_op_string(verb),
                           ptr->prefix_key,
                           (int)key_length, key, flags, 
                           (unsigned long long)expiration, value_length, 
                           (unsigned long long)cas,
                           (ptr->flags & MEM_NOREPLY) ? " noreply" : "");
  else
    write_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 
                           "%s %s%.*s %u %llu %zu%s\r\n", 
                           storage_op_string(verb),
                           ptr->prefix_key,
                           (int)key_length, key, flags, 
                           (unsigned long long)expiration, value_length,
                           (ptr->flags & MEM_NOREPLY) ? " noreply" : "");
#else
  if (cas)
    write_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 
                           "%s %s%.*s %u %llu %u %llu%s\r\n", 
                           storage_op_string(verb),
                           ptr->prefix_key,
                           (int)key_length, key, flags, 
                           (unsigned long long)expiration, value_length, 
                           (unsigned long long)cas,
                           (ptr->flags & MEM_NOREPLY) ? " noreply" : "");
  else
    write_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 
                           "%s %s%.*s %u %llu %u%s\r\n", 
                           storage_op_string(verb),
                           ptr->prefix_key,
                           (int)key_length, key, flags, 
                           (unsigned long long)expiration, value_length,
                           (ptr->flags & MEM_NOREPLY) ? " noreply" : "");
#endif

  if (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
  {
    rc= MEMCACHED_WRITE_FAILURE;
    goto error;
  }

  /* Send command header */
  rc=  memcached_do(&ptr->hosts[server_key], buffer, write_length, 0);
  if (rc != MEMCACHED_SUCCESS)
    goto error;

  /* Send command body */
  if ((sent_length= memcached_io_write(&ptr->hosts[server_key], value, value_length, 0)) == -1)
  {
    rc= MEMCACHED_WRITE_FAILURE;
    goto error;
  }

  if ((ptr->flags & MEM_BUFFER_REQUESTS) && verb == SET_OP)
    to_write= 0;
  else
    to_write= 1;

  if ((sent_length= memcached_io_write(&ptr->hosts[server_key], "\r\n", 2, to_write)) == -1)
  {
    rc= MEMCACHED_WRITE_FAILURE;
    goto error;
  }

  if (ptr->flags & MEM_NOREPLY)
  {
    memcached_server_response_decrement(&ptr->hosts[server_key]);
    return (to_write == 0) ? MEMCACHED_BUFFERED : MEMCACHED_SUCCESS;
  }

  if (to_write == 0)
    return MEMCACHED_BUFFERED;

  rc= memcached_response(&ptr->hosts[server_key], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);

  if (rc == MEMCACHED_STORED)
    return MEMCACHED_SUCCESS;
  else 
    return rc;

error:
  memcached_io_reset(&ptr->hosts[server_key]);

  return rc;
}