1. Sümer Cip
  2. lightcache

Commits

Sümer Cip  committed bcb2a6d

TP+. Finally good feel about freeing resources, zero-copy and clear function names at last.

  • Participants
  • Parent commits 759dfa2
  • Branches default

Comments (0)

Files changed (7)

File src/hashtab.c

View file
  • Ignore whitespace
 
 void hfree(_htab *ht, _hitem *item)
 {
-    item->free = 1;
-    ht->freecount++;
+    if (!item->free) {
+        item->free = 1;
+        ht->freecount++;
+    }
 }
+
+

File src/lightcache.c

View file
  • Ignore whitespace
     return conn;
 }
 
-static void free_request(request *req)
+// NOTE: htab key is re-used so we do not free it. 
+static void del_cached_req(_hitem *it)
 {
+    request *req;
+        
+    req = ((request *)it->val);
+    if (req) {
+        li_free(req->rkey);
+        li_free(req->rdata);
+        li_free(req->rextra);
+        li_free(req);
+    }
+    it->val = NULL;
+}
+
+static void free_request(conn *conn)
+{
+    request *req;
+
+    req = conn->in;
     if ((!req) || (!req->can_free)) {
         return;
     }
 
-    //LC_DEBUG(("FREEING request data.[%p], sizeof:[%u]\r\n", (void *)req, 
-        // (unsigned int)sizeof(request *)));
     li_free(req->rkey);
     li_free(req->rdata);
     li_free(req->rextra);
     li_free(req);
+    conn->in = NULL;
 }
 
-static void free_response(response *resp)
+static void free_response(conn *conn)
 {
+    response *resp;
+    
+    resp = &conn->out;
     if (resp->can_free) {
-        //LC_DEBUG(("FREEING response data.[%p]\r\n", (void *)resp->sdata));
         li_free(resp->sdata);
     }
     resp->sdata = NULL;
 
 static int init_resources(conn *conn)
 {
-    free_request(conn->in);
-    free_response(&conn->out);
+    free_request(conn);
+    free_response(conn);
     
     conn->in = (request *)li_malloc(sizeof(request));
     if (!conn->in) {
 {
     LC_DEBUG(("disconnect conn called.\r\n"));
 
-    event_del(conn);
-    
-    if (conn->in->can_free) {
-        free_request(conn->in);
-        conn->in = NULL;
-    }
-    free_response(&conn->out);
+    free_request(conn);
+    free_response(conn);
 
     conn->free = 1;
+
+    event_del(conn);
     close(conn->fd);
 
     stats.curr_connections--;
     
     LC_DEBUG(("flush_item called.\r\n"));
     
-    if (item->val) {
-        ((request *)item->val)->can_free = 1;
-        free_request((request *)item->val);    
-        item->val = NULL;
-    }
-
-    if (!item->free) {
-        hfree(cache, item);
-    }
+    del_cached_req(item);
+    hfree(cache, item);
 
     return 0;
 }
 
         if ((unsigned int)(conn->in->received-cached_req->received) > val) {
             LC_DEBUG(("Time expired for key:%s\r\n", conn->in->rkey));
-            cached_req->can_free = 1;
-            free_request(cached_req);
-            tab_item->val = NULL; // update hashtab
-            hfree(cache, tab_item); // recycle tab_item
+            del_cached_req(tab_item);
+            hfree(cache, tab_item);
             goto GET_KEY_NOTEXISTS;
         }
 
         if (ret == HEXISTS) { // key exists? then force-update the data
             tab_item = hget(cache, conn->in->rkey, conn->in->req_header.request.key_length);
             assert(tab_item != NULL);
-
-            // free the previous data
-            cached_req = (request *)tab_item->val;
-            cached_req->can_free = 1;
-            free_request(cached_req);
-            tab_item->val = conn->in;
+            del_cached_req(tab_item);
+            tab_item->val = conn->in; // update with the new request
         }
         conn->in->can_free = 0;
 
             return;
         }
 
-        cached_req = (request *)tab_item->val;
-        cached_req->can_free = 1;
-        free_request(cached_req);
-        tab_item->val = NULL;
-
+        del_cached_req(tab_item);        
         hfree(cache, tab_item);
 
         send_response(conn, SUCCESS);
         if (errno == EWOULDBLOCK || errno == EAGAIN) {
             return NEED_MORE;
         }
-        LC_DEBUG(("%s (%s)", "socket write error.\r\n", strerror(errno)));
-        syslog(LOG_ERR, "%s (%s)", "socket write error.\r\n", strerror(errno));
+        LC_DEBUG(("socket write error.[%s]\r\n", strerror(errno)));
+        syslog(LOG_ERR, "socket write error.[%s]\r\n", strerror(errno));
         return SEND_ERR;
     }
 
     if (ret != 0) {
         syslog(LOG_ERR, "setsockopt(SO_LINGER) error.(%s)", strerror(errno));
     }
+    ret = maximize_sndbuf(s);
+    if (!ret) {
+        LC_DEBUG(("maximize sendbuf failed.\r\n"));
+        syslog(LOG_ERR, "maximize_sndbuf error.(%s)", strerror(errno));
+    }
 
     // only for TCP sockets.
     if (!settings.socket_path) {

File src/mem.c

View file
  • Ignore whitespace
     }
     
     if (!settings.use_sys_malloc) {
-        p = malloc(size);
+        p = scmalloc(size);
     } else {
         if (size + mem_used > (settings.mem_avail)) {
             syslog(LOG_ERR, "No memory available![%llu MB]", (long long unsigned int)settings.mem_avail);
 #endif
     
     if (!settings.use_sys_malloc) {
-        free(ptr);
+        scfree(ptr);
     } else {
         ptr = (char *)ptr - sizeof(size_t);
         size = *(size_t *)ptr;

File src/protocol.h

View file
  • Ignore whitespace
     uint8_t bytes[8];
 } resp_header;
 
-typedef struct request request;
-struct request {
+typedef struct request {
     req_header req_header;
     char *rdata;
     char *rkey;
     unsigned int rbytes; /* current recv index */
     time_t received;
     int can_free; /* flag to indicate whether data can be freed. */
-};
+}request;
 
-typedef struct response response;
-struct response {
+typedef struct response {
     resp_header resp_header;
     char *sdata;
     unsigned int sbytes; /*current write index*/
     int can_free;
-};
+}response;
 
 typedef enum {
     CMD_GET = 0x00,

File src/socket.c

View file
  • Ignore whitespace
     return ioctl(sock, FIOBIO, &flags);
 #endif
 }
+
+int maximize_sndbuf(const int sfd) {
+    socklen_t intsize = sizeof(int);
+    int last_good = 0;
+    int min, max, avg;
+    int old_size;
+
+    /* Start with the default size. */
+    if (getsockopt(sfd, SOL_SOCKET, SO_SNDBUF, (void *)&old_size, &intsize) != 0) { 
+        return 0;
+    }
+
+    /* Binary-search for the real maximum. */
+    min = old_size;
+    max = MAX_SENDBUF_SIZE;
+
+    while (min <= max) {
+        avg = ((unsigned int)(min + max)) / 2;
+        if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, (void *)&avg, intsize) == 0) {
+            last_good = avg;
+            min = avg + 1;
+        } else {
+            max = avg - 1;
+        }
+    }
+
+    return 1;
+}
+

File src/socket.h

View file
  • Ignore whitespace
 #ifndef SOCKET_H
 #define SOCKET_H
 
+#define MAX_SENDBUF_SIZE (256 * 1024 * 1024) /* same as memcached */
 
 typedef enum {
     NEED_MORE = 0x00,
 } socket_state;
 
 int make_nonblocking(int sock);
+int maximize_sndbuf(const int sfd);
 
 #endif

File src/todo

View file
  • Ignore whitespace
 [+] TEST:Valgrind is necessary, especially after we removed the freelist.
 [+] maybe prepare_response can be merged into send_response() function for better
     design.
-[-] Valgrind uninited var warnings. 
+[+] Valgrind uninited var warnings. 
+[*] Slab allocation solves the fragmentation problem. Redis makes a contest to stress the mem.
+    fragmentation. Can we have such chance to observe fragmentation via some tests? 
+    Not easy as redis because we support slab re-assignment that makes things harder.
+    Just observe the fragmentation manually.
+[+] TEST: more delete related tests especially in memleaks.
 [-] show the rlimit hardlimit of the system like we do in esserver.
 [-] any way to exclude math.h that requires -lm dependency for the linker?
 [-] lightcache clients shall be moved to clients folder. Maybe later make another rep.
     for all of them. tests will have dependencies on them.
 [-] TEST/INSPECT: dynamic alloc. failures.(OUT_OF_MEMORY)
-[-] Slab allocation solves the fragmentation problem. Redis makes a contest to stress the mem.
-    fragmentation. Can we have such chance to observe fragmentation via some tests? 
-[-] TEST: more delete related tests especially in memleaks.
+
 [-] write a php client, there is an unpack function for PHP4-5.
 [-] ruby client. there is an unpack() cmd.
 [-] solve distribution problem on client side. http://amix.dk/blog/post/19370.