MemObject.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 "comm/Connection.h"
13#include "Generic.h"
14#include "globals.h"
15#include "HttpReply.h"
16#include "MemBuf.h"
17#include "MemObject.h"
18#include "SquidConfig.h"
19#include "Store.h"
20#include "StoreClient.h"
21
22#if USE_DELAY_POOLS
23#include "DelayPools.h"
24#endif
25
26/* TODO: make this global or private */
27#if URL_CHECKSUM_DEBUG
28static unsigned int url_checksum(const char *url);
29unsigned int
30url_checksum(const char *url)
31{
32 unsigned int ck;
34 static unsigned char digest[16];
35 SquidMD5Init(&M);
36 SquidMD5Update(&M, (unsigned char *) url, strlen(url));
37 SquidMD5Final(digest, &M);
38 memcpy(&ck, digest, sizeof(ck));
39 return ck;
40}
41
42#endif
43
45
46size_t
48{
49 return Pool().inUseCount();
50}
51
52const char *
54{
55 if (!storeId_.size()) {
56 debugs(20, DBG_IMPORTANT, "ERROR: Squid BUG: Missing MemObject::storeId value");
57 dump();
58 storeId_ = "[unknown_URI]";
59 }
60 return storeId_.termedBuf();
61}
62
63const char *
65{
66 return logUri_.size() ? logUri_.termedBuf() : storeId();
67}
68
69bool
71{
72 return storeId_.size();
73}
74
75void
76MemObject::setUris(char const *aStoreId, char const *aLogUri, const HttpRequestMethod &aMethod)
77{
78 if (hasUris())
79 return;
80
81 storeId_ = aStoreId;
82 debugs(88, 3, this << " storeId: " << storeId_);
83
84 // fast pointer comparison for a common storeCreateEntry(url,url,...) case
85 if (!aLogUri || aLogUri == aStoreId)
86 logUri_.clean(); // use storeId_ by default to minimize copying
87 else
88 logUri_ = aLogUri;
89
90 method = aMethod;
91
92#if URL_CHECKSUM_DEBUG
93 chksum = url_checksum(urlXXX());
94#endif
95}
96
98{
99 debugs(20, 3, "MemObject constructed, this=" << this);
100 ping_reply_callback = nullptr;
101 memset(&start_ping, 0, sizeof(start_ping));
102 reply_ = new HttpReply;
103}
104
106{
107 debugs(20, 3, "MemObject destructed, this=" << this);
108
109#if URL_CHECKSUM_DEBUG
110 checkUrlChecksum();
111#endif
112
113 assert(xitTable.index < 0);
114 assert(memCache.index < 0);
115 assert(swapout.sio == nullptr);
116
118}
119
120HttpReply &
122{
124 return *reply_;
125}
126
127void
129{
130 assert(r);
131 reply_ = r;
132 updatedReply_ = nullptr;
133}
134
135void
137{
138 debugs(19, 6, "memWrite: offset " << writeBuffer.offset << " len " << writeBuffer.length);
139
140 /* We don't separate out mime headers yet, so ensure that the first
141 * write is at offset 0 - where they start
142 */
143 assert (data_hdr.endOffset() || writeBuffer.offset == 0);
144
145 assert (data_hdr.write (writeBuffer));
146}
147
148void
150{
151 data_hdr.dump();
152
153 debugs(20, DBG_IMPORTANT, "MemObject->start_ping: " << start_ping);
154 debugs(20, DBG_IMPORTANT, "MemObject->inmem_hi: " << data_hdr.endOffset());
155 debugs(20, DBG_IMPORTANT, "MemObject->inmem_lo: " << inmem_lo);
156 debugs(20, DBG_IMPORTANT, "MemObject->nclients: " << nclients);
157 debugs(20, DBG_IMPORTANT, "MemObject->reply: " << reply_);
158 debugs(20, DBG_IMPORTANT, "MemObject->updatedReply: " << updatedReply_);
159 debugs(20, DBG_IMPORTANT, "MemObject->appliedUpdates: " << appliedUpdates);
160 debugs(20, DBG_IMPORTANT, "MemObject->request: " << request);
161 debugs(20, DBG_IMPORTANT, "MemObject->logUri: " << logUri_);
162 debugs(20, DBG_IMPORTANT, "MemObject->storeId: " << storeId_);
163}
164
165struct LowestMemReader : public unary_function<store_client, void> {
166 LowestMemReader(int64_t seed):current(seed) {}
167
168 void operator() (store_client const &x) {
169 if (x.getType() == STORE_MEM_CLIENT)
171 }
172
173 int64_t current;
174};
175
176struct StoreClientStats : public unary_function<store_client, void> {
177 StoreClientStats(MemBuf *anEntry):where(anEntry),index(0) {}
178
179 void operator()(store_client const &x) {
181 ++index;
182 }
183
185 size_t index;
186};
187
188void
190{
191 mb->appendf("\t" SQUIDSBUFPH " %s\n", SQUIDSBUFPRINT(method.image()), logUri());
192 if (!vary_headers.isEmpty())
193 mb->appendf("\tvary_headers: " SQUIDSBUFPH "\n", SQUIDSBUFPRINT(vary_headers));
194 mb->appendf("\tinmem_lo: %" PRId64 "\n", inmem_lo);
195 mb->appendf("\tinmem_hi: %" PRId64 "\n", data_hdr.endOffset());
196 mb->appendf("\tswapout: %" PRId64 " bytes queued\n", swapout.queue_offset);
197
198 if (swapout.sio.getRaw())
199 mb->appendf("\tswapout: %" PRId64 " bytes written\n", (int64_t) swapout.sio->offset());
200
201 if (xitTable.index >= 0)
202 mb->appendf("\ttransient index: %d state: %d\n", xitTable.index, xitTable.io);
203 if (memCache.index >= 0)
204 mb->appendf("\tmem-cache index: %d state: %d offset: %" PRId64 "\n", memCache.index, memCache.io, memCache.offset);
205 if (object_sz >= 0)
206 mb->appendf("\tobject_sz: %" PRId64 "\n", object_sz);
207
208 StoreClientStats statsVisitor(mb);
209
210 for_each<StoreClientStats>(clients, statsVisitor);
211}
212
213int64_t
215{
216 return data_hdr.endOffset();
217}
218
219void
221{
222 const int hdr_sz = endOffset();
223 assert(hdr_sz >= 0);
224 assert(reply_);
225 reply_->hdr_sz = hdr_sz;
226}
227
228int64_t
230{
231 if (object_sz < 0)
232 return endOffset();
233
234 return object_sz;
235}
236
237int64_t
239{
240 if (object_sz >= 0) {
241 debugs(20, 7, object_sz << " frozen by complete()");
242 return object_sz;
243 }
244
245 const auto hdr_sz = baseReply().hdr_sz;
246
247 // Cannot predict future length using an empty/unset or HTTP/0 reply.
248 // For any HTTP/1 reply, hdr_sz is positive -- status-line cannot be empty.
249 if (hdr_sz <= 0)
250 return -1;
251
252 const auto clen = baseReply().bodySize(method);
253 if (clen < 0) {
254 debugs(20, 7, "unknown; hdr: " << hdr_sz);
255 return -1;
256 }
257
258 const auto messageSize = clen + hdr_sz;
259 debugs(20, 7, messageSize << " hdr: " << hdr_sz << " clen: " << clen);
260 return messageSize;
261}
262
263void
265{
266 assert(swapout.sio == nullptr);
268 inmem_lo = 0;
269 /* Should we check for clients? */
270 assert(reply_);
271 reply_->reset();
272 updatedReply_ = nullptr;
273 appliedUpdates = false;
274}
275
276int64_t
278{
279 LowestMemReader lowest (endOffset() + 1);
280
281 for_each <LowestMemReader>(clients, lowest);
282
283 return lowest.current;
284}
285
286/* XXX: This is wrong. It breaks *badly* on range combining */
287bool
289{
290 const auto savedHttpHeaders = baseReply().hdr_sz;
291 const bool canRead = endOffset() - savedHttpHeaders <
293
294 if (!canRead) {
295 debugs(19, 5, "no: " << endOffset() << '-' << savedHttpHeaders <<
296 " < " << lowestMemReaderOffset() << '+' << Config.readAheadGap);
297 }
298
299 return canRead;
300}
301
302void
304{
305 ++nclients;
306 dlinkAdd(aClient, &aClient->node, &clients);
307}
308
309#if URL_CHECKSUM_DEBUG
310void
311MemObject::checkUrlChecksum () const
312{
313 assert(chksum == url_checksum(urlXXX()));
314}
315
316#endif
317
318/*
319 * How much of the object data is on the disk?
320 */
321int64_t
323{
324 /*
325 * NOTE: storeOffset() represents the disk file size,
326 * not the amount of object data on disk.
327 *
328 * If we don't have at least 'swap_hdr_sz' bytes
329 * then none of the object data is on disk.
330 *
331 * This should still be safe if swap_hdr_sz == 0,
332 * meaning we haven't even opened the swapout file
333 * yet.
334 */
335
336 if (swapout.sio.getRaw() == nullptr)
337 return 0;
338
339 int64_t nwritten = swapout.sio->offset();
340
341 if (nwritten <= (int64_t)swap_hdr_sz)
342 return 0;
343
344 return (nwritten - swap_hdr_sz);
345}
346
347int64_t
349{
350 /*
351 * Careful. lowest_offset can be greater than endOffset(), such
352 * as in the case of a range request.
353 */
354 int64_t lowest_offset = lowestMemReaderOffset();
355
356 // XXX: Remove the last (Config.onoff.memory_cache_first-based) condition
357 // and update keepForLocalMemoryCache() accordingly. The caller wants to
358 // remove all local memory that is safe to remove. Honoring caching
359 // preferences is its responsibility. Our responsibility is safety. The
360 // situation was different when ff4b33f added that condition -- there was no
361 // keepInLocalMemory/keepForLocalMemoryCache() call guard back then.
362 if (endOffset() < lowest_offset ||
365 return lowest_offset;
366
367 return inmem_lo;
368}
369
370void
372{
373 int64_t new_mem_lo = policyLowestOffsetToKeep(1);
374 /*
375 * We should only free up to what we know has been written
376 * to disk, not what has been queued for writing. Otherwise
377 * there will be a chunk of the data which is not in memory
378 * and is not yet on disk.
379 * The -1 makes sure the page isn't freed until storeSwapOut has
380 * walked to the next page.
381 */
382 int64_t on_disk;
383
384 if ((on_disk = objectBytesOnDisk()) - 1 < new_mem_lo)
385 new_mem_lo = on_disk - 1;
386
387 if (new_mem_lo == -1)
388 new_mem_lo = 0; /* the above might become -1 */
389
390 data_hdr.freeDataUpto(new_mem_lo);
391
392 inmem_lo = new_mem_lo;
393}
394
395void
397{
398 if (const int64_t new_mem_lo = policyLowestOffsetToKeep(false)) {
399 assert (new_mem_lo > 0);
400 data_hdr.freeDataUpto(new_mem_lo);
401 inmem_lo = new_mem_lo;
402 } // else we should not trim anything at this time
403}
404
405bool
407{
409 /* XXX : make this higher level */
410 debugs (19, result ? 4 :3, "MemObject::isContiguous: Returning " << (result ? "true" : "false"));
411 return result;
412}
413
414int
415MemObject::mostBytesWanted(int max, bool ignoreDelayPools) const
416{
417#if USE_DELAY_POOLS
418 if (!ignoreDelayPools) {
419 /* identify delay id with largest allowance */
420 DelayId largestAllowance = mostBytesAllowed ();
421 return largestAllowance.bytesWanted(0, max);
422 }
423#else
424 (void)ignoreDelayPools;
425#endif
426
427 return max;
428}
429
430void
431MemObject::setNoDelay(bool const newValue)
432{
433#if USE_DELAY_POOLS
434
435 for (dlink_node *node = clients.head; node; node = node->next) {
436 store_client *sc = (store_client *) node->data;
437 sc->delayId.setNoDelay(newValue);
438 }
439#else
440 (void)newValue;
441#endif
442}
443
444void
446{
447#if USE_DELAY_POOLS
449 if (DelayId mostAllowedId = mostBytesAllowed()) {
450 mostAllowedId.delayRead(aRead);
451 return;
452 }
453 }
454#endif
455 deferredReads.delay(aRead);
456}
457
458void
460{
462}
463
464#if USE_DELAY_POOLS
467{
468 int j;
469 int jmax = -1;
470 DelayId result;
471
472 for (dlink_node *node = clients.head; node; node = node->next) {
473 store_client *sc = (store_client *) node->data;
474
475 j = sc->bytesWanted();
476
477 if (j > jmax) {
478 jmax = j;
479 result = sc->delayId;
480 }
481 }
482
483 return result;
484}
485
486#endif
487
488int64_t
490{
491 return endOffset() - swapout.queue_offset;
492}
493
RemovalPolicy * mem_policy
Definition: MemObject.cc:44
#define SQUIDSBUFPH
Definition: SBuf.h:31
#define SQUIDSBUFPRINT(s)
Definition: SBuf.h:32
class SquidConfig Config
Definition: SquidConfig.cc:12
#define assert(EX)
Definition: assert.h:17
int bytesWanted(int min, int max) const
Definition: DelayId.cc:129
void schedule()
schedules and forgets all async calls previously stored by delay()
void delay(const AsyncCallPointer &)
stores the given call to schedule it at schedule() or destruction time
int64_t bodySize(const HttpRequestMethod &) const
Definition: HttpReply.cc:377
void reset() override
Definition: HttpReply.cc:59
const SBuf & image() const
int hdr_sz
Definition: Message.h:81
Definition: MemBuf.h:24
int32_t index
entry position inside the memory cache
Definition: MemObject.h:205
Io io
current I/O state
Definition: MemObject.h:208
int64_t offset
bytes written/read to/from the memory cache so far
Definition: MemObject.h:206
int64_t queue_offset
number of bytes sent to SwapDir for writing
Definition: MemObject.h:161
StoreIOState::Pointer sio
Definition: MemObject.h:162
int32_t index
entry position inside the in-transit table
Definition: MemObject.h:196
Io io
current I/O state
Definition: MemObject.h:197
void replaceBaseReply(const HttpReplyPointer &r)
Definition: MemObject.cc:128
String storeId_
StoreId for our entry (usually request URI)
Definition: MemObject.h:237
bool appliedUpdates
Definition: MemObject.h:90
int64_t lowestMemReaderOffset() const
Definition: MemObject.cc:277
DelayId mostBytesAllowed() const
Definition: MemObject.cc:466
IRCB * ping_reply_callback
Definition: MemObject.h:215
int64_t size() const
Definition: MemObject.cc:229
const char * urlXXX() const
Definition: MemObject.h:138
int nclients
Definition: MemObject.h:156
static size_t inUseCount()
Definition: MemObject.cc:47
SwapOut swapout
Definition: MemObject.h:169
HttpRequestMethod method
Definition: MemObject.h:147
int64_t availableForSwapOut() const
buffered bytes we have not swapped out yet
Definition: MemObject.cc:489
HttpRequestPointer request
Definition: MemObject.h:212
void trimSwappable()
Definition: MemObject.cc:371
int64_t policyLowestOffsetToKeep(bool swap) const
Definition: MemObject.cc:348
int64_t objectBytesOnDisk() const
Definition: MemObject.cc:322
HttpReplyPointer reply_
Definition: MemObject.h:234
void setNoDelay(bool const newValue)
Definition: MemObject.cc:431
void reset()
Definition: MemObject.cc:264
void trimUnSwappable()
Definition: MemObject.cc:396
void addClient(store_client *)
Definition: MemObject.cc:303
XitTable xitTable
current [shared] memory caching state for the entry
Definition: MemObject.h:199
int64_t expectedReplySize() const
Definition: MemObject.cc:238
SBuf vary_headers
Definition: MemObject.h:228
dlink_list clients
Definition: MemObject.h:150
String logUri_
URI used for logging (usually request URI)
Definition: MemObject.h:238
mem_hdr data_hdr
Definition: MemObject.h:148
void dump() const
Definition: MemObject.cc:149
struct timeval start_ping
Definition: MemObject.h:214
void markEndOfReplyHeaders()
sets baseReply().hdr_sz (i.e. written reply headers size) to endOffset()
Definition: MemObject.cc:220
void delayRead(const AsyncCallPointer &)
Definition: MemObject.cc:445
void write(const StoreIOBuffer &buf)
Definition: MemObject.cc:136
int64_t inmem_lo
Definition: MemObject.h:149
size_t swap_hdr_sz
Definition: MemObject.h:223
int mostBytesWanted(int max, bool ignoreDelayPools) const
Definition: MemObject.cc:415
MemCache memCache
current [shared] memory caching state for the entry
Definition: MemObject.h:210
int64_t endOffset() const
Definition: MemObject.cc:214
void setUris(char const *aStoreId, char const *aLogUri, const HttpRequestMethod &aMethod)
Definition: MemObject.cc:76
const char * storeId() const
Definition: MemObject.cc:53
const HttpReply & baseReply() const
Definition: MemObject.h:60
HttpReply & adjustableBaseReply()
Definition: MemObject.cc:121
bool hasUris() const
whether setUris() has been called
Definition: MemObject.cc:70
const char * logUri() const
client request URI used for logging; storeId() by default
Definition: MemObject.cc:64
DelayedAsyncCalls deferredReads
Definition: MemObject.h:240
HttpReplyPointer updatedReply_
Definition: MemObject.h:235
void kickReads()
Definition: MemObject.cc:459
bool readAheadPolicyCanRead() const
Definition: MemObject.cc:288
bool isContiguous() const
Definition: MemObject.cc:406
void stat(MemBuf *mb) const
Definition: MemObject.cc:189
int64_t object_sz
Definition: MemObject.h:222
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
Definition: Range.h:19
C * getRaw() const
Definition: RefCount.h:89
bool isEmpty() const
Definition: SBuf.h:431
int64_t readAheadGap
Definition: SquidConfig.h:98
int memory_cache_first
Definition: SquidConfig.h:335
struct SquidConfig::@106 onoff
size_t maxInMemObjSize
Definition: SquidConfig.h:268
struct SquidConfig::@104 Store
int64_t offset
Definition: StoreIOBuffer.h:58
off_t offset() const
Definition: StoreIOState.h:48
void clean()
Definition: String.cc:103
char const * termedBuf() const
Definition: SquidString.h:92
size_type size() const
Definition: SquidString.h:73
void dump() const
Definition: stmem.cc:361
void freeContent()
Definition: stmem.cc:59
int64_t freeDataUpto(int64_t)
Definition: stmem.cc:81
bool write(StoreIOBuffer const &)
Definition: stmem.cc:305
int64_t endOffset() const
Definition: stmem.cc:45
bool hasContigousContentRange(Range< int64_t > const &range) const
Definition: stmem.cc:247
int getType() const
Definition: store_client.cc:90
dlink_node node
Definition: StoreClient.h:142
int64_t readOffset() const
Definition: StoreClient.h:85
void dumpStats(MemBuf *output, int clientNumber) const
A const & max(A const &lhs, A const &rhs)
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
@ STORE_MEM_CLIENT
Definition: enums.h:73
SQUIDCEXTERN void SquidMD5Init(struct SquidMD5Context *context)
Definition: md5.c:73
SQUIDCEXTERN void SquidMD5Update(struct SquidMD5Context *context, const void *buf, unsigned len)
Definition: md5.c:89
SQUIDCEXTERN void SquidMD5Final(uint8_t digest[16], struct SquidMD5Context *context)
static int sc[16]
Definition: smbdes.c:121
LowestMemReader(int64_t seed)
Definition: MemObject.cc:166
int64_t current
Definition: MemObject.cc:173
void operator()(store_client const &x)
Definition: MemObject.cc:168
MemBuf * where
Definition: MemObject.cc:184
void operator()(store_client const &x)
Definition: MemObject.cc:179
StoreClientStats(MemBuf *anEntry)
Definition: MemObject.cc:177
Definition: parse.c:104
struct node * next
Definition: parse.c:105
#define PRId64
Definition: types.h:104

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors