Merge Monty
[m6w6/libmemcached] / tests / function.c
index fcf5b51104008b27b905923d8bec0103ff78565a..c505b1118088247d28f67aca9449ba6ab0079bcf 100644 (file)
@@ -1552,6 +1552,9 @@ static test_return  behavior_test(memcached_st *memc)
   value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE);
   assert(value > 0);
 
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS);
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, value + 1);
+  assert((value + 1) == memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS));
   return 0;
 }
 
@@ -3049,6 +3052,24 @@ static memcached_return  pre_binary(memcached_st *memc)
   return rc;
 }
 
+static memcached_return pre_replication(memcached_st *memc)
+{
+  memcached_return rc= MEMCACHED_FAILURE;
+  if (pre_binary(memc) == MEMCACHED_SUCCESS) 
+  {
+    /*
+     * Make sure that we store the item on all servers 
+     * (master + replicas == number of servers) 
+     */
+    rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, 
+                               memc->number_of_hosts - 1);
+    assert(rc == MEMCACHED_SUCCESS);
+    assert(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS) == memc->number_of_hosts - 1);
+  }
+
+  return rc;
+}
+
 static void my_free(memcached_st *ptr __attribute__((unused)), void *mem)
 {
   free(mem);
@@ -3550,6 +3571,179 @@ static test_return connection_pool_test(memcached_st *memc)
 }
 #endif
 
+static test_return replication_set_test(memcached_st *memc)
+{
+  memcached_return rc;
+  memcached_st *clone= memcached_clone(NULL, memc);
+  memcached_behavior_set(clone, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, 0);
+
+  rc= memcached_set(memc, "bubba", 5, "0", 1, 0, 0);
+  assert(rc == MEMCACHED_SUCCESS);
+
+  /*
+  ** "bubba" should now be stored on all of our servers. We don't have an
+  ** easy to use API to address each individual server, so I'll just iterate
+  ** through a bunch of "master keys" and I should most likely hit all of the
+  ** servers...
+  */
+  for (int x= 'a'; x <= 'z'; ++x)
+  {
+    char key[2]= { [0]= (char)x };
+    size_t len;
+    uint32_t flags;
+    char *val= memcached_get_by_key(clone, key, 1, "bubba", 5, 
+                                    &len, &flags, &rc);
+    assert(rc == MEMCACHED_SUCCESS);
+    assert(val != NULL);
+    free(val);
+  }
+
+  memcached_free(clone);
+
+  return TEST_SUCCESS;
+}
+
+static test_return replication_get_test(memcached_st *memc)
+{
+  memcached_return rc;
+
+  /*
+   * Don't do the following in your code. I am abusing the internal details
+   * within the library, and this is not a supported interface.
+   * This is to verify correct behavior in the library
+   */
+  for (uint32_t host= 0; host < memc->number_of_hosts; ++host) 
+  {
+    memcached_st *clone= memcached_clone(NULL, memc);
+    clone->hosts[host].port= 0;
+
+    for (int x= 'a'; x <= 'z'; ++x)
+    {
+      char key[2]= { [0]= (char)x };
+      size_t len;
+      uint32_t flags;
+      char *val= memcached_get_by_key(clone, key, 1, "bubba", 5, 
+                                      &len, &flags, &rc);
+      assert(rc == MEMCACHED_SUCCESS);
+      assert(val != NULL);
+      free(val);
+    }
+
+    memcached_free(clone);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return replication_mget_test(memcached_st *memc)
+{
+  memcached_return rc;
+  memcached_st *clone= memcached_clone(NULL, memc);
+  memcached_behavior_set(clone, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, 0);
+
+  char *keys[]= { "bubba", "key1", "key2", "key3" };
+  size_t len[]= { 5, 4, 4, 4 };
+
+  for (int x=0; x< 4; ++x)
+  {
+    rc= memcached_set(memc, keys[x], len[x], "0", 1, 0, 0);
+    assert(rc == MEMCACHED_SUCCESS);
+  }
+
+  /*
+   * Don't do the following in your code. I am abusing the internal details
+   * within the library, and this is not a supported interface.
+   * This is to verify correct behavior in the library
+   */
+  memcached_result_st result_obj;
+  for (uint32_t host= 0; host < clone->number_of_hosts; host++) 
+  {
+    memcached_st *new_clone= memcached_clone(NULL, memc);
+    new_clone->hosts[host].port= 0;
+
+    for (int x= 'a'; x <= 'z'; ++x)
+    {
+      char key[2]= { [0]= (char)x };
+
+      rc= memcached_mget_by_key(new_clone, key, 1, keys, len, 4);
+      assert(rc == MEMCACHED_SUCCESS);
+
+      memcached_result_st *results= memcached_result_create(new_clone, &result_obj);
+      assert(results);
+
+      int hits= 0;
+      while ((results= memcached_fetch_result(new_clone, &result_obj, &rc)) != NULL)
+      {
+        hits++;
+      }
+      assert(hits == 4);
+      memcached_result_free(&result_obj);
+    }
+
+    memcached_free(new_clone);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return replication_delete_test(memcached_st *memc)
+{
+  memcached_return rc;
+  memcached_st *clone= memcached_clone(NULL, memc);
+  /* Delete the items from all of the servers except 1 */
+  uint64_t repl= memcached_behavior_get(memc,
+                                        MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS);
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, --repl);
+
+  char *keys[]= { "bubba", "key1", "key2", "key3" };
+  size_t len[]= { 5, 4, 4, 4 };
+
+  for (int x=0; x< 4; ++x)
+  {
+    rc= memcached_delete_by_key(memc, keys[0], len[0], keys[x], len[x], 0);
+    assert(rc == MEMCACHED_SUCCESS);
+  }
+
+  /*
+   * Don't do the following in your code. I am abusing the internal details
+   * within the library, and this is not a supported interface.
+   * This is to verify correct behavior in the library
+   */
+  uint32_t hash= memcached_generate_hash(memc, keys[0], len[0]);
+  for (uint32_t x= 0; x < (repl + 1); ++x) 
+  {
+    clone->hosts[hash].port= 0;
+    if (++hash == clone->number_of_hosts)
+      hash= 0;
+  }
+
+  memcached_result_st result_obj;
+  for (uint32_t host= 0; host < clone->number_of_hosts; ++host) 
+  {
+    for (int x= 'a'; x <= 'z'; ++x)
+    {
+      char key[2]= { [0]= (char)x };
+
+      rc= memcached_mget_by_key(clone, key, 1, keys, len, 4);
+      assert(rc == MEMCACHED_SUCCESS);
+
+      memcached_result_st *results= memcached_result_create(clone, &result_obj);
+      assert(results);
+
+      int hits= 0;
+      while ((results= memcached_fetch_result(clone, &result_obj, &rc)) != NULL)
+      {
+        ++hits;
+      }
+      assert(hits == 4);
+      memcached_result_free(&result_obj);
+    }
+  }
+  memcached_free(clone);
+
+  return TEST_SUCCESS;
+}
+
 static void increment_request_id(uint16_t *id)
 {
   (*id)++;
@@ -3562,6 +3756,7 @@ static uint16_t *get_udp_request_ids(memcached_st *memc)
   uint16_t *ids= malloc(sizeof(uint16_t) * memc->number_of_hosts);
   assert(ids != NULL);
   unsigned int x;
+
   for (x= 0; x < memc->number_of_hosts; x++)
     ids[x]= get_udp_datagram_request_id((struct udp_datagram_header_st *) memc->hosts[x].write_buffer);
 
@@ -3573,6 +3768,7 @@ static test_return post_udp_op_check(memcached_st *memc, uint16_t *expected_req_
   unsigned int x;
   memcached_server_st *cur_server = memc->hosts;
   uint16_t *cur_req_ids = get_udp_request_ids(memc);
+
   for (x= 0; x < memc->number_of_hosts; x++)
   {
     assert(cur_server[x].cursor_active == 0);
@@ -3580,6 +3776,7 @@ static test_return post_udp_op_check(memcached_st *memc, uint16_t *expected_req_
   }
   free(expected_req_ids);
   free(cur_req_ids);
+
   return TEST_SUCCESS;
 }
 
@@ -3601,6 +3798,7 @@ static memcached_return init_udp(memcached_st *memc)
   memcpy(servers, memc->hosts, sizeof(memcached_server_st) * num_hosts);
   for (x= 0; x < num_hosts; x++)
     memcached_server_free(&memc->hosts[x]);
+
   memc->number_of_hosts= 0;
   memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, 1);
   for (x= 0; x < num_hosts; x++)
@@ -3608,6 +3806,7 @@ static memcached_return init_udp(memcached_st *memc)
     assert(memcached_server_add_udp(memc, servers[x].hostname, servers[x].port) == MEMCACHED_SUCCESS);
     assert(memc->hosts[x].write_buffer_offset == UDP_DATAGRAM_HEADER_LENGTH);
   }
+
   return MEMCACHED_SUCCESS;
 }
 
@@ -4255,6 +4454,14 @@ test_st user_tests[] ={
   {0, 0, 0}
 };
 
+test_st replication_tests[]= {
+  {"set", 1, replication_set_test },
+  {"get", 0, replication_get_test },
+  {"mget", 0, replication_mget_test },
+  {"delete", 0, replication_delete_test },
+  {0, 0, 0}
+};
+
 test_st generate_tests[] ={
   {"generate_pairs", 1, generate_pairs },
   {"generate_data", 1, generate_data },
@@ -4359,6 +4566,7 @@ collection_st collection[] ={
   {"consistent_ketama", pre_behavior_ketama, 0, consistent_tests},
   {"consistent_ketama_weighted", pre_behavior_ketama_weighted, 0, consistent_weighted_tests},
   {"test_hashes", 0, 0, hash_tests},
+  {"replication", pre_replication, 0, replication_tests},
   {0, 0, 0, 0}
 };