--------------------- PatchSet 1068 Date: 2001/01/04 16:29:40 Author: adri Branch: modio Tag: (none) Log: add the beginnings of a network reply object. Its the same as the internal reply object for now, except after a sucessful storeClientCopy() it calls stmemFreeDataUpto(). This will help debugging to make sure clients using data coming in from the network don't "backtrack" and request data which has already been read. Members: src/Makefile.in:1.2.2.1->1.2.2.2 src/main.c:1.2.2.5->1.2.2.6 src/protos.h:1.2.2.10->1.2.2.11 src/reply_network.c:1.1->1.1.2.1 Index: squid/src/Makefile.in =================================================================== RCS file: /cvsroot/squid-sf//squid/src/Attic/Makefile.in,v retrieving revision 1.2.2.1 retrieving revision 1.2.2.2 diff -u -r1.2.2.1 -r1.2.2.2 --- squid/src/Makefile.in 18 Dec 2000 19:10:58 -0000 1.2.2.1 +++ squid/src/Makefile.in 4 Jan 2001 16:29:40 -0000 1.2.2.2 @@ -1,7 +1,7 @@ # # Makefile for the Squid Object Cache server # -# $Id: Makefile.in,v 1.2.2.1 2000/12/18 19:10:58 adri Exp $ +# $Id: Makefile.in,v 1.2.2.2 2001/01/04 16:29:40 adri Exp $ # # Uncomment and customize the following to suit your needs: # @@ -182,6 +182,7 @@ wccp.o \ whois.o \ reply_internal.o \ + reply_network.o \ $(XTRA_OBJS) SNMP_OBJS = \ Index: squid/src/main.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/main.c,v retrieving revision 1.2.2.5 retrieving revision 1.2.2.6 diff -u -r1.2.2.5 -r1.2.2.6 --- squid/src/main.c 2 Jan 2001 14:05:32 -0000 1.2.2.5 +++ squid/src/main.c 4 Jan 2001 16:29:41 -0000 1.2.2.6 @@ -1,6 +1,6 @@ /* - * $Id: main.c,v 1.2.2.5 2001/01/02 14:05:32 adri Exp $ + * $Id: main.c,v 1.2.2.6 2001/01/04 16:29:41 adri Exp $ * * DEBUG: section 1 Startup and Main Loop * AUTHOR: Harvest Derived @@ -511,6 +511,7 @@ unlinkdInit(); #endif reply_internal_init(); + reply_network_init(); urlInitialize(); cachemgrInit(); Index: squid/src/protos.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/protos.h,v retrieving revision 1.2.2.10 retrieving revision 1.2.2.11 diff -u -r1.2.2.10 -r1.2.2.11 --- squid/src/protos.h 2 Jan 2001 14:05:32 -0000 1.2.2.10 +++ squid/src/protos.h 4 Jan 2001 16:29:41 -0000 1.2.2.11 @@ -1,6 +1,6 @@ /* - * $Id: protos.h,v 1.2.2.10 2001/01/02 14:05:32 adri Exp $ + * $Id: protos.h,v 1.2.2.11 2001/01/04 16:29:41 adri Exp $ * * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -1233,3 +1233,6 @@ */ extern void reply_internal_init(void); extern void reply_internal_create(StoreEntry *); + +extern void reply_network_init(void); +extern void reply_network_create(StoreEntry *); --- /dev/null Wed Feb 14 00:45:56 2007 +++ squid/src/reply_network.c Wed Feb 14 00:47:44 2007 @@ -0,0 +1,295 @@ +/* + * reply_network.c + * + * Handles replies which have a network as a data server. + * This module handles limiting the amount of data which is requested + * from a server so as to not flood the client, and also writing incoming + * data to a backing object if needed. + * + * Adrian Chadd + */ + + +#include "squid.h" + +struct _reply_network_state { + mem_hdr data_hdr; + off_t inmem_hi; + off_t inmem_lo; +}; + + + +typedef struct _reply_network_state reply_network_state_t; + +MemPool *reply_network_state_pool = NULL; + +/* Prototypes */ +static void reply_network_clientcopy(StoreEntry * e); +static void reply_network_clientcopy3(StoreEntry * e); + + + +void +reply_network_init(void) +{ + reply_network_state_pool = memPoolCreate("Internal reply pool", + sizeof(reply_network_state_t)); +} + + +/* + * reply_network_done + */ +static void +reply_network_done(StoreEntry *e) +{ + reply_network_state_t *state = e->stdata; + + /* Make sure noone is left ! */ + + /* Kill the state struct */ + stmemFree(&state->data_hdr); + memPoolFree(reply_network_state_pool, state); + + /* Done! */ +} + + +/* + * reply_network_memhi + */ +static off_t +reply_network_memhi(const StoreEntry *e) +{ + reply_network_state_t *state = e->stdata; + + return state->inmem_hi; +} + + +/* + * reply_network_memlo + */ +static off_t +reply_network_memlo(const StoreEntry *e) +{ + reply_network_state_t *state = e->stdata; + + return state->inmem_lo; +} + + +/* + * reply_network_append + */ +static void +reply_network_append(StoreEntry *e, const char *buf, int len) +{ + MemObject *mem = e->mem_obj; + reply_network_state_t *state = e->stdata; + assert(mem != NULL); + assert(len >= 0); + assert(e->store_status == STORE_PENDING); + if (len) { + debug(20, 5) ("storeAppend: appending %d bytes for '%s'\n", + len, + storeKeyUrl(e)); + /* Used to call storeGetMemSpace here .. */ + /* storeGetMemSpace(len); */ + stmemAppend(&state->data_hdr, buf, len); + state->inmem_hi += len; + } + if (EBIT_TEST(e->flags, DELAY_SENDING)) + return; + e->stflush(e); +} + + +/* + * reply_network_flush + */ +static void +reply_network_flush(StoreEntry *e) +{ + debug(20, 3) ("reply_network_flush: %s\n", storeKeyUrl(e)); + /* walk the entire list looking for valid callbacks */ + if (e->sc.callback_data == NULL) + return; + if (e->sc.callback == NULL) + return; + if (e->sc.flags.disk_io_pending) + return; + reply_network_clientcopy3(e); +} + + +/* store client copy evilness */ + +static void +reply_network_clientcallback(store_client * sc, ssize_t sz) +{ + STCB *callback = sc->callback; + char *buf = sc->copy_buf; + assert(sc->callback); + sc->callback = NULL; + sc->copy_buf = NULL; + if (cbdataValid(sc->callback_data)) + callback(sc->callback_data, buf, sz); +} + +static void +reply_network_clientcopyevent(void *data) +{ + StoreEntry *e = data; + debug(20, 3) ("reply_network_clientcopyevent: Running\n"); + e->sc.flags.copy_event_pending = 0; + if (!e->sc.valid) + return; + reply_network_clientcopy3(e); +} + + +/* + * This function is used below to decide if we have any more data to + * send to the client. If the store_status is STORE_PENDING, then we + * do have more data to send. If its STORE_OK, then + * we continue checking. + * If the length is >= 0, then we compare it to the requested copy + * offset. + */ +static int +reply_network_clientnomoretosend(StoreEntry * e, store_client * sc) +{ + if (e->store_status == STORE_PENDING) + return 0; + assert(objectLen(e) > -1); /* Internal objects will never be swap backed */ + if (sc->copy_offset < objectLen(e)) + return 0; + return 1; +} + +/* copy bytes requested by the client */ +static void +reply_network_clientcopy(StoreEntry * e) +{ + store_client *sc = &e->sc; + if (EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT)) { + debug(20, 5) ("reply_network_clientcopy: returning because ENTRY_FWD_HDR_WAIT set\n"); + return; + } + debug(20, 3) ("reply_network_clientcopy: %s\n", storeKeyUrl(e)); + assert(sc->callback != NULL); + /* + * We used to check for ENTRY_ABORTED here. But there were some + * problems. For example, we might have a slow client (or two) and + * the server-side is reading far ahead and swapping to disk. Even + * if the server-side aborts, we want to give the client(s) + * everything we got before the abort condition occurred. + */ + reply_network_clientcopy3(e); +} + +static void +reply_network_clientcopy3(StoreEntry * e) +{ + store_client *sc = &e->sc; + reply_network_state_t *state = e->stdata; + size_t sz; + + sc->flags.store_copying = 1; + if (reply_network_clientnomoretosend(e, sc)) { + /* There is no more to send! */ + reply_network_clientcallback(sc, 0); + goto finish; + } + if ((e->store_status == STORE_PENDING) && + (sc->copy_offset >= state->inmem_hi)) { + /* client has already seen this, wait for more */ + debug(20, 3) ("reply_network_clientcopy3: Waiting for more\n"); + goto finish; + } + + if ((sc->copy_offset >= state->inmem_lo) && + (sc->copy_offset < state->inmem_hi)) { + /* What the client wants is in memory */ + debug(20, 3) ("reply_network_clientcopy3: Copying from memory\n"); + sz = stmemCopy(&state->data_hdr, + sc->copy_offset, sc->copy_buf, sc->copy_size); + reply_network_clientcallback(sc, sz); + assert((state->inmem_lo + sz - 1) > 0); /* XXX just being paranoid for now! */ + stmemFreeDataUpto(&state->data_hdr, state->inmem_lo + sz - 1); + goto finish; + } + /* We shouldn't ever get here! */ + assert(1 == 0); + +finish: + sc->flags.store_copying = 0; +} + + +/* + * reply_makepublic - make this object public + */ +static void +reply_network_makepublic(StoreEntry *e) +{ + /* Do nothing */ +} + + +/* + * reply_makeprivate - make this object private + */ +static void +reply_network_makeprivate(StoreEntry *e) +{ + /* Do nothing */ +} + + +/* + * reply_network_release - object is being deleted + * + * Yes, its a no-op for us because all objects are private + */ +static void +reply_network_release(StoreEntry *e) +{ +} + + +/* + * reply_network_create - create an internal reply .. + */ +void +reply_network_create(StoreEntry *e) +{ + reply_network_state_t *state; + MemObject *mem; + + assert(e != NULL); + assert(e->mem_obj != NULL); + + mem = e->mem_obj; + + /* Create a new state struct */ + state = memPoolAlloc(reply_network_state_pool); + + /* Initialise it */ + e->stdata = state; + + /* Assign our functions .. */ + e->stappend = reply_network_append; + e->stflush = reply_network_flush; + e->stmemhi = reply_network_memhi; + e->stmemlo = reply_network_memlo; + e->stclientcopy = reply_network_clientcopy; + e->stmakeprivate = reply_network_makeprivate; + e->stmakepublic = reply_network_makepublic; + e->strelease = reply_network_release; + e->stdone = reply_network_done; + + /* Done! */ +}