Transients.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2022 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 20 Storage Manager */
10
11#include "squid.h"
13#include "CollapsedForwarding.h"
14#include "HttpReply.h"
15#include "ipc/mem/Page.h"
16#include "ipc/mem/Pages.h"
17#include "MemObject.h"
18#include "mime_header.h"
19#include "SquidConfig.h"
20#include "SquidMath.h"
21#include "StoreStats.h"
22#include "tools.h"
23#include "Transients.h"
24
25#include <limits>
26
28static const SBuf MapLabel("transients_map");
29
30Transients::Transients(): map(nullptr), locals(nullptr)
31{
32}
33
35{
36 delete map;
37 delete locals;
38}
39
40void
42{
43 assert(Enabled());
44 const int64_t entryLimit = EntryLimit();
45 assert(entryLimit > 0);
46
47 Must(!map);
49 map->cleaner = this;
50 map->disableHitValidation(); // Transients lacks slices to validate
51
52 locals = new Locals(entryLimit, nullptr);
53}
54
55void
57{
58#if TRANSIENT_STATS_SUPPORTED
59 const size_t pageSize = Ipc::Mem::PageSize();
60
61 stats.mem.shared = true;
62 stats.mem.capacity =
64 stats.mem.size =
66 stats.mem.count = currentCount();
67#else
68 (void)stats;
69#endif
70}
71
72void
74{
75 storeAppendPrintf(&e, "\n\nTransient Objects\n");
76
77 storeAppendPrintf(&e, "Maximum Size: %.0f KB\n", maxSize()/1024.0);
78 storeAppendPrintf(&e, "Current Size: %.2f KB %.2f%%\n",
79 currentSize() / 1024.0,
81
82 if (map) {
83 const int limit = map->entryLimit();
84 storeAppendPrintf(&e, "Maximum entries: %9d\n", limit);
85 if (limit > 0) {
86 storeAppendPrintf(&e, "Current entries: %" PRId64 " %.2f%%\n",
87 currentCount(), (100.0 * currentCount() / limit));
88 }
89 }
90}
91
92void
94{
95 // no lazy garbage collection needed
96}
97
98uint64_t
100{
101 return 0; // XXX: irrelevant, but Store parent forces us to implement this
102}
103
104uint64_t
106{
107 // Squid currently does not limit the total size of all transient objects
109}
110
111uint64_t
113{
114 // TODO: we do not get enough information to calculate this
115 // StoreEntry should update associated stores when its size changes
116 return 0;
117}
118
119uint64_t
121{
122 return map ? map->entryCount() : 0;
123}
124
125int64_t
127{
128 // Squid currently does not limit the size of a transient object
130}
131
132void
134{
135 // no replacement policy (but the cache(s) storing the entry may have one)
136}
137
138bool
140{
141 // no need to keep e in the global store_table for us; we have our own map
142 return false;
143}
144
147{
148 if (!map)
149 return nullptr;
150
151 sfileno index;
152 const Ipc::StoreMapAnchor *anchor = map->openForReading(key, index);
153 if (!anchor)
154 return nullptr;
155
156 // If we already have a local entry, the store_table should have found it.
157 // Since it did not, the local entry key must have changed from public to
158 // private. We still need to keep the private entry around for syncing as
159 // its clients depend on it, but we should not allow new clients to join.
160 if (StoreEntry *oldE = locals->at(index)) {
161 debugs(20, 3, "not joining private " << *oldE);
162 assert(EBIT_TEST(oldE->flags, KEY_PRIVATE));
164 return nullptr;
165 }
166
167 StoreEntry *e = new StoreEntry();
168 e->createMemObject();
169 anchorEntry(*e, index, *anchor);
170
171 // keep read lock to receive updates from others
172 return e;
173}
174
177{
178 if (!map)
179 return nullptr;
180
181 if (StoreEntry *oldE = locals->at(index)) {
182 debugs(20, 5, "found " << *oldE << " at " << index << " in " << MapLabel);
183 assert(oldE->mem_obj && oldE->mem_obj->xitTable.index == index);
184 return oldE;
185 }
186
187 debugs(20, 3, "no entry at " << index << " in " << MapLabel);
188 return nullptr;
189}
190
191void
193{
194 if (!e->hasTransients()) {
195 addEntry(e, key, direction);
196 assert(e->hasTransients());
197 }
198
199 const auto index = e->mem_obj->xitTable.index;
200 if (const auto old = locals->at(index)) {
201 assert(old == e);
202 } else {
203 // We do not lock e because we do not want to prevent its destruction;
204 // e is tied to us via mem_obj so we will know when it is destructed.
205 locals->at(index) = e;
206 }
207}
208
210void
212{
213 assert(e);
214 assert(e->mem_obj);
215 assert(!e->hasTransients());
216
217 Must(map); // configured to track transients
218
219 if (direction == Store::ioWriting)
220 return addWriterEntry(*e, key);
221
222 assert(direction == Store::ioReading);
223 addReaderEntry(*e, key);
224}
225
227void
229{
230 sfileno index = 0;
231 const auto anchor = map->openForWriting(key, index);
232 if (!anchor)
233 throw TextException("writer collision", Here());
234
235 // set ASAP in hope to unlock the slot if something throws
236 // and to provide index to such methods as hasWriter()
237 auto &xitTable = e.mem_obj->xitTable;
238 xitTable.index = index;
239 xitTable.io = Store::ioWriting;
240
241 anchor->set(e, key);
242 // allow reading and receive remote DELETE events, but do not switch to
243 // the reading lock because transientReaders() callers want true readers
244 map->startAppending(index);
245}
246
249void
251{
252 sfileno index = 0;
253 const auto anchor = map->openOrCreateForReading(key, index, e);
254 if (!anchor)
255 throw TextException("reader collision", Here());
256
257 anchorEntry(e, index, *anchor);
258 // keep the entry locked (for reading) to receive remote DELETE events
259}
260
262void
264{
265 // set ASAP in hope to unlock the slot if something throws
266 // and to provide index to such methods as hasWriter()
267 auto &xitTable = e.mem_obj->xitTable;
268 xitTable.index = index;
269 xitTable.io = Store::ioReading;
270
271 anchor.exportInto(e);
272}
273
274bool
276{
277 if (!e.hasTransients())
278 return false;
280}
281
282void
284{
285 // TODO: we should probably find the entry being deleted and abort it
286}
287
288void
290{
291 assert(map);
292 assert(entry.hasTransients());
293 const auto idx = entry.mem_obj->xitTable.index;
294 const auto &anchor = isWriter(entry) ?
295 map->writeableEntry(idx) : map->readableEntry(idx);
296 entryStatus.hasWriter = anchor.writing();
297 entryStatus.waitingToBeFreed = anchor.waitingToBeFreed;
298}
299
300void
302{
303 debugs(20, 5, e);
305 assert(isWriter(e));
309}
310
311int
313{
314 if (e.hasTransients()) {
315 assert(map);
317 }
318 return 0;
319}
320
321void
323{
324 debugs(20, 5, e);
325 if (e.hasTransients()) {
326 const auto index = e.mem_obj->xitTable.index;
327 if (map->freeEntry(index)) {
328 // Delay syncCollapsed(index) which may end `e` wait for updates.
329 // Calling it directly/here creates complex reentrant call chains.
331 }
332 } // else nothing to do because e must be private
333}
334
335void
337{
338 if (!map)
339 return;
340
341 const sfileno index = map->fileNoByKey(key);
342 if (map->freeEntry(index))
344}
345
346void
348{
349 debugs(20, 5, entry);
350 if (entry.hasTransients()) {
351 auto &xitTable = entry.mem_obj->xitTable;
352 assert(map);
353 if (isWriter(entry)) {
354 // completeWriting() was not called, so there could be an active
355 // Store writer out there, but we should not abortWriting() here
356 // because another writer may have succeeded, making readers happy.
357 // If none succeeded, the readers will notice the lack of writers.
358 map->closeForWriting(xitTable.index);
360 } else {
361 assert(isReader(entry));
362 map->closeForReadingAndFreeIdle(xitTable.index);
363 }
364 locals->at(xitTable.index) = nullptr;
365 xitTable.index = -1;
366 xitTable.io = Store::ioDone;
367 }
368}
369
371int64_t
373{
374 return (UsingSmp() && Store::Controller::SmpAware()) ?
376}
377
378bool
380{
381 assert(map);
382 return map->markedForDeletion(key);
383}
384
385bool
387{
388 return e.mem_obj && e.mem_obj->xitTable.io == Store::ioReading;
389}
390
391bool
393{
394 return e.mem_obj && e.mem_obj->xitTable.io == Store::ioWriting;
395}
396
399{
400public:
401 /* RegisteredRunner API */
402 virtual void useConfig();
403 virtual ~TransientsRr();
404
405protected:
406 virtual void create();
407
408private:
410};
411
413
414void
416{
419}
420
421void
423{
424 const int64_t entryLimit = Transients::EntryLimit();
425 if (entryLimit <= 0)
426 return; // no SMP configured or a misconfiguration
427
428 Must(!mapOwner);
430}
431
433{
434 delete mapOwner;
435}
436
#define Here()
source code location of the caller
Definition: Here.h:15
class SquidConfig Config
Definition: SquidConfig.cc:12
#define Must(condition)
Definition: TextException.h:71
static const SBuf MapLabel("transients_map")
shared memory segment path to use for Transients map
RunnerRegistrationEntry(TransientsRr)
Ipc::StoreMap TransientsMap
Definition: Transients.h:20
#define assert(EX)
Definition: assert.h:19
static void Broadcast(const StoreEntry &e, const bool includingThisWorker=false)
notify other workers about changes in entry state (e.g., new data)
virtual void useConfig()
Definition: Segment.cc:377
std::atomic< uint32_t > readers
number of reading users
Definition: ReadWriteLock.h:49
ReadWriteLock lock
protects slot data below
Definition: StoreMap.h:80
void exportInto(StoreEntry &) const
load StoreEntry basics that were previously stored with set()
Definition: StoreMap.cc:979
aggregates anchor and slice owners for Init() caller convenience
Definition: StoreMap.h:233
Anchor * openForWriting(const cache_key *const key, sfileno &fileno)
Definition: StoreMap.cc:140
bool markedForDeletion(const cache_key *const)
Definition: StoreMap.cc:355
Anchor & writeableEntry(const AnchorId anchorId)
writeable anchor for the entry created by openForWriting()
Definition: StoreMap.cc:237
const Anchor & readableEntry(const AnchorId anchorId) const
readable anchor for the entry created by openForReading()
Definition: StoreMap.cc:244
int entryCount() const
number of writeable and readable entries
Definition: StoreMap.cc:739
static Owner * Init(const SBuf &path, const int slotLimit)
initialize shared memory
Definition: StoreMap.cc:42
const Anchor * openOrCreateForReading(const cache_key *, sfileno &, const StoreEntry &)
openForReading() but creates a new entry if there is no old one
Definition: StoreMap.cc:103
void closeForWriting(const sfileno fileno)
successfully finish creating or updating the entry at fileno pos
Definition: StoreMap.cc:200
StoreMapCleaner * cleaner
notified before a readable entry is freed
Definition: StoreMap.h:361
const Anchor * openForReading(const cache_key *const key, sfileno &fileno)
opens entry (identified by key) for reading, increments read level
Definition: StoreMap.cc:440
bool freeEntry(const sfileno)
Definition: StoreMap.cc:313
const Anchor * peekAtWriter(const sfileno fileno) const
Definition: StoreMap.cc:297
void closeForReadingAndFreeIdle(const sfileno fileno)
same as closeForReading() but also frees the entry if it is unlocked
Definition: StoreMap.cc:506
void startAppending(const sfileno fileno)
restrict opened for writing entry to appending operations; allow reads
Definition: StoreMap.cc:191
sfileno fileNoByKey(const cache_key *const key) const
computes map entry anchor position for a given entry key
Definition: StoreMap.cc:912
const Anchor & peekAtEntry(const sfileno fileno) const
Definition: StoreMap.cc:307
void switchWritingToReading(const sfileno fileno)
stop writing (or updating) the locked entry and start reading it
Definition: StoreMap.cc:211
void disableHitValidation()
Definition: StoreMap.h:346
int entryLimit() const
maximum entryCount() possible
Definition: StoreMap.cc:733
int32_t index
entry position inside the in-transit table
Definition: MemObject.h:172
Io io
current I/O state
Definition: MemObject.h:173
XitTable xitTable
current [shared] memory caching state for the entry
Definition: MemObject.h:175
Definition: SBuf.h:94
int64_t shared_transient_entries_limit
Definition: SquidConfig.h:343
YesNoNone memShared
whether the memory cache is shared among workers
Definition: SquidConfig.h:87
MemObject * mem_obj
Definition: Store.h:221
void createMemObject()
Definition: store.cc:1542
bool hasTransients() const
whether there is a corresponding locked transients table entry
Definition: Store.h:211
High-level store statistics used by mgr:info action. Used inside PODs!
Definition: StoreStats.h:14
static bool SmpAware()
whether there are any SMP-aware storages
Definition: Controller.cc:908
an std::runtime_error with thrower location info
Definition: TextException.h:21
initializes shared memory segment used by Transients
Definition: Transients.cc:399
virtual void create()
called when the runner should create a new memory segment
Definition: Transients.cc:422
virtual ~TransientsRr()
Definition: Transients.cc:432
TransientsMap::Owner * mapOwner
Definition: Transients.cc:409
virtual void useConfig()
Definition: Transients.cc:415
shared entry metadata, used for synchronization
Definition: Transients.h:32
bool waitingToBeFreed
whether the entry was marked for deletion
Definition: Transients.h:35
bool hasWriter
whether some worker is storing the entry
Definition: Transients.h:34
int readers(const StoreEntry &e) const
number of entry readers some time ago
Definition: Transients.cc:312
virtual StoreEntry * get(const cache_key *) override
Definition: Transients.cc:146
bool hasWriter(const StoreEntry &)
whether we or somebody else is in the "writing to Transients" I/O state
Definition: Transients.cc:275
void monitorIo(StoreEntry *, const cache_key *, const Store::IoStatus)
Definition: Transients.cc:192
void addReaderEntry(StoreEntry &, const cache_key *)
Definition: Transients.cc:250
Locals * locals
Definition: Transients.h:109
virtual void noteFreeMapSlice(const Ipc::StoreMapSliceId sliceId) override
adjust slice-linked state before a locked Readable slice is erased
Definition: Transients.cc:283
virtual ~Transients()
Definition: Transients.cc:34
TransientsMap * map
shared packed info indexed by Store keys, for creating new StoreEntries
Definition: Transients.h:104
void addWriterEntry(StoreEntry &, const cache_key *)
addEntry() helper used for cache entry creators/writers
Definition: Transients.cc:228
bool isWriter(const StoreEntry &) const
whether the entry is in "writing to Transients" I/O state
Definition: Transients.cc:392
void disconnect(StoreEntry &)
the caller is done writing or reading the given entry
Definition: Transients.cc:347
StoreEntry * findCollapsed(const sfileno xitIndex)
return a local, previously collapsed entry
Definition: Transients.cc:176
void anchorEntry(StoreEntry &, const sfileno, const Ipc::StoreMapAnchor &)
fills (recently created) StoreEntry with information currently in Transients
Definition: Transients.cc:263
virtual void getStats(StoreInfoStats &stats) const override
collect statistics
Definition: Transients.cc:56
virtual int64_t maxObjectSize() const override
the maximum size of a storable object; -1 if unlimited
Definition: Transients.cc:126
virtual void stat(StoreEntry &e) const override
Definition: Transients.cc:73
void addEntry(StoreEntry *, const cache_key *, const Store::IoStatus)
creates a new Transients entry
Definition: Transients.cc:211
bool markedForDeletion(const cache_key *) const
Definition: Transients.cc:379
virtual void evictCached(StoreEntry &) override
Definition: Transients.cc:322
void status(const StoreEntry &e, EntryStatus &entryStatus) const
copies current shared entry metadata into entryStatus
Definition: Transients.cc:289
virtual uint64_t minSize() const override
the minimum size the store will shrink to via normal housekeeping
Definition: Transients.cc:99
virtual void reference(StoreEntry &e) override
somebody needs this entry (many cache replacement policies need to know)
Definition: Transients.cc:133
virtual void init() override
Definition: Transients.cc:41
virtual uint64_t maxSize() const override
Definition: Transients.cc:105
virtual bool dereference(StoreEntry &e) override
Definition: Transients.cc:139
virtual void maintain() override
perform regular periodic maintenance; TODO: move to UFSSwapDir::Maintain
Definition: Transients.cc:93
static int64_t EntryLimit()
calculates maximum number of entries we need to store and map
Definition: Transients.cc:372
bool isReader(const StoreEntry &) const
whether the entry is in "reading from Transients" I/O state
Definition: Transients.cc:386
virtual uint64_t currentSize() const override
current size
Definition: Transients.cc:112
void completeWriting(const StoreEntry &e)
called when the in-transit entry has been successfully cached
Definition: Transients.cc:301
virtual uint64_t currentCount() const override
the total number of objects stored right now
Definition: Transients.cc:120
std::vector< StoreEntry * > Locals
Definition: Transients.h:106
virtual void evictIfFound(const cache_key *) override
Definition: Transients.cc:336
static bool Enabled()
Can we create and initialize Transients?
Definition: Transients.h:91
bool configured() const
Definition: YesNoNone.h:67
A const & max(A const &lhs, A const &rhs)
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:196
#define EBIT_TEST(flag, bit)
Definition: defines.h:69
@ KEY_PRIVATE
Definition: enums.h:102
size_t PageLevel()
approximate total number of shared memory pages used now
Definition: Pages.cc:80
size_t PageSize()
returns page size in bytes; all pages are assumed to be the same size
Definition: Pages.cc:28
size_t PageLimit()
the total number of shared memory pages that can be in use at any time
Definition: Pages.cc:55
int32_t StoreMapSliceId
Definition: StoreMap.h:24
double doublePercent(const double, const double)
Definition: SquidMath.cc:25
class Ping::pingStats_ stats
IoStatus
cache "I/O" direction and status
Definition: forward.h:40
@ ioReading
Definition: forward.h:40
@ ioWriting
Definition: forward.h:40
@ ioDone
Definition: forward.h:40
unsigned char cache_key
Store key.
Definition: forward.h:29
signed_int32_t sfileno
Definition: forward.h:22
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:828
bool UsingSmp()
Whether there should be more than one worker process running.
Definition: tools.cc:693
#define PRId64
Definition: types.h:110

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors