Index: net/http/http_cache.cc |
=================================================================== |
--- net/http/http_cache.cc (revision 17313) |
+++ net/http/http_cache.cc (working copy) |
@@ -67,6 +67,8 @@ |
//----------------------------------------------------------------------------- |
+static int kTransactionTimeoutInMillisecond = 5000; |
+ |
struct HeaderNameAndValue { |
const char* name; |
const char* value; |
@@ -154,7 +156,9 @@ |
network_read_callback_(this, &Transaction::OnNetworkReadCompleted)), |
ALLOW_THIS_IN_INITIALIZER_LIST( |
cache_read_callback_(new CancelableCompletionCallback<Transaction>( |
- this, &Transaction::OnCacheReadCompleted))) { |
+ this, &Transaction::OnCacheReadCompleted))), |
+ ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), |
+ is_waiting_for_entry_(false) { |
} |
// Clean up the transaction. |
@@ -206,6 +210,10 @@ |
// to the transaction. Returns network error code. |
int EntryAvailable(ActiveEntry* entry); |
+ // Called by the HttpCache when the given disk cache entry is busy. Sets up |
+ // a timeout alarm to MessageLoop. |
+ void PendOnEntry(ActiveEntry* entry); |
+ |
private: |
// This is a helper function used to trigger a completion callback. It may |
// only be called if callback_ is non-null. |
@@ -278,6 +286,9 @@ |
// Called to signal completion of the cache's ReadData method: |
void OnCacheReadCompleted(int result); |
+ // Called to bypass cache when it took too much time to get access to cache. |
+ void OnAddToEntryTimeout(ActiveEntry* entry); |
+ |
const HttpRequestInfo* request_; |
scoped_ptr<HttpRequestInfo> custom_request_; |
HttpCache* cache_; |
@@ -296,6 +307,9 @@ |
CompletionCallbackImpl<Transaction> network_read_callback_; |
scoped_refptr<CancelableCompletionCallback<Transaction> > |
cache_read_callback_; |
+ |
+ ScopedRunnableMethodFactory<Transaction> task_factory_; |
+ bool is_waiting_for_entry_; |
}; |
HttpCache::Transaction::~Transaction() { |
@@ -538,6 +552,7 @@ |
// |
int rv; |
entry_ = entry; |
+ is_waiting_for_entry_ = false; |
switch (mode_) { |
case READ: |
rv = BeginCacheRead(); |
@@ -950,6 +965,43 @@ |
HandleResult(result); |
} |
+void HttpCache::Transaction::PendOnEntry(ActiveEntry* entry) { |
+ if (is_waiting_for_entry_) { |
+ // Don't add timeout alarm more than once. |
+ return; |
+ } |
+ |
+ is_waiting_for_entry_ = true; |
+ |
+ MessageLoop::current()->PostDelayedTask( |
+ FROM_HERE, |
+ task_factory_.NewRunnableMethod(&Transaction::OnAddToEntryTimeout, entry), |
+ kTransactionTimeoutInMillisecond); |
+} |
+ |
+void HttpCache::Transaction::OnAddToEntryTimeout(ActiveEntry* entry) { |
+ if (!is_waiting_for_entry_) { |
+ // Already added to entry. |
+ return; |
+ } |
+ |
+ if (mode_ == READ) { |
+ // We cannot bypass the cache. |
+ return; |
+ } |
+ |
+ // Check that the writer is still busy, and then give up accessing cache. |
+ if (entry->writer && |
+ entry->writer->GetLoadState() == LOAD_STATE_WAITING_FOR_USER_ACTION) { |
+ // There is a writer transaction suspended due to some error. Bypass |
+ // cache if we can. |
+ entry->pending_queue.remove(this); |
+ mode_ = NONE; |
+ is_waiting_for_entry_ = false; |
+ BeginNetworkRequest(); |
+ } |
+} |
+ |
//----------------------------------------------------------------------------- |
HttpCache::HttpCache(ProxyService* proxy_service, |
@@ -1317,6 +1369,8 @@ |
if (entry->writer || entry->will_process_pending_queue) { |
entry->pending_queue.push_back(trans); |
+ trans->PendOnEntry(entry); |
+ |
return ERR_IO_PENDING; |
} |