Example #1
0
static memcached_return_t server_add(memcached_st *ptr, const char *hostname,
                                     in_port_t port,
                                     uint32_t weight,
                                     memcached_connection_t type)
{
  memcached_server_st *new_host_list;
  memcached_server_write_instance_st instance;

  if ( (ptr->flags.use_udp && type != MEMCACHED_CONNECTION_UDP)
      || ( (type == MEMCACHED_CONNECTION_UDP) && (! ptr->flags.use_udp) ) )
    return MEMCACHED_INVALID_HOST_PROTOCOL;

  new_host_list= libmemcached_realloc(ptr, memcached_server_list(ptr),
                                      sizeof(memcached_server_st) * (ptr->number_of_hosts + 1));

  if (new_host_list == NULL)
    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;

  memcached_server_list_set(ptr, new_host_list);

  /* TODO: Check return type */
  instance= memcached_server_instance_fetch(ptr, memcached_server_count(ptr));
  (void)memcached_server_create_with(ptr, instance, hostname, port, weight, type);
  ptr->number_of_hosts++;

  instance= memcached_server_instance_fetch(ptr, 0);
  memcached_servers_set_count(instance, memcached_server_count(ptr));

  return run_distribution(ptr);
}
Example #2
0
memcached_return_t memcached_server_push(memcached_st *ptr, const memcached_server_list_st list)
{
  uint32_t count;
  memcached_server_st *new_host_list;
  uint32_t x;

  if (! list)
    return MEMCACHED_SUCCESS;

  count= memcached_server_list_count(list);
  new_host_list= libmemcached_realloc(ptr, memcached_server_list(ptr),
                                      sizeof(memcached_server_st) * (count + memcached_server_count(ptr)));

  if (! new_host_list)
    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;

  memcached_server_list_set(ptr, new_host_list);

  for (x= 0; x < count; x++)
  {
    memcached_server_write_instance_st instance;

    if ((ptr->flags.use_udp && list[x].type != MEMCACHED_CONNECTION_UDP)
            || ((list[x].type == MEMCACHED_CONNECTION_UDP)
            && ! (ptr->flags.use_udp)) )
      return MEMCACHED_INVALID_HOST_PROTOCOL;

    WATCHPOINT_ASSERT(list[x].hostname[0] != 0);

    instance= memcached_server_instance_fetch(ptr, memcached_server_count(ptr));

    /* TODO check return type */
    (void)memcached_server_create_with(ptr, instance, list[x].hostname,
                                       list[x].port, list[x].weight, list[x].type);
    ptr->number_of_hosts++;
  }

  /* Provides backwards compatibility with server list. */
  {
    memcached_server_write_instance_st instance;
    instance= memcached_server_instance_fetch(ptr, 0);
    instance->number_of_hosts= memcached_server_count(ptr);
  }

  return run_distribution(ptr);
}
Example #3
0
static memcached_return_t update_continuum(memcached_st *ptr)
{
  uint32_t host_index;
  uint32_t continuum_index= 0;
  uint32_t value;
  memcached_server_st *list;
  uint32_t pointer_index;
  uint32_t pointer_counter= 0;
  uint32_t pointer_per_server= MEMCACHED_POINTS_PER_SERVER;
  uint32_t pointer_per_hash= 1;
  uint64_t total_weight= 0;
  uint64_t is_ketama_weighted= 0;
  uint64_t is_auto_ejecting= 0;
  uint32_t points_per_server= 0;
  uint32_t live_servers= 0;
  struct timeval now;

  if (gettimeofday(&now, NULL) != 0)
  {
    ptr->cached_errno = errno;
    return MEMCACHED_ERRNO;
  }

  list = memcached_server_list(ptr);

  /* count live servers (those without a retry delay set) */
  is_auto_ejecting= _is_auto_eject_host(ptr);
  if (is_auto_ejecting)
  {
    live_servers= 0;
    ptr->next_distribution_rebuild= 0;
    for (host_index= 0; host_index < memcached_server_count(ptr); ++host_index)
    {
      if (list[host_index].next_retry <= now.tv_sec)
        live_servers++;
      else
      {
        if (ptr->next_distribution_rebuild == 0 || list[host_index].next_retry < ptr->next_distribution_rebuild)
          ptr->next_distribution_rebuild= list[host_index].next_retry;
      }
    }
  }
  else
  {
    live_servers= memcached_server_count(ptr);
  }

  is_ketama_weighted= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
  points_per_server= (uint32_t) (is_ketama_weighted ? MEMCACHED_POINTS_PER_SERVER_KETAMA : MEMCACHED_POINTS_PER_SERVER);

  if (live_servers == 0)
    return MEMCACHED_SUCCESS;

  if (live_servers > ptr->continuum_count)
  {
    memcached_continuum_item_st *new_ptr;

    new_ptr= libmemcached_realloc(ptr, ptr->continuum,
                                  sizeof(memcached_continuum_item_st) * (live_servers + MEMCACHED_CONTINUUM_ADDITION) * points_per_server);

    if (new_ptr == 0)
      return MEMCACHED_MEMORY_ALLOCATION_FAILURE;

    ptr->continuum= new_ptr;
    ptr->continuum_count= live_servers + MEMCACHED_CONTINUUM_ADDITION;
  }

  if (is_ketama_weighted)
  {
    for (host_index = 0; host_index < memcached_server_count(ptr); ++host_index)
    {
      if (list[host_index].weight == 0)
      {
        list[host_index].weight = 1;
      }
      if (! is_auto_ejecting || list[host_index].next_retry <= now.tv_sec)
        total_weight += list[host_index].weight;
    }
  }

  for (host_index= 0; host_index < memcached_server_count(ptr); ++host_index)
  {
    if (is_auto_ejecting && list[host_index].next_retry > now.tv_sec)
      continue;

    if (is_ketama_weighted)
    {
        float pct = (float)list[host_index].weight / (float)total_weight;
        pointer_per_server= (uint32_t) ((floorf((float) (pct * MEMCACHED_POINTS_PER_SERVER_KETAMA / 4 * (float)live_servers + 0.0000000001))) * 4);
        pointer_per_hash= 4;
#ifdef DEBUG
        printf("ketama_weighted:%s|%d|%llu|%u\n",
               list[host_index].hostname,
               list[host_index].port,
               (unsigned long long)list[host_index].weight,
               pointer_per_server);
#endif
    }


    if (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY)
    {
      for (pointer_index= 0;
           pointer_index < pointer_per_server / pointer_per_hash;
           pointer_index++)
      {
        char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= "";
        size_t sort_host_length;

        // Spymemcached ketema key format is: hostname/ip:port-index
        // If hostname is not available then: /ip:port-index
        sort_host_length= (size_t) snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
                                            "/%s:%u-%u",
                                            list[host_index].hostname,
                                            (uint32_t)list[host_index].port,
                                            pointer_index);
#ifdef DEBUG
        printf("update_continuum: key is %s\n", sort_host);
#endif

        WATCHPOINT_ASSERT(sort_host_length);

        if (is_ketama_weighted)
        {
          for (uint32_t x= 0; x < pointer_per_hash; x++)
          {
             value= ketama_server_hash(sort_host, sort_host_length, x);
             ptr->continuum[continuum_index].index= host_index;
             ptr->continuum[continuum_index++].value= value;
          }
        }
        else
        {
          value= hashkit_digest(&ptr->distribution_hashkit, sort_host, sort_host_length);
          ptr->continuum[continuum_index].index= host_index;
          ptr->continuum[continuum_index++].value= value;
        }
      }
    }
    else
    {
      for (pointer_index= 1;
           pointer_index <= pointer_per_server / pointer_per_hash;
           pointer_index++)
      {
        char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= "";
        size_t sort_host_length;

        if (list[host_index].port == MEMCACHED_DEFAULT_PORT)
        {
          sort_host_length= (size_t) snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
                                              "%s-%u",
                                              list[host_index].hostname,
                                              pointer_index - 1);
        }
        else
        {
          sort_host_length= (size_t) snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
                                              "%s:%u-%u",
                                              list[host_index].hostname,
                                              (uint32_t)list[host_index].port,
                                              pointer_index - 1);
        }

        WATCHPOINT_ASSERT(sort_host_length);

        if (is_ketama_weighted)
        {
          for (uint32_t x = 0; x < pointer_per_hash; x++)
          {
             value= ketama_server_hash(sort_host, sort_host_length, x);
             ptr->continuum[continuum_index].index= host_index;
             ptr->continuum[continuum_index++].value= value;
          }
        }
        else
        {
          value= hashkit_digest(&ptr->distribution_hashkit, sort_host, sort_host_length);
          ptr->continuum[continuum_index].index= host_index;
          ptr->continuum[continuum_index++].value= value;
        }
      }
    }

    pointer_counter+= pointer_per_server;
  }

  WATCHPOINT_ASSERT(ptr);
  WATCHPOINT_ASSERT(ptr->continuum);
  WATCHPOINT_ASSERT(memcached_server_count(ptr) * MEMCACHED_POINTS_PER_SERVER <= MEMCACHED_CONTINUUM_SIZE);
  ptr->continuum_points_counter= pointer_counter;
  qsort(ptr->continuum, ptr->continuum_points_counter, sizeof(memcached_continuum_item_st), continuum_item_cmp);

#ifdef DEBUG
  for (pointer_index= 0; memcached_server_count(ptr) && pointer_index < ((live_servers * MEMCACHED_POINTS_PER_SERVER) - 1); pointer_index++)
  {
    WATCHPOINT_ASSERT(ptr->continuum[pointer_index].value <= ptr->continuum[pointer_index + 1].value);
  }
#endif

  return MEMCACHED_SUCCESS;
}
Example #4
0
static memcached_return_t textual_read_one_response(memcached_server_write_instance_st ptr,
                                                    char *buffer, size_t buffer_length,
                                                    memcached_result_st *result)
{
  memcached_return_t rc= memcached_io_readline(ptr, buffer, buffer_length);
  if (rc != MEMCACHED_SUCCESS)
    return rc;

  if (!memcached_server_response_decrement(ptr, 0))
  {
    return MEMCACHED_PROTOCOL_ERROR;
  }

  switch(buffer[0])
  {
  case 'V': /* VALUE || VERSION */
    if (buffer[1] == 'A') /* VALUE */
    {
      /* We add back in one because we will need to search for END */
      memcached_server_response_increment(ptr, 0);
      return textual_value_fetch(ptr, buffer, result);
    }
    else if (buffer[1] == 'E') /* VERSION */
    {
      return MEMCACHED_SUCCESS;
    }
    else
    {
      WATCHPOINT_STRING(buffer);
      return MEMCACHED_UNKNOWN_READ_FAILURE;
    }
  case 'O': /* OK */
    return MEMCACHED_SUCCESS;
  case 'S': /* STORED STATS SERVER_ERROR */
    {
      if (buffer[2] == 'A') /* STORED STATS */
      {
        memcached_server_response_increment(ptr, 0);
        return MEMCACHED_STAT;
      }
      else if (buffer[1] == 'E') /* SERVER_ERROR */
      {
        char *rel_ptr;
        char *startptr= buffer + 13, *endptr= startptr;

        while (*endptr != '\r' && *endptr != '\n') endptr++;

        /*
          Yes, we could make this "efficent" but to do that we would need
          to maintain more state for the size of the buffer. Why waste
          memory in the struct, which is important, for something that
          rarely should happen?
        */
        rel_ptr= (char *)libmemcached_realloc(ptr->root,
                                              ptr->cached_server_error,
                                              (size_t) (endptr - startptr + 1));

        if (rel_ptr == NULL)
        {
          /* If we happened to have some memory, we just null it since we don't know the size */
          if (ptr->cached_server_error)
            ptr->cached_server_error[0]= 0;
          return MEMCACHED_SERVER_ERROR;
        }
        ptr->cached_server_error= rel_ptr;

        memcpy(ptr->cached_server_error, startptr, (size_t) (endptr - startptr));
        ptr->cached_server_error[endptr - startptr]= 0;
        return MEMCACHED_SERVER_ERROR;
      }
      else if (buffer[1] == 'T')
        return MEMCACHED_STORED;
      else
      {
        WATCHPOINT_STRING(buffer);
        return MEMCACHED_UNKNOWN_READ_FAILURE;
      }
    }
  case 'D': /* DELETED */
    return MEMCACHED_DELETED;
  case 'N': /* NOT_FOUND */
    {
      if (buffer[4] == 'F')
        return MEMCACHED_NOTFOUND;
      else if (buffer[4] == 'S')
        return MEMCACHED_NOTSTORED;
      else
      {
        WATCHPOINT_STRING(buffer);
        return MEMCACHED_UNKNOWN_READ_FAILURE;
      }
    }
  case 'E': /* PROTOCOL ERROR or END */
    {
      if (buffer[1] == 'N')
        return MEMCACHED_END;
      else if (buffer[1] == 'R')
        return MEMCACHED_PROTOCOL_ERROR;
      else if (buffer[1] == 'X')
        return MEMCACHED_DATA_EXISTS;
      else
      {
        WATCHPOINT_STRING(buffer);
        return MEMCACHED_UNKNOWN_READ_FAILURE;
      }

    }
  case 'I': /* CLIENT ERROR */
    /* We add back in one because we will need to search for END */
    memcached_server_response_increment(ptr, 0);
    return MEMCACHED_ITEM;
  case 'C': /* CLIENT ERROR */
    return MEMCACHED_CLIENT_ERROR;
  default:
    {
      unsigned long long auto_return_value;

      if (sscanf(buffer, "%llu", &auto_return_value) == 1)
        return MEMCACHED_SUCCESS;

      WATCHPOINT_STRING(buffer);
      return MEMCACHED_UNKNOWN_READ_FAILURE;
    }
  }

  /* NOTREACHED */
}