memcached_get

一、memcached_get

内部只是调用memcached_get_by_key(ptr, NULL, 0, key, key_length, value_length, flags, error)。memcached_get_by_key()内部主要调用memcached_mget_by_key_real()和memcached_fetch()。之后,它还会调用一次针对dummy的memcached_fetch()。

由于memcached_get()先使用memcached_mget_by_key_real()向某个服务器发送命令,之后调用的memcached_fetch()仅仅是获得一个key/value记录,至于从哪个机器获得以及获得的key是什么都是不做限制的,因此memcached_get()并不适合于多线程中。这种说法对不对??

哈哈,确实如此。因此需要为每个线程使用独立的memcached_st,从而每个线程使用不同的套接口,但这也导致连接数的增多。

参考链接:http://lists.libmemcached.org/pipermail/libmemcached-discuss/2008-August/000420.html

二、memcached_mget_by_key_real

static memcached_return_t memcached_mget_by_key_real(memcached_st *ptr,
                                                     const char *group_key,
                                                     size_t group_key_length,
                                                     const char * const *keys,
                                                     const size_t *key_length,
                                                     size_t number_of_keys,
                                                     bool mget_mode)
{
  bool failures_occured_in_sending= false;
  const char *get_command= "get ";
  uint8_t get_command_length= 4;
  unsigned int master_server_key= (unsigned int)-1; /* 0 is a valid server id! */

  memcached_return_t rc;
  if (memcached_failed(rc= initialize_query(ptr, true)))  //主要作用ptr->query_id++
  {
    return rc;
  }
  ...

  if (number_of_keys == 0)
  {
    return memcached_set_error(*ptr, MEMCACHED_NOTFOUND, MEMCACHED_AT, memcached_literal_param("number_of_keys was zero"));
  }

  if (memcached_failed(memcached_key_test(*ptr, keys, key_length, number_of_keys)))
  {
    return memcached_set_error(*ptr, MEMCACHED_BAD_KEY_PROVIDED, MEMCACHED_AT, memcached_literal_param("A bad key value was provided"));
  }

  bool is_group_key_set= false;
  if (group_key and group_key_length)
  {
    if (memcached_failed(memcached_key_test(*ptr, (const char * const *)&group_key, &group_key_length, 1)))
    {
      return memcached_set_error(*ptr, MEMCACHED_BAD_KEY_PROVIDED, MEMCACHED_AT, memcached_literal_param("A bad group key was provided."));
    }

    master_server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
    is_group_key_set= true;
  }

  /*
    Here is where we pay for the non-block API. We need to remove any data sitting
    in the queue before we start our get.

    It might be optimum to bounce the connection if count > some number.
  */
  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)  //将输入缓冲区中或即将进入输入缓冲区的response处理掉。
  {
    memcached_server_write_instance_st instance=
      memcached_server_instance_fetch(ptr, x);

    if (memcached_server_response_count(instance))
    {
      char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];

      if (ptr->flags.no_block)
      {
        memcached_io_write(instance);
      }

      while(memcached_server_response_count(instance))
      {
        (void)memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, &ptr->result);
      }
    }
  }

  if (ptr->flags.binary_protocol)
  {
    return binary_mget_by_key(ptr, master_server_key, is_group_key_set, keys,
                              key_length, number_of_keys, mget_mode);
  }

  if (ptr->flags.support_cas)
  {
    get_command= "gets ";
    get_command_length= 5;
  }

  /*
    If a server fails we warn about errors and start all over with sending keys
    to the server.
  */
  WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS);
  size_t hosts_connected= 0;
  for (uint32_t x= 0; x < number_of_keys; x++)
  {
    memcached_server_write_instance_st instance;
    uint32_t server_key;

    if (is_group_key_set)
    {
      server_key= master_server_key;
    }
    else
    {
      server_key= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]); //这个暂不讨论,只是产生服务器id
    }

    instance= memcached_server_instance_fetch(ptr, server_key);

    libmemcached_io_vector_st vector[]=
    {
      { get_command, get_command_length },
      { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) },
      { keys[x], key_length[x] },
      { memcached_literal_param(" ") }
    };


    if (memcached_server_response_count(instance) == 0)
    {
      rc= memcached_connect(instance); //连接尚未断开,所以直接返回成功

      if (memcached_failed(rc))
      {
        memcached_set_error(*instance, rc, MEMCACHED_AT);
        continue;
      }
      hosts_connected++;

      if ((memcached_io_writev(instance, vector, 4, false)) == -1)  //将命令写入instance的write_buffer
      {
        failures_occured_in_sending= true;
        continue;
      }
      WATCHPOINT_ASSERT(instance->cursor_active == 0);
      memcached_server_response_increment(instance);  //执行(instance)->cursor_active++
      WATCHPOINT_ASSERT(instance->cursor_active == 1);
    }
    else
    {
      if ((memcached_io_writev(instance, (vector + 1), 3, false)) == -1)
      {
        memcached_server_response_reset(instance);
        failures_occured_in_sending= true;
        continue;
      }
    }
  }

  if (hosts_connected == 0)
  {
    LIBMEMCACHED_MEMCACHED_MGET_END();

    if (memcached_failed(rc))
    {
      return rc;
    }

    return memcached_set_error(*ptr, MEMCACHED_NO_SERVERS, MEMCACHED_AT);
  }


  /*
    Should we muddle on if some servers are dead?
  */
  bool success_happened= false;
  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
  {
    memcached_server_write_instance_st instance=
      memcached_server_instance_fetch(ptr, x);

    if (memcached_server_response_count(instance))
    {
      /* We need to do something about non-connnected hosts in the future */
      if ((memcached_io_write(instance, "\r\n", 2, true)) == -1)   //此时才将instance->write_buffer中的命令发给服务器
      {
        failures_occured_in_sending= true;
      }
      else
      {
        success_happened= true;
      }
    }
  }

  LIBMEMCACHED_MEMCACHED_MGET_END();

  if (failures_occured_in_sending && success_happened)
  {
    return MEMCACHED_SOME_ERRORS;
  }

  if (success_happened)
    return MEMCACHED_SUCCESS;

  return MEMCACHED_FAILURE; // Complete failure occurred
}

三、memcached_fetch

当memcached_mget_by_key_real()执行完后,即我们已经向服务器发送了指令,服务器会给我们发送如"VALUE key 0 5\r\n"value\r\nEND\r\n"这样的答复。

第一次memcached_fetch()处理了"VALUE key 0 5\r\n"value\r\n"部分的数据,获得value值;之后,memcached_get_by_key()又一次调用memcached_fetch(),这一次是个dummy,当value最终textual_read_one_response()解析"END\r\n",并返回MEMCACHED_END。至此,一次完整的memcached_get()就算完成了

经分析,memcached_fetch(memcached_st *ptr, char *key, size_t *key_length, size_t *value_length, uint32_t *flags, memcached_return_t *error)的作用是获得一条key/value,放入ptr->result(struct memcached_result_st)中,至于从哪个服务器获得、获得哪个key并不确定。

memcached_fetch()主要调用memcached_fetch_result()。

1、memcached_fetch_result(memcached_st *ptr, memcached_result_st *result,  memcached_return_t *error)

其中,result传入&ptr->result。

memcached_result_st *memcached_fetch_result(memcached_st *ptr,
                                            memcached_result_st *result,
                                            memcached_return_t *error)
{
  ...

  *error= MEMCACHED_MAXIMUM_RETURN; // We use this to see if we ever go into the loop
  memcached_server_st *server;
  while ((server= memcached_io_get_readable_server(ptr))) //获得一个可读的服务器
  {
    char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
    *error= memcached_response(server, buffer, sizeof(buffer), result);

    if (*error == MEMCACHED_IN_PROGRESS)
    {
      continue;
    }
    else if (*error == MEMCACHED_SUCCESS)
    {
      result->count++;     //成功则result->count++,表示引用计数。
      return result;       //成功则直接返回
    }
    else if (*error == MEMCACHED_END)
    {
      memcached_server_response_reset(server);  //执行(server)->cursor_active=0,这就是解析"END\r\n"后的效果。
    }                                           //可以看到解析到"END\r\n"并不退出循环,而是看是不是还有可读的服务器?
    else if (*error != MEMCACHED_NOTFOUND)
    {
      break;
    }
  }

  if (*error == MEMCACHED_NOTFOUND and result->count)
  {
    *error= MEMCACHED_END;
  }
  else if (*error == MEMCACHED_MAXIMUM_RETURN and result->count)
  {
    *error= MEMCACHED_END;
  }
  else if (*error == MEMCACHED_MAXIMUM_RETURN) // while() loop was never entered
  {
    *error= MEMCACHED_NOTFOUND;
  }
  else if (*error == MEMCACHED_SUCCESS)
  {
    *error= MEMCACHED_END;
  }
  else if (result->count == 0)
  {
    *error= MEMCACHED_NOTFOUND;
  }

  /* We have completed reading data */  //对于MEMCACHED_END,往下继续执行
  if (memcached_is_allocated(result))
  {
    memcached_result_free(result);
  }
  else
  {
    result->count= 0;          //引用计数设为0
    memcached_string_reset(&result->value);
  }

  return NULL;
}

根据上一节,memcached_response()会调用_read_one_response(),进而调用textual_read_one_response(),对于"VALUE",会调用textual_value_fetch(ptr, buffer, result)。该函数在解析完"VALUE key 0 5\r\n"(填写memcached_result_st* result)之后会调用memcached_io_read()将随后的value值(即"value\r\n")读入result->value(即struct memcached_string_st)。不过这里还有一行"END\r\n"没有解析,留给第二次memcached_fetch()(dummy效果)处理。

2、memcached_io_get_readable_server(memcached_st *memc)

memcached_server_write_instance_st memcached_io_get_readable_server(memcached_st *memc)
{
#define MAX_SERVERS_TO_POLL 100
  struct pollfd fds[MAX_SERVERS_TO_POLL];
  unsigned int host_index= 0;

  for (uint32_t x= 0; x < memcached_server_count(memc) && host_index < MAX_SERVERS_TO_POLL; ++x)
  {
    memcached_server_write_instance_st instance= memcached_server_instance_fetch(memc, x);

    if (instance->read_buffer_length > 0) /* I have data in the buffer */
    {
      return instance;
    }

    if (memcached_server_response_count(instance) > 0)
    {
      fds[host_index].events = POLLIN;
      fds[host_index].revents = 0;
      fds[host_index].fd = instance->fd;
      ++host_index;
    }
  }

  if (host_index < 2)
  {
    /* We have 0 or 1 server with pending events.. */
    for (uint32_t x= 0; x< memcached_server_count(memc); ++x)
    {
      memcached_server_write_instance_st instance=
        memcached_server_instance_fetch(memc, x);

      if (memcached_server_response_count(instance) > 0)
      {
        return instance;
      }
    }

    return NULL;
  }

  int error= poll(fds, host_index, memc->poll_timeout);
  switch (error)
  {
  case -1:
    memcached_set_errno(*memc, get_socket_errno(), MEMCACHED_AT);
    /* FALLTHROUGH */
  case 0:
    break;

  default:
    for (size_t x= 0; x < host_index; ++x)
    {
      if (fds[x].revents & POLLIN)
      {
        for (uint32_t y= 0; y < memcached_server_count(memc); ++y)
        {
          memcached_server_write_instance_st instance=
            memcached_server_instance_fetch(memc, y);

          if (instance->fd == fds[x].fd)
            return instance;
        }
      }
    }
  }

  return NULL;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值