]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Preserve caller context across (and improve) deferred reads (#1025)
authorEduard Bagdasaryan <eduard.bagdasaryan@measurement-factory.com>
Fri, 13 May 2022 03:10:32 +0000 (03:10 +0000)
committerSquid Anubis <squid-anubis@squid-cache.org>
Fri, 13 May 2022 08:46:59 +0000 (08:46 +0000)
The transaction context was not saved/restored when dealing with
deferred reads initiated by events like the DelayPools::Update() event.
To fix this, we refactored MemObject::delayRead() and its descendants to
use an AsyncCall, which automatically stores/restores code context.

Using explicit async callbacks highlighted the danger of passing
Connection object via CommRead that does not maintain a closure
callback. There was also a related "stuck transaction" suspicion
documented in DeferredReadManager::kickARead(). Fortunately, all these
problems could now be solved by removing DeferredRead and CommRead
classes! The delayed readers already store the Connection object,
maintain closure callbacks, and have to check stored Connection validity
before reading anyway. The general/centralized delayed reading logic is
not really about reading and Connections (those parts are handled by
transaction-specific code) but about triggering reading attempts.
Asynchronous calls are perfect (and sufficient) for doing that.

Also fixed Delay Pools for Gopher: delayAwareRead() was initiated only
once from gopherSendComplete() and the subsequent read calls were
delay-unaware (i.e. immediate) reads.

Also fixed a Delay Pools problem with active transactions: A transaction
started with Delay Pools on becomes stuck if a reconfiguration turns
Delay Pools off.

Also refactored the existing AsyncCall FIFO intrusive storage, making
its reuse possible (and marked one candidate with a TODO).

43 files changed:
src/CommRead.h [deleted file]
src/CompositePoolNode.h
src/DelayId.cc
src/DelayId.h
src/DelayIdComposite.h
src/DelayPool.cc
src/DelayTagged.cc
src/DelayTagged.h
src/DelayVector.cc
src/DelayVector.h
src/DiskIO/DiskDaemon/DiskdIOStrategy.cc
src/DiskIO/DiskThreads/DiskThreadsDiskFile.cc
src/Makefile.am
src/MemObject.cc
src/MemObject.h
src/Store.h
src/adaptation/icap/ModXact.cc
src/base/AsyncCall.h
src/base/AsyncCallList.cc [new file with mode: 0644]
src/base/AsyncCallList.h [new file with mode: 0644]
src/base/AsyncCallQueue.cc
src/base/AsyncCallQueue.h
src/base/DelayedAsyncCalls.cc [new file with mode: 0644]
src/base/DelayedAsyncCalls.h [new file with mode: 0644]
src/base/Makefile.am
src/base/forward.h
src/clients/Client.cc
src/clients/Client.h
src/clients/FtpClient.cc
src/clients/FtpClient.h
src/comm.cc
src/delay_pools.cc
src/gopher.cc
src/http.cc
src/http.h
src/mgr/Forwarder.cc
src/mgr/StoreToCommWriter.cc
src/store.cc
src/tests/stub_DelayId.cc
src/tests/stub_MemObject.cc
src/tests/stub_comm.cc
src/tests/stub_store.cc
src/tunnel.cc

diff --git a/src/CommRead.h b/src/CommRead.h
deleted file mode 100644 (file)
index b0459d7..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
- *
- * Squid software is distributed under GPLv2+ license and includes
- * contributions from numerous individuals and organizations.
- * Please see the COPYING and CONTRIBUTORS files for details.
- */
-
-/* DEBUG: section 05    Comm */
-
-#ifndef COMMREAD_H
-#define COMMREAD_H
-
-#include "base/CbDataList.h"
-#include "comm.h"
-#include "comm/forward.h"
-#include "CommCalls.h"
-
-class CommRead
-{
-
-public:
-    CommRead();
-    CommRead(const Comm::ConnectionPointer &c, char *buf, int len, AsyncCall::Pointer &callback);
-    Comm::ConnectionPointer conn;
-    char *buf;
-    int len;
-    AsyncCall::Pointer callback;
-};
-
-class DeferredRead
-{
-
-public:
-    typedef void DeferrableRead(void *context, CommRead const &);
-    DeferredRead ();
-    DeferredRead (DeferrableRead *, void *, CommRead const &);
-    void markCancelled();
-    DeferrableRead *theReader;
-    void *theContext;
-    CommRead theRead;
-    bool cancelled;
-    AsyncCall::Pointer closer; ///< internal close handler used by Comm
-
-private:
-};
-
-class DeferredReadManager
-{
-
-public:
-    ~DeferredReadManager();
-    void delayRead(DeferredRead const &);
-    void kickReads(int const count);
-
-private:
-    static CLCB CloseHandler;
-    static DeferredRead popHead(CbDataListContainer<DeferredRead> &deferredReads);
-    void kickARead(DeferredRead const &);
-    void flushReads();
-    CbDataListContainer<DeferredRead> deferredReads;
-};
-
-#endif /* COMMREAD_H */
-
index add27d2d29cb08e072be16d24798b8660c858f58..e00df8ff2291957a3f076555a25548577a084df8 100644 (file)
@@ -13,7 +13,7 @@
 
 #if USE_DELAY_POOLS
 #include "auth/UserRequest.h"
-#include "CommRead.h"
+#include "base/DelayedAsyncCalls.h"
 #include "DelayIdComposite.h"
 #include "DelayPools.h"
 #include "ip/Address.h"
@@ -37,7 +37,7 @@ public:
 
     class CompositeSelectionDetails;
     virtual DelayIdComposite::Pointer id(CompositeSelectionDetails &) = 0;
-    void delayRead(DeferredRead const &);
+    void delayRead(const AsyncCallPointer &);
 
     /// \ingroup DelayPoolsAPI
     class CompositeSelectionDetails
@@ -55,7 +55,7 @@ public:
 
 protected:
     void kickReads();
-    DeferredReadManager deferredReads;
+    DelayedAsyncCalls deferredReads;
 };
 
 #endif /* USE_DELAY_POOLS */
index 961ea89ef0fe44c28096685a356a68379ae9c333..67da4a63877261f9a60e7ab51b8214147ae961a9 100644 (file)
@@ -15,8 +15,8 @@
  */
 #if USE_DELAY_POOLS
 #include "acl/FilledChecklist.h"
+#include "base/DelayedAsyncCalls.h"
 #include "client_side_request.h"
-#include "CommRead.h"
 #include "DelayId.h"
 #include "DelayPool.h"
 #include "DelayPools.h"
@@ -164,7 +164,7 @@ DelayId::bytesIn(int qty)
 }
 
 void
-DelayId::delayRead(DeferredRead const &aRead)
+DelayId::delayRead(const AsyncCall::Pointer &aRead)
 {
     assert (compositeId != NULL);
     compositeId->delayRead(aRead);
index adf9e4cbecc5fd655017311ba50a0d434a6cf0fc..c7249db45f051864d36e79c781cab88e3e00b7d5 100644 (file)
@@ -11,6 +11,7 @@
 
 #if USE_DELAY_POOLS
 
+#include "base/forward.h"
 #include "DelayIdComposite.h"
 
 class ClientHttpRequest;
@@ -34,7 +35,7 @@ public:
     int bytesWanted(int min, int max) const;
     void bytesIn (int qty);
     void setNoDelay(bool const);
-    void delayRead(DeferredRead const &);
+    void delayRead(const AsyncCallPointer &);
 
 private:
     unsigned short pool_;
index 61be1bbd2ab10cd9108873b96885fa29fb8cbe90..e6c0a53e69362b889e9a1b6c0f3e76ab1e202ee3 100644 (file)
 #define DELAYIDCOMPOSITE_H
 
 #if USE_DELAY_POOLS
+#include "base/forward.h"
 #include "base/RefCount.h"
 #include "fatal.h"
 
-class DeferredRead;
-
 class DelayIdComposite : public RefCountable
 {
 
@@ -27,7 +26,7 @@ public:
     virtual int bytesWanted (int min, int max) const =0;
     virtual void bytesIn(int qty) = 0;
     /* only aggregate and vector need this today */
-    virtual void delayRead(DeferredRead const &) {fatal("Not implemented");}
+    virtual void delayRead(const AsyncCallPointer &) { fatal("Not implemented"); }
 };
 
 #endif /* USE_DELAY_POOLS */
index f7f3214d6f1143d5bc41675651d64b5ef35388be..e684ab08d7ecd263a51ee9866ee65ae548b48fe2 100644 (file)
@@ -77,9 +77,9 @@ DelayPool::freeData()
 
 // TODO: create DelayIdComposite.cc
 void
-CompositePoolNode::delayRead(DeferredRead const &aRead)
+CompositePoolNode::delayRead(const AsyncCall::Pointer &aRead)
 {
-    deferredReads.delayRead(aRead);
+    deferredReads.delay(aRead);
 }
 
 #include "comm.h"
@@ -87,7 +87,7 @@ CompositePoolNode::delayRead(DeferredRead const &aRead)
 void
 CompositePoolNode::kickReads()
 {
-    deferredReads.kickReads(-1);
+    deferredReads.schedule();
 }
 
 #endif /* USE_DELAY_POOLS */
index c016ec811c63e7eb7636ed73edb750545601443a..bb55d05473a9773d498559efb3588b045dd62633 100644 (file)
@@ -165,7 +165,7 @@ DelayTagged::Id::bytesIn(int qty)
 }
 
 void
-DelayTagged::Id::delayRead(DeferredRead const &aRead)
+DelayTagged::Id::delayRead(const AsyncCall::Pointer &aRead)
 {
     theTagged->delayRead(aRead);
 }
index 7a1e58fdb85c291e5607aa5162917047b3710075..5061bce6c8e67c7f1831ff6cabf6c9056909030c 100644 (file)
@@ -14,6 +14,7 @@
 #if USE_DELAY_POOLS
 
 #include "auth/Gadgets.h"
+#include "base/forward.h"
 #include "CompositePoolNode.h"
 #include "DelayBucket.h"
 #include "DelayIdComposite.h"
@@ -64,7 +65,7 @@ private:
         ~Id();
         virtual int bytesWanted (int min, int max) const;
         virtual void bytesIn(int qty);
-        virtual void delayRead(DeferredRead const &);
+        virtual void delayRead(const AsyncCallPointer &);
 
     private:
         RefCount<DelayTagged> theTagged;
index 342b441fef08ff21eec59772cd27a28118514710..e09249eaad99100dfe09dd9e50195de10547578e 100644 (file)
@@ -11,8 +11,9 @@
 #include "squid.h"
 
 #if USE_DELAY_POOLS
+#include "base/AsyncCall.h"
+#include "base/DelayedAsyncCalls.h"
 #include "comm/Connection.h"
-#include "CommRead.h"
 #include "DelayVector.h"
 
 DelayVector::DelayVector()
@@ -126,7 +127,7 @@ DelayVector::Id::bytesIn(int qty)
 }
 
 void
-DelayVector::Id::delayRead(DeferredRead const &aRead)
+DelayVector::Id::delayRead(const AsyncCallPointer &aRead)
 {
     theVector->delayRead(aRead);
 }
index 1b2bd54f03a7f57ea46e9b65ae9d4adb05687c74..d0243721b534a51e049226d6dcaca1dbc03d9612 100644 (file)
@@ -11,6 +11,7 @@
 
 #if USE_DELAY_POOLS
 
+#include "base/forward.h"
 #include "CompositePoolNode.h"
 
 /// \ingroup DelayPoolsAPI
@@ -42,7 +43,7 @@ private:
         ~Id();
         virtual int bytesWanted (int min, int max) const;
         virtual void bytesIn(int qty);
-        virtual void delayRead(DeferredRead const &);
+        virtual void delayRead(const AsyncCallPointer &);
 
     private:
         RefCount<DelayVector> theVector;
index 8da369263ce1c1cb45d14cf5bf6ff8b16d9e5a0c..bb450a4c64a9fb58159922a0ce761bad074df912 100644 (file)
@@ -9,6 +9,7 @@
 /* DEBUG: section 79    Squid-side DISKD I/O functions. */
 
 #include "squid.h"
+#include "comm.h"
 #include "comm/Loops.h"
 #include "ConfigOption.h"
 #include "diomsg.h"
index 6f552ab414566f9f11b47fafd11aa90c213e5d42..275509e780181da41b3e1d7d63723de09428d658 100644 (file)
@@ -9,6 +9,7 @@
 /* DEBUG: section 79    Disk IO Routines */
 
 #include "squid.h"
+#include "comm.h"
 #include "DiskIO/IORequestor.h"
 #include "DiskIO/ReadRequest.h"
 #include "DiskIO/WriteRequest.h"
index faf9a1d0aba3182d3b72bab45550a37af9413d35..153064aa1492d073ad092ea0b9a4293fc4657eb1 100644 (file)
@@ -227,7 +227,6 @@ squid_SOURCES = \
        CollapsedForwarding.cc \
        CollapsedForwarding.h \
        CollapsingHistory.h \
-       CommRead.h \
        CommandLine.cc \
        CommandLine.h \
        ConfigOption.cc \
@@ -2775,7 +2774,8 @@ nodist_tests_testEventLoop_SOURCES = \
        EventLoop.cc \
        tests/stub_debug.cc \
        tests/stub_fatal.cc \
-       tests/stub_libtime.cc
+       tests/stub_libtime.cc \
+       tests/stub_SBuf.cc
 tests_testEventLoop_LDADD = \
        base/libbase.la \
        $(LIBCPPUNIT_LIBS) \
index 6ac49c2fb13d7b0f0d334b11fe4d3c22ab1f44da..d0d70ec62137e3511da7992af2650a28de38206a 100644 (file)
@@ -438,7 +438,7 @@ MemObject::setNoDelay(bool const newValue)
 }
 
 void
-MemObject::delayRead(DeferredRead const &aRead)
+MemObject::delayRead(const AsyncCall::Pointer &aRead)
 {
 #if USE_DELAY_POOLS
     if (readAheadPolicyCanRead()) {
@@ -448,13 +448,13 @@ MemObject::delayRead(DeferredRead const &aRead)
         }
     }
 #endif
-    deferredReads.delayRead(aRead);
+    deferredReads.delay(aRead);
 }
 
 void
 MemObject::kickReads()
 {
-    deferredReads.kickReads(-1);
+    deferredReads.schedule();
 }
 
 #if USE_DELAY_POOLS
index 1b9b6f0572fdf3c3656de41912670739e8a7b19f..e752b327482d66950881a209c2afded65c28cc03 100644 (file)
@@ -9,7 +9,7 @@
 #ifndef SQUID_MEMOBJECT_H
 #define SQUID_MEMOBJECT_H
 
-#include "CommRead.h"
+#include "base/DelayedAsyncCalls.h"
 #include "dlink.h"
 #include "http/RequestMethod.h"
 #include "RemovalPolicy.h"
@@ -192,7 +192,7 @@ public:
     PeerSelector *ircb_data = nullptr;
 
     /// used for notifying StoreEntry writers about 3rd-party initiated aborts
-    AsyncCall::Pointer abortCallback;
+    AsyncCallPointer abortCallback;
     RemovalPolicyNode repl;
     int id = 0;
     int64_t object_sz = -1;
@@ -203,7 +203,7 @@ public:
 
     SBuf vary_headers;
 
-    void delayRead(DeferredRead const &);
+    void delayRead(const AsyncCallPointer &);
     void kickReads();
 
 private:
@@ -213,7 +213,7 @@ private:
     mutable String storeId_; ///< StoreId for our entry (usually request URI)
     mutable String logUri_;  ///< URI used for logging (usually request URI)
 
-    DeferredReadManager deferredReads;
+    DelayedAsyncCalls deferredReads;
 };
 
 /** global current memory removal policy */
index 937172448e9559415db383ccc0b67177fc1752c0..f407fb80e3a90cb5b079fb47f73a68cc2f36d348 100644 (file)
@@ -9,11 +9,11 @@
 #ifndef SQUID_STORE_H
 #define SQUID_STORE_H
 
+#include "base/DelayedAsyncCalls.h"
 #include "base/Packable.h"
 #include "base/Range.h"
 #include "base/RefCount.h"
 #include "comm/forward.h"
-#include "CommRead.h"
 #include "hash.h"
 #include "http/forward.h"
 #include "http/RequestMethod.h"
@@ -42,7 +42,6 @@ class StoreEntry : public hash_link, public Packable
 {
 
 public:
-    static DeferredRead::DeferrableRead DeferReader;
     bool checkDeferRead(int fd) const;
 
     const char *getMD5Text() const;
@@ -171,8 +170,6 @@ public:
     void destroyMemObject();
     int checkTooSmall();
 
-    void delayAwareRead(const Comm::ConnectionPointer &conn, char *buf, int len, AsyncCall::Pointer callback);
-
     void setNoDelay (bool const);
     void lastModified(const time_t when) { lastModified_ = when; }
     /// \returns entry's 'effective' modification time
index ede6822c40ca821ea4745be9b6a3200d60d33aa7..a5d955c2840558d37a98406198064b7304a2a2bd 100644 (file)
@@ -436,7 +436,7 @@ void Adaptation::Icap::ModXact::virginConsume()
     const bool wantToPostpone = isRepeatable || canStartBypass || protectGroupBypass;
 
     // Why > 2? HttpState does not use the last bytes in the buffer
-    // because delayAwareRead() is arguably broken. See
+    // because Client::delayRead() is arguably broken. See
     // HttpStateData::maybeReadVirginBody for more details.
     if (wantToPostpone && bp.buf().spaceSize() > 2) {
         // Postponing may increase memory footprint and slow the HTTP side
index 1b3a32b027acf7ae2c25d78576dcb022f5512652..c88f221f597750074532f512042038efb142eea9 100644 (file)
  */
 
 class CallDialer;
-class AsyncCallQueue;
 
 class AsyncCall: public RefCountable
 {
 public:
     typedef RefCount <AsyncCall> Pointer;
-    friend class AsyncCallQueue;
 
     AsyncCall(int aDebugSection, int aDebugLevel, const char *aName);
     virtual ~AsyncCall();
@@ -83,7 +81,7 @@ protected:
 
     virtual void fire() = 0;
 
-    AsyncCall::Pointer theNext; // used exclusively by AsyncCallQueue
+    AsyncCall::Pointer theNext; ///< for AsyncCallList and similar lists
 
 private:
     const char *isCanceled; // set to the cancellation reason by cancel()
diff --git a/src/base/AsyncCallList.cc b/src/base/AsyncCallList.cc
new file mode 100644 (file)
index 0000000..faa0173
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#include "squid.h"
+#include "base/Assure.h"
+#include "base/AsyncCall.h"
+#include "base/AsyncCallList.h"
+
+void
+AsyncCallList::add(const AsyncCall::Pointer &call)
+{
+    Assure(call);
+    Assure(!call->Next());
+    if (tail) { // append to the existing list
+        Assure(head);
+        Assure(!tail->Next());
+        tail->setNext(call);
+        tail = call;
+    } else { // create a list from scratch
+        Assure(!head);
+        head = tail = call;
+    }
+    ++length;
+    Assure(length); // no overflows
+}
+
+AsyncCall::Pointer
+AsyncCallList::extract()
+{
+    if (!head)
+           return AsyncCallPointer();
+
+    Assure(tail);
+    Assure(length);
+    const auto call = head;
+    head = call->Next();
+    call->setNext(nullptr);
+    if (tail == call)
+        tail = nullptr;
+    --length;
+    return call;
+}
+
diff --git a/src/base/AsyncCallList.h b/src/base/AsyncCallList.h
new file mode 100644 (file)
index 0000000..8a8ad0c
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_BASE_ASYNCCALLLIST_H
+#define SQUID_BASE_ASYNCCALLLIST_H
+
+#include "base/forward.h"
+#include "base/RefCount.h"
+
+/// An efficient (but intrusive) AsyncCall storage preserving FIFO order.
+/// A given AsyncCall object may reside in at most one such storage.
+class AsyncCallList
+{
+public:
+    AsyncCallList() = default;
+    // prohibit copying: no AsyncCall should be present in two lists
+    AsyncCallList(const AsyncCallList &) = delete;
+    AsyncCallList &operator=(const AsyncCallList &) = delete;
+
+    /// stores the given async call
+    void add(const AsyncCallPointer &);
+
+    /// removes the earliest add()-ed call that is still stored (if any)
+    /// \returns the removed call (or nil)
+    /// \retval nil means the list stored no calls at extract() time
+    AsyncCallPointer extract();
+
+    /// the number of currently stored calls
+    size_t size() const { return length; }
+
+private:
+    AsyncCallPointer head; ///< the earliest still-stored call (or nil)
+    AsyncCallPointer tail; ///< the latest still-stored call (or nil)
+    size_t length = 0; ///< \copydoc size()
+};
+
+#endif /* SQUID_BASE_ASYNCCALLLIST_H */
+
index fdfb2d8473b91ca4cabb59565661bc6376b382cd..6c4f3e5737ff82b66406e43b59f7324e6fb12c02 100644 (file)
 
 AsyncCallQueue *AsyncCallQueue::TheInstance = 0;
 
-AsyncCallQueue::AsyncCallQueue(): theHead(NULL), theTail(NULL)
-{
-}
-
-void AsyncCallQueue::schedule(AsyncCall::Pointer &call)
-{
-    assert(call != NULL);
-    assert(!call->theNext);
-    if (theHead != NULL) { // append
-        assert(!theTail->theNext);
-        theTail->theNext = call;
-        theTail = call;
-    } else { // create queue from cratch
-        theHead = theTail = call;
-    }
-}
-
 // Fire all scheduled calls; returns true if at least one call was fired.
 // The calls may be added while the current call is in progress.
 bool
 AsyncCallQueue::fire()
 {
-    const bool made = theHead != NULL;
-    while (theHead) {
-        CodeContext::Reset(theHead->codeContext);
-        fireNext();
+    const auto made = scheduled.size() > 0;
+    while (const auto call = scheduled.extract()) {
+        CodeContext::Reset(call->codeContext);
+        debugs(call->debugSection, call->debugLevel, "entering " << *call);
+        call->make();
+        debugs(call->debugSection, call->debugLevel, "leaving " << *call);
     }
     if (made)
         CodeContext::Reset();
     return made;
 }
 
-void
-AsyncCallQueue::fireNext()
-{
-    AsyncCall::Pointer call = theHead;
-    theHead = call->theNext;
-    call->theNext = NULL;
-    if (theTail == call)
-        theTail = NULL;
-
-    debugs(call->debugSection, call->debugLevel, "entering " << *call);
-    call->make();
-    debugs(call->debugSection, call->debugLevel, "leaving " << *call);
-}
-
 AsyncCallQueue &
 AsyncCallQueue::Instance()
 {
index 6e13996da39653c01c45b40a81cfd7ecf0d9c712..0a31be8fcbbdebe8e77b3d8b7143e79451eb3518 100644 (file)
@@ -9,9 +9,8 @@
 #ifndef SQUID_ASYNCCALLQUEUE_H
 #define SQUID_ASYNCCALLQUEUE_H
 
-#include "base/AsyncCall.h"
-
-//class AsyncCall;
+#include "base/AsyncCallList.h"
+#include "base/forward.h"
 
 // The queue of asynchronous calls. All calls are fired during a single main
 // loop iteration until the queue is exhausted
@@ -22,18 +21,15 @@ public:
     static AsyncCallQueue &Instance();
 
     // make this async call when we get a chance
-    void schedule(AsyncCall::Pointer &call);
+    void schedule(const AsyncCallPointer &call) { scheduled.add(call); }
 
     // fire all scheduled calls; returns true if at least one was fired
     bool fire();
 
 private:
-    AsyncCallQueue();
-
-    void fireNext();
+    AsyncCallQueue() = default;
 
-    AsyncCall::Pointer theHead;
-    AsyncCall::Pointer theTail;
+    AsyncCallList scheduled; ///< calls waiting to be fire()d, in FIFO order
 
     static AsyncCallQueue *TheInstance;
 };
diff --git a/src/base/DelayedAsyncCalls.cc b/src/base/DelayedAsyncCalls.cc
new file mode 100644 (file)
index 0000000..ddd2a9f
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#include "squid.h"
+#include "base/AsyncCall.h"
+#include "base/DelayedAsyncCalls.h"
+#include "debug/Stream.h"
+
+void
+DelayedAsyncCalls::delay(const AsyncCall::Pointer &call)
+{
+    debugs(5, 3, call << " after " << deferredReads.size());
+    deferredReads.add(call);
+}
+
+void
+DelayedAsyncCalls::schedule()
+{
+    while (auto call = deferredReads.extract())
+        ScheduleCallHere(call);
+}
+
diff --git a/src/base/DelayedAsyncCalls.h b/src/base/DelayedAsyncCalls.h
new file mode 100644 (file)
index 0000000..affe2ad
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_BASE_DELAYEDASYNCCALLS_H
+#define SQUID_BASE_DELAYEDASYNCCALLS_H
+
+#include "base/AsyncCallList.h"
+
+/// a FIFO list of async calls, all to be scheduled in FIFO order (on demand via
+/// the schedule() method or automatically at object destruction time)
+class DelayedAsyncCalls
+{
+public:
+    ~DelayedAsyncCalls() { schedule(); }
+
+    /// stores the given call to schedule it at schedule() or destruction time
+    void delay(const AsyncCallPointer &);
+
+    /// schedules and forgets all async calls previously stored by delay()
+    void schedule();
+
+private:
+    /// delay()-ed calls waiting to be scheduled, in delay() call order
+    AsyncCallList deferredReads;
+};
+
+#endif /* SQUID_BASE_DELAYEDASYNCCALLS_H */
+
index 90b70855c5a073f1520e0f0f1f83d71085f3410b..9f7591d6c2184dc573cfcc28d6d3f189e413f7c1 100644 (file)
@@ -15,6 +15,8 @@ libbase_la_SOURCES = \
        Assure.h \
        AsyncCall.cc \
        AsyncCall.h \
+       AsyncCallList.cc \
+       AsyncCallList.h \
        AsyncCallQueue.cc \
        AsyncCallQueue.h \
        AsyncCbdataCalls.h \
@@ -30,6 +32,8 @@ libbase_la_SOURCES = \
        ClpMap.h \
        CodeContext.cc \
        CodeContext.h \
+       DelayedAsyncCalls.cc \
+       DelayedAsyncCalls.h \
        EnumIterator.h \
        File.cc \
        File.h \
index 45354740492544f5d50f3b56fffce1d14d6172cb..ba5b57519a6847af49a3b27320c41466d7079fd4 100644 (file)
@@ -9,10 +9,12 @@
 #ifndef SQUID_SRC_BASE_FORWARD_H
 #define SQUID_SRC_BASE_FORWARD_H
 
+class AsyncCall;
 class AsyncCallQueue;
 class AsyncJob;
 class CallDialer;
 class CodeContext;
+class DelayedAsyncCalls;
 class ScopedId;
 class BadOptionalAccess;
 class Raw;
@@ -26,6 +28,7 @@ template<class Job> class JobWait;
 
 typedef CbcPointer<AsyncJob> AsyncJobPointer;
 typedef RefCount<CodeContext> CodeContextPointer;
+using AsyncCallPointer = RefCount<AsyncCall>;
 
 #endif /* SQUID_SRC_BASE_FORWARD_H */
 
index 530dbbabc493714a564aaa0ca92104a9ed4b5ba2..bf3bfd77de55c715f3aeabe304ec4fc870cb07fc 100644 (file)
@@ -1025,6 +1025,15 @@ Client::adjustBodyBytesRead(const int64_t delta)
     Must(bodyBytesRead >= 0);
 }
 
+void
+Client::delayRead()
+{
+    using DeferredReadDialer = NullaryMemFunT<Client>;
+    AsyncCall::Pointer call = asyncCall(11, 5, "Client::noteDelayAwareReadChance",
+            DeferredReadDialer(this, &Client::noteDelayAwareReadChance));
+    entry->mem().delayRead(call);
+}
+
 void
 Client::addVirginReplyBody(const char *data, ssize_t len)
 {
index be79b395e4af6a793518f76016ea2e223495a9ca..8b2598324a0f4f1de46e8996faffff4777c6533a 100644 (file)
@@ -113,6 +113,10 @@ protected:
     /// whether we may receive more virgin response body bytes
     virtual bool mayReadVirginReplyBody() const = 0;
 
+    /// Called when a previously delayed dataConnection() read may be possible.
+    /// \sa delayRead()
+    virtual void noteDelayAwareReadChance() = 0;
+
     /// Entry-dependent callbacks use this check to quit if the entry went bad
     bool abortOnBadEntry(const char *abortReason);
 
@@ -160,6 +164,10 @@ protected:
 
     void adjustBodyBytesRead(const int64_t delta);
 
+    /// Defer reading until it is likely to become possible.
+    /// Eventually, noteDelayAwareReadChance() will be called.
+    void delayRead();
+
     // These should be private
     int64_t currentOffset = 0;  /**< Our current offset in the StoreEntry */
     MemBuf *responseBodyBuffer = nullptr; /**< Data temporarily buffered for ICAP */
index 3442f793b0d58842304cb7ab52a5c7589b06ebb6..afd9cd5149a2c8028558792d6dfa9412231bd543 100644 (file)
@@ -10,6 +10,8 @@
 
 #include "squid.h"
 #include "acl/FilledChecklist.h"
+#include "base/AsyncJobCalls.h"
+#include "base/Range.h"
 #include "client_side.h"
 #include "clients/FtpClient.h"
 #include "comm/ConnOpener.h"
@@ -902,6 +904,13 @@ Ftp::Client::dataConnection() const
     return data.conn;
 }
 
+void
+Ftp::Client::noteDelayAwareReadChance()
+{
+    data.read_pending = false;
+    maybeReadVirginBody();
+}
+
 void
 Ftp::Client::maybeReadVirginBody()
 {
@@ -930,9 +939,16 @@ Ftp::Client::maybeReadVirginBody()
 
     debugs(9,5,"queueing read on FD " << data.conn->fd);
 
-    typedef CommCbMemFunT<Client, CommIoCbParams> Dialer;
-    entry->delayAwareRead(data.conn, data.readBuf->space(), read_sz,
-                          JobCallback(9, 5, Dialer, this, Ftp::Client::dataRead));
+    const auto amountToRead = entry->bytesWanted(Range<size_t>(0, read_sz));
+
+    if (amountToRead <= 0) {
+        delayRead();
+        return;
+    }
+
+    using ReadDialer = CommCbMemFunT<Client, CommIoCbParams>;
+    AsyncCall::Pointer readCallback = JobCallback(9, 5, ReadDialer, this, Client::dataRead);
+    comm_read(data.conn, data.readBuf->space(), amountToRead, readCallback);
 }
 
 void
index 4b2dd61d5472a7a8a29b82d5a09b70eb536ab367..10c0e176ff447afdef68a144ac9c1e5253f945c4 100644 (file)
@@ -186,6 +186,7 @@ protected:
     virtual bool doneWithServer() const;
     virtual const Comm::ConnectionPointer & dataConnection() const;
     virtual void abortAll(const char *reason);
+    virtual void noteDelayAwareReadChance();
 
     virtual Http::StatusCode failedHttpStatus(err_type &error);
     void ctrlClosed(const CommCloseCbParams &io);
index d5b30528b9322107f999c2dd03b0b1bcaf38fc52..4bfab57d6cf7f60267702418d9f7ba8123fe6f75 100644 (file)
@@ -18,7 +18,6 @@
 #include "comm/Read.h"
 #include "comm/TcpAcceptor.h"
 #include "comm/Write.h"
-#include "CommRead.h"
 #include "compat/cmsg.h"
 #include "DescriptorSet.h"
 #include "event.h"
@@ -808,8 +807,8 @@ comm_close_complete(const FdeCbParams &params)
  * + call read handlers with ERR_CLOSING
  * + call closing handlers
  *
- * NOTE: Comm::ERR_CLOSING will NOT be called for CommReads' sitting in a
- * DeferredReadManager.
+ * A deferred reader has no Comm read handler mentioned above. To stay in sync,
+ * such a reader must register a Comm closing handler.
  */
 void
 _comm_close(int fd, char const *file, int line)
@@ -939,6 +938,8 @@ comm_add_close_handler(int fd, AsyncCall::Pointer &call)
 //    for (c = fd_table[fd].closeHandler; c; c = c->next)
 //        assert(c->handler != handler || c->data != data);
 
+    // TODO: Consider enhancing AsyncCallList to support random-access close
+    // handlers, perhaps after upgrading the remaining legacy CLCB handlers.
     call->setNext(fd_table[fd].closeHandler);
 
     fd_table[fd].closeHandler = call;
@@ -1644,149 +1645,6 @@ commHalfClosedReader(const Comm::ConnectionPointer &conn, char *, size_t size, C
     commPlanHalfClosedCheck(); // make sure this fd will be checked again
 }
 
-CommRead::CommRead() : conn(NULL), buf(NULL), len(0), callback(NULL) {}
-
-CommRead::CommRead(const Comm::ConnectionPointer &c, char *buf_, int len_, AsyncCall::Pointer &callback_)
-    : conn(c), buf(buf_), len(len_), callback(callback_) {}
-
-DeferredRead::DeferredRead () : theReader(NULL), theContext(NULL), theRead(), cancelled(false) {}
-
-DeferredRead::DeferredRead (DeferrableRead *aReader, void *data, CommRead const &aRead) : theReader(aReader), theContext (data), theRead(aRead), cancelled(false) {}
-
-DeferredReadManager::~DeferredReadManager()
-{
-    flushReads();
-    assert (deferredReads.empty());
-}
-
-/* explicit instantiation required for some systems */
-
-/// \cond AUTODOCS_IGNORE
-template cbdata_type CbDataList<DeferredRead>::CBDATA_CbDataList;
-/// \endcond
-
-void
-DeferredReadManager::delayRead(DeferredRead const &aRead)
-{
-    debugs(5, 3, "Adding deferred read on " << aRead.theRead.conn);
-    CbDataList<DeferredRead> *temp = deferredReads.push_back(aRead);
-
-    // We have to use a global function as a closer and point to temp
-    // instead of "this" because DeferredReadManager is not a job and
-    // is not even cbdata protected
-    // XXX: and yet we use cbdata protection functions on it??
-    AsyncCall::Pointer closer = commCbCall(5,4,
-                                           "DeferredReadManager::CloseHandler",
-                                           CommCloseCbPtrFun(&CloseHandler, temp));
-    comm_add_close_handler(aRead.theRead.conn->fd, closer);
-    temp->element.closer = closer; // remember so that we can cancel
-}
-
-void
-DeferredReadManager::CloseHandler(const CommCloseCbParams &params)
-{
-    if (!cbdataReferenceValid(params.data))
-        return;
-
-    CbDataList<DeferredRead> *temp = (CbDataList<DeferredRead> *)params.data;
-
-    temp->element.closer = NULL;
-    if (temp->element.theRead.conn) {
-        temp->element.theRead.conn->noteClosure();
-        temp->element.theRead.conn = nullptr;
-    }
-    temp->element.markCancelled();
-}
-
-DeferredRead
-DeferredReadManager::popHead(CbDataListContainer<DeferredRead> &deferredReads)
-{
-    assert (!deferredReads.empty());
-
-    DeferredRead &read = deferredReads.head->element;
-
-    // NOTE: at this point the connection has been paused/stalled for an unknown
-    //       amount of time. We must re-validate that it is active and usable.
-
-    // If the connection has been closed already. Cancel this read.
-    if (!fd_table || !Comm::IsConnOpen(read.theRead.conn)) {
-        if (read.closer != NULL) {
-            read.closer->cancel("Connection closed before.");
-            read.closer = NULL;
-        }
-        read.markCancelled();
-    }
-
-    if (!read.cancelled) {
-        comm_remove_close_handler(read.theRead.conn->fd, read.closer);
-        read.closer = NULL;
-    }
-
-    DeferredRead result = deferredReads.pop_front();
-
-    return result;
-}
-
-void
-DeferredReadManager::kickReads(int const count)
-{
-    /* if we had CbDataList::size() we could consolidate this and flushReads */
-
-    if (count < 1) {
-        flushReads();
-        return;
-    }
-
-    size_t remaining = count;
-
-    while (!deferredReads.empty() && remaining) {
-        DeferredRead aRead = popHead(deferredReads);
-        kickARead(aRead);
-
-        if (!aRead.cancelled)
-            --remaining;
-    }
-}
-
-void
-DeferredReadManager::flushReads()
-{
-    CbDataListContainer<DeferredRead> reads;
-    reads = deferredReads;
-    deferredReads = CbDataListContainer<DeferredRead>();
-
-    // XXX: For fairness this SHOULD randomize the order
-    while (!reads.empty()) {
-        DeferredRead aRead = popHead(reads);
-        kickARead(aRead);
-    }
-}
-
-void
-DeferredReadManager::kickARead(DeferredRead const &aRead)
-{
-    if (aRead.cancelled)
-        return;
-
-    // TODO: This check still allows theReader call with a closed theRead.conn.
-    // If a delayRead() caller has a close connection handler, then such a call
-    // would be useless and dangerous. If a delayRead() caller does not have it,
-    // then the caller will get stuck when an external connection closure makes
-    // aRead.cancelled (checked above) true.
-    if (Comm::IsConnOpen(aRead.theRead.conn) && fd_table[aRead.theRead.conn->fd].closing())
-        return;
-
-    debugs(5, 3, "Kicking deferred read on " << aRead.theRead.conn);
-
-    aRead.theReader(aRead.theContext, aRead.theRead);
-}
-
-void
-DeferredRead::markCancelled()
-{
-    cancelled = true;
-}
-
 int
 CommSelectEngine::checkEvents(int timeout)
 {
index 457847a4695e13b0ef9e701eddbcf0b20fa6e322..2ef5a75e52ed23e70cf132953ac958d7faea9a34 100644 (file)
@@ -70,7 +70,7 @@ private:
         AggregateId (RefCount<Aggregate>);
         virtual int bytesWanted (int min, int max) const;
         virtual void bytesIn(int qty);
-        virtual void delayRead(DeferredRead const &);
+        virtual void delayRead(const AsyncCallPointer &);
 
     private:
         RefCount<Aggregate> theAggregate;
@@ -239,7 +239,7 @@ protected:
 };
 
 void
-Aggregate::AggregateId::delayRead(DeferredRead const &aRead)
+Aggregate::AggregateId::delayRead(const AsyncCall::Pointer &aRead)
 {
     theAggregate->delayRead(aRead);
 }
@@ -475,7 +475,6 @@ DelayPools::InitDelayData()
 void
 DelayPools::FreeDelayData()
 {
-    eventDelete(DelayPools::Update, NULL);
     delete[] DelayPools::delay_data;
     pools_ = 0;
 }
@@ -483,7 +482,9 @@ DelayPools::FreeDelayData()
 void
 DelayPools::Update(void *)
 {
-    if (!pools())
+    // To prevent stuck transactions, stop updates only after no new transactions can
+    // register (because the pools were disabled) and the last registered transaction is gone.
+    if (!pools() && toUpdate.empty())
         return;
 
     eventAdd("DelayPools::Update", Update, NULL, 1.0, 1);
index 2006b4183a41f03394d47404be7fc7c72f7c6449..2e16cd96ed4db491fd19fe6313265b9389ae43a8 100644 (file)
@@ -9,6 +9,7 @@
 /* DEBUG: section 10    Gopher */
 
 #include "squid.h"
+#include "base/AsyncCbdataCalls.h"
 #include "comm.h"
 #include "comm/Read.h"
 #include "comm/Write.h"
@@ -102,6 +103,9 @@ public:
 
     ~GopherStateData();
 
+    /// queues or defers a read call
+    static void DelayAwareRead(GopherStateData *);
+
     /// URL for icon to display (or nil), given the Gopher item-type code.
     /// The returned c-string is invalidated by the next call to this function.
     const char *iconUrl(char);
@@ -806,12 +810,33 @@ gopherReadReply(const Comm::ConnectionPointer &conn, char *buf, size_t len, Comm
         } else {
             entry->append(buf, len);
         }
-        AsyncCall::Pointer call = commCbCall(5,4, "gopherReadReply",
-                                             CommIoCbPtrFun(gopherReadReply, gopherState));
-        comm_read(conn, buf, read_sz, call);
+        GopherStateData::DelayAwareRead(gopherState);
     }
 }
 
+void
+GopherStateData::DelayAwareRead(GopherStateData *gopherState)
+{
+    const auto &conn = gopherState->serverConn;
+
+    if (!Comm::IsConnOpen(conn) || fd_table[conn->fd].closing()) {
+        debugs(10, 3, "will not read from " << conn);
+        return;
+    }
+
+    const auto amountToRead = gopherState->entry->bytesWanted(Range<size_t>(0, BUFSIZ));
+
+    if (amountToRead <= 0) {
+        AsyncCall::Pointer delayCall = asyncCall(10, 3, "GopherStateData::DelayAwareRead",
+                                                 cbdataDialer(&GopherStateData::DelayAwareRead, gopherState));
+        gopherState->entry->mem().delayRead(delayCall);
+        return;
+    }
+
+    AsyncCall::Pointer readCall = commCbCall(5, 5, "gopherReadReply", CommIoCbPtrFun(gopherReadReply, gopherState));
+    comm_read(conn, gopherState->replybuf, amountToRead, readCall);
+}
+
 /**
  * This will be called when request write is complete. Schedule read of reply.
  */
@@ -879,10 +904,7 @@ gopherSendComplete(const Comm::ConnectionPointer &conn, char *, size_t size, Com
         entry->flush();
     }
 
-    /* Schedule read reply. */
-    AsyncCall::Pointer call =  commCbCall(5,5, "gopherReadReply",
-                                          CommIoCbPtrFun(gopherReadReply, gopherState));
-    entry->delayAwareRead(conn, gopherState->replybuf, BUFSIZ, call);
+    GopherStateData::DelayAwareRead(gopherState);
 }
 
 /**
index a7a70ffc505b87f8c42d0b20c597c802df9a4fd1..b587606cdddcbd89d6265ddbf21853351db8c958 100644 (file)
@@ -16,6 +16,7 @@
 #include "squid.h"
 #include "acl/FilledChecklist.h"
 #include "base/AsyncJobCalls.h"
+#include "base/DelayedAsyncCalls.h"
 #include "base/Raw.h"
 #include "base/TextException.h"
 #include "base64.h"
@@ -24,7 +25,6 @@
 #include "comm/Connection.h"
 #include "comm/Read.h"
 #include "comm/Write.h"
-#include "CommRead.h"
 #include "error/Detail.h"
 #include "errorpage.h"
 #include "fd.h"
@@ -1164,12 +1164,11 @@ HttpStateData::persistentConnStatus() const
     return statusIfComplete();
 }
 
-static void
-readDelayed(void *context, CommRead const &)
+void
+HttpStateData::noteDelayAwareReadChance()
 {
-    HttpStateData *state = static_cast<HttpStateData*>(context);
-    state->flags.do_next_read = true;
-    state->maybeReadVirginBody();
+    flags.do_next_read = true;
+    maybeReadVirginBody();
 }
 
 void
@@ -1207,9 +1206,7 @@ HttpStateData::readReply(const CommIoCbParams &io)
     rd.size = entry->bytesWanted(Range<size_t>(0, inBuf.spaceSize()));
 
     if (rd.size <= 0) {
-        assert(entry->mem_obj);
-        AsyncCall::Pointer nilCall;
-        entry->mem_obj->delayRead(DeferredRead(readDelayed, this, CommRead(io.conn, NULL, 0, nilCall)));
+        delayRead();
         return;
     }
 
index c4161211f86ed68ec4d33a596c0f59af6d82601a..2c369786b18126fb934db2634528978438458d2a 100644 (file)
@@ -75,6 +75,9 @@ public:
     void processSurrogateControl(HttpReply *);
 
 protected:
+    /* Client API */
+    virtual void noteDelayAwareReadChance();
+
     void processReply();
     void proceedAfter1xx();
     void handle1xx(HttpReply *msg);
index 5c9f7dcc33a2ac8ecc3f634ef48a3cd8db530818..4d884b51c488d78fa17f7c240984352f104b2f39 100644 (file)
@@ -12,6 +12,7 @@
 #include "AccessLogEntry.h"
 #include "base/AsyncJobCalls.h"
 #include "base/TextException.h"
+#include "comm.h"
 #include "comm/Connection.h"
 #include "CommCalls.h"
 #include "errorpage.h"
index 74d95ea9075d446d4d030c838ddd922763bf21b3..f2b043e2e55a4d2380fe5b0ee8a28bf114b18482 100644 (file)
@@ -11,6 +11,7 @@
 #include "squid.h"
 #include "base/AsyncCbdataCalls.h"
 #include "base/TextException.h"
+#include "comm.h"
 #include "comm/Connection.h"
 #include "comm/Write.h"
 #include "CommCalls.h"
index a9980f6d2f4f924f452841a738035705ad81d987..58ae4dbe7369516992af7ae0518cb22c7cd4082f 100644 (file)
@@ -206,44 +206,6 @@ StoreEntry::getMD5Text() const
     return storeKeyText((const cache_key *)key);
 }
 
-#include "comm.h"
-
-void
-StoreEntry::DeferReader(void *theContext, CommRead const &aRead)
-{
-    StoreEntry *anEntry = (StoreEntry *)theContext;
-    anEntry->delayAwareRead(aRead.conn,
-                            aRead.buf,
-                            aRead.len,
-                            aRead.callback);
-}
-
-void
-StoreEntry::delayAwareRead(const Comm::ConnectionPointer &conn, char *buf, int len, AsyncCall::Pointer callback)
-{
-    size_t amountToRead = bytesWanted(Range<size_t>(0, len));
-    /* sketch: readdeferer* = getdeferer.
-     * ->deferRead (fd, buf, len, callback, DelayAwareRead, this)
-     */
-
-    if (amountToRead <= 0) {
-        assert (mem_obj);
-        mem_obj->delayRead(DeferredRead(DeferReader, this, CommRead(conn, buf, len, callback)));
-        return;
-    }
-
-    if (fd_table[conn->fd].closing()) {
-        // Readers must have closing callbacks if they want to be notified. No
-        // readers appeared to care around 2009/12/14 as they skipped reading
-        // for other reasons. Closing may already be true at the delyaAwareRead
-        // call time or may happen while we wait after delayRead() above.
-        debugs(20, 3, "will not read from closing " << conn << " for " << callback);
-        return; // the read callback will never be called
-    }
-
-    comm_read(conn, buf, amountToRead, callback);
-}
-
 size_t
 StoreEntry::bytesWanted (Range<size_t> const aRange, bool ignoreDelayPools) const
 {
index 23942a09bb0b44b6393af57ff099d07440a4a832..5624a4476e34b336e8fe3112e9830ae9d775b6ab 100644 (file)
@@ -20,7 +20,7 @@
 DelayId::DelayId(): pool_(0), compositeId(NULL), markedAsNoDelay(false) {}
 DelayId::~DelayId() {}
 
-void DelayId::delayRead(DeferredRead const&) STUB_NOP
+void DelayId::delayRead(const AsyncCallPointer &) STUB_NOP
 void BandwidthBucket::refillBucket() STUB
 bool BandwidthBucket::applyQuota(int &, Comm::IoCallback *) STUB_RETVAL(false)
 BandwidthBucket *BandwidthBucket::SelectBucket(fde *) STUB_RETVAL(nullptr)
index e9dce01ce1a8bd4a16dcbae8831651ec39b8f8cf..990b5b51d08fdadaa1412534c41a20a08bd09d06 100644 (file)
@@ -38,7 +38,7 @@ const char *MemObject::storeId() const STUB_RETVAL(NULL)
 const char *MemObject::logUri() const STUB_RETVAL(NULL)
 void MemObject::setUris(char const *, char const *, const HttpRequestMethod &) STUB
 void MemObject::reset() STUB
-void MemObject::delayRead(DeferredRead const &) STUB
+void MemObject::delayRead(const AsyncCallPointer &) STUB
 bool MemObject::readAheadPolicyCanRead() const STUB_RETVAL(false)
 void MemObject::setNoDelay(bool const) STUB
 MemObject::~MemObject() STUB
index f86e93356ef81a578af62d61fc08f69804531c30..25de5d06405e7f2a977318ceb1467d315192210d 100644 (file)
 // void comm_read(const Comm::ConnectionPointer &, char *, int, IOCB *, void *) STUB
 // void comm_read(const Comm::ConnectionPointer &, char*, int, AsyncCall::Pointer &) STUB
 
-/* should be in stub_CommRead */
-#include "CommRead.h"
-CommRead::CommRead(const Comm::ConnectionPointer &, char *, int, AsyncCall::Pointer &) STUB
-CommRead::CommRead() STUB
-DeferredReadManager::~DeferredReadManager() STUB
-DeferredRead::DeferredRead(DeferrableRead *, void *, CommRead const &) STUB
-void DeferredReadManager::delayRead(DeferredRead const &) STUB
-void DeferredReadManager::kickReads(int const) STUB
+/* should be in stub_libbase */
+#include "base/DelayedAsyncCalls.h"
+void DelayedAsyncCalls::delay(const AsyncCall::Pointer &) STUB
+void DelayedAsyncCalls::schedule() STUB
 
 #include "comm.h"
 bool comm_iocallbackpending(void) STUB_RETVAL(false)
index 2bf80f1ece7aa1d6e46ad763c692a9b40358fbc5..72cced6b3a02a6c854d4bae3523f5e2490230e33 100644 (file)
@@ -64,7 +64,6 @@ bool StoreEntry::timestampsSet() STUB_RETVAL(false)
 void StoreEntry::unregisterAbortCallback(const char *) STUB
 void StoreEntry::destroyMemObject() STUB
 int StoreEntry::checkTooSmall() STUB_RETVAL(0)
-void StoreEntry::delayAwareRead(const Comm::ConnectionPointer&, char *, int, AsyncCall::Pointer) STUB
 void StoreEntry::setNoDelay (bool const) STUB
 bool StoreEntry::modifiedSince(const time_t, const int) const STUB_RETVAL(false)
 bool StoreEntry::hasIfMatchEtag(const HttpRequest &) const STUB_RETVAL(false)
index 7b1accdc2b2390f3f76fd664d8b3a4f1da510a1f..b956a075bde37775137a723c7ee4b376e163cd93 100644 (file)
@@ -863,7 +863,7 @@ TunnelStateData::copyRead(Connection &from, IOCB *completion)
     int bw = from.bytesWanted(1, SQUID_TCP_SO_RCVBUF);
     // XXX: Delay pools must not delay client-to-Squid traffic (i.e. when
     // from.readPendingFunc is tunnelDelayedClientRead()).
-    // XXX: Bug #4913: Use DeferredRead instead.
+    // XXX: Bug #4913: For delay pools, use delayRead() API instead.
     if (bw == 1 && ++from.delayedLoops < 10) {
         from.readPending = this;
         eventAdd("tunnelDelayedServerRead", from.readPendingFunc, from.readPending, 0.3, true);