]> git.ipfire.org Git - thirdparty/squid.git/blame - src/store_client.cc
debugging and gindent
[thirdparty/squid.git] / src / store_client.cc
CommitLineData
f09f5b26 1#include "squid.h"
2
e3ef2b09 3/*
4 * NOTE: 'Header' refers to the swapfile metadata header.
5 * 'Body' refers to the swapfile body, which is the full
6 * HTTP reply (including HTTP headers and body).
7 */
8static DRCB storeClientReadBody;
9static DRCB storeClientReadHeader;
10static SIH storeClientFileOpened;
f09f5b26 11static void storeClientCopy2(StoreEntry * e, store_client * sc);
e3ef2b09 12static void storeClientFileRead(store_client * sc);
f09f5b26 13
14/* check if there is any client waiting for this object at all */
15/* return 1 if there is at least one client */
16int
17storeClientWaiting(const StoreEntry * e)
18{
19 MemObject *mem = e->mem_obj;
20 store_client *sc;
21 for (sc = mem->clients; sc; sc = sc->next) {
22 if (sc->callback_data != NULL)
23 return 1;
24 }
25 return 0;
26}
27
28store_client *
29storeClientListSearch(const MemObject * mem, void *data)
30{
31 store_client *sc;
32 for (sc = mem->clients; sc; sc = sc->next) {
33 if (sc->callback_data == data)
34 break;
35 }
36 return sc;
37}
38
39/* add client with fd to client list */
40void
41storeClientListAdd(StoreEntry * e, void *data)
42{
43 MemObject *mem = e->mem_obj;
44 store_client **T;
45 store_client *sc;
46 assert(mem);
47 if (storeClientListSearch(mem, data) != NULL)
48 return;
49 mem->nclients++;
7021844c 50 sc = memAllocate(MEM_STORE_CLIENT);
f09f5b26 51 cbdataAdd(sc, MEM_STORE_CLIENT); /* sc is callback_data for file_read */
52 sc->callback_data = data;
53 sc->seen_offset = 0;
54 sc->copy_offset = 0;
55 sc->swapin_fd = -1;
f115fadd 56 sc->flags.disk_io_pending = 0;
07304bf9 57 sc->entry = e;
f09f5b26 58 if (e->store_status == STORE_PENDING && mem->swapout.fd == -1)
59 sc->type = STORE_MEM_CLIENT;
60 else
61 sc->type = STORE_DISK_CLIENT;
62 for (T = &mem->clients; *T; T = &(*T)->next);
63 *T = sc;
64}
65
f115fadd 66static void
67storeClientCopyEvent(void *data)
68{
69 store_client *sc = data;
70 int valid = cbdataValid(sc);
fe4a33ac 71 debug(20, 3) ("storeClientCopyEvent: Running\n");
f115fadd 72 cbdataUnlock(sc);
73 if (!valid)
74 return;
75 assert(!sc->flags.store_copying);
76 sc->flags.store_copying = 1;
77 storeClientCopy2(sc->entry, sc);
78 sc->flags.store_copying = 0;
79}
80
f09f5b26 81/* copy bytes requested by the client */
82void
83storeClientCopy(StoreEntry * e,
84 off_t seen_offset,
85 off_t copy_offset,
86 size_t size,
87 char *buf,
88 STCB * callback,
89 void *data)
90{
91 store_client *sc;
f09f5b26 92 assert(e->store_status != STORE_ABORTED);
f09f5b26 93 debug(20, 3) ("storeClientCopy: %s, seen %d, want %d, size %d, cb %p, cbdata %p\n",
94 storeKeyText(e->key),
95 (int) seen_offset,
96 (int) copy_offset,
97 (int) size,
98 callback,
99 data);
100 sc = storeClientListSearch(e->mem_obj, data);
101 assert(sc != NULL);
102 assert(sc->callback == NULL);
103 sc->copy_offset = copy_offset;
104 sc->seen_offset = seen_offset;
105 sc->callback = callback;
106 sc->copy_buf = buf;
107 sc->copy_size = size;
108 sc->copy_offset = copy_offset;
f115fadd 109 if (sc->flags.store_copying) {
110 cbdataLock(sc);
fe4a33ac 111 debug(20, 3) ("storeClientCopy: Queueing storeClientCopyEvent()\n");
f115fadd 112 eventAdd("storeClientCopyEvent", storeClientCopyEvent, sc, 0);
113 } else {
fe4a33ac 114 sc->flags.store_copying = 1;
115 storeClientCopy2(e, sc);
116 sc->flags.store_copying = 0;
f115fadd 117 }
f09f5b26 118}
119
07304bf9 120/*
121 * This function is used below to decide if we have any more data to
122 * send to the client. If the store_status is STORE_ABORTED, that case
123 * should be handled before this function gets called. If the
124 * store_status is STORE_PENDING, then we do have more data to send.
125 * If its STORE_OK, then we continue checking. If the object length is
126 * negative, then we don't know the real length and must open the swap
127 * file to find out. If the lenght is >= 0, then we compare it to the
128 * requested copy offset.
129 */
130static int
131storeClientNoMoreToSend(StoreEntry * e, store_client * sc)
132{
133 ssize_t len;
134 if (e->store_status != STORE_OK)
135 return 0;
136 if ((len = objectLen(e)) < 0)
137 return 0;
138 if (sc->copy_offset < len)
139 return 0;
140 return 1;
141}
142
f09f5b26 143static void
144storeClientCopy2(StoreEntry * e, store_client * sc)
145{
146 STCB *callback = sc->callback;
147 MemObject *mem = e->mem_obj;
148 size_t sz;
149 static int loopdetect = 0;
150 assert(++loopdetect < 10);
151 debug(20, 3) ("storeClientCopy2: %s\n", storeKeyText(e->key));
152 assert(callback != NULL);
153 if (e->store_status == STORE_ABORTED) {
154#if USE_ASYNC_IO
f115fadd 155 if (sc->flags.disk_io_pending == 1) {
f09f5b26 156 if (sc->swapin_fd >= 0)
157 aioCancel(sc->swapin_fd, NULL);
158 else
159 aioCancel(-1, sc);
160 }
161#endif
f115fadd 162 sc->flags.disk_io_pending = 0;
f09f5b26 163 sc->callback = NULL;
164 callback(sc->callback_data, sc->copy_buf, 0);
07304bf9 165 } else if (storeClientNoMoreToSend(e, sc)) {
f09f5b26 166 /* There is no more to send! */
167#if USE_ASYNC_IO
f115fadd 168 if (sc->flags.disk_io_pending == 1) {
f09f5b26 169 if (sc->swapin_fd >= 0)
170 aioCancel(sc->swapin_fd, NULL);
171 else
172 aioCancel(-1, sc);
173 }
174#endif
f115fadd 175 sc->flags.disk_io_pending = 0;
f09f5b26 176 sc->callback = NULL;
177 callback(sc->callback_data, sc->copy_buf, 0);
178 } else if (e->store_status == STORE_PENDING && sc->seen_offset == mem->inmem_hi) {
179 /* client has already seen this, wait for more */
180 debug(20, 3) ("storeClientCopy2: Waiting for more\n");
181 } else if (sc->copy_offset >= mem->inmem_lo && mem->inmem_lo < mem->inmem_hi) {
182 /* What the client wants is in memory */
183 debug(20, 3) ("storeClientCopy2: Copying from memory\n");
184 sz = stmemCopy(mem->data, sc->copy_offset, sc->copy_buf, sc->copy_size);
185#if USE_ASYNC_IO
f115fadd 186 if (sc->flags.disk_io_pending == 1) {
f09f5b26 187 if (sc->swapin_fd >= 0)
188 aioCancel(sc->swapin_fd, NULL);
189 else
190 aioCancel(-1, sc);
191 }
192#endif
f115fadd 193 sc->flags.disk_io_pending = 0;
f09f5b26 194 sc->callback = NULL;
195 callback(sc->callback_data, sc->copy_buf, sz);
196 } else if (sc->swapin_fd < 0) {
197 debug(20, 3) ("storeClientCopy2: Need to open swap in file\n");
198 assert(sc->type == STORE_DISK_CLIENT);
199 /* gotta open the swapin file */
200 /* assert(sc->copy_offset == 0); */
f115fadd 201 if (sc->flags.disk_io_pending == 0) {
202 sc->flags.disk_io_pending = 1;
e3ef2b09 203 storeSwapInStart(e, storeClientFileOpened, sc);
f09f5b26 204 } else {
205 debug(20, 2) ("storeClientCopy2: Averted multiple fd operation\n");
206 }
207 } else {
208 debug(20, 3) ("storeClientCopy: reading from disk FD %d\n",
209 sc->swapin_fd);
210 assert(sc->type == STORE_DISK_CLIENT);
f115fadd 211 if (sc->flags.disk_io_pending == 0) {
e3ef2b09 212 storeClientFileRead(sc);
f09f5b26 213 } else {
214 debug(20, 2) ("storeClientCopy2: Averted multiple fd operation\n");
215 }
216 }
217 --loopdetect;
218}
219
220static void
e3ef2b09 221storeClientFileOpened(int fd, void *data)
f09f5b26 222{
223 store_client *sc = data;
224 STCB *callback = sc->callback;
225 if (fd < 0) {
e3ef2b09 226 debug(20, 3) ("storeClientFileOpened: failed\n");
f115fadd 227 sc->flags.disk_io_pending = 0;
f09f5b26 228 sc->callback = NULL;
229 callback(sc->callback_data, sc->copy_buf, -1);
230 return;
231 }
232 sc->swapin_fd = fd;
e3ef2b09 233 storeClientFileRead(sc);
f09f5b26 234}
235
236static void
e3ef2b09 237storeClientFileRead(store_client * sc)
f09f5b26 238{
07304bf9 239 MemObject *mem = sc->entry->mem_obj;
f09f5b26 240 assert(sc->callback != NULL);
e3ef2b09 241 if (mem->swap_hdr_sz == 0)
242 file_read(sc->swapin_fd,
d8b9a541 243 sc->copy_buf,
244 sc->copy_size,
e3ef2b09 245 0,
246 storeClientReadHeader,
247 sc);
248 else
249 file_read(sc->swapin_fd,
250 sc->copy_buf,
251 sc->copy_size,
252 sc->copy_offset + mem->swap_hdr_sz,
253 storeClientReadBody,
254 sc);
f115fadd 255 sc->flags.disk_io_pending = 1;
f09f5b26 256}
257
258static void
e3ef2b09 259storeClientReadBody(int fd, const char *buf, int len, int flagnotused, void *data)
f09f5b26 260{
261 store_client *sc = data;
07304bf9 262 MemObject *mem = sc->entry->mem_obj;
f09f5b26 263 STCB *callback = sc->callback;
f115fadd 264 assert(sc->flags.disk_io_pending != 0);
265 sc->flags.disk_io_pending = 0;
f09f5b26 266 assert(sc->callback != NULL);
e3ef2b09 267 debug(20, 3) ("storeClientReadBody: FD %d, len %d\n", fd, len);
cb69b4c7 268 if (sc->copy_offset == 0 && len > 0 && mem->reply->sline.status == 0)
269 httpReplyParse(mem->reply, sc->copy_buf);
f09f5b26 270 sc->callback = NULL;
271 callback(sc->callback_data, sc->copy_buf, len);
272}
273
e3ef2b09 274static void
275storeClientReadHeader(int fd, const char *buf, int len, int flagnotused, void *data)
276{
e3ef2b09 277 store_client *sc = data;
07304bf9 278 StoreEntry *e = sc->entry;
279 MemObject *mem = e->mem_obj;
e3ef2b09 280 STCB *callback = sc->callback;
281 int swap_hdr_sz = 0;
282 size_t body_sz;
283 size_t copy_sz;
284 tlv *tlv_list;
f115fadd 285 assert(sc->flags.disk_io_pending != 0);
286 sc->flags.disk_io_pending = 0;
e3ef2b09 287 assert(sc->callback != NULL);
288 debug(20, 3) ("storeClientReadHeader: FD %d, len %d\n", fd, len);
289 if (len < 0) {
25535cbe 290 debug(20, 3) ("storeClientReadHeader: FD %d: %s\n", fd, xstrerror());
25535cbe 291 sc->callback = NULL;
292 callback(sc->callback_data, sc->copy_buf, len);
e3ef2b09 293 return;
294 }
295 tlv_list = storeSwapMetaUnpack(buf, &swap_hdr_sz);
296 if (tlv_list == NULL) {
25535cbe 297 debug(20, 1) ("storeClientReadHeader: failed to unpack meta data\n");
25535cbe 298 sc->callback = NULL;
299 callback(sc->callback_data, sc->copy_buf, -1);
e3ef2b09 300 return;
301 }
302 /*
303 * XXX Here we should check the meta data and make sure we got
304 * the right object.
305 */
07304bf9 306 storeSwapTLVFree(tlv_list);
e3ef2b09 307 mem->swap_hdr_sz = swap_hdr_sz;
07304bf9 308 mem->object_sz = e->swap_file_sz - swap_hdr_sz;
e3ef2b09 309 /*
310 * If our last read got some data the client wants, then give
311 * it to them, otherwise schedule another read.
312 */
313 body_sz = len - swap_hdr_sz;
314 if (sc->copy_offset < body_sz) {
315 /*
25535cbe 316 * we have (part of) what they want
e3ef2b09 317 */
318 copy_sz = XMIN(sc->copy_size, body_sz);
25535cbe 319 debug(20, 3) ("storeClientReadHeader: copying %d bytes of body\n",
320 copy_sz);
d8b9a541 321 xmemmove(sc->copy_buf, sc->copy_buf + swap_hdr_sz, copy_sz);
cb69b4c7 322 if (sc->copy_offset == 0 && len > 0 && mem->reply->sline.status == 0)
323 httpReplyParse(mem->reply, sc->copy_buf);
e3ef2b09 324 sc->callback = NULL;
25535cbe 325 callback(sc->callback_data, sc->copy_buf, copy_sz);
e3ef2b09 326 return;
327 }
328 /*
329 * we don't have what the client wants, but at least we now
330 * know the swap header size.
331 */
e3ef2b09 332 storeClientFileRead(sc);
333}
334
f09f5b26 335int
336storeClientCopyPending(StoreEntry * e, void *data)
337{
338 /* return 1 if there is a callback registered for this client */
339 store_client *sc = storeClientListSearch(e->mem_obj, data);
340 if (sc == NULL)
341 return 0;
342 if (sc->callback == NULL)
343 return 0;
344 return 1;
345}
346
347int
348storeUnregister(StoreEntry * e, void *data)
349{
350 MemObject *mem = e->mem_obj;
351 store_client *sc;
352 store_client **S;
353 STCB *callback;
354 if (mem == NULL)
355 return 0;
356 debug(20, 3) ("storeUnregister: called for '%s'\n", storeKeyText(e->key));
357 for (S = &mem->clients; (sc = *S) != NULL; S = &(*S)->next) {
358 if (sc->callback_data == data)
359 break;
360 }
361 if (sc == NULL)
362 return 0;
363 *S = sc->next;
364 mem->nclients--;
f115fadd 365 sc->flags.disk_io_pending = 0;
f09f5b26 366 if (e->store_status == STORE_OK && e->swap_status != SWAPOUT_DONE)
367 storeCheckSwapOut(e);
368 if (sc->swapin_fd > -1) {
369 commSetSelect(sc->swapin_fd, COMM_SELECT_READ, NULL, NULL, 0);
370 file_close(sc->swapin_fd);
371 }
372#if USE_ASYNC_IO
373 else
374 aioCancel(-1, sc);
375#endif
376 if ((callback = sc->callback) != NULL) {
377 /* callback with ssize = -1 to indicate unexpected termination */
378 debug(20, 3) ("storeUnregister: store_client for %s has a callback\n",
379 mem->url);
380 sc->callback = NULL;
381 callback(sc->callback_data, sc->copy_buf, -1);
382 }
383 cbdataFree(sc);
384 return 1;
385}
386
387off_t
388storeLowestMemReaderOffset(const StoreEntry * entry)
389{
390 const MemObject *mem = entry->mem_obj;
391 off_t lowest = mem->inmem_hi;
392 store_client *sc;
393 store_client *nx = NULL;
394 for (sc = mem->clients; sc; sc = nx) {
395 nx = sc->next;
396 if (sc->callback_data == NULL) /* open slot */
397 continue;
398 if (sc->type != STORE_MEM_CLIENT)
399 continue;
400 if (sc->copy_offset < lowest)
401 lowest = sc->copy_offset;
402 }
403 return lowest;
404}
405
406/* Call handlers waiting for data to be appended to E. */
407void
408InvokeHandlers(StoreEntry * e)
409{
410 int i = 0;
411 MemObject *mem = e->mem_obj;
412 store_client *sc;
413 store_client *nx = NULL;
414 assert(mem->clients != NULL || mem->nclients == 0);
415 debug(20, 3) ("InvokeHandlers: %s\n", storeKeyText(e->key));
416 /* walk the entire list looking for valid callbacks */
417 for (sc = mem->clients; sc; sc = nx) {
418 nx = sc->next;
419 debug(20, 3) ("InvokeHandlers: checking client #%d\n", i++);
420 if (sc->callback_data == NULL)
421 continue;
422 if (sc->callback == NULL)
423 continue;
424 storeClientCopy2(e, sc);
425 }
426}
427
428int
429storePendingNClients(const StoreEntry * e)
430{
f09f5b26 431 MemObject *mem = e->mem_obj;
36547bcf 432 int npend = NULL == mem ? 0 : mem->nclients;
433#if OLD_CODE
f09f5b26 434 store_client *sc;
435 store_client *nx = NULL;
436 if (mem == NULL)
437 return 0;
438 for (sc = mem->clients; sc; sc = nx) {
439 nx = sc->next;
440 /* Changed from callback_data to just callback. There can be no use */
441 /* for callback_data without a callback, and sc->callback we know */
442 /* gets reset, but not necessarily sc->callback_data */
443 if (sc->callback == NULL)
444 continue;
445 npend++;
446 }
36547bcf 447#endif
1afe05c5 448 debug(20, 3) ("storePendingNClients: returning %d\n", npend);
f09f5b26 449 return npend;
450}