]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
This change should fix bug #1637.
authorrousskov <>
Thu, 12 Apr 2007 20:07:10 +0000 (20:07 +0000)
committerrousskov <>
Thu, 12 Apr 2007 20:07:10 +0000 (20:07 +0000)
Server transactions keep refcounted pointer to FwdState that launched them.
Server transactions use the pointer to call FwdState upon completion or
abnormal termination. If nobody else points to the FwdState object after the
transaction is done, the object gets destroyed, even if there are other
servers to be tried.

To avoid FwdState destruction when selecting the next server, FwdState must
keep a refcounted pointer to self. That pointer should be created before the
server-selection loop and cleared after the loop. Currently, we create the
pointer when FwdState is created (which is earlier than needed) and clear it
in various places (which may be late and is probably buggy).

Based on Christos Tsantilas' work.

src/forward.cc
src/forward.h

index 7d114230e7b4e1cca28c4f5a9871e8b3faf26af8..5b0fc156fc082c5b5673cd6f7cf770a0852c7937 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: forward.cc,v 1.154 2007/04/06 04:50:06 rousskov Exp $
+ * $Id: forward.cc,v 1.155 2007/04/12 14:07:10 rousskov Exp $
  *
  * DEBUG: section 17    Request Forwarding
  * AUTHOR: Duane Wessels
@@ -99,10 +99,24 @@ FwdState::FwdState(int fd, StoreEntry * e, HttpRequest * r)
 
     ;
     EBIT_SET(e->flags, ENTRY_FWD_HDR_WAIT);
+}
+
+// Called once, right after object creation, when it is safe to set self
+void FwdState::start(Pointer aSelf) {
+    // Protect ourselves from being destroyed when the only Server pointing
+    // to us is gone (while we expect to talk to more Servers later).
+    // Once we set self, we are responsible for clearing it when we do not
+    // expect to talk to any servers.
+    self = aSelf; // refcounted
+
+    // We hope that either the store entry aborts or peer is selected.
+    // Otherwise we are going to leak our object.
 
-    self = this;       // refcounted
+    storeRegisterAbort(entry, FwdState::abort, this);
+    peerSelect(request, entry, fwdStartCompleteWrapper, this);
 
-    storeRegisterAbort(e, FwdState::abort, this);
+    // TODO: set self _after_ the peer is selected because we do not need 
+    // self until we start talking to some Server.
 }
 
 void
@@ -245,9 +259,8 @@ FwdState::fwdStart(int client_fd, StoreEntry *entry, HttpRequest *request)
         return;
 
     default:
-        FwdState *fwd = new FwdState(client_fd, entry, request);
-       fwd->flags.forward_completed = 0;
-        peerSelect(request, entry, fwdStartCompleteWrapper, fwd);
+        FwdState::Pointer fwd = new FwdState(client_fd, entry, request);
+        fwd->start(fwd);
         return;
     }
 
@@ -314,14 +327,6 @@ FwdState::complete()
 
         storeEntryReset(e);
 
-        /*
-         * Need to re-establish the self-reference here since we'll
-         * be trying to forward the request again.  Otherwise the
-         * ref count could go to zero before a connection is
-         * established.
-         */
-        self = this;   // refcounted
-
         startComplete(servers);
     } else {
         debug(17, 3) ("fwdComplete: not re-forwarding status %d\n",
@@ -330,6 +335,7 @@ FwdState::complete()
        entry->complete();
        if (server_fd < 0)
                completed();
+        self = NULL; // refcounted
     }
 }
 
@@ -937,12 +943,6 @@ FwdState::dispatch()
             break;
         }
     }
-
-    /*
-     * remove our self-refcount now that we've handed off the request
-     * to a server-side module
-     */
-    self = NULL;
 }
 
 int
index 16451ec041582f891aab7ef75e180b868876ce41..19b796148009143ca06ad13d984e1a23f4c682bd 100644 (file)
@@ -22,7 +22,6 @@ class FwdState : public RefCountable
 
 public:
     typedef RefCount<FwdState> Pointer;
-    FwdState(int fd, StoreEntry *, HttpRequest *);
     ~FwdState();
     static void initModule();
     static void RegisterWithCacheManager(CacheManager & manager);
@@ -57,6 +56,10 @@ public:
     static void serversFree(FwdServer **);
 
 private:
+    // hidden for safer management of self; use static fwdStart
+    FwdState(int fd, StoreEntry *, HttpRequest *);
+    void start(Pointer aSelf);
+
     static void logReplyStatus(int tries, http_status status);
     void completed();