]> git.ipfire.org Git - thirdparty/squid.git/blame - src/Store.h
Preserve caller context across (and improve) deferred reads (#1025)
[thirdparty/squid.git] / src / Store.h
CommitLineData
e6ccf245 1/*
bf95c10a 2 * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
e6ccf245 3 *
bbc27441
AJ
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.
e6ccf245 7 */
bbc27441 8
e6ccf245 9#ifndef SQUID_STORE_H
10#define SQUID_STORE_H
11
a928fdfd 12#include "base/DelayedAsyncCalls.h"
0f33a01d 13#include "base/Packable.h"
21dfc374 14#include "base/Range.h"
8bf217bd 15#include "base/RefCount.h"
3e4bebf8 16#include "comm/forward.h"
c6983ec7 17#include "hash.h"
f35c0145 18#include "http/forward.h"
c24f7fb6 19#include "http/RequestMethod.h"
43ca19e0 20#include "HttpReply.h"
04ebce55 21#include "MemObject.h"
aa839030 22#include "RemovalPolicy.h"
2745fea5
AR
23#include "store/Controller.h"
24#include "store/forward.h"
e1ba42a4 25#include "store_key_md5.h"
582c2af2 26#include "StoreIOBuffer.h"
93bc1434 27#include "StoreStats.h"
528b2c61 28
f41735ea 29#if USE_SQUID_ESI
f99c2cfe 30#include "esi/Element.h"
43ae1d95 31#endif
32
27e059d4 33#include <ostream>
27e059d4 34
65517dc8 35class AsyncCall;
582c2af2 36class HttpRequest;
71b673d4 37class RequestFlags;
c8f4eac4 38
8822ebee
AR
39extern StoreIoStats store_io_stats;
40
0f33a01d 41class StoreEntry : public hash_link, public Packable
62e76326 42{
43
332dafa2 44public:
a46d2c0e 45 bool checkDeferRead(int fd) const;
62e76326 46
69565793 47 const char *getMD5Text() const;
c8f4eac4 48 StoreEntry();
6d8d05b5 49 virtual ~StoreEntry();
43ae1d95 50
66d51f4f
AR
51 MemObject &mem() { assert(mem_obj); return *mem_obj; }
52 const MemObject &mem() const { assert(mem_obj); return *mem_obj; }
53
54 /// \retval * the address of freshest reply (if mem_obj exists)
55 /// \retval nullptr when mem_obj does not exist
56 /// \see MemObject::freshestReply()
57 const HttpReply *hasFreshestReply() const { return mem_obj ? &mem_obj->freshestReply() : nullptr; }
58
69565793 59 void write(StoreIOBuffer);
04ebce55 60
69565793 61 /** Check if the Store entry is empty
04ebce55
FC
62 * \retval true Store contains 0 bytes of data.
63 * \retval false Store contains 1 or more bytes of data.
64 * \retval false Store contains negative content !!!!!!
65 */
66d51f4f 66 bool isEmpty() const { return mem().endOffset() == 0; }
69565793
EB
67 bool isAccepting() const;
68 size_t bytesWanted(Range<size_t> const aRange, bool ignoreDelayPool = false) const;
ba3fe8d9
EB
69
70 /// Signals that the entire response has been stored and no more append()
71 /// calls should be expected; cf. completeTruncated().
72 void completeSuccessfully(const char *whyWeAreSureWeStoredTheWholeReply);
73
74 /// Signals that a partial response (if any) has been stored but no more
75 /// append() calls should be expected; cf. completeSuccessfully().
76 void completeTruncated(const char *whyWeConsiderTheReplyTruncated);
77
78 /// \deprecated use either completeSuccessfully() or completeTruncated() instead
69565793 79 void complete();
ba3fe8d9 80
69565793 81 store_client_t storeClientType() const;
66d51f4f
AR
82 /// \returns a malloc()ed buffer containing a length-long packed swap header
83 const char *getSerialisedMetaData(size_t &length) const;
eacfca83
AR
84 /// Store a prepared error response. MemObject locks the reply object.
85 void storeErrorResponse(HttpReply *reply);
66d51f4f 86 void replaceHttpReply(const HttpReplyPointer &, const bool andStartWriting = true);
3756e5c0 87 void startWriting(); ///< pack and write reply headers and, maybe, body
5b55f1f1 88 /// whether we may start writing to disk (now or in the future)
69565793
EB
89 bool mayStartSwapOut();
90 void trimMemory(const bool preserveSwappable);
0cdcf3d7 91
2da4bfe6 92 // called when a decision to cache in memory has been made
0cdcf3d7
AR
93 void memOutDecision(const bool willCacheInRam);
94 // called when a decision to cache on disk has been made
95 void swapOutDecision(const MemObject::SwapOut::Decision &decision);
96
bfb55b6f 97 void abort();
4310f8b0 98 bool makePublic(const KeyScope keyScope = ksDefault);
39fe14b2
EB
99 void makePrivate(const bool shareable);
100 /// A low-level method just resetting "private key" flags.
101 /// To avoid key inconsistency please use forcePublicKey()
102 /// or similar instead.
103 void clearPrivate();
4310f8b0 104 bool setPublicKey(const KeyScope keyScope = ksDefault);
1a210de4
EB
105 /// Resets existing public key to a public key with default scope,
106 /// releasing the old default-scope entry (if any).
107 /// Does nothing if the existing public key already has default scope.
108 void clearPublicKeyScope();
4310f8b0
EB
109
110 /// \returns public key (if the entry has it) or nil (otherwise)
111 const cache_key *publicKey() const {
112 return (!EBIT_TEST(flags, KEY_PRIVATE)) ?
113 reinterpret_cast<const cache_key*>(key): // may be nil
114 nullptr;
115 }
116
117 /// Either fills this entry with private key or changes the existing key
118 /// from public to private.
119 /// \param permanent whether this entry should be private forever.
120 void setPrivateKey(const bool shareable, const bool permanent);
121
d88e3c49 122 void expireNow();
4310f8b0
EB
123 /// Makes the StoreEntry private and marks the corresponding entry
124 /// for eventual removal from the Store.
39fe14b2 125 void releaseRequest(const bool shareable = false);
d88e3c49 126 void negativeCache();
9837567d 127 bool cacheNegatively(); // TODO: why both negativeCache() and cacheNegatively() ?
d88e3c49 128 void invokeHandlers();
9487bae9 129 void cacheInMemory(); ///< start or continue storing in memory cache
c07cbbf4 130 void swapOut();
5b55f1f1
CT
131 /// whether we are in the process of writing this entry to disk
132 bool swappingOut() const { return swap_status == SWAPOUT_WRITING; }
4310f8b0
EB
133 /// whether the entire entry is now on disk (possibly marked for deletion)
134 bool swappedOut() const { return swap_status == SWAPOUT_DONE; }
02ba667b
EB
135 /// whether we failed to write this entry to disk
136 bool swapoutFailed() const { return swap_status == SWAPOUT_FAILED; }
aa1a691e 137 void swapOutFileClose(int how);
3900307b 138 const char *url() const;
7015a149
AR
139 /// Satisfies cachability requirements shared among disk and RAM caches.
140 /// Encapsulates common checks of mayStartSwapOut() and memoryCachable().
141 /// TODO: Rename and make private so only those two methods can call this.
142 bool checkCachable();
3900307b 143 int checkNegativeHit() const;
508590d9 144 int locked() const { return lock_count; }
3900307b 145 int validToSend() const;
97754f5a 146 bool memoryCachable(); ///< checkCachable() and can be cached in memory
4475555f 147
76d61119
EB
148 /// initialize mem_obj; assert if mem_obj already exists
149 /// avoid this method in favor of createMemObject(trio)!
150 void createMemObject();
c877c0bc 151
76d61119 152 /// initialize mem_obj with URIs/method; assert if mem_obj already exists
c877c0bc 153 void createMemObject(const char *storeId, const char *logUri, const HttpRequestMethod &aMethod);
4475555f 154
76d61119
EB
155 /// initialize mem_obj (if needed) and set URIs/method (if missing)
156 void ensureMemObject(const char *storeId, const char *logUri, const HttpRequestMethod &aMethod);
157
3900307b 158 void dump(int debug_lvl) const;
159 void hashDelete();
160 void hashInsert(const cache_key *);
7e9f330d
EB
161 /// notify the StoreEntry writer of a 3rd-party initiated StoreEntry abort
162 void registerAbortCallback(const AsyncCall::Pointer &);
3900307b 163 void reset();
164 void setMemStatus(mem_status_t);
1a210de4 165 bool timestampsSet();
7e9f330d
EB
166 /// Avoid notifying anybody about a 3rd-party initiated StoreEntry abort.
167 /// Calling this method does not cancel the already queued notification.
168 /// TODO: Refactor to represent the end of (shared) ownership by our writer.
169 void unregisterAbortCallback(const char *reason);
3900307b 170 void destroyMemObject();
171 int checkTooSmall();
528b2c61 172
a46d2c0e 173 void setNoDelay (bool const);
438b41ba
EB
174 void lastModified(const time_t when) { lastModified_ = when; }
175 /// \returns entry's 'effective' modification time
176 time_t lastModified() const {
177 // may still return -1 if timestamp is not set
178 return lastModified_ < 0 ? timestamp : lastModified_;
179 }
180 /// \returns a formatted string with entry's timestamps
181 const char *describeTimestamps() const;
182 // TODO: consider removing currently unsupported imslen parameter
183 bool modifiedSince(const time_t ims, const int imslen = -1) const;
79c8035e
AR
184 /// has ETag matching at least one of the If-Match etags
185 bool hasIfMatchEtag(const HttpRequest &request) const;
186 /// has ETag matching at least one of the If-None-Match etags
187 bool hasIfNoneMatchEtag(const HttpRequest &request) const;
46017fdd
CT
188 /// whether this entry has an ETag; if yes, puts ETag value into parameter
189 bool hasEtag(ETag &etag) const;
63be0a78 190
66d51f4f
AR
191 /// Updates easily-accessible non-Store-specific parts of the entry.
192 /// Use Controller::updateOnNotModified() instead of this helper.
193 /// \returns whether anything was actually updated
194 bool updateOnNotModified(const StoreEntry &e304);
195
2745fea5
AR
196 /// the disk this entry is [being] cached on; asserts for entries w/o a disk
197 Store::Disk &disk() const;
4310f8b0
EB
198 /// whether one of this StoreEntry owners has locked the corresponding
199 /// disk entry (at the specified disk entry coordinates, if any)
200 bool hasDisk(const sdirno dirn = -1, const sfileno filen = -1) const;
201 /// Makes hasDisk(dirn, filn) true. The caller should have locked
202 /// the corresponding disk store entry for reading or writing.
203 void attachToDisk(const sdirno, const sfileno, const swap_status_t);
204 /// Makes hasDisk() false. The caller should have unlocked
205 /// the corresponding disk store entry.
206 void detachFromDisk();
207
208 /// whether there is a corresponding locked transients table entry
209 bool hasTransients() const { return mem_obj && mem_obj->xitTable.index >= 0; }
210 /// whether there is a corresponding locked shared memory table entry
211 bool hasMemStore() const { return mem_obj && mem_obj->memCache.index >= 0; }
a46d2c0e 212
d2a6dcba
EB
213 /// whether this entry can feed collapsed requests and only them
214 bool hittingRequiresCollapsing() const { return EBIT_TEST(flags, ENTRY_REQUIRES_COLLAPSING); }
215
216 /// allow or forbid collapsed requests feeding
217 void setCollapsingRequirement(const bool required);
819be284 218
e6ccf245 219 MemObject *mem_obj;
220 RemovalPolicyNode repl;
221 /* START OF ON-DISK STORE_META_STD TLV field */
222 time_t timestamp;
223 time_t lastref;
224 time_t expires;
438b41ba
EB
225private:
226 time_t lastModified_; ///< received Last-Modified value or -1; use lastModified()
227public:
47f6e231 228 uint64_t swap_file_sz;
f45dd259
AJ
229 uint16_t refcount;
230 uint16_t flags;
e6ccf245 231 /* END OF ON-DISK STORE_META_STD */
62e76326 232
051dedf9
AR
233 /// unique ID inside a cache_dir for swapped out entries; -1 for others
234 sfileno swap_filen:25; // keep in sync with SwapFilenMax
d1398b75
HN
235
236 sdirno swap_dirn:7;
62e76326 237
d1398b75 238 mem_status_t mem_status:3;
62e76326 239
d1398b75 240 ping_status_t ping_status:3;
62e76326 241
d1398b75 242 store_status_t store_status:3;
62e76326 243
d1398b75 244 swap_status_t swap_status:3;
62e76326 245
e6ccf245 246public:
247 static size_t inUseCount();
528b2c61 248
0b934349
AJ
249 void *operator new(size_t byteCount);
250 void operator delete(void *address);
f41735ea 251#if USE_SQUID_ESI
43ae1d95 252
253 ESIElement::Pointer cachedESITree;
254#endif
66d51f4f
AR
255 int64_t objectLen() const { return mem().object_sz; }
256 int64_t contentLen() const { return objectLen() - mem().baseReply().hdr_sz; }
c21ad0f5 257
18994992 258 /// claim shared ownership of this entry (for use in a given context)
acc5dc4c 259 /// matching lock() and unlock() contexts eases leak triage but is optional
18994992 260 void lock(const char *context);
1bfe9ade 261
18994992 262 /// disclaim shared ownership; may remove entry from store and delete it
2f8abb64 263 /// returns remaining lock level (zero for unlocked and possibly gone entry)
acc5dc4c 264 int unlock(const char *context);
1bfe9ade
AR
265
266 /// returns a local concurrent use counter, for debugging
267 int locks() const { return static_cast<int>(lock_count); }
268
18994992
AR
269 /// update last reference timestamp and related Store metadata
270 void touch();
271
4310f8b0
EB
272 /// One of the three methods to get rid of an unlocked StoreEntry object.
273 /// Removes all unlocked (and marks for eventual removal all locked) Store
274 /// entries, including attached and unattached entries that have our key.
275 /// Also destroys us if we are unlocked or makes us private otherwise.
69565793 276 void release(const bool shareable = false);
39fe14b2 277
4310f8b0
EB
278 /// One of the three methods to get rid of an unlocked StoreEntry object.
279 /// May destroy this object if it is unlocked; does nothing otherwise.
280 /// Unlike release(), may not trigger eviction of underlying store entries,
281 /// but, unlike destroyStoreEntry(), does honor an earlier release request.
282 void abandon(const char *context) { if (!locked()) doAbandon(context); }
283
39fe14b2
EB
284 /// May the caller commit to treating this [previously locked]
285 /// entry as a cache hit?
286 bool mayStartHitting() const {
287 return !EBIT_TEST(flags, KEY_PRIVATE) || shareableWhenPrivate;
288 }
62e76326 289
0ad2b63b
CT
290#if USE_ADAPTATION
291 /// call back producer when more buffer space is available
292 void deferProducer(const AsyncCall::Pointer &producer);
293 /// calls back producer registered with deferProducer
294 void kickProducer();
295#endif
296
0f33a01d
AJ
297 /* Packable API */
298 virtual void append(char const *, int);
299 virtual void vappendf(const char *, va_list);
7e10ac87
AJ
300 virtual void buffer();
301 virtual void flush();
0f33a01d 302
0cdcf3d7 303protected:
4310f8b0
EB
304 typedef Store::EntryGuard EntryGuard;
305
0cdcf3d7 306 void transientsAbandonmentCheck();
4310f8b0
EB
307 /// does nothing except throwing if disk-associated data members are inconsistent
308 void checkDisk() const;
0cdcf3d7 309
e6ccf245 310private:
4310f8b0 311 void doAbandon(const char *context);
2be042f6 312 bool checkTooBig() const;
1a210de4 313 void forcePublicKey(const cache_key *newkey);
4310f8b0 314 StoreEntry *adjustVary();
1a210de4 315 const cache_key *calcPublicKey(const KeyScope keyScope);
2be042f6 316
ba3fe8d9
EB
317 /// flags [truncated or too big] entry with ENTRY_BAD_LENGTH and releases it
318 void lengthWentBad(const char *reason);
319
04eb0689 320 static MemAllocator *pool;
528b2c61 321
f53969cc 322 unsigned short lock_count; /* Assume < 65536! */
1bfe9ade 323
39fe14b2
EB
324 /// Nobody can find/lock KEY_PRIVATE entries, but some transactions
325 /// (e.g., collapsed requests) find/lock a public entry before it becomes
326 /// private. May such transactions start using the now-private entry
327 /// they previously locked? This member should not affect transactions
328 /// that already started reading from the entry.
329 bool shareableWhenPrivate;
330
0ad2b63b
CT
331#if USE_ADAPTATION
332 /// producer callback registered with deferProducer
333 AsyncCall::Pointer deferredProducer;
334#endif
335
528b2c61 336 bool validLength() const;
79c8035e 337 bool hasOneOfEtags(const String &reqETags, const bool allowWeakMatch) const;
39fe14b2
EB
338
339 friend std::ostream &operator <<(std::ostream &os, const StoreEntry &e);
e6ccf245 340};
341
2c4cd1ad
AR
342std::ostream &operator <<(std::ostream &os, const StoreEntry &e);
343
63be0a78 344/// \ingroup StoreAPI
c8f4eac4 345typedef void (*STOREGETCLIENT) (StoreEntry *, void *cbdata);
346
2745fea5 347namespace Store {
4310f8b0
EB
348
349/// a smart pointer similar to std::unique_ptr<> that automatically
350/// release()s and unlock()s the guarded Entry on stack-unwinding failures
351class EntryGuard {
352public:
353 /// \param entry either nil or a locked Entry to manage
354 /// \param context default unlock() message
355 EntryGuard(Entry *entry, const char *context):
356 entry_(entry), context_(context) {
357 assert(!entry_ || entry_->locked());
358 }
359
360 ~EntryGuard() {
361 if (entry_) {
362 // something went wrong -- the caller did not unlockAndReset() us
363 onException();
364 }
365 }
366
367 EntryGuard(EntryGuard &&) = delete; // no copying or moving (for now)
368
369 /// like std::unique_ptr::get()
370 /// \returns nil or the guarded (locked) entry
371 Entry *get() {
372 return entry_;
373 }
374
375 /// like std::unique_ptr::reset()
376 /// stops guarding the entry
377 /// unlocks the entry (which may destroy it)
378 void unlockAndReset(const char *resetContext = nullptr) {
379 if (entry_) {
380 entry_->unlock(resetContext ? resetContext : context_);
381 entry_ = nullptr;
382 }
383 }
384
385private:
386 void onException() noexcept;
387
388 Entry *entry_; ///< the guarded Entry or nil
389 const char *context_; ///< default unlock() message
390};
391
7d84d4ca
SM
392void Stats(StoreEntry *output);
393void Maintain(void *unused);
4310f8b0 394}; // namespace Store
c8f4eac4 395
63be0a78 396/// \ingroup StoreAPI
71b673d4 397size_t storeEntryInUse();
63be0a78 398
399/// \ingroup StoreAPI
71b673d4 400const char *storeEntryFlags(const StoreEntry *);
63be0a78 401
402/// \ingroup StoreAPI
71b673d4 403void storeEntryReplaceObject(StoreEntry *, HttpReply *);
e6ccf245 404
63be0a78 405/// \ingroup StoreAPI
71b673d4 406StoreEntry *storeGetPublic(const char *uri, const HttpRequestMethod& method);
63be0a78 407
408/// \ingroup StoreAPI
1a210de4 409StoreEntry *storeGetPublicByRequest(HttpRequest * request, const KeyScope keyScope = ksDefault);
63be0a78 410
411/// \ingroup StoreAPI
1a210de4 412StoreEntry *storeGetPublicByRequestMethod(HttpRequest * request, const HttpRequestMethod& method, const KeyScope keyScope = ksDefault);
63be0a78 413
414/// \ingroup StoreAPI
1bfe9ade 415/// Like storeCreatePureEntry(), but also locks the entry and sets entry key.
71b673d4 416StoreEntry *storeCreateEntry(const char *, const char *, const RequestFlags &, const HttpRequestMethod&);
63be0a78 417
1bfe9ade
AR
418/// \ingroup StoreAPI
419/// Creates a new StoreEntry with mem_obj and sets initial flags/states.
4310f8b0 420StoreEntry *storeCreatePureEntry(const char *storeId, const char *logUrl, const HttpRequestMethod&);
1bfe9ade 421
63be0a78 422/// \ingroup StoreAPI
71b673d4 423void storeInit(void);
63be0a78 424
63be0a78 425/// \ingroup StoreAPI
71b673d4 426void storeConfigure(void);
63be0a78 427
428/// \ingroup StoreAPI
71b673d4 429void storeFreeMemory(void);
63be0a78 430
431/// \ingroup StoreAPI
71b673d4 432int expiresMoreThan(time_t, time_t);
63be0a78 433
63be0a78 434/// \ingroup StoreAPI
71b673d4 435void storeAppendPrintf(StoreEntry *, const char *,...) PRINTF_FORMAT_ARG2;
63be0a78 436
437/// \ingroup StoreAPI
71b673d4 438void storeAppendVPrintf(StoreEntry *, const char *, va_list ap);
63be0a78 439
440/// \ingroup StoreAPI
71b673d4 441int storeTooManyDiskFilesOpen(void);
63be0a78 442
443/// \ingroup StoreAPI
71b673d4 444void storeHeapPositionUpdate(StoreEntry *, SwapDir *);
63be0a78 445
446/// \ingroup StoreAPI
71b673d4 447void storeSwapFileNumberSet(StoreEntry * e, sfileno filn);
63be0a78 448
449/// \ingroup StoreAPI
71b673d4 450void storeFsInit(void);
63be0a78 451
452/// \ingroup StoreAPI
71b673d4 453void storeFsDone(void);
63be0a78 454
455/// \ingroup StoreAPI
71b673d4 456void storeReplAdd(const char *, REMOVALPOLICYCREATE *);
63be0a78 457
4310f8b0
EB
458/// One of the three methods to get rid of an unlocked StoreEntry object.
459/// This low-level method ignores lock()ing and release() promises. It never
460/// leaves the entry in the local store_table.
461/// TODO: Hide by moving its functionality into the StoreEntry destructor.
c8f4eac4 462extern FREE destroyStoreEntry;
e6ccf245 463
6d3c2758 464/// \ingroup StoreAPI
71b673d4 465void storeGetMemSpace(int size);
6d3c2758 466
e6ccf245 467#endif /* SQUID_STORE_H */
f53969cc 468