]> git.ipfire.org Git - thirdparty/squid.git/blame - src/MemBuf.cc
Document the 'carp' cache_peer option
[thirdparty/squid.git] / src / MemBuf.cc
CommitLineData
f740a279 1
cb69b4c7 2/*
528b2c61 3 * $Id: MemBuf.cc,v 1.33 2003/01/23 00:37:14 robertc Exp $
cb69b4c7 4 *
123abbe1 5 * DEBUG: section 59 auto-growing Memory Buffer with printf
cb69b4c7 6 * AUTHOR: Alex Rousskov
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 9 * ----------------------------------------------------------
cb69b4c7 10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
cb69b4c7 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
cb69b4c7 34 */
35
cb69b4c7 36/*
2246b732 37 * To-Do: use memory pools for .buf recycling @?@ @?@
cb69b4c7 38 */
39
1a3db59c 40/*
2ac76861 41 * Rationale:
42 * ----------
43 *
44 * Here is how one would comm_write an object without MemBuffer:
45 *
46 * {
47 * -- allocate:
48 * buf = malloc(big_enough);
49 *
50 * -- "pack":
51 * snprintf object(s) piece-by-piece constantly checking for overflows
52 * and maintaining (buf+offset);
53 * ...
54 *
55 * -- write
56 * comm_write(buf, free, ...);
57 * }
58 *
59 * The whole "packing" idea is quite messy: We are given a buffer of fixed
60 * size and we have to check all the time that we still fit. Sounds logical.
eb139d08 61 *
62 * However, what happens if we have more data? If we are lucky to stop before
63 * we overrun any buffers, we still may have garbage (e.g. half of ETag) in
64 * the buffer.
2ac76861 65 *
66 * MemBuffer:
67 * ----------
68 *
69 * MemBuffer is a memory-resident buffer with printf()-like interface. It
70 * hides all offest handling and overflow checking. Moreover, it has a
71 * build-in control that no partial data has been written.
72 *
73 * MemBuffer is designed to handle relatively small data. It starts with a
74 * small buffer of configurable size to avoid allocating huge buffers all the
75 * time. MemBuffer doubles the buffer when needed. It assert()s that it will
76 * not grow larger than a configurable limit. MemBuffer has virtually no
77 * overhead (and can even reduce memory consumption) compared to old
78 * "packing" approach.
79 *
80 * MemBuffer eliminates both "packing" mess and truncated data:
81 *
82 * {
83 * -- setup
84 * MemBuf buf;
85 *
86 * -- required init with optional size tuning (see #defines for defaults)
87 * memBufInit(&buf, initial-size, absolute-maximum);
88 *
89 * -- "pack" (no need to handle offsets or check for overflows)
90 * memBufPrintf(&buf, ...);
91 * ...
92 *
93 * -- write
2246b732 94 * comm_write_mbuf(fd, buf, handler, data);
95 *
2ac76861 96 * -- *iff* you did not give the buffer away, free it yourself
51251ed1 97 * -- memBufClean(&buf);
2ac76861 98 * }
99 */
1a3db59c 100
cb69b4c7 101
102#include "squid.h"
103
1a3db59c 104/* local constants */
105
106/* default values for buffer sizes, used by memBufDefInit */
107#define MEM_BUF_INIT_SIZE (2*1024)
b8890359 108#define MEM_BUF_MAX_SIZE (2*1000*1024*1024)
1a3db59c 109
110
cb69b4c7 111/* local routines */
2ac76861 112static void memBufGrow(MemBuf * mb, mb_size_t min_cap);
cb69b4c7 113
114
1a3db59c 115/* init with defaults */
116void
2ac76861 117memBufDefInit(MemBuf * mb)
1a3db59c 118{
119 memBufInit(mb, MEM_BUF_INIT_SIZE, MEM_BUF_MAX_SIZE);
120}
121
cb69b4c7 122
1a3db59c 123/* init with specific sizes */
cb69b4c7 124void
2ac76861 125memBufInit(MemBuf * mb, mb_size_t szInit, mb_size_t szMax)
cb69b4c7 126{
127 assert(mb);
128 assert(szInit > 0 && szMax > 0);
129
130 mb->buf = NULL;
131 mb->size = 0;
132 mb->max_capacity = szMax;
133 mb->capacity = 0;
1eb41ae8 134 mb->stolen = 0;
cb69b4c7 135
136 memBufGrow(mb, szInit);
137}
138
1a3db59c 139/*
140 * cleans the mb; last function to call if you do not give .buf away with
141 * memBufFreeFunc
142 */
cb69b4c7 143void
2ac76861 144memBufClean(MemBuf * mb)
cb69b4c7 145{
2ac76861 146 assert(mb);
147 assert(mb->buf);
1eb41ae8 148 assert(!mb->stolen); /* not frozen */
cb69b4c7 149
1eb41ae8 150 memFreeBuf(mb->capacity, mb->buf);
2ac76861 151 mb->buf = NULL;
152 mb->size = mb->capacity = 0;
cb69b4c7 153}
154
137ee196 155/* cleans the buffer without changing its capacity
156 * if called with a Null buffer, calls memBufDefInit() */
157void
158memBufReset(MemBuf * mb)
159{
160 assert(mb);
161
1d21d91d 162 if (memBufIsNull(mb)) {
137ee196 163 memBufDefInit(mb);
164 } else {
1eb41ae8 165 assert(!mb->stolen); /* not frozen */
137ee196 166 /* reset */
167 memset(mb->buf, 0, mb->capacity);
168 mb->size = 0;
169 }
170}
171
b8890359 172/* unfortunate hack to test if the buffer has been Init()ialized */
1d21d91d 173int
174memBufIsNull(MemBuf * mb)
175{
176 assert(mb);
177 if (!mb->buf && !mb->max_capacity && !mb->capacity && !mb->size)
b8890359 178 return 1; /* is null (not initialized) */
0cdcddb9 179 assert(mb->buf && mb->max_capacity && mb->capacity); /* paranoid */
1d21d91d 180 return 0;
181}
182
183
1a3db59c 184/* calls memcpy, appends exactly size bytes, extends buffer if needed */
cb69b4c7 185void
2ac76861 186memBufAppend(MemBuf * mb, const char *buf, mb_size_t sz)
cb69b4c7 187{
188 assert(mb && buf && sz >= 0);
189 assert(mb->buf);
1eb41ae8 190 assert(!mb->stolen); /* not frozen */
cb69b4c7 191
192 if (sz > 0) {
cc5bb70f 193 if (mb->size + sz + 1 > mb->capacity)
194 memBufGrow(mb, mb->size + sz + 1);
2ac76861 195 assert(mb->size + sz <= mb->capacity); /* paranoid */
cb69b4c7 196 xmemcpy(mb->buf + mb->size, buf, sz);
197 mb->size += sz;
cc5bb70f 198 mb->buf[mb->size] = '\0'; /* \0 terminate in case we are used as a string. Not counted in the size */
cb69b4c7 199 }
200}
201
19ecac48 202/* calls memBufVPrintf */
6de2df60 203#if STDC_HEADERS
cb69b4c7 204void
2ac76861 205memBufPrintf(MemBuf * mb, const char *fmt,...)
cb69b4c7 206{
207 va_list args;
208 va_start(args, fmt);
209#else
210void
211memBufPrintf(va_alist)
212 va_dcl
213{
214 va_list args;
215 MemBuf *mb = NULL;
216 const char *fmt = NULL;
217 mb_size_t sz = 0;
218 va_start(args);
219 mb = va_arg(args, MemBuf *);
220 fmt = va_arg(args, char *);
221#endif
222 memBufVPrintf(mb, fmt, args);
223 va_end(args);
224}
225
226
19ecac48 227/* vprintf for other printf()'s to use; calls vsnprintf, extends buf if needed */
cb69b4c7 228void
2ac76861 229memBufVPrintf(MemBuf * mb, const char *fmt, va_list vargs)
cb69b4c7 230{
19ecac48 231 int sz = 0;
cb69b4c7 232 assert(mb && fmt);
233 assert(mb->buf);
1eb41ae8 234 assert(!mb->stolen); /* not frozen */
2246b732 235 /* assert in Grow should quit first, but we do not want to have a scary infinite loop */
2ac76861 236 while (mb->capacity <= mb->max_capacity) {
cb69b4c7 237 mb_size_t free_space = mb->capacity - mb->size;
238 /* put as much as we can */
19ecac48 239 sz = vsnprintf(mb->buf + mb->size, free_space, fmt, vargs);
240 /* check for possible overflow */
241 /* snprintf on Linuz returns -1 on overflows */
242 /* snprintf on FreeBSD returns at least free_space on overflows */
137ee196 243 if (sz < 0 || sz >= free_space)
2ac76861 244 memBufGrow(mb, mb->capacity + 1);
cb69b4c7 245 else
246 break;
247 }
19ecac48 248 mb->size += sz;
137ee196 249 /* on Linux and FreeBSD, '\0' is not counted in return value */
250 /* on XXX it might be counted */
251 /* check that '\0' is appended and not counted */
43d2af69 252 if (!mb->size || mb->buf[mb->size - 1]) {
137ee196 253 assert(!mb->buf[mb->size]);
43d2af69 254 } else {
137ee196 255 mb->size--;
43d2af69 256 }
cb69b4c7 257}
258
1a3db59c 259/*
260 * returns free() function to be used.
261 * Important:
262 * calling this function "freezes" mb,
263 * do not _update_ mb after that in any way
264 * (you still can read-access .buf and .size)
265 */
cb69b4c7 266FREE *
2ac76861 267memBufFreeFunc(MemBuf * mb)
cb69b4c7 268{
269 FREE *ff;
270 assert(mb);
271 assert(mb->buf);
1eb41ae8 272 assert(!mb->stolen); /* not frozen */
cb69b4c7 273
fa80a8ef 274 ff = memFreeBufFunc((size_t) mb->capacity);
275 mb->stolen = 1; /* freeze */
cb69b4c7 276 return ff;
277}
278
279/* grows (doubles) internal buffer to satisfy required minimal capacity */
280static void
2ac76861 281memBufGrow(MemBuf * mb, mb_size_t min_cap)
cb69b4c7 282{
1eb41ae8 283 size_t new_cap;
284 size_t buf_cap;
137ee196 285
cb69b4c7 286 assert(mb);
1eb41ae8 287 assert(!mb->stolen);
cb69b4c7 288 assert(mb->capacity < min_cap);
289
290 /* determine next capacity */
fa80a8ef 291 if (min_cap > 64 * 1024) {
292 new_cap = 64 * 1024;
293 while (new_cap < (size_t) min_cap)
294 new_cap += 64 * 1024; /* increase in reasonable steps */
1eb41ae8 295 } else {
fa80a8ef 296 new_cap = (size_t) min_cap;
1eb41ae8 297 }
cb69b4c7 298
299 /* last chance to fit before we assert(!overflow) */
fa80a8ef 300 if (new_cap > (size_t) mb->max_capacity)
301 new_cap = (size_t) mb->max_capacity;
137ee196 302
fa80a8ef 303 assert(new_cap <= (size_t) mb->max_capacity); /* no overflow */
304 assert(new_cap > (size_t) mb->capacity); /* progress */
1eb41ae8 305
fa80a8ef 306 buf_cap = (size_t) mb->capacity;
e6ccf245 307 mb->buf = (char *)memReallocBuf(mb->buf, new_cap, &buf_cap);
137ee196 308
309 /* done */
fa80a8ef 310 mb->capacity = (mb_size_t) buf_cap;
cb69b4c7 311}
312
1a3db59c 313
314/* Reports */
315
316/* puts report on MemBuf _module_ usage into mb */
cb69b4c7 317void
2ac76861 318memBufReport(MemBuf * mb)
cb69b4c7 319{
320 assert(mb);
321 memBufPrintf(mb, "memBufReport is not yet implemented @?@\n");
322}
528b2c61 323
324#ifndef _USE_INLINE_
325#include "MemBuf.cci"
326#endif