/* * MDCacheD basic functionality test application / regression tests * (c) 2007.-2011. Ivan Voras * $Id: test_mdcached.c 475 2012-04-08 10:27:00Z ivoras $ */ #include #include #include #include #include #include #include #include #include #include #include "linux-shims.h" #include #include #include #include #include #include #include #include #include #include "mc_protocol.h" #include "mc_client.h" char *server_host = MC_DEFAULT_UNIX_SOCKET; int server_port = MC_DEFAULT_INET_PORT; int is_unix_socket = TRUE; int scale = 1; struct mc_connection *conn; #define N_HANDSHAKES 10000 #define N_DATA 10000 double get_time() { struct timeval tv; gettimeofday(&tv, NULL); return (double)(tv.tv_sec) + (double)(tv.tv_usec / 1000000.0); } int gen_value(char *value, int i) { return sprintf(value, "%05d - %03x %d %d %d", i, N_DATA-i, i, i, i); } int main(int argc, char **argv) { int i; int ch, res; char *err; double t1, t2; char *name, *value, *value0; unsigned int name_len, value_len, value0_len, n_tags; struct mc_tag tags1[2], *tags; tag_value_t tval[2]; struct mc_multidata_result *mdres; struct mc_multistring_result *msres; struct mc_data_entry *records[2]; uint16_t key_lengths[2]; char *keys[2]; struct mc_data_entry *rp; int64_t ll; while ((ch = getopt(argc, argv, "c:s:h")) != -1) { switch (ch) { case 'h': printf("usage: %s [-c server] [-s #] [-h]\n", argv[0]); printf(" -c server Server to connect to (default = local unix socket)\n"); printf(" -s # Scale of tests (larger # -> test more data)\n"); exit(0); break; case 'c': server_host = optarg; is_unix_socket = FALSE; break; case 's': scale = atoi(optarg); break; default: fprintf(stderr, "Unknown argument: %c\n", ch); exit(1); } } printf("Structure size survey: mc_header(%zd) mc_handshake(%zd) mc_data_entry(%zd)\nConnecting...\n", sizeof(struct mc_header), sizeof(struct mc_handshake), sizeof(struct mc_data_entry)); if (is_unix_socket) conn = mc_connect_local(server_host, TRUE, &err); else conn = mc_connect_tcp(server_host, server_port, TRUE, &err); if (conn == NULL) errx(1, "%s", err); /* Test basic operations */ printf("Connection ok (with handshake). Testing handshake speed.\n"); t1 = get_time(); for (i = 0; i < N_HANDSHAKES*scale; i++) if (mc_perform_handshake(conn, &err) != MC_RESULT_OK) errx(1, "%s", err); t2 = get_time(); printf("%u handshakes took %0.3lf seconds: %0.1lf handshakes/s\n", N_HANDSHAKES*scale, t2-t1, (N_HANDSHAKES*scale)/(t2-t1)); name = malloc(100); value = malloc(500); printf("Testing ADD operation\n"); t1 = get_time(); for (i = 0; i < N_DATA*scale; i++) { name_len = sprintf(name, "%d", i); value_len = gen_value(value, i); if (mc_put_simple(conn, name, name_len, value, value_len, 120, &err) != MC_RESULT_OK) errx(1, "mc_put_simple: %s", err); } t2 = get_time(); printf("%u additions took %0.3lf seconds: %0.1lf additions/s\n", N_DATA*scale, t2-t1, (N_DATA*scale)/(t2-t1)); printf("Testing GET operation\n"); t1 = get_time(); for (i = 0; i < N_DATA*scale; i++) { name_len = sprintf(name, "%d", i); value_len = gen_value(value, i); res = mc_get_simple(conn, name, name_len, &value0, &value0_len, &err); if (res != MC_RESULT_OK) errx(1, "Error in mc_get_simple: %s (%d)", err, res); if (memcmp(value0, value, value0_len) != 0) errx(1, "Value mismatch for %s", name); free(value0); } t2 = get_time(); printf("%u retrievals took %0.3lf seconds: %0.1lf additions/s\n", N_DATA*scale, t2-t1, (N_DATA*scale)/(t2-t1)); printf("Testing large data PUT & GET\n"); value_len = 64*1024; value = realloc(value, value_len); name_len = sprintf(name, "large-data"); if (mc_put_simple(conn, name, name_len, value, value_len, 120, &err) != MC_RESULT_OK) errx(1, "mc_put_simple: %s\n", err); res = mc_get_simple(conn, name, name_len, &value0, &value0_len, &err); if (res != MC_RESULT_OK) errx(1, "mc_get_simple: %s\n", err); /* Test tags: insertion */ printf("Testing ADD with TAGS operation\n"); t1 = get_time(); for (i = 0; i < N_DATA*scale; i++) { name_len = sprintf(name, "t-%d", i); value_len = gen_value(value, i); tags1[0].key = -1; tags1[0].value = i; tags1[1].key = i % 500; tags1[1].value = i; if (mc_put_simple_tags(conn, name, name_len, value, value_len, tags1, 2, 120, &err) != MC_RESULT_OK) errx(1, "%s", err); } t2 = get_time(); printf("%u additions took %0.3lf seconds: %0.1lf additions/s\n", N_DATA*scale, t2-t1, (N_DATA*scale)/(t2-t1)); /* Test tags: retrieval */ printf("Testing TAGS retrieval\n"); tval[0] = 0; tval[1] = 10; res = mc_get_by_tag_values(conn, -1, tval, 2, &mdres, &err); if (res != MC_RESULT_OK) errx(1, "mc_get_by_tag_values: %s (%d)", err, res); if (mdres->n_records != 2) errx(1, "Exactly 2 records needed to be returned; instead, %d were returned", mdres->n_records); name = calloc(1, 100); for (i = 0; i < mdres->n_records; i++) { rp = mdres->records[i]; strlcpy(name, mc_data_entry_key(rp), rp->name_size+1); if (strcmp(name, "t-0") != 0 && strcmp(name, "t-10") != 0) errx(1, "Returned records not the #0 and #10 as exepected! Got \"%s\"", name); } assert(mdres->pkt != NULL); mc_multidata_result_free(mdres); /* Test tags: deletion */ printf("Testing TAGS deletion\n"); if (mc_perform_handshake(conn, &err) != MC_RESULT_OK) errx(1, "%s", err); if (mc_del_by_tag_values(conn, -1, tval, 2, NULL, &err) != MC_RESULT_OK) errx(1, "mc_del_by_tag_values: %s", err); /* Test get_all_keys */ printf("Testing GET_ALL_KEYS\n"); if ((res = mc_get_all_keys(conn, 0, &msres, &err)) != MC_RESULT_OK) errx(1, "mc_get_all_keys: %d, %s", res, err); for (i = 0; i < msres->n_records; i++) if (memcmp(msres->records[i]->data, "t-0", 4) == 0 || memcmp(msres->records[i]->data, "t-10", 5) == 0) errx(1, "Found supposedly deleted record: %s", msres->records[i]->data); if (mc_perform_handshake(conn, &err) != MC_RESULT_OK) errx(1, "%s", err); /* Test mput */ printf("Testing MPUT\n"); mc_build_data_entry(&records[0], "mdr0", 5, "data0", 6, NULL, 0, 10, MC_SEQ); mc_build_data_entry(&records[1], "mdr1", 5, "data1", 6, NULL, 0, 10, MC_SEQ); if (mc_mput(conn, 2, records, 0, &err) != MC_RESULT_OK) errx(1, "mc_mput: %s", err); if (mc_get_simple(conn, "mdr0", 5, &value0, &value0_len, &err) != MC_RESULT_OK) errx(1, "mc_get_simple after mc_mput failure: %s (0)", err); if (mc_get_simple(conn, "mdr1", 5, &value0, &value0_len, &err) != MC_RESULT_OK) errx(1, "mc_get_simple after mc_mput failure: %s (1)", err); if (mc_perform_handshake(conn, &err) != MC_RESULT_OK) errx(1, "%s", err); /* Test mget */ printf("Testing MGET\n"); key_lengths[0] = key_lengths[1] = 5; keys[0] = "mdr0"; keys[1] = "mdr1"; if (mc_mget(conn, 2, key_lengths, keys, 0, &mdres, &err) != MC_RESULT_OK) errx(1, "mc_mget: %s", err); if (mdres->n_records != 2) errx(1, "n_records after mc_mget mismatch (%d)", mdres->n_records); rp = mdres->records[0]; if (memcmp(mc_data_entry_key(rp), keys[0], 5) != 0) errx(1, "memcmp after mc_mget failure (name, 0)"); if (memcmp(mc_data_entry_value(rp), "data0", 6) != 0) errx(1, "memcmp after mc_mget failure (data, 0)"); rp = mdres->records[1]; if (memcmp(mc_data_entry_key(rp), keys[1], 5) != 0) errx(1, "memcmp after mc_mget failure (name, 1)"); if (memcmp(mc_data_entry_value(rp), "data1", 6) != 0) errx(1, "memcmp after mc_mget failure (data, 1)"); if (mc_perform_handshake(conn, &err) != MC_RESULT_OK) errx(1, "%s", err); /* Test tstack operation */ printf("Testing TSTACK\n"); tags1[0].key = 50; tags1[0].value = 100; if (mc_tstack_push(conn, tags1, 1, "in_tstack1", sizeof("in_tstack1"), &name, &name_len, &err) != MC_RESULT_OK) errx(1, "%s", err); if (mc_tstack_push(conn, tags1, 1, "in_tstack2", sizeof("in_tstack2"), &name, &name_len, &err) != MC_RESULT_OK) errx(1, "%s", err); i = 0; while (1) { if ((res = mc_tstack_pop(conn, tags1[0].key, tags1[0].value, &rp, &err)) == MC_RESULT_OK) { switch (i) { case 0: if (memcmp(mc_data_entry_value(rp), "in_tstack2", sizeof("in_tstack2")) != 0) warnx("Unexpected stack element at 0: %s", mc_data_entry_value(rp)); break; case 1: if (memcmp(mc_data_entry_value(rp), "in_tstack1", sizeof("in_tstack2")) != 0) warnx("Unexpected stack element at 0: %s", mc_data_entry_value(rp)); break; default: errx(1, "tstack failure: more elements than there should be"); } free(rp); i++; } else { if (i != 2) errx(1, "tstack failure: less elements than there should be!"); break; } } /* Test atomic ops */ printf("Testing ATOMIC\n"); if ((res = mc_atomic_get(conn, "atomic-", 7, &ll, &err)) != MC_RESULT_NOT_FOUND) errx(1, "ATOMIC_GET failure: found impossible record: %d", res); if (mc_atomic_put(conn, "atomic0", 7, 0, NULL, 0, 0, &err) != MC_RESULT_OK) errx(1, "%s", err); if (mc_atomic_add(conn, "atomic0", 7, 5, &ll, &err) != MC_RESULT_OK) errx(1, "%s", err); if (ll != 5) errx(1, "ATOMIC_ADD failure: got %lld, expected %lld", (long long)ll, 5LL); if (mc_atomic_get(conn, "atomic0", 7, &ll, &err) != MC_RESULT_OK) errx(1, "ATOMIC_GET failure"); if (ll != 5) errx(1, "ATOMIC_GET failure: got %lld, expected %lld", (long long)ll, 5LL); printf("Testing SET_TAGS\n"); if (mc_put_simple(conn, "recT", 4, "value0", 6, 120, &err) != MC_RESULT_OK) errx(1, "mc_put_simple"); if (mc_get_simple_tags(conn, "recT", 4, &value, &value_len, &tags, &n_tags, &err) != MC_RESULT_OK) errx(1, "mc_get_simple_tags"); if (n_tags != 0) errx(1, "mc_get_simple_tags returned a record with %d tags", n_tags); tags1[0].key = 31; tags1[0].value = 41; tags1[1].key = 59; tags1[1].value = 26; if (mc_set_tags(conn, "recT", 4, tags1, 2, &err) != MC_RESULT_OK) errx(1, "mc_set_tags"); if (mc_get_simple_tags(conn, "recT", 4, &value, &value_len, &tags, &n_tags, &err) != MC_RESULT_OK) errx(1, "mc_get_simple_tags"); if (n_tags != 2) errx(1, "mc_get_simple_tags returned a record with %d tags", n_tags); for (i = 0; i < 2; i++) if ((tags[i].key != 31 && tags[i].key != 59) || (tags[i].value != 41 && tags[i].value != 26)) errx(1, "tags bogus?"); if (mc_perform_handshake(conn, &err) != MC_RESULT_OK) errx(1, "%s", err); printf("Ok.\n"); return 0; }