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

 

Introduction

Documentation

Support

Miscellaneous