return sum / REDIS_OPS_SEC_SAMPLES;
}
-void closeTimedoutClient(redisClient *c) {
- time_t now = time(NULL);
+/* Check for timeouts. Returns non-zero if the client was terminated */
+int clientsCronHandleTimeout(redisClient *c) {
+ time_t now = server.unixtime;
if (server.maxidletime &&
!(c->flags & REDIS_SLAVE) && /* no timeout for slaves */
{
redisLog(REDIS_VERBOSE,"Closing idle client");
freeClient(c);
+ return 1;
} else if (c->flags & REDIS_BLOCKED) {
if (c->bpop.timeout != 0 && c->bpop.timeout < now) {
addReply(c,shared.nullmultibulk);
unblockClientWaitingData(c);
}
}
+ return 0;
+}
+
+/* The client query buffer is an sds.c string that can end with a lot of
+ * free space not used, this function reclaims space if needed.
+ *
+ * The funciton always returns 0 as it never terminates the client. */
+int clientsCronResizeQueryBuffer(redisClient *c) {
+ size_t querybuf_size = sdsAllocSize(c->querybuf);
+ time_t idletime = server.unixtime - c->lastinteraction;
+
+ /* There are two conditions to resize the query buffer:
+ * 1) Query buffer is > BIG_ARG and too big for latest peak.
+ * 2) Client is inactive and the buffer is bigger than 1k. */
+ if (((querybuf_size > REDIS_MBULK_BIG_ARG) &&
+ (querybuf_size/(c->querybuf_peak+1)) > 2) ||
+ (querybuf_size > 1024 && idletime > 2))
+ {
+ /* Only resize the query buffer if it is actually wasting space. */
+ if (sdsavail(c->querybuf) > 1024) {
+ c->querybuf = sdsRemoveFreeSpace(c->querybuf);
+ }
+ }
+ /* Reset the peak again to capture the peak memory usage in the next
+ * cycle. */
+ c->querybuf_peak = 0;
+ return 0;
}
void clientsCron(void) {
* in the worst case we process all the clients in 10 seconds.
* In normal conditions (a reasonable number of clients) we process
* all the clients in a shorter time. */
- int iterations = listLength(server.clients)/100;
- if (iterations < 50) iterations = 50;
+ int numclients = listLength(server.clients);
+ int iterations = numclients/100;
+ if (iterations < 50)
+ iterations = (numclients < 50) ? numclients : 50;
while(listLength(server.clients) && iterations--) {
redisClient *c;
listNode *head;
listRotate(server.clients);
head = listFirst(server.clients);
c = listNodeValue(head);
- closeTimedoutClient(c);
+ /* The following functions do different service checks on the client.
+ * The protocol is that they return non-zero if the client was
+ * terminated. */
+ if (clientsCronHandleTimeout(c)) continue;
+ if (clientsCronResizeQueryBuffer(c)) continue;
}
}
fprintf(stderr,"Usage: ./redis-server [/path/to/redis.conf] [options]\n");
fprintf(stderr," ./redis-server - (read config from stdin)\n");
fprintf(stderr," ./redis-server -v or --version\n");
- fprintf(stderr," ./redis-server -h or --help\n\n");
+ fprintf(stderr," ./redis-server -h or --help\n");
+ fprintf(stderr," ./redis-server --test-memory <megabytes>\n\n");
fprintf(stderr,"Examples:\n");
fprintf(stderr," ./redis-server (run the server with default conf)\n");
fprintf(stderr," ./redis-server /etc/redis/6379.conf\n");
return;
}
+void memtest(size_t megabytes, int passes);
+
int main(int argc, char **argv) {
long long start;
struct timeval tv;
strcmp(argv[1], "--version") == 0) version();
if (strcmp(argv[1], "--help") == 0 ||
strcmp(argv[1], "-h") == 0) usage();
+ if (strcmp(argv[1], "--test-memory") == 0) {
+ if (argc == 3) {
+ memtest(atoi(argv[2]),10000);
+ exit(0);
+ } else {
+ fprintf(stderr,"Please specify the amount of memory to test in megabytes.\n");
+ fprintf(stderr,"Example: ./redis-server --test-memory 4096\n\n");
+ exit(1);
+ }
+ }
+
/* First argument is the config file name? */
if (argv[j][0] != '-' || argv[j][1] != '-')
configfile = argv[j++];