Changeset 492
- Timestamp:
- 04/10/07 11:51:57 (2 years ago)
- Files:
-
- trunk/server/ChangeLog (modified) (1 diff)
- trunk/server/assoc.c (modified) (12 diffs)
- trunk/server/configure.ac (modified) (1 diff)
- trunk/server/items.c (modified) (3 diffs)
- trunk/server/memcached.c (modified) (34 diffs)
- trunk/server/slabs.c (modified) (1 diff)
- trunk/server/slabs.h (modified) (1 diff)
- trunk/server/t/whitespace.t (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/server/ChangeLog
r489 r492 5 5 null checks, adds asserts at the top of each function for any 6 6 use of conn *c without checking to see if c is NULL first. 7 8 * Also adjust clean-whitespace.pl to clean *.ac files. Add 9 script to test-suite to test for tabs. 7 10 8 11 2007-04-04 Paul Lindner <lindner@inuus.com> trunk/server/assoc.c
r468 r492 70 70 is commonly produced by subtraction) look like a single 1-bit 71 71 difference. 72 * the base values were pseudorandom, all zero but one bit set, or 72 * the base values were pseudorandom, all zero but one bit set, or 73 73 all zero plus a counter that starts at zero. 74 74 … … 80 80 Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing 81 81 for "differ" defined as + with a one-bit base and a two-bit delta. I 82 used http://burtleburtle.net/bob/hash/avalanche.html to choose 82 used http://burtleburtle.net/bob/hash/avalanche.html to choose 83 83 the operations, constants, and arrangements of the variables. 84 84 … … 119 119 is commonly produced by subtraction) look like a single 1-bit 120 120 difference. 121 * the base values were pseudorandom, all zero but one bit set, or 121 * the base values were pseudorandom, all zero but one bit set, or 122 122 all zero plus a counter that starts at zero. 123 123 … … 143 143 144 144 #if HASH_LITTLE_ENDIAN == 1 145 static uint32_t hash( 145 static uint32_t hash( 146 146 const void *key, /* the key to hash */ 147 147 size_t length, /* length of the key */ … … 151 151 union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */ 152 152 153 /* Set up the internal state */ 153 /* Set up the internal state */ 154 154 a = b = c = 0xdeadbeef + ((uint32_t)length) + initval; 155 155 … … 173 173 174 174 /*----------------------------- handle the last (probably partial) block */ 175 /* 175 /* 176 176 * "k[2]&0xffffff" actually reads beyond the end of the string, but 177 177 * then masks off the part it's not allowed to read. Because the … … 322 322 * This is the same as hashword() on big-endian machines. It is different 323 323 * from hashlittle() on all machines. hashbig() takes advantage of 324 * big-endian byte ordering. 324 * big-endian byte ordering. 325 325 */ 326 326 static uint32_t hash( const void *key, size_t length, const uint32_t initval) … … 351 351 352 352 /*----------------------------- handle the last (probably partial) block */ 353 /* 353 /* 354 354 * "k[2]<<8" actually reads beyond the end of the string, but 355 355 * then shifts out the part it's not allowed to read. Because the … … 448 448 } 449 449 #else // HASH_XXX_ENDIAN == 1 450 #error Must define HASH_BIG_ENDIAN or HASH_LITTLE_ENDIAN 450 #error Must define HASH_BIG_ENDIAN or HASH_LITTLE_ENDIAN 451 451 #endif // hash_XXX_ENDIAN == 1 452 452 … … 542 542 primary_hashtable = calloc(hashsize(hashpower + 1), sizeof(void *)); 543 543 if (primary_hashtable) { 544 if (settings.verbose > 1)545 fprintf(stderr, "Hash table expansion starting\n");544 if (settings.verbose > 1) 545 fprintf(stderr, "Hash table expansion starting\n"); 546 546 hashpower++; 547 547 expanding = 1; 548 548 expand_bucket = 0; 549 assoc_move_next_bucket();549 assoc_move_next_bucket(); 550 550 } else { 551 551 primary_hashtable = old_hashtable; 552 /* Bad news, but we can keep running. */552 /* Bad news, but we can keep running. */ 553 553 } 554 554 } … … 561 561 if (expanding) { 562 562 for (it = old_hashtable[expand_bucket]; NULL != it; it = next) { 563 next = it->h_next;563 next = it->h_next; 564 564 565 565 bucket = hash(ITEM_key(it), it->nkey, 0) & hashmask(hashpower); 566 566 it->h_next = primary_hashtable[bucket]; 567 567 primary_hashtable[bucket] = it; 568 }569 570 expand_bucket++;571 if (expand_bucket == hashsize(hashpower - 1)) {572 expanding = 0;573 free(old_hashtable);574 if (settings.verbose > 1)575 fprintf(stderr, "Hash table expansion done\n");576 }568 } 569 570 expand_bucket++; 571 if (expand_bucket == hashsize(hashpower - 1)) { 572 expanding = 0; 573 free(old_hashtable); 574 if (settings.verbose > 1) 575 fprintf(stderr, "Hash table expansion done\n"); 576 } 577 577 } 578 578 } … … 614 614 return; 615 615 } 616 /* Note: we never actually get here. the callers don't delete things 616 /* Note: we never actually get here. the callers don't delete things 617 617 they can't find. */ 618 618 assert(*before != 0); trunk/server/configure.ac
r468 r492 102 102 AC_CHECK_HEADER(malloc.h, AC_DEFINE(HAVE_MALLOC_H,,[do we have malloc.h?])) 103 103 AC_CHECK_MEMBER([struct mallinfo.arena], [ 104 AC_DEFINE(HAVE_STRUCT_MALLINFO,,[do we have stuct mallinfo?])105 ], ,[106 # include <malloc.h>107 ]104 AC_DEFINE(HAVE_STRUCT_MALLINFO,,[do we have stuct mallinfo?]) 105 ], ,[ 106 # include <malloc.h> 107 ] 108 108 ) 109 109 trunk/server/items.c
r489 r492 49 49 * Generates the variable-sized part of the header for an object. 50 50 * 51 * key - The key 51 * key - The key 52 52 * nkey - The length of the key 53 53 * flags - key flags … … 64 64 return sizeof(item) + nkey + *nsuffix + nbytes; 65 65 } 66 66 67 67 /*@null@*/ 68 68 item *item_alloc(char *key, const size_t nkey, const int flags, const rel_time_t exptime, const int nbytes) { … … 87 87 if (settings.evict_to_free == 0) return NULL; 88 88 89 /* 90 * try to get one off the right LRU 89 /* 90 * try to get one off the right LRU 91 91 * don't necessariuly unlink the tail because it may be locked: refcount>0 92 92 * search up from tail an item with refcount==0 and unlink it; give up after 50 trunk/server/memcached.c
r489 r492 68 68 69 69 /* 70 * forward declarations 70 * forward declarations 71 71 */ 72 72 static void drive_machine(conn *c); … … 275 275 276 276 /*@null@*/ 277 static conn *conn_new(const int sfd, const int init_state, const int event_flags, 277 static conn *conn_new(const int sfd, const int init_state, const int event_flags, 278 278 const int read_buffer_size, const bool is_udp) { 279 279 conn *c; … … 487 487 c->isize = ITEM_LIST_INITIAL; 488 488 } 489 /* TODO check error condition? */489 /* TODO check error condition? */ 490 490 } 491 491 … … 496 496 c->msgsize = MSG_LIST_INITIAL; 497 497 } 498 /* TODO check error condition? */498 /* TODO check error condition? */ 499 499 } 500 500 … … 505 505 c->iovsize = IOV_LIST_INITIAL; 506 506 } 507 /* TODO check return value */507 /* TODO check return value */ 508 508 } 509 509 } … … 750 750 #define KEY_MAX_LENGTH 250 751 751 752 #define MAX_TOKENS 6 752 #define MAX_TOKENS 6 753 753 754 754 /* … … 757 757 * Returns total number of tokens. The last valid token is the terminal 758 758 * token (value points to the first unprocessed character of the string and 759 * length zero). 759 * length zero). 760 760 * 761 761 * Usage example: … … 775 775 size_t ntokens = 0; 776 776 777 assert(command != NULL && tokens != NULL && max_tokens > 1); 777 assert(command != NULL && tokens != NULL && max_tokens > 1); 778 778 779 779 cp = command; 780 780 while(*cp != '\0' && ntokens < max_tokens - 1) { 781 781 if(*cp == ' ') { 782 // If we've accumulated a token, this is the end of it. 782 // If we've accumulated a token, this is the end of it. 783 783 if(length > 0) { 784 784 tokens[ntokens].value = value; … … 905 905 return; 906 906 } 907 907 908 908 fd = open("/proc/self/maps", O_RDONLY); 909 909 if (fd == -1) { … … 927 927 c->write_and_free = wbuf; 928 928 c->wcurr = wbuf; 929 c->wbytes = res + 5; // Don't write the terminal '\0' 929 c->wbytes = res + 5; // Don't write the terminal '\0' 930 930 conn_set_state(c, conn_write); 931 931 c->write_and_go = conn_read; … … 1032 1032 do { 1033 1033 while(key_token->length != 0) { 1034 1034 1035 1035 key = key_token->value; 1036 1036 nkey = key_token->length; 1037 1037 1038 1038 if(nkey > KEY_MAX_LENGTH) { 1039 1039 out_string(c, "CLIENT_ERROR bad command line format"); 1040 1040 return; 1041 1041 } 1042 1042 1043 1043 stats.get_cmds++; 1044 1044 it = get_item(key, nkey); … … 1051 1051 } else break; 1052 1052 } 1053 1053 1054 1054 /* 1055 1055 * Construct the response. Each hit adds three elements to the … … 1073 1073 *(c->ilist + i) = it; 1074 1074 i++; 1075 1075 1076 1076 } else stats.get_misses++; 1077 1077 1078 1078 key_token++; 1079 1079 } … … 1087 1087 key_token = tokens; 1088 1088 } 1089 1089 1090 1090 } while(key_token->value != NULL); 1091 1091 1092 1092 c->icurr = c->ilist; 1093 1093 c->ileft = i; 1094 1094 1095 1095 if (settings.verbose > 1) 1096 1096 fprintf(stderr, ">%d END\n", c->sfd); 1097 1097 add_iov(c, "END\r\n", 5); 1098 1098 1099 1099 if (c->udp && build_udp_headers(c) != 0) { 1100 1100 out_string(c, "SERVER_ERROR out of memory"); … … 1128 1128 exptime = strtol(tokens[3].value, NULL, 10); 1129 1129 vlen = strtol(tokens[4].value, NULL, 10); 1130 1130 1131 1131 if(errno == ERANGE || ((flags == 0 || exptime == 0) && errno == EINVAL)) { 1132 1132 out_string(c, "CLIENT_ERROR bad command line format"); 1133 1133 return; 1134 1134 } 1135 1135 1136 1136 if (settings.managed) { 1137 1137 int bucket = c->bucket; … … 1159 1159 return; 1160 1160 } 1161 1161 1162 1162 c->item_comm = comm; 1163 1163 c->item = it; … … 1179 1179 1180 1180 assert(c != NULL); 1181 1182 if(tokens[KEY_TOKEN].length > KEY_MAX_LENGTH) { 1181 1182 if(tokens[KEY_TOKEN].length > KEY_MAX_LENGTH) { 1183 1183 out_string(c, "CLIENT_ERROR bad command line format"); 1184 1184 return; … … 1187 1187 key = tokens[KEY_TOKEN].value; 1188 1188 nkey = tokens[KEY_TOKEN].length; 1189 1189 1190 1190 if (settings.managed) { 1191 1191 int bucket = c->bucket; … … 1208 1208 1209 1209 delta = strtoul(tokens[2].value, NULL, 10); 1210 1210 1211 1211 if(errno == ERANGE) { 1212 1212 out_string(c, "CLIENT_ERROR bad command line format"); … … 1216 1216 ptr = ITEM_data(it); 1217 1217 while ((*ptr != '\0') && (*ptr < '0' && *ptr > '9')) ptr++; // BUG: can't be true 1218 1218 1219 1219 value = strtol(ptr, NULL, 10); 1220 1220 … … 1223 1223 return; 1224 1224 } 1225 1225 1226 1226 if (incr != 0) 1227 1227 value += delta; … … 1255 1255 item *it; 1256 1256 time_t exptime = 0; 1257 1257 1258 1258 assert(c != NULL); 1259 1259 … … 1270 1270 } 1271 1271 } 1272 1272 1273 1273 key = tokens[KEY_TOKEN].value; 1274 1274 nkey = tokens[KEY_TOKEN].length; … … 1281 1281 if(ntokens == 4) { 1282 1282 exptime = strtol(tokens[2].value, NULL, 10); 1283 1283 1284 1284 if(errno == ERANGE) { 1285 1285 out_string(c, "CLIENT_ERROR bad command line format"); … … 1293 1293 return; 1294 1294 } 1295 1295 1296 1296 if (exptime == 0) { 1297 1297 item_unlink(it); … … 1304 1304 todelete = new_delete; 1305 1305 deltotal *= 2; 1306 } else { 1307 /* 1306 } else { 1307 /* 1308 1308 * can't delete it immediately, user wants a delay, 1309 1309 * but we ran out of memory for the delete queue … … 1313 1313 } 1314 1314 } 1315 1315 1316 1316 it->refcount++; 1317 1317 /* use its expiration time as its deletion time now */ … … 1324 1324 1325 1325 static void process_command(conn *c, char *command) { 1326 1326 1327 1327 token_t tokens[MAX_TOKENS]; 1328 1328 size_t ntokens; … … 1334 1334 fprintf(stderr, "<%d %s\n", c->sfd, command); 1335 1335 1336 /* 1336 /* 1337 1337 * for commands set/add/replace, we build an item and read the data 1338 1338 * directly into it, then continue in nread_complete(). 1339 */ 1340 1339 */ 1340 1341 1341 c->msgcurr = 0; 1342 1342 c->msgused = 0; … … 1352 1352 ((strcmp(tokens[COMMAND_TOKEN].value, "get") == 0) || 1353 1353 (strcmp(tokens[COMMAND_TOKEN].value, "bget") == 0))) { 1354 1354 1355 1355 process_get_command(c, tokens, ntokens); 1356 1356 1357 } else if (ntokens == 6 && 1358 ((strcmp(tokens[COMMAND_TOKEN].value, "add") == 0 && (comm = NREAD_ADD)) || 1357 } else if (ntokens == 6 && 1358 ((strcmp(tokens[COMMAND_TOKEN].value, "add") == 0 && (comm = NREAD_ADD)) || 1359 1359 (strcmp(tokens[COMMAND_TOKEN].value, "set") == 0 && (comm = NREAD_SET)) || 1360 1360 (strcmp(tokens[COMMAND_TOKEN].value, "replace") == 0 && (comm = NREAD_REPLACE)))) { 1361 1361 1362 1362 process_update_command(c, tokens, ntokens, comm); 1363 1363 … … 1380 1380 return; 1381 1381 } 1382 1382 1383 1383 if (sscanf(tokens[1].value, "%u:%u", &bucket,&gen) == 2) { 1384 1384 if ((bucket < 0) || (bucket >= MAX_BUCKETS)) { … … 1436 1436 1437 1437 } else if (ntokens >= 2 && (strcmp(tokens[COMMAND_TOKEN].value, "stats") == 0)) { 1438 1438 1439 1439 process_stat(c, tokens, ntokens); 1440 1440 … … 1460 1460 out_string(c, "OK"); 1461 1461 return; 1462 1462 1463 1463 } else if (ntokens == 2 && (strcmp(tokens[COMMAND_TOKEN].value, "version") == 0)) { 1464 1464 … … 1468 1468 1469 1469 conn_set_state(c, conn_closing); 1470 1470 1471 1471 } else if (ntokens == 5 && (strcmp(tokens[COMMAND_TOKEN].value, "slabs") == 0 && 1472 1472 strcmp(tokens[COMMAND_TOKEN + 1].value, "reassign") == 0)) { trunk/server/slabs.c
r489 r492 79 79 * a given size. 80 80 * 81 * Given object size, return id to use when allocating/freeing memory for object 82 * 0 means error: can't store such a large object 81 * Given object size, return id to use when allocating/freeing memory for object 82 * 0 means error: can't store such a large object 83 83 */ 84 84 trunk/server/slabs.h
r468 r492 7 7 8 8 9 /* 9 /* 10 10 * Given object size, return id to use when allocating/freeing memory for object 11 11 * 0 means error: can't store such a large object
