Beispiel #1
0
/* create a memcached structure */
static memcached_st *memc_new()
{
  char config_string[1024];
  memcached_st *memc = NULL;
  memcached_server_st *servers = NULL;
  unsigned long long getter;
  memcached_return_t rc;

  pthread_mutex_lock (&printmutex);
  sprintf(config_string, "--SERVER=%s --BINARY-PROTOCOL", serverip);
  printf("config_string = %s\n", config_string);
  //memc = memcached(config_string, strlen(config_string));
  memc = memcached_create(NULL);
  servers = memcached_server_list_append(servers, serverip, 11211, &rc);
  rc = memcached_server_push(memc, servers);
  if (rc == MEMCACHED_SUCCESS)
	  fprintf(stderr, "Added server successfully\n");
  else
	  fprintf(stderr, "Couldnt add server: %s\n", serverip);

  getter = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NO_BLOCK);
  printf("No block: %lld\n", getter);
  getter = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE);
  printf("Socket send size: %lld\n", getter);
  getter = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE);
  printf("Socket recv size: %lld\n", getter);
  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1);

  pthread_mutex_unlock (&printmutex);
  return memc;
}
Beispiel #2
0
/**
  @note This should be testing to see if the server really supports the binary protocol.
*/
static test_return_t pre_binary(memcached_st *memc)
{
    memcached_return_t rc= MEMCACHED_FAILURE;
    memcached_st *memc_clone;
    memcached_server_instance_st instance;

    memc_clone= memcached_clone(NULL, memc);
    test_true(memc_clone);
    // The memcached_version needs to be done on a clone, because the server
    // will not toggle protocol on an connection.
    memcached_version(memc_clone);

    instance= memcached_server_instance_by_position(memc_clone, 0);

    if (instance->major_version >= 1 && instance->minor_version > 2)
    {
        rc = memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1);
        test_true(rc == MEMCACHED_SUCCESS);
        test_true(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 1);
    }

    memcached_free(memc_clone);

    return rc == MEMCACHED_SUCCESS ? TEST_SUCCESS : TEST_SKIPPED;
}
/*
  Set the value, then quit to make sure it is flushed.
  Come back in and test that add fails.
*/
static test_return_t add_test(memcached_st *memc)
{
  memcached_return_t rc;
  const char *key= "foo";
  const char *value= "when we sanitize";
  unsigned long long setting_value;

  setting_value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NO_BLOCK);

  rc= memcached_set(memc, key, strlen(key),
                    value, strlen(value),
                    (time_t)0, (uint32_t)0);
  test_true(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
  memcached_quit(memc);
  rc= memcached_add(memc, key, strlen(key),
                    value, strlen(value),
                    (time_t)0, (uint32_t)0);

  /* Too many broken OS'es have broken loopback in async, so we can't be sure of the result */
  if (setting_value)
  {
    test_true(rc == MEMCACHED_NOTSTORED || rc == MEMCACHED_STORED);
  }
  else
  {
    test_true(rc == MEMCACHED_NOTSTORED);
  }

  return 0;
}
static int php_memc_sess_lock(memcached_st *memc, const char *key)
{
	char *lock_key = NULL;
	int lock_key_len = 0;
	unsigned long attempts;
	long write_retry_attempts = 0;
	long lock_maxwait = MEMC_G(sess_lock_max_wait);
	long lock_wait = MEMC_G(sess_lock_wait);
	long lock_expire = MEMC_G(sess_lock_expire);
	time_t expiration;
	memcached_return status;
	/* set max timeout for session_start = max_execution_time.  (c) Andrei Darashenka, Richter & Poweleit GmbH */
	if (lock_maxwait <= 0) {
		lock_maxwait = zend_ini_long(ZEND_STRS("max_execution_time"), 0);
		if (lock_maxwait <= 0) {
			lock_maxwait = MEMC_SESS_LOCK_EXPIRATION;
		}
	}
	if (lock_wait == 0) {
		lock_wait = MEMC_SESS_DEFAULT_LOCK_WAIT;
	}
	if (lock_expire <= 0) {
		lock_expire = lock_maxwait;
	}
	expiration  = lock_expire + 1;
	attempts = (unsigned long)((1000000.0 / lock_wait) * lock_maxwait);

	/* Set the number of write retry attempts to the number of replicas times the number of attempts to remove a server */
	if (MEMC_G(sess_remove_failed_enabled)) {
		write_retry_attempts = MEMC_G(sess_number_of_replicas) * ( memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT) + 1);
	}

	lock_key_len = spprintf(&lock_key, 0, "lock.%s", key);
	do {
		status = memcached_add(memc, lock_key, lock_key_len, "1", sizeof("1")-1, expiration, 0);
		if (status == MEMCACHED_SUCCESS) {
			MEMC_G(sess_locked) = 1;
			MEMC_G(sess_lock_key) = lock_key;
			MEMC_G(sess_lock_key_len) = lock_key_len;
			return 0;
		} else if (status != MEMCACHED_NOTSTORED && status != MEMCACHED_DATA_EXISTS) {
			if (write_retry_attempts > 0) {
				write_retry_attempts--;
				continue;
			}
			php_error_docref(NULL, E_WARNING, "Write of lock failed");
			break;
		}

		if (lock_wait > 0) {
			usleep(lock_wait);
		}
	} while(--attempts > 0);

	efree(lock_key);
	return -1;
}
Beispiel #5
0
/* create a memcached structure */
static memcached_st *memc_new()
{
  char config_string[1024];
  memcached_st *memc = NULL;
  unsigned long long getter;

  pthread_mutex_lock (&printmutex);
  sprintf(config_string, "--SERVER=%s --BINARY-PROTOCOL", serverip);
  printf("config_string = %s\n", config_string);
  memc = memcached(config_string, strlen(config_string));

  getter = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NO_BLOCK);
  printf("No block: %lld\n", getter);
  getter = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE);
  printf("Socket send size: %lld\n", getter);
  getter = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE);
  printf("Socket recv size: %lld\n", getter);

  pthread_mutex_unlock (&printmutex);
  return memc;
}
memcached_return run_distribution(memcached_st *ptr)
{
  switch (ptr->distribution) 
  {
  case MEMCACHED_DISTRIBUTION_CONSISTENT:
  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
    return update_continuum(ptr);
  case MEMCACHED_DISTRIBUTION_MODULA:
    if (ptr->flags & MEM_USE_SORT_HOSTS)
      sort_hosts(ptr);
    if (memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS))
      update_live_host_indices(ptr);
    break;
  case MEMCACHED_DISTRIBUTION_RANDOM:
    if (memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS))
      update_live_host_indices(ptr);
    break;
  default:
    WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
  }

  return MEMCACHED_SUCCESS;
}
memcached_return 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 = ptr->hosts;

  /* count live servers (those without a retry delay set) */
  is_auto_ejecting= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS);
  if (is_auto_ejecting)
  {
    live_servers= 0;
    ptr->next_distribution_rebuild= 0;
    for (host_index= 0; host_index < ptr->number_of_hosts; ++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= ptr->number_of_hosts;

  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= ptr->call_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 < ptr->number_of_hosts; ++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 < ptr->number_of_hosts; ++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
    }
    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-%d",
                                            list[host_index].hostname,
                                            pointer_index - 1);

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

      if (is_ketama_weighted)
      {
        unsigned int i;
        for (i = 0; i < pointer_per_hash; i++)
        {
          value= ketama_server_hash(sort_host, (uint32_t) sort_host_length, (int) i);
          ptr->continuum[continuum_index].index= host_index;
          ptr->continuum[continuum_index++].value= value;
        }
      }
      else
      {
        value= memcached_generate_hash_value(sort_host, sort_host_length, ptr->hash_continuum);
        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(ptr->number_of_hosts * 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; ptr->number_of_hosts && 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;
}
Beispiel #8
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;
}
Beispiel #9
0
static int mcache_set_options(pr_memcache_t *mcache, unsigned long flags,
    uint64_t nreplicas) {
  memcached_return res;
  uint64_t val;

  val = memcached_behavior_get(mcache->mc, MEMCACHED_BEHAVIOR_TCP_NODELAY);
  if (val != 1) {
    res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1);
    if (res != MEMCACHED_SUCCESS) {
      pr_trace_msg(trace_channel, 4,
        "error setting TCP_NODELAY behavior on connection: %s",
        memcached_strerror(mcache->mc, res));
    }
  }

  /* Enable caching of DNS lookups. */
  val = memcached_behavior_get(mcache->mc, MEMCACHED_BEHAVIOR_CACHE_LOOKUPS);
  if (val != 1) {
    res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_CACHE_LOOKUPS,
      1);
    if (res != MEMCACHED_SUCCESS) {
      pr_trace_msg(trace_channel, 4,
        "error setting CACHE_LOOKUPS behavior on connection: %s",
        memcached_strerror(mcache->mc, res));
    }
  }

  /* Verify that all keys are correct. */
  val = memcached_behavior_get(mcache->mc, MEMCACHED_BEHAVIOR_VERIFY_KEY);
  if (val != 1) {
    res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_VERIFY_KEY, 1);
    if (res != MEMCACHED_SUCCESS) {
      pr_trace_msg(trace_channel, 4,
        "error setting VERIFY_KEY behavior on connection: %s",
        memcached_strerror(mcache->mc, res));
    }
  }

  /* We always want consistent hashing, to minimize cache churn when
   * servers are added/removed from the list.
   */
  val = memcached_behavior_get(mcache->mc, MEMCACHED_BEHAVIOR_DISTRIBUTION);
  if (val != MEMCACHED_DISTRIBUTION_CONSISTENT) {
    res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_DISTRIBUTION,
      MEMCACHED_DISTRIBUTION_CONSISTENT);
    if (res != MEMCACHED_SUCCESS) {
      pr_trace_msg(trace_channel, 4,
        "error setting DISTRIBUTION_CONSISTENT behavior on connection: %s",
        memcached_strerror(mcache->mc, res));
    }
  }

  /* Use blocking IO */
  val = memcached_behavior_get(mcache->mc, MEMCACHED_BEHAVIOR_NO_BLOCK);
  if (val != 0) {
    res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_NO_BLOCK, 0);
    if (res != MEMCACHED_SUCCESS) {
      pr_trace_msg(trace_channel, 4,
        "error setting NO_BLOCK behavior on connection: %s",
        memcached_strerror(mcache->mc, res));
    }
  }

  val = memcached_behavior_get(mcache->mc,
    MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT);
  if (memcache_sess_conn_failures > 0) {
    res = memcached_behavior_set(mcache->mc,
      MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT, memcache_sess_conn_failures);

    if (res != MEMCACHED_SUCCESS) {
      pr_trace_msg(trace_channel, 4,
        "error setting SERVER_FAILURE_LIMIT behavior on connection: %s",
        memcached_strerror(mcache->mc, res));

    } else {
      /* Automatically eject hosts which have reached this failure limit;
       * keeping them around in the memcached_st struct only causes
       * confusion.  Note that this requires that an ejected timeout value
       * be configured.
       */

      if (memcache_ejected_sec > 0) {
        res = memcached_behavior_set(mcache->mc,
          MEMCACHED_BEHAVIOR_RETRY_TIMEOUT, memcache_ejected_sec);
        if (res != MEMCACHED_SUCCESS) {
          pr_trace_msg(trace_channel, 4,
            "error setting RETRY_TIMEOUT behavior on connection to %lu ms: %s",
            memcache_ejected_sec, memcached_strerror(mcache->mc, res));
        }

        res = memcached_behavior_set(mcache->mc,
          MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS, 1);
        if (res != MEMCACHED_SUCCESS) {
          pr_trace_msg(trace_channel, 4,
            "error setting AUTO_EJECT_HOSTS behavior on connection: %s",
            memcached_strerror(mcache->mc, res));
        }
      }
    }
  }

  /* Use the binary protocol by default, unless explicitly requested not to. */
  val = memcached_behavior_get(mcache->mc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL);
  pr_trace_msg(trace_channel, 16,
    "found BINARY_PROTOCOL=%s default behavior (val %lu) for connection",
    val != 1 ? "false" : "true", (unsigned long) val);

  if (val != 1) {
    if (!(flags & PR_MEMCACHE_FL_NO_BINARY_PROTOCOL)) {
      res = memcached_behavior_set(mcache->mc,
        MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1);
      if (res != MEMCACHED_SUCCESS) {
        pr_trace_msg(trace_channel, 4,
          "error setting BINARY_PROTOCOL=true behavior on connection: %s",
          memcached_strerror(mcache->mc, res));

      } else {
        pr_trace_msg(trace_channel, 16, "%s",
          "set BINARY_PROTOCOL=true for connection");
      }
    }

  } else {
    if (flags & PR_MEMCACHE_FL_NO_BINARY_PROTOCOL) {
      res = memcached_behavior_set(mcache->mc,
        MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 0);
      if (res != MEMCACHED_SUCCESS) {
        pr_trace_msg(trace_channel, 4,
          "error setting BINARY_PROTOCOL=false behavior on connection: %s",
          memcached_strerror(mcache->mc, res));

      } else {
        pr_trace_msg(trace_channel, 16, "%s",
          "set BINARY_PROTOCOL=false for connection");
      }
    }
  }

  /* Configure the timeouts. */
  res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT,
    memcache_conn_millis);
  if (res != MEMCACHED_SUCCESS) {
    pr_trace_msg(trace_channel, 4,
      "error setting CONNECT_TIMEOUT behavior on connection to %lu ms: %s",
      memcache_conn_millis, memcached_strerror(mcache->mc, res));
  }

  res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_RCV_TIMEOUT,
    memcache_rcv_millis);
  if (res != MEMCACHED_SUCCESS) {
    pr_trace_msg(trace_channel, 4,
      "error setting RCV_TIMEOUT behavior on connection to %lu ms: %s",
      memcache_rcv_millis, memcached_strerror(mcache->mc, res));
  }

  res = memcached_behavior_set(mcache->mc, MEMCACHED_BEHAVIOR_SND_TIMEOUT,
    memcache_snd_millis);
  if (res != MEMCACHED_SUCCESS) {
    pr_trace_msg(trace_channel, 4,
      "error setting SND_TIMEOUT behavior on connection to %lu ms: %s",
      memcache_snd_millis, memcached_strerror(mcache->mc, res));
  }

  /* Make sure that the requested number of replicas does not exceed the
   * server count.
   */
  if (nreplicas > memcached_server_count(mcache->mc)) {
    nreplicas = memcached_server_count(mcache->mc);
  }

  /* XXX Some caveats about libmemcached replication:
   *
   *  1.  Replication is enabled only if the binary protocol is used.
   *  2.  Replication occurs only for 'delete', 'get, 'set' operations, NOT
   *      'add', 'cas', 'incr', 'decr', etc.
   */

  if (nreplicas > 0 &&
      !(flags & PR_MEMCACHE_FL_NO_BINARY_PROTOCOL)) {

    res = memcached_behavior_set(mcache->mc,
      MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, nreplicas);
    if (res != MEMCACHED_SUCCESS) {
      pr_trace_msg(trace_channel, 4,
        "error setting NUMBER_OF_REPLICAS behavior on connection: %s",
        memcached_strerror(mcache->mc, res));

    } else {
      pr_trace_msg(trace_channel, 9, "storing %lu %s",
        (unsigned long) nreplicas, nreplicas != 1 ? "replicas" : "replica");
    }
  }

  /* Use randomized reads from replicas by default, unless explicitly
   * requested not to.
   */
  val = memcached_behavior_get(mcache->mc,
    MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ);
  if (val != 1) {
    if (!(flags & PR_MEMCACHE_FL_NO_RANDOM_REPLICA_READ)) {
      res = memcached_behavior_set(mcache->mc,
        MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ, 1);

      if (res != MEMCACHED_SUCCESS) {
        pr_trace_msg(trace_channel, 4,
          "error setting RANDOMIZE_REPLICA_READ behavior on connection: %s",
          memcached_strerror(mcache->mc, res));
      }
    }
  }

  return 0;
}
Beispiel #10
0
static bool use_binary(memcached_st* mc) {
  return memcached_behavior_get(mc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) != 0;
}
Beispiel #11
0
memcached_return update_continuum(memcached_st *ptr)
{
  uint32_t index;
  uint32_t host_index;
  uint32_t continuum_index= 0;
  uint32_t value;
  memcached_server_st *list;
  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;
  uint32_t is_ketama_weighted= 0;
  uint32_t points_per_server= 0;

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

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

    if (ptr->call_realloc)
      new_ptr= (memcached_continuum_item_st *)ptr->call_realloc(ptr, ptr->continuum, sizeof(memcached_continuum_item_st) * (ptr->number_of_hosts + MEMCACHED_CONTINUUM_ADDITION) * points_per_server);
    else
      new_ptr= (memcached_continuum_item_st *)realloc(ptr->continuum, sizeof(memcached_continuum_item_st) * (ptr->number_of_hosts + MEMCACHED_CONTINUUM_ADDITION) * points_per_server);

    if (new_ptr == 0)
      return MEMCACHED_MEMORY_ALLOCATION_FAILURE;

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

  list = ptr->hosts;

  if (is_ketama_weighted) 
  {
    for (host_index = 0; host_index < ptr->number_of_hosts; ++host_index) 
    {
      if (list[host_index].weight == 0)
      {
        list[host_index].weight = 1;
      }
      total_weight += list[host_index].weight;
    }
  }

  for (host_index = 0; host_index < ptr->number_of_hosts; ++host_index) 
  {
    if (is_ketama_weighted) 
    {
        float pct = (float)list[host_index].weight / (float)total_weight;
        pointer_per_server= floorf(pct * MEMCACHED_POINTS_PER_SERVER_KETAMA / 4 * (float)(ptr->number_of_hosts) + 0.0000000001) * 4;
        pointer_per_hash= 4;
#ifdef HAVE_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
    }
    for (index= 1; index <= pointer_per_server / pointer_per_hash; ++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= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH, "%s-%d", 
                                   list[host_index].hostname, index - 1);

      }
      else
      {
        sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH, "%s:%d-%d", 
                                   list[host_index].hostname, list[host_index].port, index - 1);
      }
      WATCHPOINT_ASSERT(sort_host_length);

      if (is_ketama_weighted)
      {
        int i;
        for (i = 0; i < pointer_per_hash; i++)
        {
          value= ketama_server_hash(sort_host, sort_host_length, i);
          ptr->continuum[continuum_index].index= host_index;
          ptr->continuum[continuum_index++].value= value;
        }
      }
      else
      {
        value= generate_hash_value(sort_host, sort_host_length, ptr->hash_continuum);
        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(ptr->number_of_hosts * 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 HAVE_DEBUG
  for (index= 0; ptr->number_of_hosts && index < ((ptr->number_of_hosts * MEMCACHED_POINTS_PER_SERVER) - 1); index++) 
  {
    WATCHPOINT_ASSERT(ptr->continuum[index].value <= ptr->continuum[index + 1].value);
  }
#endif

  return MEMCACHED_SUCCESS;
}