]>
Commit | Line | Data |
---|---|---|
f09f5b26 | 1 | #include "squid.h" |
2 | ||
3 | static void storeClientCopy2(StoreEntry * e, store_client * sc); | |
4 | static SIH storeClientCopyFileOpened; | |
5 | static void storeClientCopyFileRead(store_client * sc); | |
6 | static 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 */ | |
10 | int | |
11 | storeClientWaiting(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 | ||
22 | store_client * | |
23 | storeClientListSearch(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 */ | |
34 | void | |
35 | storeClientListAdd(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 */ | |
61 | void | |
62 | storeClientCopy(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 | ||
94 | static void | |
95 | storeClientCopy2(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 | ||
172 | static void | |
173 | storeClientCopyFileOpened(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 | ||
188 | static void | |
189 | storeClientCopyFileRead(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 | ||
200 | static void | |
201 | storeClientCopyHandleRead(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 | ||
221 | int | |
222 | storeClientCopyPending(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 | ||
233 | int | |
234 | storeUnregister(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 | ||
273 | off_t | |
274 | storeLowestMemReaderOffset(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. */ | |
293 | void | |
294 | InvokeHandlers(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 | ||
314 | int | |
315 | storePendingNClients(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 | } |