stmem.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9/* DEBUG: section 19 Store Memory Primitives */
10
11#include "squid.h"
12#include "Generic.h"
13#include "HttpReply.h"
14#include "mem_node.h"
15#include "MemObject.h"
16#include "stmem.h"
17
18/*
19 * NodeGet() is called to get the data buffer to pass to storeIOWrite().
20 * By setting the write_pending flag here we are assuming that there
21 * will be no other users of NodeGet(). The storeIOWrite() callback
22 * is memNodeWriteComplete(), which, for whatever reason, lives in
23 * mem_node.cc.
24 */
25char *
27{
28 assert(!aNode->write_pending);
29 aNode->write_pending = true;
30 return aNode->data;
31}
32
33int64_t
35{
36 const SplayNode<mem_node *> *theStart = nodes.start();
37
38 if (theStart)
39 return theStart->data->nodeBuffer.offset;
40
41 return 0;
42}
43
44int64_t
46{
47 int64_t result = 0;
48 const SplayNode<mem_node *> *theEnd = nodes.finish();
49
50 if (theEnd)
51 result = theEnd->data->dataRange().end;
52
53 assert (result == inmem_hi);
54
55 return result;
56}
57
58void
60{
61 nodes.destroy();
62 inmem_hi = 0;
63 debugs(19, 9, this << " hi: " << inmem_hi);
64}
65
66bool
68{
69 if (aNode->write_pending) {
70 debugs(0, DBG_CRITICAL, "ERROR: cannot unlink mem_node " << aNode << " while write_pending");
71 return false;
72 }
73
74 debugs(19, 8, this << " removing " << aNode);
75 nodes.remove (aNode, NodeCompare);
76 delete aNode;
77 return true;
78}
79
80int64_t
81mem_hdr::freeDataUpto(int64_t target_offset)
82{
83 debugs(19, 8, this << " up to " << target_offset);
84 /* keep the last one to avoid change to other part of code */
85 SplayNode<mem_node*> const * theStart;
86
87 while ((theStart = nodes.start())) {
88 if (theStart == nodes.finish())
89 break;
90
91 if (theStart->data->end() > target_offset )
92 break;
93
94 if (!unlink(theStart->data))
95 break;
96 }
97
98 assert (lowestOffset () <= target_offset);
99
100 return lowestOffset ();
101}
102
103size_t
104mem_hdr::writeAvailable(mem_node *aNode, int64_t location, size_t amount, char const *source)
105{
106 /* if we attempt to overwrite existing data or leave a gap within a node */
107 assert (location == aNode->nodeBuffer.offset + (int64_t)aNode->nodeBuffer.length);
108 /* And we are not at the end of the node */
109 assert (aNode->canAccept (location));
110
111 /* these two can go I think */
112 assert (location - aNode->nodeBuffer.offset == (int64_t)aNode->nodeBuffer.length);
113 size_t copyLen = min(amount, aNode->space());
114
115 memcpy(aNode->nodeBuffer.data + aNode->nodeBuffer.length, source, copyLen);
116
117 debugs(19, 9, this << " hi: " << inmem_hi);
118 if (inmem_hi <= location)
119 inmem_hi = location + copyLen;
120
121 /* Adjust the ptr and len according to what was deposited in the page */
122 aNode->nodeBuffer.length += copyLen;
123
124 debugs(19, 9, this << " hi: " << inmem_hi);
125 debugs(19, 9, this << " hi: " << endOffset());
126 return copyLen;
127}
128
129void
131{
132 nodes.insert (aNode, NodeCompare);
133}
134
135/* returns a mem_node that contains location..
136 * If no node contains the start, it returns NULL.
137 */
138mem_node *
140{
141 // Optimize: do not create a whole mem_node just to store location
142 mem_node target (location);
143 target.nodeBuffer.length = 1;
144 mem_node *const *result = nodes.find (&target, NodeCompare);
145
146 if (result)
147 return *result;
148
149 return nullptr;
150}
151
152size_t
153mem_hdr::copyAvailable(mem_node *aNode, int64_t location, size_t amount, char *target) const
154{
155 if (aNode->nodeBuffer.offset > location)
156 return 0;
157
158 assert (aNode->nodeBuffer.offset <= location);
159
160 assert (aNode->end() > location);
161
162 size_t copyOffset = location - aNode->nodeBuffer.offset;
163
164 size_t copyLen = min(amount, aNode->nodeBuffer.length - copyOffset);
165
166 memcpy(target, aNode->nodeBuffer.data + copyOffset, copyLen);
167
168 return copyLen;
169}
170
171void
173{
174 debugs (19, 0, "mem_hdr::debugDump: lowest offset: " << lowestOffset() << " highest offset + 1: " << endOffset() << ".");
175 std::ostringstream result;
176 PointerPrinter<mem_node *> foo(result, " - ");
177 getNodes().visit(foo);
178 debugs (19, 0, "mem_hdr::debugDump: Current available data is: " << result.str() << ".");
179}
180
181/* XXX: how do we deal with sparse results -
182 * where we have (say)
183 * 0-500 and 1000-1500, but are asked for
184 * 0-2000
185 * Partial answer:
186 * we supply 0-500 and stop.
187 */
188ssize_t
189mem_hdr::copy(StoreIOBuffer const &target) const
190{
191
192 assert(target.range().end > target.range().start);
193 debugs(19, 6, "memCopy: " << this << " " << target.range());
194
195 /* we shouldn't ever ask for absent offsets */
196
197 if (nodes.size() == 0) {
198 debugs(19, DBG_IMPORTANT, "mem_hdr::copy: No data to read");
199 debugDump();
200 assert (0);
201 return 0;
202 }
203
204 /* RC: the next assert is nearly useless */
205 assert(target.length > 0);
206
207 /* Seek our way into store */
209
210 if (!p) {
211 debugs(19, DBG_IMPORTANT, "ERROR: memCopy: could not find start of " << target.range() <<
212 " in memory.");
213 debugDump();
214 fatal_dump("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 preceding 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");
215 return 0;
216 }
217
218 size_t bytes_to_go = target.length;
219 char *ptr_to_buf = target.data;
220 int64_t location = target.offset;
221
222 /* Start copying beginning with this block until
223 * we're satiated */
224
225 while (p && bytes_to_go > 0) {
226 size_t bytes_to_copy = copyAvailable (p,
227 location, bytes_to_go, ptr_to_buf);
228
229 /* hit a sparse patch */
230
231 if (bytes_to_copy == 0)
232 return target.length - bytes_to_go;
233
234 location += bytes_to_copy;
235
236 ptr_to_buf += bytes_to_copy;
237
238 bytes_to_go -= bytes_to_copy;
239
240 p = getBlockContainingLocation(location);
241 }
242
243 return target.length - bytes_to_go;
244}
245
246bool
248{
249 int64_t currentStart = range.start;
250
251 while (mem_node *curr = getBlockContainingLocation(currentStart)) {
252 currentStart = curr->end();
253
254 if (currentStart >= range.end)
255 return true;
256 }
257
258 return !range.size(); // empty range is contiguous
259}
260
261bool
263{
264 assert (candidate.offset >= 0);
265 mem_node target(candidate.offset);
266 target.nodeBuffer.length = candidate.length;
267 return nodes.find (&target, NodeCompare);
268}
269
270mem_node *
272{
273 /* case 1: Nothing in memory */
274
275 if (!nodes.size()) {
276 appendNode (new mem_node(offset));
277 return nodes.start()->data;
278 }
279
280 mem_node *candidate = nullptr;
281 /* case 2: location fits within an extant node */
282
283 if (offset > 0) {
284 mem_node search (offset - 1);
285 search.nodeBuffer.length = 1;
286 mem_node *const *leadup = nodes.find (&search, NodeCompare);
287
288 if (leadup)
289 candidate = *leadup;
290 }
291
292 if (candidate && candidate->canAccept(offset))
293 return candidate;
294
295 /* candidate can't accept, so we need a new node */
296 candidate = new mem_node(offset);
297
298 appendNode (candidate);
299
300 /* simpler to write than a indented if */
301 return candidate;
302}
303
304bool
305mem_hdr::write (StoreIOBuffer const &writeBuffer)
306{
307 debugs(19, 6, "mem_hdr::write: " << this << " " << writeBuffer.range() << " object end " << endOffset());
308
309 if (unionNotEmpty(writeBuffer)) {
310 debugs(19, DBG_CRITICAL, "mem_hdr::write: writeBuffer: " << writeBuffer.range());
311 debugDump();
312 fatal_dump("Attempt to overwrite already in-memory data. Preceding 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");
313 return false;
314 }
315
316 assert (writeBuffer.offset >= 0);
317
318 mem_node *target;
319 int64_t currentOffset = writeBuffer.offset;
320 char *currentSource = writeBuffer.data;
321 size_t len = writeBuffer.length;
322
323 while (len && (target = nodeToRecieve(currentOffset))) {
324 size_t wrote = writeAvailable(target, currentOffset, len, currentSource);
325 assert (wrote);
326 len -= wrote;
327 currentOffset += wrote;
328 currentSource += wrote;
329 }
330
331 return true;
332}
333
334mem_hdr::mem_hdr() : inmem_hi(0)
335{
336 debugs(19, 9, this << " hi: " << inmem_hi);
337}
338
340{
341 freeContent();
342}
343
344/* splay of mem nodes:
345 * conditions:
346 * a = b if a.intersection(b).size > 0;
347 * a < b if a < b
348 */
349int
350mem_hdr::NodeCompare(mem_node * const &left, mem_node * const &right)
351{
352 // possibly Range can help us at some point.
353
354 if (left->dataRange().intersection(right->dataRange()).size() > 0)
355 return 0;
356
357 return *left < *right ? -1 : 1;
358}
359
360void
362{
363 debugs(20, DBG_IMPORTANT, "mem_hdr: " << (void *)this << " nodes.start() " << nodes.start());
364 debugs(20, DBG_IMPORTANT, "mem_hdr: " << (void *)this << " nodes.finish() " << nodes.finish());
365}
366
367size_t
369{
370 return nodes.size();
371}
372
373const Splay<mem_node *> &
375{
376 return nodes;
377}
378
#define assert(EX)
Definition: assert.h:17
Definition: Range.h:19
C start
Definition: Range.h:24
S size() const
Definition: Range.h:61
C end
Definition: Range.h:25
Value data
Definition: splay.h:25
Value const * find(FindValue const &, int(*compare)(FindValue const &a, Value const &b)) const
void remove(Value const &, SPLAYCMP *compare)
Definition: splay.h:332
SplayNode< V > const * start() const
Definition: splay.h:345
void insert(Value const &, SPLAYCMP *compare)
Definition: splay.h:318
SplayNode< V > const * finish() const
Definition: splay.h:355
size_t size() const
Definition: splay.h:377
void visit(ValueVisitor &) const
left-to-right visit of all stored Values
void destroy(SPLAYFREE *=DefaultFree)
Definition: splay.h:365
int64_t offset
Definition: StoreIOBuffer.h:58
Range< int64_t > range() const
Definition: StoreIOBuffer.h:42
int64_t inmem_hi
Definition: stmem.h:52
const Splay< mem_node * > & getNodes() const
Definition: stmem.cc:374
bool unlink(mem_node *aNode)
Definition: stmem.cc:67
void dump() const
Definition: stmem.cc:361
ssize_t copy(StoreIOBuffer const &) const
Definition: stmem.cc:189
void freeContent()
Definition: stmem.cc:59
bool unionNotEmpty(StoreIOBuffer const &)
Definition: stmem.cc:262
int64_t freeDataUpto(int64_t)
Definition: stmem.cc:81
mem_hdr()
Definition: stmem.cc:334
size_t writeAvailable(mem_node *aNode, int64_t location, size_t amount, char const *source)
Definition: stmem.cc:104
mem_node * nodeToRecieve(int64_t offset)
Definition: stmem.cc:271
size_t copyAvailable(mem_node *aNode, int64_t location, size_t amount, char *target) const
Definition: stmem.cc:153
static Splay< mem_node * >::SPLAYCMP NodeCompare
Definition: stmem.h:42
bool write(StoreIOBuffer const &)
Definition: stmem.cc:305
char * NodeGet(mem_node *aNode)
Definition: stmem.cc:26
void debugDump() const
Definition: stmem.cc:172
size_t size() const
Definition: stmem.cc:368
~mem_hdr()
Definition: stmem.cc:339
Splay< mem_node * > nodes
Definition: stmem.h:53
int64_t endOffset() const
Definition: stmem.cc:45
void appendNode(mem_node *aNode)
Definition: stmem.cc:130
bool hasContigousContentRange(Range< int64_t > const &range) const
Definition: stmem.cc:247
mem_node * getBlockContainingLocation(int64_t location) const
Definition: stmem.cc:139
int64_t lowestOffset() const
Definition: stmem.cc:34
StoreIOBuffer nodeBuffer
Definition: mem_node.h:35
Range< int64_t > dataRange() const
Definition: mem_node.cc:80
size_t space() const
Definition: mem_node.cc:86
char data[SM_PAGE_SIZE]
Definition: mem_node.h:37
bool canAccept(int64_t const &location) const
Definition: mem_node.cc:102
int64_t end() const
Definition: mem_node.cc:74
bool write_pending
Definition: mem_node.h:38
A const & min(A const &lhs, A const &rhs)
#define DBG_IMPORTANT
Definition: Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:194
#define DBG_CRITICAL
Definition: Stream.h:37
void fatal_dump(const char *message)
Definition: fatal.cc:78

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors