/*
- * $Id: MemBuf.cc,v 1.3 1998/02/21 18:46:34 rousskov Exp $
+ * $Id: MemBuf.cc,v 1.4 1998/02/26 07:06:14 rousskov Exp $
*
* DEBUG: section 59 auto-growing Memory Buffer with printf
* AUTHOR: Alex Rousskov
*
*/
-/* see MemBuf.h for documentation */
-
/*
* To-Do: uses memory pools for .buf recycling @?@
*/
+/*
+ Rationale:
+ ----------
+
+ Here is how one would comm_write an object without MemBuffer:
+
+ {
+ -- allocate:
+ buf = malloc(big_enough);
+
+ -- "pack":
+ snprintf object(s) piece-by-piece constantly checking for overflows
+ and maintaining (buf+offset);
+ ...
+
+ -- write
+ comm_write(buf, free, ...);
+ }
+
+ The whole "packing" idea is quite messy: We are given a buffer of fixed
+ size and we have to check all the time that we still fit. Sounds logical.
+ However, what happens if we have more data? If we are lucky to be careful
+ to stop before we overrun any buffers, we still may have garbage (e.g.
+ half of ETag) in the buffer.
+
+ MemBuffer:
+ ----------
+
+ MemBuffer is a memory-resident buffer with printf()-like interface. It
+ hides all offest handling and overflow checking. Moreover, it has a
+ build-in control that no partial data has been written.
+
+ MemBuffer is designed to handle relatively small data. It starts with a
+ small buffer of configurable size to avoid allocating huge buffers all the
+ time. MemBuffer doubles the buffer when needed. It assert()s that it will
+ not grow larger than a configurable limit. MemBuffer has virtually no
+ overhead (and can even reduce memory consumption) compared to old
+ "packing" approach.
+
+ MemBuffer eliminates both "packing" mess and truncated data:
+
+ {
+ -- setup
+ MemBuf buf;
+
+ -- required init with optional size tuning (see #defines for defaults)
+ memBufInit(&buf, initial-size, absolute-maximum);
+
+ -- "pack" (no need to handle offsets or check for overflows)
+ memBufPrintf(&buf, ...);
+ ...
+
+ -- write
+ comm_write(buf.buf, memBufFreeFunc(&buf), ...);
+
+ -- *iff* you did not give the buffer away, free it yourself
+ -- memBufFree(&buf);
+ }
+*/
+
#include "squid.h"
+/* local constants */
+
+/* default values for buffer sizes, used by memBufDefInit */
+#define MEM_BUF_INIT_SIZE (2*1024)
+#define MEM_BUF_MAX_SIZE (32*1024)
+
+
/* local routines */
static void memBufGrow(MemBuf *mb, mb_size_t min_cap);
+/* init with defaults */
+void
+memBufDefInit(MemBuf *mb)
+{
+ memBufInit(mb, MEM_BUF_INIT_SIZE, MEM_BUF_MAX_SIZE);
+}
+
+/* init with specific sizes */
void
memBufInit(MemBuf *mb, mb_size_t szInit, mb_size_t szMax)
{
memBufGrow(mb, szInit);
}
+/*
+ * cleans the mb; last function to call if you do not give .buf away with
+ * memBufFreeFunc
+ */
void
memBufClean(MemBuf *mb)
{
mb->size = mb->capacity = 0;
}
+/* calls memcpy, appends exactly size bytes, extends buffer if needed */
void
memBufAppend(MemBuf *mb, const char *buf, mb_size_t sz)
{
}
}
+/* calls snprintf, extends buffer if needed */
#ifdef __STDC__
void
memBufPrintf(MemBuf *mb, const char *fmt, ...)
}
+/* vprintf for other printf()'s to use */
void
memBufVPrintf(MemBuf *mb, const char *fmt, va_list vargs)
{
mb->size += sz-1; /* note that we cut 0-terminator as store does @?@ @?@ */
}
+/*
+ * returns free() function to be used.
+ * Important:
+ * calling this function "freezes" mb,
+ * do not _update_ mb after that in any way
+ * (you still can read-access .buf and .size)
+ */
FREE *
memBufFreeFunc(MemBuf *mb)
{
mb->capacity = new_cap;
}
+
+/* Reports */
+
+/* puts report on MemBuf _module_ usage into mb */
void
memBufReport(MemBuf *mb)
{
extern void ipcache_restart(void);
extern int ipcacheUnregister(const char *name, void *data);
+/* MemBuf */
+/* init with specific sizes */
+extern void memBufInit(MemBuf *mb, mb_size_t szInit, mb_size_t szMax);
+/* init with defaults */
+extern void memBufDefInit(MemBuf *mb);
+/* cleans the mb; last function to call if you do not give .buf away */
+extern void memBufClean(MemBuf *mb);
+/* calls memcpy, appends exactly size bytes, extends buffer if needed */
+extern void memBufAppend(MemBuf *mb, const char *buf, mb_size_t size);
+/* calls snprintf, extends buffer if needed */
+#ifdef __STDC__
+extern void memBufPrintf(MemBuf *mb, const char *fmt, ...);
+#else
+extern void memBufPrintf();
+#endif
+/* vprintf for other printf()'s to use */
+extern void memBufVPrintf(MemBuf *mb, const char *fmt, va_list ap);
+/* returns free() function to be used, _freezes_ the object! */
+extern FREE *memBufFreeFunc(MemBuf *mb);
+/* puts report on MemBuf _module_ usage into mb */
+extern void memBufReport(MemBuf *mb);
+
extern char *mime_get_header(const char *mime, const char *header);
extern char *mime_headers_end(const char *mime);
extern int mk_mime_hdr(char *result, const char *type, int size, time_t ttl, time_t lmt);
hash_link *current_ptr;
};
-#include "MemBuf.h"
-#include "Packer.h"
-
/* server cache control */
struct _HttpScc {
int mask;
} Http, Ftp, Gopher, Wais;
};
+/* auto-growing memory-resident buffer with printf interface */
+struct _MemBuf {
+ /* public, read-only */
+ char *buf;
+ mb_size_t size; /* used space, does not count 0-terminator */
+
+ /* 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 */
+};
+
+
struct _mem_node {
char *data;
int len;
struct _store_client *next;
};
+#include "Packer.h"
+
/* This structure can be freed while object is purged out from memory */
struct _MemObject {
method_t method;
int fd;
void *ctrl;
} swapout;
-#if 0
- struct _http_reply *reply;
-#else
HttpReply *reply;
-#endif
request_t *request;
struct timeval start_ping;
IRCB *icp_reply_callback;