1 /*
2  * Copyright (C) 1996-2021 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 #ifndef SQUID_PCONN_H
10 #define SQUID_PCONN_H
11 
12 #include "base/CbcPointer.h"
13 #include "base/RunnersRegistry.h"
14 #include "mgr/forward.h"
15 
16 #include <set>
17 
18 /**
19  \defgroup PConnAPI Persistent Connection API
20  \ingroup Component
21  *
22  \todo CLEANUP: Break multiple classes out of the generic pconn.h header
23  */
24 
25 class PconnPool;
26 class PeerPoolMgr;
27 
28 #include "cbdata.h"
29 #include "hash.h"
30 /* for IOCB */
31 #include "comm.h"
32 
33 /// \ingroup PConnAPI
34 #define PCONN_HIST_SZ (1<<16)
35 
36 /** \ingroup PConnAPI
37  * A list of connections currently open to a particular destination end-point.
38  */
39 class IdleConnList: public hash_link, private IndependentRunner
40 {
41     CBDATA_CLASS(IdleConnList);
42 
43 public:
44     IdleConnList(const char *key, PconnPool *parent);
45     ~IdleConnList();
46 
47     /// Pass control of the connection to the idle list.
48     void push(const Comm::ConnectionPointer &conn);
49 
50     /// get first conn which is not pending read fd.
51     Comm::ConnectionPointer pop();
52 
53     /** Search the list for a connection which matches the 'key' details
54      * and pop it off the list.
55      * The list is created based on remote IP:port hash. This further filters
56      * the choices based on specific local-end details requested.
57      * If nothing usable is found the a nil pointer is returned.
58      */
59     Comm::ConnectionPointer findUseable(const Comm::ConnectionPointer &key);
60 
61     void clearHandlers(const Comm::ConnectionPointer &conn);
62 
count()63     int count() const { return size_; }
64     void closeN(size_t count);
65 
66     // IndependentRunner API
67     virtual void endingShutdown();
68 private:
69     bool isAvailable(int i) const;
70     bool removeAt(int index);
71     int findIndexOf(const Comm::ConnectionPointer &conn) const;
72     void findAndClose(const Comm::ConnectionPointer &conn);
73     static IOCB Read;
74     static CTCB Timeout;
75 
76 private:
77     /** List of connections we are holding.
78      * Sorted as FIFO list for most efficient speeds on pop() and findUsable()
79      * The worst-case pop() and scans occur on timeout and link closure events
80      * where timing is less critical. Occasional slow additions are okay.
81      */
82     Comm::ConnectionPointer *theList_;
83 
84     /// Number of entries theList can currently hold without re-allocating (capacity).
85     int capacity_;
86     ///< Number of in-use entries in theList
87     int size_;
88 
89     /** The pool containing this sub-list.
90      * The parent performs all stats accounting, and
91      * will delete us when it dies. It persists for the
92      * full duration of our existence.
93      */
94     PconnPool *parent_;
95 
96     char fakeReadBuf_[4096]; // TODO: kill magic number.
97 };
98 
99 #include "ip/forward.h"
100 
101 class StoreEntry;
102 class IdleConnLimit;
103 
104 /* for hash_table */
105 #include "hash.h"
106 
107 /** \ingroup PConnAPI
108  * Manages idle persistent connections to a caller-defined set of
109  * servers (e.g., all HTTP servers). Uses a collection of IdleConnLists
110  * internally to list the individual open connections to each server.
111  * Controls lists existence and limits the total number of
112  * idle connections across the collection.
113  */
114 class PconnPool
115 {
116 
117 public:
118     PconnPool(const char *aDescription, const CbcPointer<PeerPoolMgr> &aMgr);
119     ~PconnPool();
120 
121     void moduleInit();
122     void push(const Comm::ConnectionPointer &serverConn, const char *domain);
123 
124     /**
125      * Returns either a pointer to a popped connection to dest or nil.
126      * Closes the connection before returning its pointer unless keepOpen.
127      *
128      * A caller with a non-retriable transaction should set keepOpen to false
129      * and call pop() anyway, even though the caller does not want a pconn.
130      * This forces us to close an available persistent connection, avoiding
131      * creating a growing number of open connections when many transactions
132      * create (and push) persistent connections but are not retriable and,
133      * hence, do not need to pop a connection.
134      */
135     Comm::ConnectionPointer pop(const Comm::ConnectionPointer &dest, const char *domain, bool keepOpen);
136     void count(int uses);
137     void dumpHist(StoreEntry *e) const;
138     void dumpHash(StoreEntry *e) const;
139     void unlinkList(IdleConnList *list);
140     void noteUses(int uses);
141     /// closes any n connections, regardless of their destination
142     void closeN(int n);
count()143     int count() const { return theCount; }
noteConnectionAdded()144     void noteConnectionAdded() { ++theCount; }
noteConnectionRemoved()145     void noteConnectionRemoved() { assert(theCount > 0); --theCount; }
146 
147     // sends an async message to the pool manager, if any
148     void notifyManager(const char *reason);
149 
150 private:
151 
152     static const char *key(const Comm::ConnectionPointer &destLink, const char *domain);
153 
154     int hist[PCONN_HIST_SZ];
155     hash_table *table;
156     const char *descr;
157     CbcPointer<PeerPoolMgr> mgr; ///< optional pool manager (for notifications)
158     int theCount; ///< the number of pooled connections
159 };
160 
161 class StoreEntry;
162 class PconnPool;
163 
164 /** \ingroup PConnAPI
165  * The global registry of persistent connection pools.
166  */
167 class PconnModule
168 {
169 
170 public:
171     /** the module is a singleton until we have instance based cachemanager
172      * management
173      */
174     static PconnModule * GetInstance();
175     /** A thunk to the still C like CacheManager callback api. */
176     static void DumpWrapper(StoreEntry *e);
177 
178     PconnModule();
179     void registerWithCacheManager(void);
180 
181     void add(PconnPool *);
182     void remove(PconnPool *); ///< unregister and forget about this pool object
183 
184     OBJH dump;
185 
186 private:
187     typedef std::set<PconnPool*> Pools; ///< unordered PconnPool collection
188     Pools pools; ///< all live pools
189 
190     static PconnModule * instance;
191 };
192 
193 #endif /* SQUID_PCONN_H */
194 
195