[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