--------------------- PatchSet 2399 Date: 2001/05/28 21:04:47 Author: hno Branch: etag Tag: (none) Log: Maintaing an index of variants and entity tags within the dummy Vary object Members: src/http.c:1.13.14.1->1.13.14.2 src/store.c:1.12.14.5->1.12.14.6 Index: squid/src/http.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/http.c,v retrieving revision 1.13.14.1 retrieving revision 1.13.14.2 diff -u -r1.13.14.1 -r1.13.14.2 --- squid/src/http.c 28 May 2001 16:20:15 -0000 1.13.14.1 +++ squid/src/http.c 28 May 2001 21:04:47 -0000 1.13.14.2 @@ -1,6 +1,6 @@ /* - * $Id: http.c,v 1.13.14.1 2001/05/28 16:20:15 hno Exp $ + * $Id: http.c,v 1.13.14.2 2001/05/28 21:04:47 hno Exp $ * * DEBUG: section 11 Hypertext Transfer Protocol (HTTP) * AUTHOR: Harvest Derived @@ -133,8 +133,6 @@ int remove = 0; int forbidden = 0; StoreEntry *pe; - if (!EBIT_TEST(e->flags, KEY_PRIVATE)) - return; switch (status) { case HTTP_OK: case HTTP_NON_AUTHORITATIVE_INFORMATION: @@ -166,14 +164,16 @@ } if (!remove && !forbidden) return; - assert(e->mem_obj); - if (e->mem_obj->request) - pe = storeGetPublicByRequest(e->mem_obj->request); - else - pe = storeGetPublic(e->mem_obj->url, e->mem_obj->method); - if (pe != NULL) { - assert(e != pe); - storeRelease(pe); + if (EBIT_TEST(e->flags, KEY_PRIVATE)) { + assert(e->mem_obj); + if (e->mem_obj->request) + pe = storeGetPublicByRequest(e->mem_obj->request); + else + pe = storeGetPublic(e->mem_obj->url, e->mem_obj->method); + if (pe != NULL) { + assert(e != pe); + storeRelease(pe); + } } /* * Also remove any cached HEAD response in case the object has @@ -183,8 +183,7 @@ pe = storeGetPublicByRequestMethod(e->mem_obj->request, METHOD_HEAD); else pe = storeGetPublic(e->mem_obj->url, METHOD_HEAD); - if (pe != NULL) { - assert(e != pe); + if (pe != NULL && e != pe) { storeRelease(pe); } if (forbidden) @@ -426,8 +425,6 @@ storeTimestampsSet(entry); /* Check if object is cacheable or not based on reply code */ debug(11, 3) ("httpProcessReplyHeader: HTTP CODE: %d\n", reply->sline.status); - if (neighbors_do_private_keys) - httpMaybeRemovePublic(entry, reply->sline.status); switch (httpCachableReply(httpState)) { case 1: if (httpHeaderHas(&reply->header, HDR_VARY) @@ -463,6 +460,8 @@ else if (EBIT_TEST(reply->cache_control->mask, CC_MUST_REVALIDATE)) EBIT_SET(entry->flags, ENTRY_REVALIDATE); } + if (neighbors_do_private_keys) + httpMaybeRemovePublic(entry, reply->sline.status); if (httpState->flags.keepalive) if (httpState->peer) httpState->peer->stats.n_keepalives_sent++; Index: squid/src/store.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/store.c,v retrieving revision 1.12.14.5 retrieving revision 1.12.14.6 diff -u -r1.12.14.5 -r1.12.14.6 --- squid/src/store.c 28 May 2001 16:20:44 -0000 1.12.14.5 +++ squid/src/store.c 28 May 2001 21:04:47 -0000 1.12.14.6 @@ -1,6 +1,6 @@ /* - * $Id: store.c,v 1.12.14.5 2001/05/28 16:20:44 hno Exp $ + * $Id: store.c,v 1.12.14.6 2001/05/28 21:04:47 hno Exp $ * * DEBUG: section 20 Storage Manager * AUTHOR: Harvest Derived @@ -374,6 +374,183 @@ storeHashInsert(e, newkey); } +typedef struct { + StoreEntry *oe; + StoreEntry *e; + store_client *sc; + char *url; + char *key; + char *vary_headers; + char *etag; + int offset; + int seen_offset; + char *buf; + int done:1; + struct { + char *key; + char *etag; + int this_key:1; + int key_used:1; + int ignore:1; + } current; +} AddVaryState; +CBDATA_TYPE(AddVaryState); +static void free_AddVaryState(void *data) +{ + AddVaryState *state = data; + debug(11, 0) ("free_AddVaryState: %p\n", data); + if (!state->done) { + assert(state->key); + storeAppendPrintf(state->e, "Key: %s\n", state->key); + if (state->etag) + storeAppendPrintf(state->e, "ETag: %s\n", state->etag); + storeAppendPrintf(state->e, "VaryData: %s\n", state->vary_headers); + } + storeBufferFlush(state->e); + storeTimestampsSet(state->e); + storeComplete(state->e); + storeTimestampsSet(state->e); + storeUnlockObject(state->e); + state->e = NULL; + if (state->oe) { + storeUnlockObject(state->oe); + state->oe = NULL; + } + safe_free(state->url); + safe_free(state->key); + safe_free(state->vary_headers); + safe_free(state->etag); + safe_free(state->current.key); + safe_free(state->current.etag); + if (state->buf) { + memFree(state->buf, MEM_CLIENT_SOCK_BUF); + state->buf = NULL; + } +} + +static void storeAddVaryFlush(AddVaryState *state) +{ + if (state->current.ignore || state->current.key_used) { + /* do nothing */ + } else if (state->current.this_key) { + storeAppendPrintf(state->e, "Key: %s\n", state->key); + if (state->etag) + storeAppendPrintf(state->e, "ETag: %s\n", state->etag); + storeAppendPrintf(state->e, "VaryData: %s\n", state->vary_headers); + state->done = 1; + state->current.key_used = 1; + } else if (state->current.key) { + storeAppendPrintf(state->e, "Key: %s\n", state->current.key); + safe_free(state->current.key); + if (state->current.etag) { + storeAppendPrintf(state->e, "ETag: %s\n", state->current.etag); + safe_free(state->current.etag); + } + state->current.key_used = 1; + } +} + +static int inline +strmatchbeg(const char *search, const char *match, int maxlen) +{ + int mlen = strlen(match); + if (maxlen < mlen) + return -1; + return strncmp(search, match, mlen); +} + +static int inline +strmatch(const char *search, const char *match, int maxlen) +{ + int mlen = strlen(match); + if (maxlen < mlen) + return -1; + return strncmp(search, match, maxlen); +} + +static void +storeReadVary(void *data, char *buf, ssize_t size) +{ + AddVaryState *state = data; + int l = size; + char *e; + char *p = buf; + debug(11, 0) ("storeReadVary: %p offset=%d seen_offset=%d size=%d\n", data, state->offset, state->seen_offset, size); + if (size <= 0) { + storeUnregister(state->sc, state->oe, state); + state->sc = NULL; + cbdataFree(state); + debug(11, 0) ("storeReadVary: DONE\n"); + return; + } + state->seen_offset += size; + while ((e = memchr(p, '\n', l)) != NULL) { + int l2; + char *p2; + if (strmatchbeg(p, "Key: ", l) == 0) { + /* key field */ + p2 = p + 5; + l2 = e - p2; + if (state->current.this_key) { + storeAddVaryFlush(state); + } + safe_free(state->current.key); + safe_free(state->current.etag); + memset(&state->current, 0, sizeof(state->current)); + state->current.key = xmalloc(l2+1); + memcpy(state->current.key, p2, l2); + state->current.key[l2] = '\0'; + if (strcmp(state->current.key, state->key) == 0) { + state->current.this_key = 1; + } + debug(11, 0) ("storeReadVary: Key: %s%s\n", state->current.key, state->current.this_key ? " (THIS)" : ""); + } else if (strmatchbeg(p, "ETag: ", l) == 0) { + /* etag field */ + p2 = p + 6; + l2 = e - p2; + safe_free(state->current.etag); + state->current.etag = xmalloc(l2+1); + memcpy(state->current.etag, p2, l2); + state->current.etag[l2] = '\0'; + if (strcmp(state->current.etag, state->etag) == 0) { + const cache_key *oldkey = storeKeyScan(state->current.key); + if (strmatch(p2, state->key, l) != 0) { + StoreEntry *old_e = storeGet(oldkey); + if (old_e) + storeRelease(old_e); + safe_free(state->current.key); + state->current.key = xstrdup(state->key); + state->current.this_key = 1; + } + } else if (state->current.this_key) { + state->current.ignore = 1; + } + debug(11, 0) ("storeReadVary: ETag: %s%s%s\n", state->current.etag, state->current.this_key ? " (THIS)" : "", state->current.ignore ? " (IGNORE)" : ""); + } else if (!state->current.ignore && strmatchbeg(p, "VaryData: ", l) == 0) { + /* vary field */ + p2 = p + 10; + l2 = e - p2; + storeAddVaryFlush(state); + if (strmatch(p2, state->vary_headers, l2) != 0) { + storeAppend(state->e, p, e - p + 1); + debug(11, 0) ("storeReadVary: %s\n", p); + } + } + e += 1; + l -= p - e; + p = e; + } + state->offset += p - buf; + debug(11, 0) ("storeReadVary: %p offset=%d seen_offset=%d\n", data, state->offset, state->seen_offset); + storeClientCopy(state->sc, state->oe, + state->seen_offset, + state->offset, + CLIENT_SOCK_SZ, + state->buf, + storeReadVary, + state); +} + /* * Adds/updates a Vary record. * For updates only one of key or etag needs to be specified @@ -382,38 +559,59 @@ static void storeAddVary(const char *url, const char *log_url, const method_t method, const cache_key *key, const char *etag, const char *vary, const char *vary_headers) { - StoreEntry *pe; + AddVaryState *state; http_version_t version; request_flags flags = null_request_flags; + CBDATA_INIT_TYPE_FREECB(AddVaryState, free_AddVaryState); + state = cbdataAlloc(AddVaryState); + state->url = xstrdup(url); + state->key = xstrdup(storeKeyText(key)); + state->vary_headers = xstrdup(vary_headers); + state->etag = xstrdup(etag); + state->oe = storeGetPublic(url, method); + debug(11, 0) ("storeAddVary: %s (%s) %s %s\n", + state->url, state->key, state->vary_headers, state->etag); + if (state->oe) + storeLockObject(state->oe); flags.cachable = 1; - pe = storeCreateEntry(url, log_url, flags, method); + state->e = storeCreateEntry(url, log_url, flags, method); httpBuildVersion(&version, 1, 0); - httpReplySetHeaders(pe->mem_obj->reply, version, HTTP_OK, "Internal marker object", "x-squid-internal/vary", -1, -1, squid_curtime + 100000); - httpHeaderPutStr(&pe->mem_obj->reply->header, HDR_VARY, vary); - storeSetPublicKey(pe); - httpReplySwapOut(pe->mem_obj->reply, pe); - storeAppendPrintf(pe, "Key: %s\n", storeKeyText(key)); - if (etag) - storeAppendPrintf(pe, "ETag: %s\n", etag); - storeAppendPrintf(pe, "VaryData: %s\n", vary_headers); - /* XXX Here we need to tack on the old etag/vary information, and we should - * merge, clean up etc - * - * Suggestion: - * swap in the old file, looking for ETag, Key and VaryData. If a match is - * found then - * - on ETag, update the key, and expire the old object if different - * - on Key, drop the old data if ETag is different, else nothing - * - on VaryData, remove the line if a different key. If this makes - * the searched key "empty" then expire it and remove it from the - * map - * - VaryData is added last in the Key record it corresponds to (after - * modifications above) - */ - storeBufferFlush(pe); - storeTimestampsSet(pe); - storeComplete(pe); - storeUnlockObject(pe); + httpReplySetHeaders(state->e->mem_obj->reply, version, HTTP_OK, "Internal marker object", "x-squid-internal/vary", -1, -1, squid_curtime + 100000); + httpHeaderPutStr(&state->e->mem_obj->reply->header, HDR_VARY, vary); + storeSetPublicKey(state->e); + httpReplySwapOut(state->e->mem_obj->reply, state->e); + if (state->oe) { + /* XXX Here we need to tack on the old etag/vary information, and we should + * merge, clean up etc + * + * Suggestion: + * swap in the old file, looking for ETag, Key and VaryData. If a match is + * found then + * - on ETag, update the key, and expire the old object if different + * - on Key, drop the old data if ETag is different, else nothing + * - on VaryData, remove the line if a different key. If this makes + * the searched key "empty" then expire it and remove it from the + * map + * - VaryData is added last in the Key record it corresponds to (after + * modifications above) + */ + /* Swap in the dummy Vary object */ + if (!state->oe->mem_obj) { + storeCreateMemObject(state->oe, state->url, log_url); + state->oe->mem_obj->method = method; + } + state->sc = storeClientListAdd(state->oe, state); + state->buf = memAllocate(MEM_CLIENT_SOCK_BUF); + debug(11, 0) ("storeAddVary: %p\n", state); + storeClientCopy(state->sc, state->oe, 0, 0, + CLIENT_SOCK_SZ, + state->buf, + storeReadVary, + state); + return; + } else { + cbdataFree(state); + } } void