[memcached] hachi, r480: Raw checkin of changes from Aaron

commits at code.sixapart.com commits at code.sixapart.com
Fri Mar 30 09:07:28 UTC 2007


Raw checkin of changes from Aaron

U   branches/client-xs-20070328/Cache-Memcached-GetParserXS/GetParserXS.xs


Modified: branches/client-xs-20070328/Cache-Memcached-GetParserXS/GetParserXS.xs
===================================================================
--- branches/client-xs-20070328/Cache-Memcached-GetParserXS/GetParserXS.xs	2007-03-30 08:53:11 UTC (rev 479)
+++ branches/client-xs-20070328/Cache-Memcached-GetParserXS/GetParserXS.xs	2007-03-30 09:07:27 UTC (rev 480)
@@ -24,51 +24,51 @@
   return 0;
 }
 
-void set_key (AV* self, const char *key) {
-  av_store(self, KEY, newSVpv(key, strlen(key)));
+inline void set_key (AV* self, const char *key, int len) {
+  av_store(self, KEY, newSVpv(key, len));
 }
 
-SV *get_key_sv (AV* self) {
+inline SV *get_key_sv (AV* self) {
   SV** svp = av_fetch(self, KEY, 0);
   if (svp)
     return (SV*) *svp;
   return 0;
 }
 
-SV *get_on_item (AV* self) {
+inline SV *get_on_item (AV* self) {
   SV** svp = av_fetch(self, ON_ITEM, 0);
   if (svp)
     return (SV*) *svp;
   return 0;
 }
 
-void set_flags (AV* self, int flags) {
+inline void set_flags (AV* self, int flags) {
   av_store(self, FLAGS, newSViv(flags));
 }
 
-void set_offset (AV* self, int offset) {
+inline void set_offset (AV* self, int offset) {
   av_store(self, OFFSET, newSViv(offset));
 }
 
-void set_state (AV* self, int state) {
+inline void set_state (AV* self, int state) {
   av_store(self, STATE, newSViv(state));
 }
 
-HV* get_dest (AV* self) {
+inline HV* get_dest (AV* self) {
   SV** svp = av_fetch(self, DEST, 0);
   if (svp)
     return (HV*) SvRV(*svp);
   return 0;
 }
 
-int get_state (AV* self) {
+inline int get_state (AV* self) {
   SV** svp = av_fetch(self, STATE, 0);
   if (svp)
     return SvIV((SV*) *svp);
   return 0;
 }
 
-SV* get_buffer (AV* self) {
+inline SV* get_buffer (AV* self) {
   SV** svp = av_fetch(self, BUF, 0);
   if (svp)
     return *svp;
@@ -87,54 +87,106 @@
   SV* bufsv = get_buffer(self);
   STRLEN len;
   char* buf;
-  char key[257];
   unsigned int itemlen;
   unsigned int flags;
   int scanned;
   int nslen = get_nslen(self);
   SV* on_item = get_on_item(self);
-
+  register signed char c;
+  char *key;
+  register char *p;
+  int key_len, barelen;
+  int state, copy, new_p;
+  char *barekey;
+  
   if (DEBUG)
     printf("get_buffer (nslen = %d)...\n", nslen);
 
   while (1) {
     int rv;
     buf = SvPV(bufsv, len);
+    p = buf;
 
-    if (DEBUG)
-      printf(" buf (len=%d) = [%s]\n", len, buf);
+    if (DEBUG) {
+	char first_line[1000];
+	int i;
+	char *end;
+	for (i = 0, end = buf; *end && *end != '\n' && i++ < 900; end++)
+	  ;
+	end += 10;
+	strncpy (first_line, buf, end - buf + 1);
+	first_line[end - buf + 1] = '\0';
+        printf("GOT buf (len=%d)\nFirst line: %s\n", len, first_line);
+    }
 
-    scanned = 0;
-    rv = sscanf(buf, "VALUE %256s %u %u%n", key, &flags, &itemlen, &scanned);
+    if ((c = *p++) == 'V') {
+      if (*p++ != 'A' || *p++ != 'L' || *p++ != 'U' || *p++ != 'E' || *p++ != ' ') {
+	if (DEBUG)
+	  puts ("ERROR: Illegal command beginning with V");
+	goto recover_from_partial_line;
+      }
+	
+      // Parsing VALUE %s<key> %u<flags> %u<bytes>
 
-    if (DEBUG)
-      printf("rv=%d, scanned=%d, one=[%d], two=[%d]\n",
-             rv, scanned, buf[scanned], buf[scanned+1]);
+      for (key = p; *p++ > ' ';)
+	;
+      key_len = p - key - 1;
+      if (*(p - 1) != ' ') {
+	if (DEBUG)
+	  printf ("ERROR: key not space-terminated: key %s, char %c\n", key, *(p - 1));
+	goto recover_from_partial_line;		
+      }
+      // Note that key just points into the buffer and is not null-terminated
+      // yet.  Leave it that way in case we're dealing with a partial line.
 
-    if (rv >= 3 && scanned && buf[scanned+1] == '\n') {
-      int p     = scanned + 2;      /* 2 to skip \r\n */
-      int state = itemlen + 2;      /* 2 to include reading final \r\n, a different \r\n */
-      int copy  = len - p > state ? state : len - p;
-      char *barekey = key + nslen;
+      // Get flags and itemlen as integers.  Note invalid characters 
+      // are not caught and will result in strange numbers.
 
-      if (DEBUG)
+      for (flags = 0; (c = *p++ - '0') >= 0; flags = flags * 10 + c)
+	;
+      if (c != (signed char)' ' - '0') {
+	if (DEBUG)
+	  puts ("ERROR: Flags not space terminated");
+	goto recover_from_partial_line;			
+      }
+
+      
+      for (itemlen = 0; (c = *p++ - '0') >= 0; itemlen = itemlen * 10 + c)
+	;
+      if (c != (signed char)'\r' - '0' || *p++ != '\n') {
+	if (DEBUG)
+	  puts ("ERROR: byte count not CRLF-terminated");
+	goto recover_from_partial_line;			
+      }
+
+
+      // p is left at the start of the value data.
+
+      new_p = p - buf;
+      state = itemlen + 2;      /* 2 to include reading final \r\n, a different \r\n */
+      copy  = len - new_p > state ? state : len - new_p;
+      barekey = key + nslen;
+      barelen = key_len - nslen;
+
+      if (DEBUG) {
+	char temp_key[256];
+	strncpy (temp_key, key, key_len);
+	temp_key[key_len] = '\0';
         printf("key=[%s], state=%d, copy=%d\n", key, state, copy);
+      }
 
       if (copy) {
-        //SV*  newSVpv(const char*, STRLEN);
-        //SV**  hv_store(HV*, const char* key, U32 klen, SV* val, U32 hash);
-        /*  $ret->{$self->[KEY]} = substr($self->[BUF], $p, $copy) */
-        hv_store(ret, barekey, strlen(barekey), newSVpv(buf + p, copy), 0);
-        buf[p + copy - 1] = '\0';
+	*(key + key_len) = '\0';	// Null-terminate the key in-buffer
+        hv_store(ret, barekey, barelen, newSVpv(buf + new_p, copy), 0);
+        buf[new_p + copy - 1] = '\0';
 
         if (DEBUG)
-          printf("doing store:  len=%d key=[%s] of data [%s]\n",
-                 strlen(barekey), barekey,
-                 buf + p);
+          printf("doing store:  len=%d key=[%s] of data [%c]\n",
+                 strlen(barekey), barekey, *(buf + new_p));
       }
 
       /* delete the stuff we used */
-      sv_chop(bufsv, buf + p + copy);
+      sv_chop(bufsv, buf + new_p + copy);
 
       if (copy == state) {
         dSP ;
@@ -143,7 +195,7 @@
         ENTER ;
         SAVETMPS ;
         PUSHMARK(SP) ;
-        XPUSHs(sv_2mortal(newSVpv(barekey, strlen(barekey))));
+        XPUSHs(sv_2mortal(newSVpv(barekey, barelen)));
         XPUSHs(sv_2mortal(newSViv(flags)));
         PUTBACK ;
         call_sv(on_item, G_VOID | G_DISCARD);
@@ -157,7 +209,7 @@
         /* don't have it all... but buffer is now empty */
         set_offset(self, copy);
         set_flags(self, flags);
-        set_key(self, barekey);
+        set_key(self, barekey, barelen);
         set_state(self, state);
 
         if (DEBUG)
@@ -167,12 +219,19 @@
       }
     }
 
-    if (strncmp(buf, "END\r\n", 5) == 0) {
-      /* we're done successfully, return 1 to finish */
-      return final_answer(self, 1);
+    else if (c == 'E') {
+      
+      // Parsing END
+      
+      if (*p++ == 'N' && *p++ == 'D' && *p++ == '\r' && *p == '\n')
+	return final_answer(self, 1);
     }
+    // Just fall through if after 'E' was not "ND\r\n"
 
+    else 
+      ;			// Unknown command: not 'E' or 'V' at [0]
 
+
     /* # if we're here probably means we only have a partial VALUE
        # or END line in the buffer. Could happen with multi-get,
        # though probably very rarely. Exit the loop and let it read
@@ -182,6 +241,7 @@
        # partial VALUE/END line.
     */
 
+  recover_from_partial_line:
     set_offset(self, len);
     return 0;
   }




More information about the memcached-commits mailing list