]> git.ipfire.org Git - thirdparty/squid.git/blame - src/store_client.cc
STORE.C SPLIT
[thirdparty/squid.git] / src / store_client.cc
CommitLineData
f09f5b26 1#include "squid.h"
2
3static void storeClientCopy2(StoreEntry * e, store_client * sc);
4static SIH storeClientCopyFileOpened;
5static void storeClientCopyFileRead(store_client * sc);
6static DRCB storeClientCopyHandleRead;
7
8/* check if there is any client waiting for this object at all */
9/* return 1 if there is at least one client */
10int
11storeClientWaiting(const StoreEntry * e)
12{
13 MemObject *mem = e->mem_obj;
14 store_client *sc;
15 for (sc = mem->clients; sc; sc = sc->next) {
16 if (sc->callback_data != NULL)
17 return 1;
18 }
19 return 0;
20}
21
22store_client *
23storeClientListSearch(const MemObject * mem, void *data)
24{
25 store_client *sc;
26 for (sc = mem->clients; sc; sc = sc->next) {
27 if (sc->callback_data == data)
28 break;
29 }
30 return sc;
31}
32
33/* add client with fd to client list */
34void
35storeClientListAdd(StoreEntry * e, void *data)
36{
37 MemObject *mem = e->mem_obj;
38 store_client **T;
39 store_client *sc;
40 assert(mem);
41 if (storeClientListSearch(mem, data) != NULL)
42 return;
43 mem->nclients++;
44 sc = memAllocate(MEM_STORE_CLIENT, 1);
45 cbdataAdd(sc, MEM_STORE_CLIENT); /* sc is callback_data for file_read */
46 sc->callback_data = data;
47 sc->seen_offset = 0;
48 sc->copy_offset = 0;
49 sc->swapin_fd = -1;
50 sc->disk_op_in_progress = 0;
51 sc->mem = mem;
52 if (e->store_status == STORE_PENDING && mem->swapout.fd == -1)
53 sc->type = STORE_MEM_CLIENT;
54 else
55 sc->type = STORE_DISK_CLIENT;
56 for (T = &mem->clients; *T; T = &(*T)->next);
57 *T = sc;
58}
59
60/* copy bytes requested by the client */
61void
62storeClientCopy(StoreEntry * e,
63 off_t seen_offset,
64 off_t copy_offset,
65 size_t size,
66 char *buf,
67 STCB * callback,
68 void *data)
69{
70 store_client *sc;
71 static int recurse_detect = 0;
72 assert(e->store_status != STORE_ABORTED);
73 assert(recurse_detect < 3); /* could == 1 for IMS not modified's */
74 debug(20, 3) ("storeClientCopy: %s, seen %d, want %d, size %d, cb %p, cbdata %p\n",
75 storeKeyText(e->key),
76 (int) seen_offset,
77 (int) copy_offset,
78 (int) size,
79 callback,
80 data);
81 sc = storeClientListSearch(e->mem_obj, data);
82 assert(sc != NULL);
83 assert(sc->callback == NULL);
84 sc->copy_offset = copy_offset;
85 sc->seen_offset = seen_offset;
86 sc->callback = callback;
87 sc->copy_buf = buf;
88 sc->copy_size = size;
89 sc->copy_offset = copy_offset;
90 storeClientCopy2(e, sc);
91 recurse_detect--;
92}
93
94static void
95storeClientCopy2(StoreEntry * e, store_client * sc)
96{
97 STCB *callback = sc->callback;
98 MemObject *mem = e->mem_obj;
99 size_t sz;
100 static int loopdetect = 0;
101 assert(++loopdetect < 10);
102 debug(20, 3) ("storeClientCopy2: %s\n", storeKeyText(e->key));
103 assert(callback != NULL);
104 if (e->store_status == STORE_ABORTED) {
105#if USE_ASYNC_IO
106 if (sc->disk_op_in_progress == 1) {
107 if (sc->swapin_fd >= 0)
108 aioCancel(sc->swapin_fd, NULL);
109 else
110 aioCancel(-1, sc);
111 }
112#endif
113 sc->disk_op_in_progress = 0;
114 sc->callback = NULL;
115 callback(sc->callback_data, sc->copy_buf, 0);
116 } else if (e->store_status == STORE_OK && sc->copy_offset == e->object_len) {
117 /* There is no more to send! */
118#if USE_ASYNC_IO
119 if (sc->disk_op_in_progress == 1) {
120 if (sc->swapin_fd >= 0)
121 aioCancel(sc->swapin_fd, NULL);
122 else
123 aioCancel(-1, sc);
124 }
125#endif
126 sc->disk_op_in_progress = 0;
127 sc->callback = NULL;
128 callback(sc->callback_data, sc->copy_buf, 0);
129 } else if (e->store_status == STORE_PENDING && sc->seen_offset == mem->inmem_hi) {
130 /* client has already seen this, wait for more */
131 debug(20, 3) ("storeClientCopy2: Waiting for more\n");
132 } else if (sc->copy_offset >= mem->inmem_lo && mem->inmem_lo < mem->inmem_hi) {
133 /* What the client wants is in memory */
134 debug(20, 3) ("storeClientCopy2: Copying from memory\n");
135 sz = stmemCopy(mem->data, sc->copy_offset, sc->copy_buf, sc->copy_size);
136#if USE_ASYNC_IO
137 if (sc->disk_op_in_progress == 1) {
138 if (sc->swapin_fd >= 0)
139 aioCancel(sc->swapin_fd, NULL);
140 else
141 aioCancel(-1, sc);
142 }
143#endif
144 sc->disk_op_in_progress = 0;
145 sc->callback = NULL;
146 callback(sc->callback_data, sc->copy_buf, sz);
147 } else if (sc->swapin_fd < 0) {
148 debug(20, 3) ("storeClientCopy2: Need to open swap in file\n");
149 assert(sc->type == STORE_DISK_CLIENT);
150 /* gotta open the swapin file */
151 /* assert(sc->copy_offset == 0); */
152 if (sc->disk_op_in_progress == 0) {
153 sc->disk_op_in_progress = 1;
154 storeSwapInStart(e, storeClientCopyFileOpened, sc);
155 } else {
156 debug(20, 2) ("storeClientCopy2: Averted multiple fd operation\n");
157 }
158 } else {
159 debug(20, 3) ("storeClientCopy: reading from disk FD %d\n",
160 sc->swapin_fd);
161 assert(sc->type == STORE_DISK_CLIENT);
162 if (sc->disk_op_in_progress == 0) {
163 sc->disk_op_in_progress = 1;
164 storeClientCopyFileRead(sc);
165 } else {
166 debug(20, 2) ("storeClientCopy2: Averted multiple fd operation\n");
167 }
168 }
169 --loopdetect;
170}
171
172static void
173storeClientCopyFileOpened(int fd, void *data)
174{
175 store_client *sc = data;
176 STCB *callback = sc->callback;
177 if (fd < 0) {
178 debug(20, 3) ("storeClientCopyFileOpened: failed\n");
179 sc->disk_op_in_progress = 0;
180 sc->callback = NULL;
181 callback(sc->callback_data, sc->copy_buf, -1);
182 return;
183 }
184 sc->swapin_fd = fd;
185 storeClientCopyFileRead(sc);
186}
187
188static void
189storeClientCopyFileRead(store_client * sc)
190{
191 assert(sc->callback != NULL);
192 file_read(sc->swapin_fd,
193 sc->copy_buf,
194 sc->copy_size,
195 sc->copy_offset,
196 storeClientCopyHandleRead,
197 sc);
198}
199
200static void
201storeClientCopyHandleRead(int fd, const char *buf, int len, int flagnotused, void *data)
202{
203 store_client *sc = data;
204 MemObject *mem = sc->mem;
205 STCB *callback = sc->callback;
206 int hdr_len = 0;
207 assert(sc->disk_op_in_progress != 0);
208 sc->disk_op_in_progress = 0;
209 assert(sc->callback != NULL);
210 debug(20, 3) ("storeClientCopyHandleRead: FD %d, len %d\n", fd, len);
211 if (sc->copy_offset == 0 && len > 0 && mem != NULL) {
212 hdr_len = storeGetMetaBuf(buf, mem);
213 memmove((char *) buf, (char *) (buf + hdr_len), len - hdr_len);
214 len -= hdr_len;
215 httpParseReplyHeaders(buf, mem->reply);
216 }
217 sc->callback = NULL;
218 callback(sc->callback_data, sc->copy_buf, len);
219}
220
221int
222storeClientCopyPending(StoreEntry * e, void *data)
223{
224 /* return 1 if there is a callback registered for this client */
225 store_client *sc = storeClientListSearch(e->mem_obj, data);
226 if (sc == NULL)
227 return 0;
228 if (sc->callback == NULL)
229 return 0;
230 return 1;
231}
232
233int
234storeUnregister(StoreEntry * e, void *data)
235{
236 MemObject *mem = e->mem_obj;
237 store_client *sc;
238 store_client **S;
239 STCB *callback;
240 if (mem == NULL)
241 return 0;
242 debug(20, 3) ("storeUnregister: called for '%s'\n", storeKeyText(e->key));
243 for (S = &mem->clients; (sc = *S) != NULL; S = &(*S)->next) {
244 if (sc->callback_data == data)
245 break;
246 }
247 if (sc == NULL)
248 return 0;
249 *S = sc->next;
250 mem->nclients--;
251 sc->disk_op_in_progress = 0;
252 if (e->store_status == STORE_OK && e->swap_status != SWAPOUT_DONE)
253 storeCheckSwapOut(e);
254 if (sc->swapin_fd > -1) {
255 commSetSelect(sc->swapin_fd, COMM_SELECT_READ, NULL, NULL, 0);
256 file_close(sc->swapin_fd);
257 }
258#if USE_ASYNC_IO
259 else
260 aioCancel(-1, sc);
261#endif
262 if ((callback = sc->callback) != NULL) {
263 /* callback with ssize = -1 to indicate unexpected termination */
264 debug(20, 3) ("storeUnregister: store_client for %s has a callback\n",
265 mem->url);
266 sc->callback = NULL;
267 callback(sc->callback_data, sc->copy_buf, -1);
268 }
269 cbdataFree(sc);
270 return 1;
271}
272
273off_t
274storeLowestMemReaderOffset(const StoreEntry * entry)
275{
276 const MemObject *mem = entry->mem_obj;
277 off_t lowest = mem->inmem_hi;
278 store_client *sc;
279 store_client *nx = NULL;
280 for (sc = mem->clients; sc; sc = nx) {
281 nx = sc->next;
282 if (sc->callback_data == NULL) /* open slot */
283 continue;
284 if (sc->type != STORE_MEM_CLIENT)
285 continue;
286 if (sc->copy_offset < lowest)
287 lowest = sc->copy_offset;
288 }
289 return lowest;
290}
291
292/* Call handlers waiting for data to be appended to E. */
293void
294InvokeHandlers(StoreEntry * e)
295{
296 int i = 0;
297 MemObject *mem = e->mem_obj;
298 store_client *sc;
299 store_client *nx = NULL;
300 assert(mem->clients != NULL || mem->nclients == 0);
301 debug(20, 3) ("InvokeHandlers: %s\n", storeKeyText(e->key));
302 /* walk the entire list looking for valid callbacks */
303 for (sc = mem->clients; sc; sc = nx) {
304 nx = sc->next;
305 debug(20, 3) ("InvokeHandlers: checking client #%d\n", i++);
306 if (sc->callback_data == NULL)
307 continue;
308 if (sc->callback == NULL)
309 continue;
310 storeClientCopy2(e, sc);
311 }
312}
313
314int
315storePendingNClients(const StoreEntry * e)
316{
317 int npend = 0;
318 MemObject *mem = e->mem_obj;
319 store_client *sc;
320 store_client *nx = NULL;
321 if (mem == NULL)
322 return 0;
323 for (sc = mem->clients; sc; sc = nx) {
324 nx = sc->next;
325 /* Changed from callback_data to just callback. There can be no use */
326 /* for callback_data without a callback, and sc->callback we know */
327 /* gets reset, but not necessarily sc->callback_data */
328 if (sc->callback == NULL)
329 continue;
330 npend++;
331 }
332 return npend;
333}