Esempio n. 1
0
void memcached_quit_server(memcached_server_st *ptr, bool io_death)
{
  if (ptr->fd != -1)
  {
    if (io_death == false && ptr->type != MEMCACHED_CONNECTION_UDP && ptr->options.is_shutting_down == false)
    {
      memcached_return_t rc;
      char buffer[MEMCACHED_MAX_BUFFER];

      ptr->options.is_shutting_down= true;

      if (ptr->root->flags.binary_protocol)
      {
        protocol_binary_request_quit request;
        memset(&request, 0, sizeof(request));
        request.message.header.request.magic = PROTOCOL_BINARY_REQ;
        request.message.header.request.opcode = PROTOCOL_BINARY_CMD_QUIT;
        request.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
        rc= memcached_do(ptr, request.bytes, sizeof(request.bytes), true);
      }
      else
      {
        rc= memcached_do(ptr, "quit\r\n", strlen("quit\r\n"), true);
      }

      WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_FETCH_NOTFINISHED);
      (void)rc; /* Shut up ICC */

      /* read until socket is closed, or there is an error
       * closing the socket before all data is read
       * results in server throwing away all data which is
       * not read
       *
       * In .40 we began to only do this if we had been doing buffered
       * requests of had replication enabled.
       */
      if (ptr->root->flags.buffer_requests || ptr->root->number_of_replicas)
      {
        ssize_t nread;
        while (memcached_io_read(ptr, buffer, sizeof(buffer)/sizeof(*buffer),
                                 &nread) == MEMCACHED_SUCCESS);
      }


      /*
       * memcached_io_read may call memcached_quit_server with io_death if
       * it encounters problems, but we don't care about those occurences.
       * The intention of that loop is to drain the data sent from the
       * server to ensure that the server processed all of the data we
       * sent to the server.
       */
      ptr->server_failure_counter= 0;
    }
    memcached_io_close(ptr);
  }

  ptr->fd= -1;
  ptr->io_bytes_sent= 0;
  ptr->write_buffer_offset= (size_t) ((ptr->type == MEMCACHED_CONNECTION_UDP) ? UDP_DATAGRAM_HEADER_LENGTH : 0);
  ptr->read_buffer_length= 0;
  ptr->read_ptr= ptr->read_buffer;
  ptr->options.is_shutting_down= false;
  memcached_server_response_reset(ptr);

  /* We reset the version so that if we end up talking to a different server */
  /* we don't have stale server version information. */
  ptr->major_version= ptr->minor_version= ptr->micro_version= UINT8_MAX;

  if (io_death)
  {
    ptr->server_failure_counter++;
    set_last_disconnected_host(ptr);
  }
}
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;
}