--------------------- PatchSet 3340 Date: 2001/11/20 06:53:20 Author: jkay Branch: push Tag: (none) Log: Handle hint cache messages Members: src/HintCacheNet.c:1.1->1.1.2.1 --- /dev/null Wed Feb 14 00:55:47 2007 +++ squid/src/HintCacheNet.c Wed Feb 14 00:56:31 2007 @@ -0,0 +1,560 @@ +/* + * $Date: 2001/11/20 06:53:20 $ $Id: HintCacheNet.c,v 1.1.2.1 2001/11/20 06:53:20 jkay Exp $ + * + * DEBUG: section 55 Hint cache networking. + * AUTHOR: Mike Dahlin, UT Austin, 1998 + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * -------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by + * the National Science Foundation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + *------------------------------------------------------------------ + * LESS Group + * Computer Sciences Department + * University of Texas at Austin + * + * HCNet --- Simple send interface built on squid async send stuff. + *------------------------------------------------------------------ + */ + +#include "squid.h" +#include + +#define HCNET_DEBUG 55 + +#define RECV_DEBUG(type, u, hdr, src) \ + debug(HCNET_DEBUG, 2, "Got %s: 0x%x at <%s,%d> from <%s,%d>\n", \ + (type), *(int *) &(u)->entry.key.key, \ + inet_ntoa((u)->entry.ipaddr), (u)->entry.port, \ + inet_ntoa((src)->sin_addr), (hdr)->httpport) + +static void enqueueBytes(HCNet *n, char *data, int nbytes); +static int copyToLocal(HCUpdate *updatesA, char *data, int len, + int oneUpdateSize); +static void clear(HCNet *n); +static void updateHierarchy(HCUpdate *updatesA, int nupdates, + struct sockaddr_in *source); +static void suppress(HCUpdate *updateA, int nupdates); +static void scoldParent(struct sockaddr_in *parent); + +void +HCNet_Init(HCNet *n) +{ +#ifdef DOTEST + n->testMode = 0; + n->testCount = 0; +#endif + clear(n); +} + +static void +clear(HCNet *n) +{ + HCNetHeader hdr; + const char *url = "route://updates"; + int flags = 0; + + assert(n); + + /* Set up entry with request */ + BIT_SET(flags, REQ_CACHABLE); + BIT_SET(flags, KEEP_INMEM); + BIT_SET(flags, DONT_FREE_FOR); + n->sendBuffer = storeCreateEntry(url, url, NULL, 0, flags, METHOD_GET); + n->sendBuffer->mem_obj->request = + requestLink(urlParse(METHOD_GET, (char *) url)); + + n->sendLength = 0; + + n->state = HC_filling; + + /* Prepare header for next transmission */ + hdr.httpport = htons(Config.Port.http); + hdr.updlen = htons(sizeof(Net_HCUpdate)); + enqueueBytes(n, (char *) &hdr, sizeof(hdr)); +} + +void HCNet_Destroy(HCNet *n) +{ + storeRelease(n->sendBuffer); + n->state = HC_destroyed; +} + +void +HCNet_Enqueue(HCNet *n, int action, HCEntry *entry, int hopcount) +{ + HCUpdate update; + Net_HCUpdate netUpdate; + +#ifdef DOTEST + if(n->testMode){ + n->testCount++; + return; + } +#endif + debug(HCNET_DEBUG, 4, + "HCNet_Enqueue onto 0x%x (action %d) (entry.key %llx entry.ipaddr %s port %d)\n", + n, action, entry->key.key, inet_ntoa(entry->ipaddr), entry->port); + + HCUpdate_Init(&update, action, entry, hopcount); + Net_HCUpdate_Init(&netUpdate, &update); + enqueueBytes(n, (char *)&netUpdate, sizeof(Net_HCUpdate)); +} + +static void +enqueueBytes(HCNet *n, char *data, int nbytes) +{ + static enqreentrancy = 0; + + assert(n->state == HC_filling); + assert(!enqreentrancy); + ++enqreentrancy; + n->sendLength += nbytes; + storeAppend(n->sendBuffer, data, nbytes); + --enqreentrancy; +} + +int +HCNet_bytesReady(HCNet *n) +{ + return n->sendLength; +} + +void +HCNet_Complete(HCNet *n) +{ + + assert(n); + assert(n->state == HC_filling); + n->state = HC_full; + HCFinishHeader(n->sendBuffer); + storeComplete(n->sendBuffer); +} + +void +HCNet_SendTo(HCNet *n, struct sockaddr_in *dest) +{ + assert(n->state == HC_full); + assert(n->sendLength > sizeof(HCNetHeader)); + debug(HCNET_DEBUG, 2, "HCNet_SendTo: sending routes on 0x%x to <%s,%d>\n", + n, inet_ntoa(dest->sin_addr), dest->sin_port); + putSend(n->sendBuffer, dest, NULL, NULL, 0, 0); +} + +void +HCNet_Done(HCNet *n) +{ + StoreEntry *entry = n->sendBuffer; + + assert(n->state == HC_full); + + BIT_RESET(entry->flag, KEEP_INMEM); + BIT_SET(entry->flag, RELEASE_REQUEST); + storeUnlockObject(entry); + + clear(n); +} + + +#ifdef DOTEST +void +HCNet_SetTestMode(HCNet *n) +{ + n->testMode = 1; + n->testCount = 0; +} + +int +HCNet_GetTestCount(HCNet *n) +{ + return n->testCount; +} +#endif /* DOTEST */ + +/* + *------------------------------------------------------------------ + * + * HCNet_DataArrives -- + * + * Action to take when messages arrive from network. + * + * Arguments: + * char *data -- unaligned buffer of network-formatted HCNetUpdates + * int len -- number of bytes in that buffer + * struct sockaddr *source -- who sent the buffer + * + * Results: + * None. + * + * Side effects: + * Many. + * + *------------------------------------------------4.2.1998------------ + */ +void +HCNet_DataArrives(char *data, int len, HCNetHeader *hdr, + struct sockaddr_in *source) +{ + struct sockaddr_in sin; + HCUpdate *updatesA; + int nupdates; + int iupdate; + + if (!HC_ACTIVE()) { + /* Hint cache is inoperative. Nothing to do. */ + return; + } + + assert(source->sin_family == AF_INET); + assert(hdr->updlen >= HCU_MINLEN); + + debug(HCNET_DEBUG, 3, + "HCDataArrives: got %d bytes of stuff (probably %d updates xtra=%d\n", + len, len / hdr->updlen, len % hdr->updlen); + + /* Copy to alignment buffer and local format */ + updatesA = (HCUpdate *)xmalloc(len); + nupdates = copyToLocal(updatesA, data, len, hdr->updlen); + + /* + * Suppress loops. Better to do this on send-side, but + * this should be uncommon --> no performance impact + */ + suppress(updatesA, nupdates); + + /* + * Help hierarchy learn about who our children are. + */ + source->sin_port = hdr->httpport; + + updateHierarchy(updatesA, nupdates, source); + + /* + * Prefetch if we have a large number of requests. + * Idea is to tell OS to start bringing in the pages + * that we are about to touch. + */ + if (nupdates >= HCD_PREFETCH_THRESH){ + HCDisk_prefetch(hcDisk, updatesA, nupdates); + } + + /* + * OK. Now we can start processing the messages. + */ + for(iupdate = 0; iupdate < nupdates; iupdate++){ + switch(updatesA[iupdate].action){ + case HC_InvalToParent: + RECV_DEBUG("HC_InvalToParent", &updatesA[iupdate], hdr, source); + hcprop_handleInvalToParent(&updatesA[iupdate], source, 0); + break; + + case HC_InvalToChild: + RECV_DEBUG("HC_InvalToChild", &updatesA[iupdate], hdr, source); + hcprop_handleInvalToChild(&updatesA[iupdate], source, 0); + break; + + case HC_InformToParent: + RECV_DEBUG("HC_InformToParent", &updatesA[iupdate], hdr, source); + hcprop_handleInformToParent(&updatesA[iupdate], source, 0); + break; + + case HC_InformToChild: + RECV_DEBUG("HC_InformToChild", &updatesA[iupdate], hdr, source); + hcprop_handleInformToChild(&updatesA[iupdate], source, 0); + break; + + case HC_Join: + /* New cache node! Add to list. */ + RECV_DEBUG("HC_Join", &updatesA[iupdate], hdr, source); + /* + * MDD 7.18.1998 + * When a node relays a join/leave to us, make sure + * that we send future joins to that node by adding + * that node to the peer list if it's not already there. + */ + sin.sin_family = AF_INET; + sin.sin_addr = source->sin_addr; + sin.sin_port = hdr->httpport; + HCHier_updateMembershipNeighbor(&sin, NEIGHBOR_ADD); + + /* + * Now update local state for join + */ + sin.sin_family = AF_INET; + sin.sin_addr = updatesA[iupdate].entry.ipaddr; + sin.sin_port = updatesA[iupdate].entry.port; + HCHier_newNode(&sin, updatesA[iupdate].hopcount, + updatesA[iupdate].entry.key.key); + break; + + case HC_Leave: + /* Cache node is either dead or has been detected dead. */ + RECV_DEBUG("HC_Leave", &updatesA[iupdate], hdr, source); + sin.sin_family = AF_INET; + sin.sin_addr = updatesA[iupdate].entry.ipaddr; + sin.sin_port = updatesA[iupdate].entry.port; + HCHier_delNode(&sin, updatesA[iupdate].hopcount, updatesA[iupdate].entry +.key.key); + + /* + * MDD 7.18.1998 + * When we receive a join from a node, make sure + * that we send future joins to that node by adding + * that node to the peer list if it's not already there. + */ + HCHier_updateMembershipNeighbor(source, NEIGHBOR_ADD); + /* + * MDD 7.18.1998 + * And the node we just heard about is gone, so it must + * no longer be a neighbor across which to propagate changes + * in membership. + */ + HCHier_updateMembershipNeighbor(&sin, NEIGHBOR_REMOVE); + + break; + + case HC_NotChild: + /* + * This message should have been handled and suppressed + * (by making it "HC_Ignore") in the updateHierarchy() code. + */ + RECV_DEBUG("HC_NotChild", &updatesA[iupdate], hdr, source); + assert(0); + break; + + case HC_Ignore: + /* This message was suppressed either because it is + * part of a loop or because it came from a node that + * thinks it is my parent but isnt. + */ + break; + + default: + /* Ignore bad messages */ + debug(HCNET_DEBUG, 1, + "HCHintCache: unknown update action %d from net\n", + updatesA[iupdate].action); + break; + } + } + + xfree(updatesA); +} + +/* + *------------------------------------------------------------------ + * + * copyToLocal -- + * + * Copy unaligned network-format buffer to aligned, local format + * array of updates + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * Nelements + * + * Side effects: + * Copies data into udpatesA + * + *-----------------------------------------------3.31.1998----------- + */ +static int +copyToLocal(HCUpdate *updatesA, char *data, int len, int oneUpdateSize) +{ + char *alignbuf; + int uoff; + Net_HCUpdate *nupdatep; + int ii; + + alignbuf = xmalloc(len); + memcpy(alignbuf, data, len); + + for (uoff = 0, ii = 0; uoff < len; uoff += oneUpdateSize, ii++) { + nupdatep = (Net_HCUpdate *) (alignbuf + uoff); + Net_HCUpdate_LocalFormat(nupdatep, &updatesA[ii]); + } + xfree(alignbuf); + return ii; +} + +/* + *------------------------------------------------------------------ + * + * suppress -- + * + * Decide if any of these hints have bounced around + * network too much to be worth looking at (mainly + * we want to suppress loops.) In prinicple, + * the algorithm guarantees that loops cannot occur, + * but best to be safe. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * May modify records in updateA to mark them as "ignore." + * + *-----------------------------------------------4.1.1998------------- + */ +static void +suppress(HCUpdate *updateA, int nupdates) +{ +#ifdef NOTYET + /* Need to fill this in */ + int iupdate; + + for(iupdate = 0; iupdate < nupdates; iupdate++){ + if (stoppable update) { + updateA[iupdate].action = HC_Ignore; + } + } +#endif + + return; +} + +/* + *------------------------------------------------------------------ + * + * updateHierarchy -- + * + * We also need to help figure out the hierarchy for Plaxton's + * algorithm. Plaxton's algorithm figures out who the parents + * are, but it doesn't know who the children are. We observe + * messages to keep in sync. + * On recv message: + * recv parent msg from parent: process parent message + * recv child msg from child: process child message + * recv parent msg from !parent: send "I am not child" to parent; + * drop message + * recv child msg from !child: add child to child list; + * process child message + * recv "I am not child" from child: remove child + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * May modify records in update array to be "HC_Ignore." + * + *------------------------------------------------4.1.1998------------ + */ +static void +updateHierarchy(HCUpdate *updatesA, int nupdates, struct sockaddr_in *source) +{ + int iupdate; + int parentScolded = 0; + + for(iupdate = 0; iupdate < nupdates; iupdate++){ + switch(updatesA[iupdate].action){ + case HC_InformToChild: + case HC_InvalToChild: + if(!HCHier_CheckIfParent(updatesA[iupdate].entry.key, source)){ + if(!parentScolded){ + scoldParent(source); + parentScolded = 1; + } + updatesA[iupdate].action = HC_Ignore; + } + break; + + case HC_InformToParent: + case HC_InvalToParent: +#if 1 /* XXX! - disabling parent&child lists */ + if(!HCHier_CheckIfChild(source)){ + HCHier_AddChild(source); + } +#endif + break; + + case HC_NotChild: + HCHier_RemoveChild(source); + updatesA[iupdate].action = HC_Ignore; + break; + + + default: + /* + * Other messages don't affect hierarchy. Ignore them here. + */ + break; + } + } +} + +/* + *------------------------------------------------------------------ + * + * scoldParent -- + * + * Tell parent "I am not child". Need to use + * our own private HCNet queue since all of the + * other queues are associated with the hierarchy + * and this message is to tell someone they + * are *not* in the hierarchy. + * + * Arguments: + * type1 arg1 -- description. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------4.2.1998------------ + */ +static void +scoldParent(struct sockaddr_in *parent) +{ + static int initialized = 0; + static HCNet netBuf; + static HCEntry dummyEntry; + static URLKey dummyKey; + + debug(HCNET_DEBUG, 7, "In scoldParent %s\n", inet_ntoa(parent->sin_addr)); + + if(!initialized){ + HCNet_Init(&netBuf); + URLKey_Init(&dummyKey, NULL); + HCEntry_Init(&dummyEntry, dummyKey, + &Config.Sockaddr.http->s, + squid_curtime); + initialized = 1; + } + + HCNet_Enqueue(&netBuf, HC_NotChild, &dummyEntry, 1); + HCNet_Complete(&netBuf); + HCNet_SendTo(&netBuf, parent); + HCNet_Done(&netBuf); + return; +} +