static void storeClientCopy3(StoreEntry * e, store_client * sc) { MemObject *mem = e->mem_obj; ssize_t sz; if (storeClientNoMoreToSend(e, sc)) { /* There is no more to send! */ storeClientCallback(sc, 0); return; } if (e->store_status == STORE_PENDING && sc->seen_offset >= mem->inmem_hi) { /* client has already seen this, wait for more */ debug(20, 3) ("storeClientCopy3: Waiting for more\n"); /* If the read is backed off and all clients have seen all the data in * memory, re-poll the fd */ if ((EBIT_TEST(e->flags, ENTRY_DEFER_READ)) && (storeLowestMemReaderOffset(e) == mem->inmem_hi)) { debug(20, 3) ("storeClientCopy3: %s - clearing ENTRY_DEFER_READ\n", e->mem_obj->url); /* Clear the flag and re-poll the fd */ storeResumeRead(e); } return; } /* * Slight weirdness here. We open a swapin file for any * STORE_DISK_CLIENT, even if we can copy the requested chunk * from memory in the next block. We must try to open the * swapin file before sending any data to the client side. If * we postpone the open, and then can not open the file later * on, the client loses big time. Its transfer just gets cut * off. Better to open it early (while the client side handler * is clientCacheHit) so that we can fall back to a cache miss * if needed. */ if (STORE_DISK_CLIENT == sc->type && NULL == sc->swapin_sio) { debug(20, 3) ("storeClientCopy3: Need to open swap in file\n"); /* gotta open the swapin file */ if (storeTooManyDiskFilesOpen()) { /* yuck -- this causes a TCP_SWAPFAIL_MISS on the client side */ storeClientCallback(sc, -1); return; } else if (!sc->flags.disk_io_pending) { /* Don't set store_io_pending here */ storeSwapInStart(sc); if (NULL == sc->swapin_sio) { storeClientCallback(sc, -1); return; } /* * If the open succeeds we either copy from memory, or * schedule a disk read in the next block. */ } else { debug(20, 1) ("WARNING: Averted multiple fd operation (1)\n"); return; } } if (sc->copy_offset >= mem->inmem_lo && sc->copy_offset < mem->inmem_hi) { /* What the client wants is in memory */ debug(20, 3) ("storeClientCopy3: Copying from memory\n"); sz = stmemCopy(&mem->data_hdr, sc->copy_offset, sc->copy_buf, sc->copy_size); if (EBIT_TEST(e->flags, RELEASE_REQUEST)) storeSwapOutMaintainMemObject(e); storeClientCallback(sc, sz); return; } /* What the client wants is not in memory. Schedule a disk read */ assert(STORE_DISK_CLIENT == sc->type); assert(!sc->flags.disk_io_pending); debug(20, 3) ("storeClientCopy3: reading from STORE\n"); storeClientFileRead(sc); }
static void storeClientCopy2(StoreEntry * e, store_client * sc) { STCB *callback = sc->callback; MemObject *mem = e->mem_obj; size_t sz; if (sc->flags.copy_event_pending) return; if (EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT)) { debug(20, 5) ("storeClientCopy2: returning because ENTRY_FWD_HDR_WAIT set\n"); return; } if (sc->flags.store_copying) { sc->flags.copy_event_pending = 1; debug(20, 3) ("storeClientCopy2: Queueing storeClientCopyEvent()\n"); eventAdd("storeClientCopyEvent", storeClientCopyEvent, sc, 0.0, 0); return; } cbdataLock(sc); /* ick, prevent sc from getting freed */ sc->flags.store_copying = 1; debug(20, 3) ("storeClientCopy2: %s\n", storeKeyText(e->key)); assert(callback != NULL); /* * We used to check for ENTRY_ABORTED here. But there were some * problems. For example, we might have a slow client (or two) and * the server-side is reading far ahead and swapping to disk. Even * if the server-side aborts, we want to give the client(s) * everything we got before the abort condition occurred. */ if (storeClientNoMoreToSend(e, sc)) { /* There is no more to send! */ sc->flags.disk_io_pending = 0; sc->callback = NULL; callback(sc->callback_data, sc->copy_buf, 0); } else if (e->store_status == STORE_PENDING && sc->seen_offset >= mem->inmem_hi) { /* client has already seen this, wait for more */ debug(20, 3) ("storeClientCopy2: Waiting for more\n"); } else if (sc->copy_offset >= mem->inmem_lo && sc->copy_offset < mem->inmem_hi) { /* What the client wants is in memory */ debug(20, 3) ("storeClientCopy2: Copying from memory\n"); sz = stmemCopy(&mem->data_hdr, sc->copy_offset, sc->copy_buf, sc->copy_size); sc->flags.disk_io_pending = 0; sc->callback = NULL; callback(sc->callback_data, sc->copy_buf, sz); } else if (sc->swapin_sio == NULL) { debug(20, 3) ("storeClientCopy2: Need to open swap in file\n"); assert(sc->type == STORE_DISK_CLIENT); /* gotta open the swapin file */ if (storeTooManyDiskFilesOpen()) { /* yuck -- this causes a TCP_SWAPFAIL_MISS on the client side */ sc->callback = NULL; callback(sc->callback_data, sc->copy_buf, -1); } else if (!sc->flags.disk_io_pending) { sc->flags.disk_io_pending = 1; storeSwapInStart(sc); if (NULL == sc->swapin_sio) { sc->flags.disk_io_pending = 0; sc->callback = NULL; callback(sc->callback_data, sc->copy_buf, -1); } else { storeClientFileRead(sc); } } else { debug(20, 2) ("storeClientCopy2: Averted multiple fd operation\n"); } } else { debug(20, 3) ("storeClientCopy: reading from STORE\n"); assert(sc->type == STORE_DISK_CLIENT); if (!sc->flags.disk_io_pending) { sc->flags.disk_io_pending = 1; storeClientFileRead(sc); } else { debug(20, 2) ("storeClientCopy2: Averted multiple fd operation\n"); } } sc->flags.store_copying = 0; cbdataUnlock(sc); /* ick, allow sc to be freed */ }