int redis_lpush(lua_State *vm) { char *cmd; sds str; int len, argc, i; const char *id, *key; argc = lua_gettop(vm); argc += 1; id = luaL_checkstring(vm, 1); str = sdsnew("LPUSH"); for(i=2; i<argc; i++) { key = luaL_checkstring(vm, i); str = sdscatprintf(str, " %s", key); } len = redisFormatCommand(&cmd, "%s", str); redis_pack_command(vm, id, cmd, len); zfree(cmd); sdsfree(str); cmd = NULL; return lua_yield(vm, 0); }
int redis_get(lua_State *vm) { int len; char *cmd; const char *id = luaL_checkstring(vm, 1); const char *key = luaL_checkstring(vm, 2); len = redisFormatCommand(&cmd, "GET %s", key); redis_pack_command(vm, id, cmd, len); zfree(cmd); return lua_yield(vm, 0); }
int redis_lindex(lua_State *vm) { int len; char *cmd; const char *id = luaL_checkstring(vm, 1); const char *key = luaL_checkstring(vm, 2); const char *ind = luaL_checkstring(vm, 3); len = redisFormatCommand(&cmd, "LINDEX %s %s", key, ind); redis_pack_command(vm, id, cmd, len); zfree(cmd); cmd = NULL; return lua_yield(vm, 0); }
static void test_append_formatted_commands(struct config config) { redisContext *c; redisReply *reply; char *cmd; int len; c = connect(config); test("Append format command: "); len = redisFormatCommand(&cmd, "SET foo bar"); test_cond(redisAppendFormattedCommand(c, cmd, len) == REDIS_OK); assert(redisGetReply(c, (void*)&reply) == REDIS_OK); free(cmd); freeReplyObject(reply); disconnect(c, 0); }
int main(int argc, const char **argv) { int i; char *data, *cmd; int len; client c; signal(SIGHUP, SIG_IGN); signal(SIGPIPE, SIG_IGN); config.numclients = 50; config.requests = 10000; config.liveclients = 0; config.el = aeCreateEventLoop(1024*10); aeCreateTimeEvent(config.el,1,showThroughput,NULL,NULL); config.keepalive = 1; config.datasize = 3; config.pipeline = 1; config.randomkeys = 0; config.randomkeys_keyspacelen = 0; config.quiet = 0; config.csv = 0; config.loop = 0; config.idlemode = 0; config.latency = NULL; config.clients = listCreate(); config.hostip = "127.0.0.1"; config.hostport = 6379; config.hostsocket = NULL; config.tests = NULL; config.dbnum = 0; i = parseOptions(argc,argv); argc -= i; argv += i; // printf ("SET PAGE POOL SIZE\n"); // set_page_pool_size(config.requests); config.latency = zmalloc(sizeof(long long)*config.requests); if (config.keepalive == 0) { printf("WARNING: keepalive disabled, you probably need 'echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse' for Linux and 'sudo sysctl -w net.inet.tcp.msl=1000' for Mac OS X in order to use a lot of clients/requests\n"); } if (config.idlemode) { printf("Creating %d idle connections and waiting forever (Ctrl+C when done)\n", config.numclients); c = createClient("",0,NULL); /* will never receive a reply */ createMissingClients(c); aeMain(config.el); /* and will wait for every */ } /* Run benchmark with command in the remainder of the arguments. */ if (argc) { sds title = sdsnew(argv[0]); for (i = 1; i < argc; i++) { title = sdscatlen(title, " ", 1); title = sdscatlen(title, (char*)argv[i], strlen(argv[i])); } do { len = redisFormatCommandArgv(&cmd,argc,argv,NULL); benchmark(title,cmd,len); free(cmd); } while(config.loop); return 0; } /* Run default benchmark suite. */ do { data = zmalloc(config.datasize+1); memset(data,'x',config.datasize); data[config.datasize] = '\0'; if (test_is_selected("ping_inline") || test_is_selected("ping")) benchmark("PING_INLINE","PING\r\n",6); if (test_is_selected("ping_mbulk") || test_is_selected("ping")) { len = redisFormatCommand(&cmd,"PING"); benchmark("PING_BULK",cmd,len); free(cmd); } if (test_is_selected("set")) { len = redisFormatCommand(&cmd,"SET key:__rand_int__ %s",data); benchmark("SET",cmd,len); free(cmd); } if (test_is_selected("get")) { len = redisFormatCommand(&cmd,"GET key:__rand_int__"); benchmark("GET",cmd,len); free(cmd); } if (test_is_selected("incr")) { len = redisFormatCommand(&cmd,"INCR counter:__rand_int__"); benchmark("INCR",cmd,len); free(cmd); } if (test_is_selected("lpush")) { len = redisFormatCommand(&cmd,"LPUSH mylist %s",data); benchmark("LPUSH",cmd,len); free(cmd); } if (test_is_selected("lpop")) { len = redisFormatCommand(&cmd,"LPOP mylist"); benchmark("LPOP",cmd,len); free(cmd); } if (test_is_selected("sadd")) { len = redisFormatCommand(&cmd, "SADD myset element:__rand_int__"); benchmark("SADD",cmd,len); free(cmd); } if (test_is_selected("spop")) { len = redisFormatCommand(&cmd,"SPOP myset"); benchmark("SPOP",cmd,len); free(cmd); } if (test_is_selected("lrange") || test_is_selected("lrange_100") || test_is_selected("lrange_300") || test_is_selected("lrange_500") || test_is_selected("lrange_600")) { len = redisFormatCommand(&cmd,"LPUSH mylist %s",data); benchmark("LPUSH (needed to benchmark LRANGE)",cmd,len); free(cmd); } if (test_is_selected("lrange") || test_is_selected("lrange_100")) { len = redisFormatCommand(&cmd,"LRANGE mylist 0 99"); benchmark("LRANGE_100 (first 100 elements)",cmd,len); free(cmd); } if (test_is_selected("lrange") || test_is_selected("lrange_300")) { len = redisFormatCommand(&cmd,"LRANGE mylist 0 299"); benchmark("LRANGE_300 (first 300 elements)",cmd,len); free(cmd); } if (test_is_selected("lrange") || test_is_selected("lrange_500")) { len = redisFormatCommand(&cmd,"LRANGE mylist 0 449"); benchmark("LRANGE_500 (first 450 elements)",cmd,len); free(cmd); } if (test_is_selected("lrange") || test_is_selected("lrange_600")) { len = redisFormatCommand(&cmd,"LRANGE mylist 0 599"); benchmark("LRANGE_600 (first 600 elements)",cmd,len); free(cmd); } if (test_is_selected("mset")) { const char *argv[21]; argv[0] = "MSET"; for (i = 1; i < 21; i += 2) { argv[i] = "key:__rand_int__"; argv[i+1] = data; } len = redisFormatCommandArgv(&cmd,21,argv,NULL); benchmark("MSET (10 keys)",cmd,len); free(cmd); } if (!config.csv) printf("\n"); } while(config.loop); return 0; }
static void test_format_commands(void) { char *cmd; int len; test("Format command without interpolation: "); len = redisFormatCommand(&cmd,"SET foo bar"); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && len == 4+4+(3+2)+4+(3+2)+4+(3+2)); free(cmd); test("Format command with %%s string interpolation: "); len = redisFormatCommand(&cmd,"SET %s %s","foo","bar"); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && len == 4+4+(3+2)+4+(3+2)+4+(3+2)); free(cmd); test("Format command with %%s and an empty string: "); len = redisFormatCommand(&cmd,"SET %s %s","foo",""); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 && len == 4+4+(3+2)+4+(3+2)+4+(0+2)); free(cmd); test("Format command with an empty string in between proper interpolations: "); len = redisFormatCommand(&cmd,"SET %s %s","","foo"); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$0\r\n\r\n$3\r\nfoo\r\n",len) == 0 && len == 4+4+(3+2)+4+(0+2)+4+(3+2)); free(cmd); test("Format command with %%b string interpolation: "); len = redisFormatCommand(&cmd,"SET %b %b","foo",3,"b\0r",3); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nb\0r\r\n",len) == 0 && len == 4+4+(3+2)+4+(3+2)+4+(3+2)); free(cmd); test("Format command with %%b and an empty string: "); len = redisFormatCommand(&cmd,"SET %b %b","foo",3,"",0); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 && len == 4+4+(3+2)+4+(3+2)+4+(0+2)); free(cmd); test("Format command with literal %%: "); len = redisFormatCommand(&cmd,"SET %% %%"); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$1\r\n%\r\n$1\r\n%\r\n",len) == 0 && len == 4+4+(3+2)+4+(1+2)+4+(1+2)); free(cmd); test("Format command with printf-delegation (long long): "); len = redisFormatCommand(&cmd,"key:%08lld",1234ll); test_cond(strncmp(cmd,"*1\r\n$12\r\nkey:00001234\r\n",len) == 0 && len == 4+5+(12+2)); free(cmd); test("Format command with printf-delegation (float): "); len = redisFormatCommand(&cmd,"v:%06.1f",12.34f); test_cond(strncmp(cmd,"*1\r\n$8\r\nv:0012.3\r\n",len) == 0 && len == 4+4+(8+2)); free(cmd); test("Format command with printf-delegation and extra interpolation: "); len = redisFormatCommand(&cmd,"key:%d %b",1234,"foo",3); test_cond(strncmp(cmd,"*2\r\n$8\r\nkey:1234\r\n$3\r\nfoo\r\n",len) == 0 && len == 4+4+(8+2)+4+(3+2)); free(cmd); test("Format command with wrong printf format and extra interpolation: "); len = redisFormatCommand(&cmd,"key:%08p %b",1234,"foo",3); test_cond(strncmp(cmd,"*2\r\n$6\r\nkey:8p\r\n$3\r\nfoo\r\n",len) == 0 && len == 4+4+(6+2)+4+(3+2)); free(cmd); const char *argv[3]; argv[0] = "SET"; argv[1] = "foo\0xxx"; argv[2] = "bar"; size_t lens[3] = { 3, 7, 3 }; int argc = 3; test("Format command by passing argc/argv without lengths: "); len = redisFormatCommandArgv(&cmd,argc,argv,NULL); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && len == 4+4+(3+2)+4+(3+2)+4+(3+2)); free(cmd); test("Format command by passing argc/argv with lengths: "); len = redisFormatCommandArgv(&cmd,argc,argv,lens); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$7\r\nfoo\0xxx\r\n$3\r\nbar\r\n",len) == 0 && len == 4+4+(3+2)+4+(7+2)+4+(3+2)); free(cmd); }
/* Create a benchmark client, configured to send the command passed as 'cmd' of * 'len' bytes. * * The command is copied N times in the client output buffer (that is reused * again and again to send the request to the server) accordingly to the configured * pipeline size. * * Also an initial SELECT command is prepended in order to make sure the right * database is selected, if needed. The initial SELECT will be discarded as soon * as the first reply is received. * * To create a client from scratch, the 'from' pointer is set to NULL. If instead * we want to create a client using another client as reference, the 'from' pointer * points to the client to use as reference. In such a case the following * information is take from the 'from' client: * * 1) The command line to use. * 2) The offsets of the __rand_int__ elements inside the command line, used * for arguments randomization. * * Even when cloning another client, prefix commands are applied if needed.*/ static client createClient(char *cmd, size_t len, client from) { int j; client c = zmalloc(sizeof(struct _client)); if (config.hostsocket == NULL) { c->context = redisConnectNonBlock(config.hostip,config.hostport); } else { c->context = redisConnectUnixNonBlock(config.hostsocket); } if (c->context->err) { fprintf(stderr,"Could not connect to Redis at "); if (config.hostsocket == NULL) fprintf(stderr,"%s:%d: %s\n",config.hostip,config.hostport,c->context->errstr); else fprintf(stderr,"%s: %s\n",config.hostsocket,c->context->errstr); exit(1); } /* Suppress hiredis cleanup of unused buffers for max speed. */ c->context->reader->maxbuf = 0; /* Build the request buffer: * Queue N requests accordingly to the pipeline size, or simply clone * the example client buffer. */ c->obuf = sdsempty(); /* Prefix the request buffer with AUTH and/or SELECT commands, if applicable. * These commands are discarded after the first response, so if the client is * reused the commands will not be used again. */ c->prefix_pending = 0; if (config.auth) { char *buf = NULL; int len = redisFormatCommand(&buf, "AUTH %s", config.auth); c->obuf = sdscatlen(c->obuf, buf, len); free(buf); c->prefix_pending++; } /* If a DB number different than zero is selected, prefix our request * buffer with the SELECT command, that will be discarded the first * time the replies are received, so if the client is reused the * SELECT command will not be used again. */ if (config.dbnum != 0) { c->obuf = sdscatprintf(c->obuf,"*2\r\n$6\r\nSELECT\r\n$%d\r\n%s\r\n", (int)sdslen(config.dbnumstr),config.dbnumstr); c->prefix_pending++; } c->prefixlen = sdslen(c->obuf); /* Append the request itself. */ if (from) { c->obuf = sdscatlen(c->obuf, from->obuf+from->prefixlen, sdslen(from->obuf)-from->prefixlen); } else { for (j = 0; j < config.pipeline; j++) c->obuf = sdscatlen(c->obuf,cmd,len); } c->written = 0; c->pending = config.pipeline+c->prefix_pending; c->randptr = NULL; c->randlen = 0; /* Find substrings in the output buffer that need to be randomized. */ if (config.randomkeys) { if (from) { c->randlen = from->randlen; c->randfree = 0; c->randptr = zmalloc(sizeof(char*)*c->randlen); /* copy the offsets. */ for (j = 0; j < (int)c->randlen; j++) { c->randptr[j] = c->obuf + (from->randptr[j]-from->obuf); /* Adjust for the different select prefix length. */ c->randptr[j] += c->prefixlen - from->prefixlen; } } else { char *p = c->obuf; c->randlen = 0; c->randfree = RANDPTR_INITIAL_SIZE; c->randptr = zmalloc(sizeof(char*)*c->randfree); while ((p = strstr(p,"__rand_int__")) != NULL) { if (c->randfree == 0) { c->randptr = zrealloc(c->randptr,sizeof(char*)*c->randlen*2); c->randfree += c->randlen; } c->randptr[c->randlen++] = p; c->randfree--; p += 12; /* 12 is strlen("__rand_int__). */ } } } if (config.idlemode == 0) aeCreateFileEvent(config.el,c->context->fd,AE_WRITABLE,writeHandler,c); listAddNodeTail(config.clients,c); config.liveclients++; return c; }
static void test_format_commands(void) { char *cmd; int len; test("Format command without interpolation: "); len = redisFormatCommand(&cmd,"SET foo bar"); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && len == 4+4+(3+2)+4+(3+2)+4+(3+2)); free(cmd); test("Format command with %%s string interpolation: "); len = redisFormatCommand(&cmd,"SET %s %s","foo","bar"); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && len == 4+4+(3+2)+4+(3+2)+4+(3+2)); free(cmd); test("Format command with %%s and an empty string: "); len = redisFormatCommand(&cmd,"SET %s %s","foo",""); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 && len == 4+4+(3+2)+4+(3+2)+4+(0+2)); free(cmd); test("Format command with an empty string in between proper interpolations: "); len = redisFormatCommand(&cmd,"SET %s %s","","foo"); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$0\r\n\r\n$3\r\nfoo\r\n",len) == 0 && len == 4+4+(3+2)+4+(0+2)+4+(3+2)); free(cmd); test("Format command with %%b string interpolation: "); len = redisFormatCommand(&cmd,"SET %b %b","foo",(size_t)3,"b\0r",(size_t)3); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nb\0r\r\n",len) == 0 && len == 4+4+(3+2)+4+(3+2)+4+(3+2)); free(cmd); test("Format command with %%b and an empty string: "); len = redisFormatCommand(&cmd,"SET %b %b","foo",(size_t)3,"",(size_t)0); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 && len == 4+4+(3+2)+4+(3+2)+4+(0+2)); free(cmd); test("Format command with literal %%: "); len = redisFormatCommand(&cmd,"SET %% %%"); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$1\r\n%\r\n$1\r\n%\r\n",len) == 0 && len == 4+4+(3+2)+4+(1+2)+4+(1+2)); free(cmd); /* Vararg width depends on the type. These tests make sure that the * width is correctly determined using the format and subsequent varargs * can correctly be interpolated. */ #define INTEGER_WIDTH_TEST(fmt, type) do { \ type value = 123; \ test("Format command with printf-delegation (" #type "): "); \ len = redisFormatCommand(&cmd,"key:%08" fmt " str:%s", value, "hello"); \ test_cond(strncmp(cmd,"*2\r\n$12\r\nkey:00000123\r\n$9\r\nstr:hello\r\n",len) == 0 && \ len == 4+5+(12+2)+4+(9+2)); \ free(cmd); \ } while(0) #define FLOAT_WIDTH_TEST(type) do { \ type value = 123.0; \ test("Format command with printf-delegation (" #type "): "); \ len = redisFormatCommand(&cmd,"key:%08.3f str:%s", value, "hello"); \ test_cond(strncmp(cmd,"*2\r\n$12\r\nkey:0123.000\r\n$9\r\nstr:hello\r\n",len) == 0 && \ len == 4+5+(12+2)+4+(9+2)); \ free(cmd); \ } while(0) INTEGER_WIDTH_TEST("d", int); INTEGER_WIDTH_TEST("hhd", char); INTEGER_WIDTH_TEST("hd", short); INTEGER_WIDTH_TEST("ld", long); INTEGER_WIDTH_TEST("lld", long long); INTEGER_WIDTH_TEST("u", unsigned int); INTEGER_WIDTH_TEST("hhu", unsigned char); INTEGER_WIDTH_TEST("hu", unsigned short); INTEGER_WIDTH_TEST("lu", unsigned long); INTEGER_WIDTH_TEST("llu", unsigned long long); FLOAT_WIDTH_TEST(float); FLOAT_WIDTH_TEST(double); test("Format command with invalid printf format: "); len = redisFormatCommand(&cmd,"key:%08p %b",(void*)1234,"foo",(size_t)3); test_cond(len == -1); const char *argv[3]; argv[0] = "SET"; argv[1] = "foo\0xxx"; argv[2] = "bar"; size_t lens[3] = { 3, 7, 3 }; int argc = 3; test("Format command by passing argc/argv without lengths: "); len = redisFormatCommandArgv(&cmd,argc,argv,NULL); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && len == 4+4+(3+2)+4+(3+2)+4+(3+2)); free(cmd); test("Format command by passing argc/argv with lengths: "); len = redisFormatCommandArgv(&cmd,argc,argv,lens); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$7\r\nfoo\0xxx\r\n$3\r\nbar\r\n",len) == 0 && len == 4+4+(3+2)+4+(7+2)+4+(3+2)); free(cmd); }
int main(int argc, const char **argv) { int i; char *data, *cmd; int len; client c; #ifdef _WIN32 w32initWinSock(); #endif signal(SIGHUP, SIG_IGN); signal(SIGPIPE, SIG_IGN); config.numclients = 50; config.requests = 10000; config.liveclients = 0; config.el = aeCreateEventLoop(); aeCreateTimeEvent(config.el,1,showThroughput,NULL,NULL); config.keepalive = 1; config.datasize = 3; config.randomkeys = 0; config.randomkeys_keyspacelen = 0; config.quiet = 0; config.loop = 0; config.idlemode = 0; config.latency = NULL; config.clients = listCreate(); config.hostip = "127.0.0.1"; config.hostport = 6379; config.hostsocket = NULL; i = parseOptions(argc,argv); argc -= i; argv += i; config.latency = zmalloc(sizeof(long long)*config.requests); if (config.keepalive == 0) { printf("WARNING: keepalive disabled, you probably need 'echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse' for Linux and 'sudo sysctl -w net.inet.tcp.msl=1000' for Mac OS X in order to use a lot of clients/requests\n"); } if (config.idlemode) { printf("Creating %d idle connections and waiting forever (Ctrl+C when done)\n", config.numclients); c = createClient("",0); /* will never receive a reply */ createMissingClients(c); aeMain(config.el); /* and will wait for every */ } /* Run benchmark with command in the remainder of the arguments. */ if (argc) { sds title = sdsnew(argv[0]); for (i = 1; i < argc; i++) { title = sdscatlen(title, " ", 1); title = sdscatlen(title, (char*)argv[i], strlen(argv[i])); } do { len = redisFormatCommandArgv(&cmd,argc,argv,NULL); benchmark(title,cmd,len); free(cmd); } while(config.loop); return 0; } /* Run default benchmark suite. */ do { data = zmalloc(config.datasize+1); memset(data,'x',config.datasize); data[config.datasize] = '\0'; benchmark("PING (inline)","PING\r\n",6); len = redisFormatCommand(&cmd,"PING"); benchmark("PING",cmd,len); free(cmd); const char *argv[21]; argv[0] = "MSET"; for (i = 1; i < 21; i += 2) { argv[i] = "foo:rand:000000000000"; argv[i+1] = data; } len = redisFormatCommandArgv(&cmd,21,argv,NULL); benchmark("MSET (10 keys)",cmd,len); free(cmd); len = redisFormatCommand(&cmd,"SET foo:rand:000000000000 %s",data); benchmark("SET",cmd,len); free(cmd); len = redisFormatCommand(&cmd,"GET foo:rand:000000000000"); benchmark("GET",cmd,len); free(cmd); len = redisFormatCommand(&cmd,"INCR counter:rand:000000000000"); benchmark("INCR",cmd,len); free(cmd); len = redisFormatCommand(&cmd,"LPUSH mylist %s",data); benchmark("LPUSH",cmd,len); free(cmd); len = redisFormatCommand(&cmd,"LPOP mylist"); benchmark("LPOP",cmd,len); free(cmd); len = redisFormatCommand(&cmd,"SADD myset counter:rand:000000000000"); benchmark("SADD",cmd,len); free(cmd); len = redisFormatCommand(&cmd,"SPOP myset"); benchmark("SPOP",cmd,len); free(cmd); len = redisFormatCommand(&cmd,"LPUSH mylist %s",data); benchmark("LPUSH (again, in order to bench LRANGE)",cmd,len); free(cmd); len = redisFormatCommand(&cmd,"LRANGE mylist 0 99"); benchmark("LRANGE (first 100 elements)",cmd,len); free(cmd); len = redisFormatCommand(&cmd,"LRANGE mylist 0 299"); benchmark("LRANGE (first 300 elements)",cmd,len); free(cmd); len = redisFormatCommand(&cmd,"LRANGE mylist 0 449"); benchmark("LRANGE (first 450 elements)",cmd,len); free(cmd); len = redisFormatCommand(&cmd,"LRANGE mylist 0 599"); benchmark("LRANGE (first 600 elements)",cmd,len); free(cmd); printf("\n"); } while(config.loop); #ifdef _WIN32 WSACleanup(); #endif return 0; }