many parts of the code.
/*
- * $Id: MemBuf.cc,v 1.28 2001/04/20 21:26:22 hno Exp $
+ * $Id: MemBuf.cc,v 1.29 2002/02/13 19:34:02 hno Exp $
*
* DEBUG: section 59 auto-growing Memory Buffer with printf
* AUTHOR: Alex Rousskov
mb->size = 0;
mb->max_capacity = szMax;
mb->capacity = 0;
- mb->freefunc = NULL;
+ mb->stolen = 0;
memBufGrow(mb, szInit);
}
{
assert(mb);
assert(mb->buf);
- assert(mb->freefunc); /* not frozen */
+ assert(!mb->stolen); /* not frozen */
- (*mb->freefunc) (mb->buf); /* free */
- mb->freefunc = NULL; /* freeze */
+ memFreeBuf(mb->capacity, mb->buf);
mb->buf = NULL;
mb->size = mb->capacity = 0;
}
if (memBufIsNull(mb)) {
memBufDefInit(mb);
} else {
- assert(mb->freefunc); /* not frozen */
+ assert(!mb->stolen); /* not frozen */
/* reset */
memset(mb->buf, 0, mb->capacity);
mb->size = 0;
{
assert(mb && buf && sz >= 0);
assert(mb->buf);
- assert(mb->freefunc); /* not frozen */
+ assert(!mb->stolen); /* not frozen */
if (sz > 0) {
if (mb->size + sz > mb->capacity)
int sz = 0;
assert(mb && fmt);
assert(mb->buf);
- assert(mb->freefunc); /* not frozen */
+ assert(!mb->stolen); /* not frozen */
/* assert in Grow should quit first, but we do not want to have a scary infinite loop */
while (mb->capacity <= mb->max_capacity) {
mb_size_t free_space = mb->capacity - mb->size;
FREE *ff;
assert(mb);
assert(mb->buf);
- assert(mb->freefunc); /* not frozen */
+ assert(!mb->stolen); /* not frozen */
- ff = mb->freefunc;
- mb->freefunc = NULL; /* freeze */
+ ff = memFreeBufFunc((size_t)mb->capacity);
+ mb->stolen = 1; /* freeze */
return ff;
}
static void
memBufGrow(MemBuf * mb, mb_size_t min_cap)
{
- mb_size_t new_cap;
- MemBuf old_mb;
+ size_t new_cap;
+ size_t buf_cap;
assert(mb);
+ assert(!mb->stolen);
assert(mb->capacity < min_cap);
/* determine next capacity */
- new_cap = mb->capacity;
- if (new_cap > 0)
- while (new_cap < min_cap)
- new_cap *= 2; /* double */
- else
- new_cap = min_cap;
+ if (min_cap > 64*1024) {
+ new_cap = 64*1024;
+ while (new_cap < (size_t)min_cap)
+ new_cap += 64*1024; /* increase in reasonable steps */
+ } else {
+ new_cap = (size_t)min_cap;
+ }
/* last chance to fit before we assert(!overflow) */
- if (new_cap > mb->max_capacity)
- new_cap = mb->max_capacity;
-
- assert(new_cap <= mb->max_capacity); /* no overflow */
- assert(new_cap > mb->capacity); /* progress */
-
- old_mb = *mb;
-
- /* allocate new memory */
- switch (new_cap) {
- case 2048:
- mb->buf = memAllocate(MEM_2K_BUF);
- mb->freefunc = &memFree2K;
- break;
- case 4096:
- mb->buf = memAllocate(MEM_4K_BUF);
- mb->freefunc = &memFree4K;
- break;
- case 8192:
- mb->buf = memAllocate(MEM_8K_BUF);
- mb->freefunc = &memFree8K;
- break;
- case 16384:
- mb->buf = memAllocate(MEM_16K_BUF);
- mb->freefunc = &memFree16K;
- break;
- case 32768:
- mb->buf = memAllocate(MEM_32K_BUF);
- mb->freefunc = &memFree32K;
- break;
- case 65536:
- mb->buf = memAllocate(MEM_64K_BUF);
- mb->freefunc = &memFree64K;
- break;
- default:
- /* recycle if old buffer was not "pool"ed */
- if (old_mb.freefunc == &xfree) {
- mb->buf = xrealloc(old_mb.buf, new_cap);
- old_mb.buf = NULL;
- old_mb.freefunc = NULL;
- /* init tail, just in case */
- memset(mb->buf + mb->size, 0, new_cap - mb->size);
- } else {
- mb->buf = xcalloc(1, new_cap);
- mb->freefunc = &xfree;
- }
- }
+ if (new_cap > (size_t)mb->max_capacity)
+ new_cap = (size_t)mb->max_capacity;
- /* copy and free old buffer if needed */
- if (old_mb.buf && old_mb.freefunc) {
- xmemcpy(mb->buf, old_mb.buf, old_mb.size);
- (*old_mb.freefunc) (old_mb.buf);
- } else {
- assert(!old_mb.buf && !old_mb.freefunc);
- }
+ assert(new_cap <= (size_t)mb->max_capacity); /* no overflow */
+ assert(new_cap > (size_t)mb->capacity); /* progress */
+
+ buf_cap = (size_t)mb->capacity;
+ mb->buf = memReallocBuf(mb->buf, new_cap, &buf_cap);
/* done */
- mb->capacity = new_cap;
+ mb->capacity = (mb_size_t)buf_cap;
}
/*
- * $Id: client_side.cc,v 1.561 2001/12/12 23:44:18 hno Exp $
+ * $Id: client_side.cc,v 1.562 2002/02/13 19:34:01 hno Exp $
*
* DEBUG: section 33 Client-side Routines
* AUTHOR: Duane Wessels
authenticateAuthUserRequestUnlock(connState->auth_user_request);
connState->auth_user_request = NULL;
authenticateOnCloseConnection(connState);
- if (connState->in.size == CLIENT_REQ_BUF_SZ)
- memFree(connState->in.buf, MEM_CLIENT_REQ_BUF);
- else
- safe_free(connState->in.buf);
- /* XXX account connState->in.buf */
+ memFreeBuf(connState->in.size, connState->in.buf);
pconnHistCount(0, connState->nrequests);
cbdataFree(connState);
#ifdef _SQUID_LINUX_
int parser_return_code = 0;
request_t *request = NULL;
int size;
- void *p;
method_t method;
clientHttpRequest *http = NULL;
clientHttpRequest **H = NULL;
commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, conn, 0);
if (len == 0) {
/* Grow the request memory area to accomodate for a large request */
- conn->in.size += CLIENT_REQ_BUF_SZ;
- if (conn->in.size == 2 * CLIENT_REQ_BUF_SZ) {
- p = conn->in.buf; /* get rid of fixed size Pooled buffer */
- conn->in.buf = xcalloc(2, CLIENT_REQ_BUF_SZ);
- xmemcpy(conn->in.buf, p, CLIENT_REQ_BUF_SZ);
- memFree(p, MEM_CLIENT_REQ_BUF);
- } else
- conn->in.buf = xrealloc(conn->in.buf, conn->in.size);
- /* XXX account conn->in.buf */
+ conn->in.buf = memReallocBuf(conn->in.buf, conn->in.size * 2, &conn->in.size);
debug(33, 2) ("growing request buffer: offset=%ld size=%ld\n",
(long) conn->in.offset, (long) conn->in.size);
len = conn->in.size - conn->in.offset - 1;
connState->log_addr.s_addr &= Config.Addrs.client_netmask.s_addr;
connState->me = me;
connState->fd = fd;
- connState->in.size = CLIENT_REQ_BUF_SZ;
- connState->in.buf = memAllocate(MEM_CLIENT_REQ_BUF);
- /* XXX account connState->in.buf */
+ connState->in.buf = memAllocBuf(CLIENT_REQ_BUF_SZ, &connState->in.size);
comm_add_close_handler(fd, connStateFree, connState);
if (Config.onoff.log_fqdn)
fqdncache_gethostbyaddr(peer.sin_addr, FQDN_LOOKUP_IF_MISS);
connState->log_addr.s_addr &= Config.Addrs.client_netmask.s_addr;
connState->me = me;
connState->fd = fd;
- connState->in.size = CLIENT_REQ_BUF_SZ;
- connState->in.buf = memAllocate(MEM_CLIENT_REQ_BUF);
+ connState->in.buf = memAllocBuf(CLIENT_REQ_BUF_SZ, &connState->in.size);
/* XXX account connState->in.buf */
comm_add_close_handler(fd, connStateFree, connState);
if (Config.onoff.log_fqdn)
/*
- * $Id: enums.h,v 1.203 2001/12/21 09:47:34 hno Exp $
+ * $Id: enums.h,v 1.204 2002/02/13 19:34:01 hno Exp $
*
*
* SQUID Web Proxy Cache http://www.squid-cache.org/
MEM_EVENT,
MEM_TLV,
MEM_SWAP_LOG_DATA,
- MEM_CLIENT_REQ_BUF,
MEM_MAX
} mem_type;
/*
- * $Id: ftp.cc,v 1.316 2001/11/09 07:05:00 hno Exp $
+ * $Id: ftp.cc,v 1.317 2002/02/13 19:34:02 hno Exp $
*
* DEBUG: section 9 File Transfer Protocol (FTP)
* AUTHOR: Harvest Derived
char *buf;
size_t size;
off_t offset;
- FREE *freefunc;
wordlist *message;
char *last_command;
char *last_reply;
char *buf;
size_t size;
off_t offset;
- FREE *freefunc;
char *host;
u_short port;
} data;
storeUnlockObject(ftpState->entry);
if (ftpState->reply_hdr) {
memFree(ftpState->reply_hdr, MEM_8K_BUF);
- /* this seems unnecessary, but people report SEGV's
- * when freeing memory in this function */
ftpState->reply_hdr = NULL;
}
requestUnlink(ftpState->request);
if (ftpState->ctrl.buf) {
- ftpState->ctrl.freefunc(ftpState->ctrl.buf);
- /* this seems unnecessary, but people report SEGV's
- * when freeing memory in this function */
+ memFreeBuf(ftpState->ctrl.size, ftpState->ctrl.buf);
ftpState->ctrl.buf = NULL;
}
if (ftpState->data.buf) {
- ftpState->data.freefunc(ftpState->data.buf);
- /* this seems unnecessary, but people report SEGV's
- * when freeing memory in this function */
+ memFreeBuf(ftpState->data.size, ftpState->data.buf);
ftpState->data.buf = NULL;
}
if (ftpState->pathcomps)
ftpState->user, ftpState->password);
ftpState->state = BEGIN;
ftpState->ctrl.last_command = xstrdup("Connect to server");
- ftpState->ctrl.buf = memAllocate(MEM_4K_BUF);
- ftpState->ctrl.freefunc = memFree4K;
- ftpState->ctrl.size = 4096;
+ ftpState->ctrl.buf = memAllocBuf(4096, &ftpState->ctrl.size);
ftpState->ctrl.offset = 0;
- ftpState->data.buf = xmalloc(SQUID_TCP_SO_RCVBUF);
- ftpState->data.size = SQUID_TCP_SO_RCVBUF;
- ftpState->data.freefunc = xfree;
+ ftpState->data.buf = memAllocBuf(SQUID_TCP_SO_RCVBUF, &ftpState->data.size);
ftpScheduleReadControlReply(ftpState, 0);
}
static void
ftpHandleControlReply(FtpStateData * ftpState)
{
- char *oldbuf;
wordlist **W;
int bytes_used = 0;
wordlistDestroy(&ftpState->ctrl.message);
if (ftpState->ctrl.message == NULL) {
/* didn't get complete reply yet */
if (ftpState->ctrl.offset == ftpState->ctrl.size) {
- oldbuf = ftpState->ctrl.buf;
- ftpState->ctrl.buf = xcalloc(ftpState->ctrl.size << 1, 1);
- xmemcpy(ftpState->ctrl.buf, oldbuf, ftpState->ctrl.size);
- ftpState->ctrl.size <<= 1;
- ftpState->ctrl.freefunc(oldbuf);
- ftpState->ctrl.freefunc = xfree;
+ ftpState->ctrl.buf = memReallocBuf(ftpState->ctrl.buf, ftpState->ctrl.size << 1, &ftpState->ctrl.size);
}
ftpScheduleReadControlReply(ftpState, 0);
return;
/*
- * $Id: mem.cc,v 1.60 2002/02/13 17:22:36 hno Exp $
+ * $Id: mem.cc,v 1.61 2002/02/13 19:34:02 hno Exp $
*
* DEBUG: section 13 High Level Memory Pool Management
* AUTHOR: Harvest Derived
static MemMeter StrCountMeter;
static MemMeter StrVolumeMeter;
+static MemMeter HugeBufCountMeter;
+static MemMeter HugeBufVolumeMeter;
/* local routines */
"Other Strings",
xpercentInt(StrCountMeter.level - pooled_count, StrCountMeter.level),
xpercentInt(StrVolumeMeter.level - pooled_volume, StrVolumeMeter.level));
+ storeAppendPrintf(sentry, "\n");
+}
+
+static void
+memBufStats(StoreEntry *sentry)
+{
+ storeAppendPrintf(sentry, "Large buffers: %d (%d KB)\n",
+ HugeBufCountMeter.level,
+ HugeBufVolumeMeter.level / 1024);
}
static void
storeBuffer(sentry);
memReport(sentry);
memStringStats(sentry);
+ memBufStats(sentry);
storeBufferFlush(sentry);
}
pool ? memPoolFree(pool, buf) : xfree(buf);
}
+/* Find the best fit MEM_X_BUF type */
+static mem_type
+memFindBufSizeType(size_t net_size, size_t * gross_size)
+{
+ mem_type type;
+ size_t size;
+ if (net_size <= 2*1024) {
+ type = MEM_2K_BUF;
+ size = 2*1024;
+ } else if (net_size <= 4*1024) {
+ type = MEM_4K_BUF;
+ size = 4*1024;
+ } else if (net_size <= 8*1024) {
+ type = MEM_8K_BUF;
+ size = 8*1024;
+ } else if (net_size <= 16*1024) {
+ type = MEM_16K_BUF;
+ size = 16*1024;
+ } else if (net_size <= 32*1024) {
+ type = MEM_32K_BUF;
+ size = 32*1024;
+ } else if (net_size <= 64*1024) {
+ type = MEM_64K_BUF;
+ size = 64*1024;
+ } else {
+ type = MEM_NONE;
+ size = net_size;
+ }
+ if (gross_size)
+ *gross_size = size;
+ return type;
+}
+
+/* allocate a variable size buffer using best-fit pool */
+void *
+memAllocBuf(size_t net_size, size_t * gross_size)
+{
+ mem_type type = memFindBufSizeType(net_size, gross_size);
+ if (type != MEM_NONE)
+ return memAllocate(type);
+ else {
+ memMeterInc(HugeBufCountMeter);
+ memMeterAdd(HugeBufVolumeMeter, *gross_size);
+ return xcalloc(1, net_size);
+ }
+}
+
+/* resize a variable sized buffer using best-fit pool */
+void *
+memReallocBuf(void *oldbuf, size_t net_size, size_t * gross_size)
+{
+ /* XXX This can be optimized on very large buffers to use realloc() */
+ int new_gross_size;
+ void *newbuf = memAllocBuf(net_size, &new_gross_size);
+ if (oldbuf) {
+ int data_size = *gross_size;
+ if (data_size > net_size)
+ data_size = net_size;
+ memcpy(newbuf, oldbuf, data_size);
+ memFreeBuf(*gross_size, oldbuf);
+ }
+ *gross_size = new_gross_size;
+ return newbuf;
+}
+
+/* free buffer allocated with memAllocBuf() */
+void
+memFreeBuf(size_t size, void *buf)
+{
+ mem_type type = memFindBufSizeType(size, NULL);
+ if (type != MEM_NONE)
+ memFree(buf, type);
+ else {
+ xfree(buf);
+ memMeterDec(HugeBufCountMeter);
+ memMeterDel(HugeBufVolumeMeter, size);
+ }
+}
+
+
void
memInit(void)
{
memDataInit(MEM_HELPER_STATEFUL_REQUEST, "helper_stateful_request",
sizeof(helper_stateful_request), 0);
memDataInit(MEM_TLV, "storeSwapTLV", sizeof(tlv), 0);
- memDataInit(MEM_CLIENT_REQ_BUF, "clientRequestBuffer", CLIENT_REQ_BUF_SZ, 0);
memDataInit(MEM_SWAP_LOG_DATA, "storeSwapLogData", sizeof(storeSwapLogData), 0);
/* init string pools */
/* ick */
-void
+static void
memFree2K(void *p)
{
memFree(p, MEM_2K_BUF);
memFree(p, MEM_8K_BUF);
}
-void
+static void
memFree16K(void *p)
{
memFree(p, MEM_16K_BUF);
}
-void
+static void
memFree32K(void *p)
{
memFree(p, MEM_32K_BUF);
}
-void
+static void
memFree64K(void *p)
{
memFree(p, MEM_64K_BUF);
}
+
+FREE *
+memFreeBufFunc(size_t size)
+{
+ switch(size)
+ {
+ case 2*1024:
+ return memFree2K;
+ case 4*1024:
+ return memFree4K;
+ case 8*1024:
+ return memFree8K;
+ case 16*1024:
+ return memFree16K;
+ case 32*1024:
+ return memFree32K;
+ case 64*1024:
+ return memFree64K;
+ default:
+ memMeterDec(HugeBufCountMeter);
+ memMeterDel(HugeBufVolumeMeter, size);
+ return xfree;
+ }
+}
/*
- * $Id: protos.h,v 1.424 2002/02/13 17:22:36 hno Exp $
+ * $Id: protos.h,v 1.425 2002/02/13 19:34:02 hno Exp $
*
*
* SQUID Web Proxy Cache http://www.squid-cache.org/
extern void memConfigure(void);
extern void *memAllocate(mem_type);
extern void *memAllocString(size_t net_size, size_t * gross_size);
+extern void *memAllocBuf(size_t net_size, size_t * gross_size);
+extern void *memReallocBuf(void *buf, size_t net_size, size_t * gross_size);
extern void memFree(void *, int type);
-extern void memFreeString(size_t size, void *);
-extern void memFree2K(void *);
extern void memFree4K(void *);
extern void memFree8K(void *);
-extern void memFree16K(void *);
-extern void memFree32K(void *);
-extern void memFree64K(void *);
+extern void memFreeString(size_t size, void *);
+extern void memFreeBuf(size_t size, void *);
+extern FREE *memFreeBufFunc(size_t size);
extern int memInUse(mem_type);
extern size_t memTotalAllocated(void);
extern void memDataInit(mem_type, const char *, size_t, int);
/*
- * $Id: structs.h,v 1.408 2001/12/01 18:03:10 hno Exp $
+ * $Id: structs.h,v 1.409 2002/02/13 19:34:02 hno Exp $
*
*
* SQUID Web Proxy Cache http://www.squid-cache.org/
/* private, stay away; use interface function instead */
mb_size_t max_capacity; /* when grows: assert(new_capacity <= max_capacity) */
mb_size_t capacity; /* allocated space */
- FREE *freefunc; /* what to use to free the buffer, NULL after memBufFreeFunc() is called */
+ unsigned stolen:1; /* the buffer has been stolen for use by someone else */
};
/* see Packer.c for description */