From: Alex Rousskov Date: Thu, 4 Aug 2011 07:18:25 +0000 (-0600) Subject: Added disk_io_timeout to squid.conf to control approximately how long Squid X-Git-Tag: take07 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0a11e0390a5387b03f6747aba493eeb91bc243fe;p=thirdparty%2Fsquid.git Added disk_io_timeout to squid.conf to control approximately how long Squid allowsDisconnecting: Timeout, server not responding. queuing time. If the anticipated I/O time exceeds the configured limit, Squid will not swap the corresponding object in or out, allowing for the disk queues to drain. --- diff --git a/src/DiskIO/IpcIo/IpcIoFile.cc b/src/DiskIO/IpcIo/IpcIoFile.cc index 679b56645f..d58b010066 100644 --- a/src/DiskIO/IpcIo/IpcIoFile.cc +++ b/src/DiskIO/IpcIo/IpcIoFile.cc @@ -17,6 +17,7 @@ #include "ipc/StrandSearch.h" #include "ipc/UdsOp.h" #include "ipc/mem/Pages.h" +#include "SquidTime.h" CBDATA_CLASS_INIT(IpcIoFile); @@ -159,13 +160,13 @@ IpcIoFile::close() bool IpcIoFile::canRead() const { - return diskId >= 0; + return diskId >= 0 && canWait(); } bool IpcIoFile::canWrite() const { - return diskId >= 0; + return diskId >= 0 && canWait(); } bool @@ -304,6 +305,7 @@ IpcIoFile::push(IpcIoPendingRequest *const pending) IpcIoMsg ipcIo; try { ipcIo.requestId = lastRequestId; + ipcIo.start = current_time; if (pending->readRequest) { ipcIo.command = IpcIo::cmdRead; ipcIo.offset = pending->readRequest->offset; @@ -340,6 +342,25 @@ IpcIoFile::push(IpcIoPendingRequest *const pending) } } +/// whether we think there is enough time to complete the I/O +bool +IpcIoFile::canWait() const { + if (!Config.Timeout.disk_io) + return true; // no timeout specified + + IpcIoMsg oldestIo; + if (!queue->peek(diskId, oldestIo) || oldestIo.start.tv_sec <= 0) + return true; // we cannot estimate expected wait time; assume it is OK + + const int expectedWait = tvSubMsec(oldestIo.start, current_time); + if (expectedWait < 0 || + static_cast(expectedWait) < Config.Timeout.disk_io) + return true; // expected wait time is acceptible + + debugs(47,2, HERE << "cannot wait: " << expectedWait); + return false; // do not want to wait that long +} + /// called when coordinator responds to worker open request void IpcIoFile::HandleOpenResponse(const Ipc::StrandSearchResponse &response) @@ -517,6 +538,7 @@ IpcIoFile::getFD() const IpcIoMsg::IpcIoMsg(): requestId(0), offset(0), len(0), command(IpcIo::cmdNone), xerrno(0) { + start.tv_sec = 0; } /* IpcIoPendingRequest */ diff --git a/src/DiskIO/IpcIo/IpcIoFile.h b/src/DiskIO/IpcIo/IpcIoFile.h index ba1043133e..f116f98ff7 100644 --- a/src/DiskIO/IpcIo/IpcIoFile.h +++ b/src/DiskIO/IpcIo/IpcIoFile.h @@ -37,6 +37,7 @@ public: Ipc::Mem::PageId page; IpcIo::Command command; ///< what disker is supposed to do or did + struct timeval start; ///< when the I/O request was converted to IpcIoMsg int xerrno; ///< I/O error code or zero }; @@ -75,6 +76,7 @@ protected: void openCompleted(const Ipc::StrandSearchResponse *const response); void readCompleted(ReadRequest *readRequest, IpcIoMsg *const response); void writeCompleted(WriteRequest *writeRequest, const IpcIoMsg *const response); + bool canWait() const; private: void trackPendingRequest(IpcIoPendingRequest *const pending); diff --git a/src/cf.data.pre b/src/cf.data.pre index 4da9db7839..566fe00491 100644 --- a/src/cf.data.pre +++ b/src/cf.data.pre @@ -4603,6 +4603,21 @@ DOC_START many ident requests going at once. DOC_END +NAME: disk_io_timeout +TYPE: time_msec +DEFAULT: 0 milliseconds +LOC: Config.Timeout.disk_io +DOC_START + Squid will not start a new disk I/O operation if it estimates that the + operation will take more than the specified disk I/O timeout. + Only Rock Store supports this timeout for now. + + By default and when set to zero, disables the disk I/O time limit + enforcement. +DOC_END + + + NAME: shutdown_lifetime COMMENT: time-units TYPE: time_t diff --git a/src/fs/rock/RockIoState.cc b/src/fs/rock/RockIoState.cc index 57fb7d25bc..dbb60f74b0 100644 --- a/src/fs/rock/RockIoState.cc +++ b/src/fs/rock/RockIoState.cc @@ -53,7 +53,6 @@ void Rock::IoState::read_(char *buf, size_t len, off_t coreOff, STRCB *cb, void *data) { assert(theFile != NULL); - assert(theFile->canRead()); assert(coreOff >= 0); offset_ = coreOff; @@ -109,7 +108,6 @@ void Rock::IoState::startWriting() { assert(theFile != NULL); - assert(theFile->canWrite()); assert(!theBuf.isNull()); // TODO: if DiskIO module is mmap-based, we should be writing whole pages diff --git a/src/fs/rock/RockSwapDir.cc b/src/fs/rock/RockSwapDir.cc index f95f864b47..2b6e81f4c5 100644 --- a/src/fs/rock/RockSwapDir.cc +++ b/src/fs/rock/RockSwapDir.cc @@ -43,7 +43,7 @@ Rock::SwapDir::search(String const url, HttpRequest *) StoreEntry * Rock::SwapDir::get(const cache_key *key) { - if (!map) + if (!map || !theFile || !theFile->canRead()) return NULL; sfileno fileno; diff --git a/src/ipc/Queue.cc b/src/ipc/Queue.cc index ad1ee0d41b..41e240674e 100644 --- a/src/ipc/Queue.cc +++ b/src/ipc/Queue.cc @@ -162,12 +162,12 @@ Ipc::FewToFewBiQueue::validProcessId(const Group group, const int processId) con return false; } -Ipc::OneToOneUniQueue & -Ipc::FewToFewBiQueue::oneToOneQueue(const Group fromGroup, const int fromProcessId, const Group toGroup, const int toProcessId) +int +Ipc::FewToFewBiQueue::oneToOneQueueIndex(const Group fromGroup, const int fromProcessId, const Group toGroup, const int toProcessId) const { Must(fromGroup != toGroup); - Must(validProcessId(fromGroup, fromProcessId)); - Must(validProcessId(toGroup, toProcessId)); + assert(validProcessId(fromGroup, fromProcessId)); + assert(validProcessId(toGroup, toProcessId)); int index1; int index2; int offset; @@ -181,7 +181,19 @@ Ipc::FewToFewBiQueue::oneToOneQueue(const Group fromGroup, const int fromProcess offset = metadata->theGroupASize * metadata->theGroupBSize; } const int index = offset + index1 * metadata->theGroupBSize + index2; - return (*queues)[index]; + return index; +} + +Ipc::OneToOneUniQueue & +Ipc::FewToFewBiQueue::oneToOneQueue(const Group fromGroup, const int fromProcessId, const Group toGroup, const int toProcessId) +{ + return (*queues)[oneToOneQueueIndex(fromGroup, fromProcessId, toGroup, toProcessId)]; +} + +const Ipc::OneToOneUniQueue & +Ipc::FewToFewBiQueue::oneToOneQueue(const Group fromGroup, const int fromProcessId, const Group toGroup, const int toProcessId) const +{ + return (*queues)[oneToOneQueueIndex(fromGroup, fromProcessId, toGroup, toProcessId)]; } Ipc::QueueReader & diff --git a/src/ipc/Queue.h b/src/ipc/Queue.h index 7d5fdf2086..94a98f758e 100644 --- a/src/ipc/Queue.h +++ b/src/ipc/Queue.h @@ -94,6 +94,9 @@ public: /// returns true iff the caller must notify the reader of the pushed item template bool push(const Value &value, QueueReader *const reader = NULL); + /// returns true iff the value was set; the value may be stale! + template bool peek(Value &value) const; + private: unsigned int theIn; ///< input index, used only in push() @@ -179,8 +182,13 @@ public: /// calls OneToOneUniQueue::push() using the given process queue template bool push(const int remoteProcessId, const Value &value); + /// calls OneToOneUniQueue::peek() using the given process queue + template bool peek(const int remoteProcessId, Value &value) const; + private: bool validProcessId(const Group group, const int processId) const; + int oneToOneQueueIndex(const Group fromGroup, const int fromProcessId, const Group toGroup, const int toProcessId) const; + const OneToOneUniQueue &oneToOneQueue(const Group fromGroup, const int fromProcessId, const Group toGroup, const int toProcessId) const; OneToOneUniQueue &oneToOneQueue(const Group fromGroup, const int fromProcessId, const Group toGroup, const int toProcessId); QueueReader &reader(const Group group, const int processId); int remoteGroupSize() const { return theLocalGroup == groupA ? metadata->theGroupBSize : metadata->theGroupASize; } @@ -229,6 +237,22 @@ OneToOneUniQueue::pop(Value &value, QueueReader *const reader) return true; } +template +bool +OneToOneUniQueue::peek(Value &value) const +{ + if (sizeof(value) > theMaxItemSize) + throw ItemTooLarge(); + + if (empty()) + return false; + + // the reader may pop() before we copy; making this method imprecise + const unsigned int pos = (theOut % theCapacity) * theMaxItemSize; + memcpy(&value, theBuffer + pos, sizeof(value)); + return true; +} + template bool OneToOneUniQueue::push(const Value &value, QueueReader *const reader) @@ -296,6 +320,19 @@ FewToFewBiQueue::push(const int remoteProcessId, const Value &value) return remoteQueue.push(value, &remoteReader); } +template +bool +FewToFewBiQueue::peek(const int remoteProcessId, Value &value) const +{ + // we may be called before remote process configured its queue end + if (!validProcessId(remoteGroup(), remoteProcessId)) + return false; + + const OneToOneUniQueue &remoteQueue = oneToOneQueue(theLocalGroup, theLocalProcessId, remoteGroup(), remoteProcessId); + debugs(54, 7, HERE << "peeking from " << theLocalProcessId << " to " << remoteProcessId << " at " << remoteQueue.size()); + return remoteQueue.peek(value); +} + } // namespace Ipc #endif // SQUID_IPC_QUEUE_H diff --git a/src/ipc/mem/Pages.cc b/src/ipc/mem/Pages.cc index cdd13af518..ceed891f99 100644 --- a/src/ipc/mem/Pages.cc +++ b/src/ipc/mem/Pages.cc @@ -68,7 +68,7 @@ Ipc::Mem::PageLimit(const int purpose) return Config.memMaxSize > 0 ? Config.memMaxSize / PageSize() : 0; case PageId::ioPage: // XXX: this should be independent from memory cache pages - return PageLimit(PageId::cachePage) * 0.5; + return PageLimit(PageId::cachePage)/2; default: Must(false); } diff --git a/src/structs.h b/src/structs.h index 8d79f866d3..10d5e2dc3c 100644 --- a/src/structs.h +++ b/src/structs.h @@ -214,6 +214,7 @@ struct SquidConfig { int icp_query_max; /* msec */ int icp_query_min; /* msec */ int mcast_icp_query; /* msec */ + time_msec_t disk_io; #if !USE_DNSSERVERS