]> git.ipfire.org Git - thirdparty/squid.git/blame - src/stmem.cc
Bug #1327: NTLM authentication fails when low on filedescriptors or
[thirdparty/squid.git] / src / stmem.cc
CommitLineData
df92bd2a 1
30a4f2a8 2/*
d06925a4 3 * $Id: stmem.cc,v 1.88 2005/04/01 21:11:28 serassio Exp $
30a4f2a8 4 *
6f6f0853 5 * DEBUG: section 19 Store Memory Primitives
30a4f2a8 6 * AUTHOR: Harvest Derived
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 9 * ----------------------------------------------------------
30a4f2a8 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.
30a4f2a8 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 *
42a503bd 34 * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
019dd986 35 */
ed43818f 36
44a47c6e 37#include "squid.h"
528b2c61 38#include "stmem.h"
39#include "mem_node.h"
40#include "MemObject.h"
b8bad68c 41#include "Generic.h"
528b2c61 42
d06925a4 43char *
44mem_hdr::NodeGet(mem_node * aNode)
45{
46 aNode->uses++;
47 return aNode->data;
48}
49
528b2c61 50int
51mem_hdr::lowestOffset () const
52{
42a503bd 53 const SplayNode<mem_node *> *theStart = nodes.start();
54
55 if (theStart)
56 return theStart->data->nodeBuffer.offset;
62e76326 57
528b2c61 58 return 0;
59}
60
61off_t
62mem_hdr::endOffset () const
63{
64 off_t result = 0;
b8bad68c 65 const SplayNode<mem_node *> *theEnd = nodes.finish();
62e76326 66
42a503bd 67 if (theEnd)
68 result = theEnd->data->dataRange().end;
62e76326 69
528b2c61 70 assert (result == inmem_hi);
62e76326 71
528b2c61 72 return result;
73}
090089c4 74
d89d1fb6 75void
528b2c61 76mem_hdr::freeContent()
77{
42a503bd 78 nodes.destroy(SplayNode<mem_node *>::DefaultFree);
528b2c61 79 inmem_hi = 0;
80}
81
82void
42a503bd 83mem_hdr::unlink(mem_node *aNode)
528b2c61 84{
42a503bd 85 nodes.remove (aNode, NodeCompare);
d06925a4 86
87 if (!aNode->uses)
88 delete aNode;
89 else
90 aNode->uses--;
91
090089c4 92}
93
d89d1fb6 94int
528b2c61 95mem_hdr::freeDataUpto(int target_offset)
96{
97 /* keep the last one to avoid change to other part of code */
62e76326 98
42a503bd 99 SplayNode<mem_node*> const * theStart = nodes.start();
100
b8bad68c 101 while (theStart && theStart != nodes.finish() &&
42a503bd 102 theStart->data->end() <= (size_t) target_offset ) {
103 unlink(theStart->data);
104 theStart = nodes.start();
105 }
62e76326 106
528b2c61 107 assert (lowestOffset () <= target_offset);
62e76326 108
528b2c61 109 return lowestOffset ();
110}
111
62e76326 112int
528b2c61 113mem_hdr::appendToNode(mem_node *aNode, const char *data, int maxLength)
114{
115 size_t result = writeAvailable (aNode, aNode->nodeBuffer.offset + aNode->nodeBuffer.length ,maxLength, data);
116 return result;
117}
118
119size_t
120mem_hdr::writeAvailable(mem_node *aNode, size_t location, size_t amount, char const *source)
121{
122 /* if we attempt to overwrite existing data or leave a gap within a node */
123 assert (location == aNode->nodeBuffer.offset + aNode->nodeBuffer.length);
124 /* And we are not at the end of the node */
125 assert (aNode->canAccept (location));
62e76326 126
528b2c61 127 /* these two can go I think */
e4a67a80 128 assert (location - aNode->nodeBuffer.offset == aNode->nodeBuffer.length);
528b2c61 129 size_t copyLen = XMIN (amount, aNode->space());
130
131 xmemcpy(aNode->nodeBuffer.data + aNode->nodeBuffer.length, source, copyLen);
132
133 if (inmem_hi <= (off_t) location)
62e76326 134 inmem_hi = location + copyLen;
135
528b2c61 136 /* Adjust the ptr and len according to what was deposited in the page */
137 aNode->nodeBuffer.length += copyLen;
62e76326 138
528b2c61 139 mem_node::store_mem_size += copyLen;
62e76326 140
528b2c61 141 return copyLen;
142}
143
144void
145mem_hdr::appendNode (mem_node *aNode)
146{
42a503bd 147 nodes.insert (aNode, NodeCompare);
090089c4 148}
149
e6e5d90d 150void
528b2c61 151mem_hdr::makeAppendSpace()
152{
42a503bd 153 if (!nodes.size()) {
154 appendNode (new mem_node (0));
62e76326 155 return;
090089c4 156 }
62e76326 157
b8bad68c 158 if (!nodes.finish()->data->space())
62e76326 159 appendNode (new mem_node (endOffset()));
160
b8bad68c 161 assert (nodes.finish()->data->space());
528b2c61 162}
163
164void
165mem_hdr::internalAppend(const char *data, int len)
166{
90703668 167 debugs(19, 6, "memInternalAppend: len " << len);
62e76326 168
090089c4 169 while (len > 0) {
62e76326 170 makeAppendSpace();
b8bad68c 171 int copied = appendToNode (nodes.finish()->data, data, len);
62e76326 172 assert (copied);
173
174 len -= copied;
175 data += copied;
090089c4 176 }
090089c4 177}
178
528b2c61 179/* returns a mem_node that contains location..
180 * If no node contains the start, it returns NULL.
181 */
182mem_node *
183mem_hdr::getBlockContainingLocation (size_t location) const
184{
42a503bd 185 mem_node target (location);
186 target.nodeBuffer.length = 1;
187 mem_node *const *result = nodes.find (&target, NodeCompare);
62e76326 188
42a503bd 189 if (result)
190 return *result;
62e76326 191
42a503bd 192 return NULL;
528b2c61 193}
194
195size_t
196mem_hdr::copyAvailable(mem_node *aNode, size_t location, size_t amount, char *target) const
197{
198 if (aNode->nodeBuffer.offset > (off_t) location)
62e76326 199 return 0;
200
528b2c61 201 assert (aNode->nodeBuffer.offset <= (off_t) location);
62e76326 202
528b2c61 203 assert (aNode->end() > location);
62e76326 204
528b2c61 205 size_t copyOffset = location - aNode->nodeBuffer.offset;
62e76326 206
528b2c61 207 size_t copyLen = XMIN (amount, aNode->nodeBuffer.length - copyOffset);
208
209 xmemcpy(target, aNode->nodeBuffer.data + copyOffset, copyLen);
62e76326 210
528b2c61 211 return copyLen;
212}
213
b8bad68c 214void
215mem_hdr::debugDump() const
216{
db7778f1 217 debugs (19, 0, "mem_hdr::debugDump: lowest offset: " << lowestOffset() << " highest offset + 1: " << endOffset() << ".");
b8bad68c 218 std::ostringstream result;
219 PointerPrinter<mem_node *> foo(result, " - ");
220 for_each (getNodes().begin(), getNodes().end(), foo);
db7778f1 221 debugs (19, 0, "mem_hdr::debugDump: Current available data is: " << result.str() << ".");
b8bad68c 222}
223
62e76326 224/* FIXME: how do we deal with sparse results -
528b2c61 225 * where we have (say)
226 * 0-500 and 1000-1500, but are asked for
227 * 0-2000
228 * Partial answer:
229 * we supply 0-500 and stop.
230 */
02be0294 231ssize_t
90703668 232mem_hdr::copy(StoreIOBuffer const &target) const
090089c4 233{
528b2c61 234
90703668 235 debugs(19, 6, "memCopy: " << target.range());
62e76326 236
b8bad68c 237 /* we shouldn't ever ask for absent offsets */
238
42a503bd 239 if (nodes.size() == 0) {
b8bad68c 240 debugs(19, 1, "mem_hdr::copy: No data to read");
241 debugDump();
42a503bd 242 assert (0);
62e76326 243 return 0;
42a503bd 244 }
62e76326 245
528b2c61 246 /* RC: the next assert is nearly useless */
90703668 247 assert(target.length > 0);
528b2c61 248
090089c4 249 /* Seek our way into store */
90703668 250 mem_node *p = getBlockContainingLocation((size_t)target.offset);
62e76326 251
528b2c61 252 if (!p) {
90703668 253 debugs(19, 1, "memCopy: could not find start of " << target.range() <<
e4049756 254 " in memory.");
b8bad68c 255 debugDump();
17d97ab3 256 fatal("Squid has attempted to read data from memory that is not present. This is an indication of of (pre-3.0) code that hasn't been updated to deal with sparse objects in memory. Squid should coredump.allowing to review the cause. Immediately preceeding this message is a dump of the available data in the format [start,end). The [ means from the value, the ) means up to the value. I.e. [1,5) means that there are 4 bytes of data, at offsets 1,2,3,4.\n");
62e76326 257 return 0;
090089c4 258 }
62e76326 259
90703668 260 size_t bytes_to_go = target.length;
261 char *ptr_to_buf = target.data;
262 off_t location = target.offset;
62e76326 263
090089c4 264 /* Start copying begining with this block until
265 * we're satiated */
528b2c61 266
090089c4 267 while (p && bytes_to_go > 0) {
62e76326 268 size_t bytes_to_copy = copyAvailable (p,
269 location, bytes_to_go, ptr_to_buf);
270
271 /* hit a sparse patch */
272
273 if (bytes_to_copy == 0)
90703668 274 return target.length - bytes_to_go;
62e76326 275
276 location += bytes_to_copy;
277
278 ptr_to_buf += bytes_to_copy;
279
280 bytes_to_go -= bytes_to_copy;
281
42a503bd 282 p = getBlockContainingLocation(location);
090089c4 283 }
62e76326 284
90703668 285 return target.length - bytes_to_go;
090089c4 286}
528b2c61 287
288bool
4c50505b 289mem_hdr::hasContigousContentRange(Range<size_t> const & range) const
528b2c61 290{
4c50505b 291 size_t currentStart = range.start;
62e76326 292
528b2c61 293 while (mem_node *curr = getBlockContainingLocation(currentStart)) {
62e76326 294 currentStart = curr->end();
295
4c50505b 296 if (currentStart >= range.end)
62e76326 297 return true;
528b2c61 298 }
62e76326 299
528b2c61 300 return false;
301}
302
303bool
304mem_hdr::unionNotEmpty(StoreIOBuffer const &candidate)
305{
528b2c61 306 assert (candidate.offset >= 0);
42a503bd 307 mem_node target(candidate.offset);
308 target.nodeBuffer.length = candidate.length;
309 return nodes.find (&target, NodeCompare);
528b2c61 310}
311
312mem_node *
313mem_hdr::nodeToRecieve(off_t offset)
314{
315 /* case 1: Nothing in memory */
62e76326 316
42a503bd 317 if (!nodes.size()) {
62e76326 318 appendNode (new mem_node(offset));
42a503bd 319 return nodes.start()->data;
528b2c61 320 }
321
42a503bd 322 mem_node *candidate = NULL;
528b2c61 323 /* case 2: location fits within an extant node */
62e76326 324
42a503bd 325 if (offset > 0) {
326 mem_node search (offset - 1);
327 search.nodeBuffer.length = 1;
328 mem_node *const *leadup = nodes.find (&search, NodeCompare);
329
330 if (leadup)
331 candidate = *leadup;
528b2c61 332 }
333
42a503bd 334 if (candidate && candidate->canAccept(offset))
62e76326 335 return candidate;
528b2c61 336
337 /* candidate can't accept, so we need a new node */
338 candidate = new mem_node(offset);
62e76326 339
528b2c61 340 appendNode (candidate);
62e76326 341
528b2c61 342 /* simpler to write than a indented if */
343 return candidate;
344}
345
346
347bool
348mem_hdr::write (StoreIOBuffer const &writeBuffer)
349{
1d5161bd 350 PROF_start(mem_hdr_write);
90703668 351 debugs(19, 6, "mem_hdr::write: " << writeBuffer.range() << " object end " << endOffset());
528b2c61 352
353 if (unionNotEmpty(writeBuffer)) {
97545f5e 354 debugs(19,0,"mem_hdr::write: writeBuffer: " << writeBuffer.range());
db7778f1 355 debugDump();
356 fatal("Attempt to overwrite already in-memory data. Preceeding this there should be a mem_hdr::write output that lists the attempted write, and the currently present data. Please get a 'backtrace full' from this error - using the generated core, and file a bug report with the squid developers including the last 10 lines of cache.log and the backtrace.\n");
1d5161bd 357 PROF_stop(mem_hdr_write);
62e76326 358 return false;
528b2c61 359 }
360
361 assert (writeBuffer.offset >= 0);
362
363 mem_node *target;
364 off_t currentOffset = writeBuffer.offset;
365 char *currentSource = writeBuffer.data;
366 size_t len = writeBuffer.length;
62e76326 367
528b2c61 368 while (len && (target = nodeToRecieve(currentOffset))) {
62e76326 369 size_t wrote = writeAvailable(target, currentOffset, len, currentSource);
370 assert (wrote);
371 len -= wrote;
372 currentOffset += wrote;
373 currentSource += wrote;
528b2c61 374 }
375
1d5161bd 376 PROF_stop(mem_hdr_write);
528b2c61 377 return true;
378}
4c50505b 379
42a503bd 380mem_hdr::mem_hdr() : inmem_hi(0)
4c50505b 381{}
382
383mem_hdr::~mem_hdr()
384{
385 freeContent();
386}
42a503bd 387
388/* splay of mem nodes:
389 * conditions:
390 * a = b if a.intersection(b).size > 0;
391 * a < b if a < b
392 */
393int
394mem_hdr::NodeCompare(mem_node * const &left, mem_node * const &right)
395{
396 // possibly Range can help us at some point.
397
398 if (left->dataRange().intersection(right->dataRange()).size() > 0)
399 return 0;
400
401 return *left < *right ? -1 : 1;
402}
403
404void
405mem_hdr::dump() const
406{
90703668 407 debugs(20, 1, "mem_hdr: " << (void *)this << " nodes.start() " << nodes.start());
408 debugs(20, 1, "mem_hdr: " << (void *)this << " nodes.finish() " << nodes.finish());
42a503bd 409}
410
411size_t
412mem_hdr::size() const
413{
414 return nodes.size();
415}
416
417mem_node const *
418mem_hdr::start() const
419{
420 const SplayNode<mem_node *> * result = nodes.start();
421
422 if (result)
423 return result->data;
424
425 return NULL;
426}
b8bad68c 427
428const Splay<mem_node *> &
429mem_hdr::getNodes() const
430{
431 return nodes;
432}