Revert of HttpCache::Transaction layer allowing parallel validation (patchset #33 id:800001 of https://codereview.chromium.org/2721933002/ )

Reason for revert:
Breaks tricky-tot-chrome-pfq-informational audio_CrasSanity autotest: https://uberchromegw.corp.google.com/i/chromeos.chrome/builders/tricky-tot-chrome-pfq-informational/builds/4271

Original issue's description:
> This CL is a precursor to allowing shared writing to fix cache lock.
>
> This CL allows transactions to continue to their validation phase even when another
> transaction is the active reader/writer. After the validation phase, if its a match
> the transaction might wait till the response is written to the cache by the active
> writer. If its not a match the transaction will doom the entry and go to the
> network. In a subsequent CL, the not matching case will create a new entry as well.
>
> BUG=472740
>
> Review-Url: https://codereview.chromium.org/2721933002
> Cr-Commit-Position: refs/heads/master@{#467426}
> Committed: https://chromium.googlesource.com/chromium/src/+/1e2e347f957ef889aaee527bb757849f76e8a808

[email protected],[email protected],[email protected],[email protected]
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=472740

Review-Url: https://codereview.chromium.org/2847653002
Cr-Commit-Position: refs/heads/master@{#467556}
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc
index 42f8c17..968cffa 100644
--- a/net/http/http_cache.cc
+++ b/net/http/http_cache.cc
@@ -96,29 +96,28 @@
 //-----------------------------------------------------------------------------
 
 HttpCache::ActiveEntry::ActiveEntry(disk_cache::Entry* entry)
-    : disk_entry(entry) {}
+    : disk_entry(entry),
+      writer(NULL),
+      will_process_pending_queue(false),
+      doomed(false) {
+}
 
 HttpCache::ActiveEntry::~ActiveEntry() {
   if (disk_entry) {
     disk_entry->Close();
-    disk_entry = nullptr;
+    disk_entry = NULL;
   }
 }
 
 size_t HttpCache::ActiveEntry::EstimateMemoryUsage() const {
   // Skip |disk_entry| which is tracked in simple_backend_impl; Skip |readers|
-  // and |add_to_entry_queue| because the Transactions are owned by their
-  // respective URLRequestHttpJobs.
+  // and |pending_queue| because the Transactions are owned by their respective
+  // URLRequestHttpJobs.
   return 0;
 }
 
 bool HttpCache::ActiveEntry::HasNoTransactions() {
-  return !writer && readers.empty() && add_to_entry_queue.empty() &&
-         done_headers_queue.empty() && !headers_transaction;
-}
-
-bool HttpCache::ActiveEntry::HasNoActiveTransactions() {
-  return !writer && readers.empty() && !headers_transaction;
+  return !writer && readers.empty() && pending_queue.empty();
 }
 
 //-----------------------------------------------------------------------------
@@ -343,17 +342,15 @@
   weak_factory_.InvalidateWeakPtrs();
 
   // If we have any active entries remaining, then we need to deactivate them.
-  // We may have some pending tasks to process queued transactions ,but since
-  // those won't run (due to our destruction), we can simply ignore the
-  // corresponding flags.
+  // We may have some pending calls to OnProcessPendingQueue, but since those
+  // won't run (due to our destruction), we can simply ignore the corresponding
+  // will_process_pending_queue flag.
   while (!active_entries_.empty()) {
     ActiveEntry* entry = active_entries_.begin()->second.get();
-    entry->will_process_queued_transactions = false;
-    entry->add_to_entry_queue.clear();
+    entry->will_process_pending_queue = false;
+    entry->pending_queue.clear();
     entry->readers.clear();
-    entry->done_headers_queue.clear();
-    entry->headers_transaction = nullptr;
-    entry->writer = nullptr;
+    entry->writer = NULL;
     DeactivateEntry(entry);
   }
 
@@ -614,8 +611,7 @@
   entry_ptr->doomed = true;
 
   DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() ||
-         entry_ptr->headers_transaction ||
-         entry_ptr->will_process_queued_transactions);
+         entry_ptr->will_process_pending_queue);
   return OK;
 }
 
@@ -671,7 +667,7 @@
 
 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) {
   auto it = active_entries_.find(key);
-  return it != active_entries_.end() ? it->second.get() : nullptr;
+  return it != active_entries_.end() ? it->second.get() : NULL;
 }
 
 HttpCache::ActiveEntry* HttpCache::ActivateEntry(
@@ -683,7 +679,7 @@
 }
 
 void HttpCache::DeactivateEntry(ActiveEntry* entry) {
-  DCHECK(!entry->will_process_queued_transactions);
+  DCHECK(!entry->will_process_pending_queue);
   DCHECK(!entry->doomed);
   DCHECK(entry->disk_entry);
   DCHECK(entry->HasNoTransactions());
@@ -813,261 +809,121 @@
   }
 }
 
-int HttpCache::AddTransactionToEntry(ActiveEntry* entry,
-                                     Transaction* transaction) {
+int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) {
   DCHECK(entry);
   DCHECK(entry->disk_entry);
-  // Always add a new transaction to the queue to maintain FIFO order.
-  entry->add_to_entry_queue.push_back(transaction);
-  ProcessQueuedTransactions(entry);
-  return ERR_IO_PENDING;
-}
 
-int HttpCache::DoneWithResponseHeaders(ActiveEntry* entry,
-                                       Transaction* transaction) {
-  // If |transaction| is the current writer, do nothing. This can happen for
-  // range requests since they can go back to headers phase after starting to
-  // write.
-  if (entry->writer == transaction)
-    return OK;
+  // We implement a basic reader/writer lock for the disk cache entry.  If
+  // there is already a writer, then everyone has to wait for the writer to
+  // finish before they can access the cache entry.  There can be multiple
+  // readers.
+  //
+  // NOTE: If the transaction can only write, then the entry should not be in
+  // use (since any existing entry should have already been doomed).
 
-  DCHECK_EQ(entry->headers_transaction, transaction);
-
-  entry->headers_transaction = nullptr;
-
-  // If transaction is responsible for writing the response body, then do not go
-  // through done_headers_queue for performance benefit. (Also, in case of
-  // writer transaction, the consumer sometimes depend on synchronous behaviour
-  // e.g. while computing raw headers size. (crbug.com/711766))
-  if (transaction->mode() & Transaction::WRITE) {
-    DCHECK(entry->done_headers_queue.empty());
-    DCHECK(!entry->writer);
-    entry->writer = transaction;
-    ProcessQueuedTransactions(entry);
-    return OK;
+  if (entry->writer || entry->will_process_pending_queue) {
+    entry->pending_queue.push_back(trans);
+    return ERR_IO_PENDING;
   }
 
-  // If this is not the first transaction in done_headers_queue, it should be a
-  // read-mode transaction.
-  DCHECK(entry->done_headers_queue.empty() ||
-         !(transaction->mode() & Transaction::WRITE));
+  if (trans->mode() & Transaction::WRITE) {
+    // transaction needs exclusive access to the entry
+    if (entry->readers.empty()) {
+      entry->writer = trans;
+    } else {
+      entry->pending_queue.push_back(trans);
+      return ERR_IO_PENDING;
+    }
+  } else {
+    // transaction needs read access to the entry
+    entry->readers.insert(trans);
+  }
 
-  entry->done_headers_queue.push_back(transaction);
-  ProcessQueuedTransactions(entry);
-  return ERR_IO_PENDING;
+  // We do this before calling EntryAvailable to force any further calls to
+  // AddTransactionToEntry to add their transaction to the pending queue, which
+  // ensures FIFO ordering.
+  if (!entry->writer && !entry->pending_queue.empty())
+    ProcessPendingQueue(entry);
+
+  return OK;
 }
 
-void HttpCache::DoneWithEntry(ActiveEntry* entry,
-                              Transaction* transaction,
+void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans,
                               bool cancel) {
-  // Transaction is waiting in the done_headers_queue.
-  auto it = std::find(entry->done_headers_queue.begin(),
-                      entry->done_headers_queue.end(), transaction);
-  if (it != entry->done_headers_queue.end()) {
-    entry->done_headers_queue.erase(it);
-    if (cancel)
-      ProcessEntryFailure(entry);
+  // If we already posted a task to move on to the next transaction and this was
+  // the writer, there is nothing to cancel.
+  if (entry->will_process_pending_queue && entry->readers.empty())
     return;
-  }
 
-  // Transaction is removed in the headers phase.
-  if (transaction == entry->headers_transaction) {
-    // If the response is not written (cancel is true), consider it a failure.
-    DoneWritingToEntry(entry, !cancel, transaction);
-    return;
-  }
+  if (entry->writer) {
+    DCHECK(trans == entry->writer);
 
-  // Transaction is removed in the writing phase.
-  if (transaction == entry->writer) {
     // Assume there was a failure.
     bool success = false;
     if (cancel) {
       DCHECK(entry->disk_entry);
       // This is a successful operation in the sense that we want to keep the
       // entry.
-      success = transaction->AddTruncatedFlag();
+      success = trans->AddTruncatedFlag();
       // The previous operation may have deleted the entry.
-      if (!transaction->entry())
+      if (!trans->entry())
         return;
     }
-    DoneWritingToEntry(entry, success, transaction);
-    return;
+    DoneWritingToEntry(entry, success);
+  } else {
+    DoneReadingFromEntry(entry, trans);
   }
-
-  // Transaction is reading from the entry.
-  DoneReadingFromEntry(entry, transaction);
 }
 
-void HttpCache::DoneWritingToEntry(ActiveEntry* entry,
-                                   bool success,
-                                   Transaction* transaction) {
-  DCHECK(transaction == entry->writer ||
-         transaction == entry->headers_transaction);
+void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) {
+  DCHECK(entry->readers.empty());
 
-  if (transaction == entry->writer)
-    entry->writer = nullptr;
-  else
-    entry->headers_transaction = nullptr;
+  entry->writer = NULL;
 
-  // If writer fails, restart the headers_transaction by setting its state.
-  // Since the headers_transactions is awaiting an asynchronous operation
-  // completion, when it's IO callback is invoked, it will be restarted.
-  if (!success && entry->headers_transaction) {
-    entry->headers_transaction->SetValidatingCannotProceed();
-    entry->headers_transaction = nullptr;
-    DCHECK(entry->HasNoActiveTransactions());
+  if (success) {
+    ProcessPendingQueue(entry);
+  } else {
+    DCHECK(!entry->will_process_pending_queue);
+
+    // We failed to create this entry.
+    TransactionList pending_queue;
+    pending_queue.swap(entry->pending_queue);
+
+    entry->disk_entry->Doom();
+    DestroyEntry(entry);
+
+    // We need to do something about these pending entries, which now need to
+    // be added to a new entry.
+    while (!pending_queue.empty()) {
+      // ERR_CACHE_RACE causes the transaction to restart the whole process.
+      pending_queue.front()->io_callback().Run(ERR_CACHE_RACE);
+      pending_queue.pop_front();
+    }
   }
-  if (!success)
-    ProcessEntryFailure(entry);
-  else
-    ProcessQueuedTransactions(entry);
 }
 
-void HttpCache::DoneReadingFromEntry(ActiveEntry* entry,
-                                     Transaction* transaction) {
+void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) {
   DCHECK(!entry->writer);
-  auto it = entry->readers.find(transaction);
+
+  auto it = entry->readers.find(trans);
   DCHECK(it != entry->readers.end());
+
   entry->readers.erase(it);
 
-  ProcessQueuedTransactions(entry);
+  ProcessPendingQueue(entry);
 }
 
-void HttpCache::RemoveAllQueuedTransactions(ActiveEntry* entry,
-                                            TransactionList* list) {
-  // Process done_headers_queue before add_to_entry_queue to maintain FIFO
-  // order.
-  for (auto* transaction : entry->done_headers_queue)
-    list->push_back(transaction);
-  entry->done_headers_queue.clear();
+void HttpCache::ConvertWriterToReader(ActiveEntry* entry) {
+  DCHECK(entry->writer);
+  DCHECK(entry->writer->mode() == Transaction::READ_WRITE);
+  DCHECK(entry->readers.empty());
 
-  for (auto* transaction : entry->add_to_entry_queue)
-    list->push_back(transaction);
-  entry->add_to_entry_queue.clear();
-}
+  Transaction* trans = entry->writer;
 
-void HttpCache::ProcessEntryFailure(ActiveEntry* entry) {
-  // Failure case is either writer failing to completely write the response to
-  // the cache or validating transaction received a non-304 response.
-  TransactionList list;
-  if (entry->HasNoActiveTransactions() &&
-      !entry->will_process_queued_transactions) {
-    entry->disk_entry->Doom();
-    RemoveAllQueuedTransactions(entry, &list);
-    DestroyEntry(entry);
-  } else {
-    DoomActiveEntry(entry->disk_entry->GetKey());
-    RemoveAllQueuedTransactions(entry, &list);
-  }
-  // ERR_CACHE_RACE causes the transaction to restart the whole process.
-  for (auto* transaction : list)
-    transaction->io_callback().Run(net::ERR_CACHE_RACE);
-}
+  entry->writer = NULL;
+  entry->readers.insert(trans);
 
-void HttpCache::ProcessQueuedTransactions(ActiveEntry* entry) {
-  // Multiple readers may finish with an entry at once, so we want to batch up
-  // calls to OnProcessQueuedTransactions. This flag also tells us that we
-  // should not delete the entry before OnProcessQueuedTransactions runs.
-  if (entry->will_process_queued_transactions)
-    return;
-
-  entry->will_process_queued_transactions = true;
-
-  // Post a task instead of invoking the io callback of another transaction here
-  // to avoid re-entrancy.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(&HttpCache::OnProcessQueuedTransactions, GetWeakPtr(), entry));
-}
-
-void HttpCache::ProcessAddToEntryQueue(ActiveEntry* entry) {
-  DCHECK(!entry->add_to_entry_queue.empty());
-
-  // Note the entry may be new or may already have a response body written to
-  // it. In both cases, a transaction needs to wait since only one transaction
-  // can be in the headers phase at a time.
-  if (entry->headers_transaction) {
-    return;
-  }
-  Transaction* transaction = entry->add_to_entry_queue.front();
-  entry->add_to_entry_queue.erase(entry->add_to_entry_queue.begin());
-  entry->headers_transaction = transaction;
-
-  transaction->io_callback().Run(OK);
-}
-
-void HttpCache::ProcessDoneHeadersQueue(ActiveEntry* entry) {
-  DCHECK(!entry->writer);
-  DCHECK(!entry->done_headers_queue.empty());
-
-  Transaction* transaction = entry->done_headers_queue.front();
-
-  // If this transaction is responsible for writing the response body.
-  if (transaction->mode() & Transaction::WRITE) {
-    entry->writer = transaction;
-  } else {
-    // If a transaction is in front of this queue with only read mode set and
-    // there is no writer, it implies response body is already written, convert
-    // to a reader.
-    auto return_val = entry->readers.insert(transaction);
-    DCHECK_EQ(return_val.second, true);
-  }
-
-  // Post another task to give a chance to more transactions to either join
-  // readers or another transaction to start parallel validation.
-  ProcessQueuedTransactions(entry);
-
-  entry->done_headers_queue.erase(entry->done_headers_queue.begin());
-  transaction->io_callback().Run(OK);
-}
-
-bool HttpCache::CanTransactionWriteResponseHeaders(ActiveEntry* entry,
-                                                   Transaction* transaction,
-                                                   bool is_match) const {
-  if (transaction != entry->headers_transaction)
-    return false;
-
-  if (!(transaction->mode() & Transaction::WRITE))
-    return false;
-
-  // If its not a match then check if it is the transaction responsible for
-  // writing the response body.
-  if (!is_match) {
-    return !entry->writer && entry->done_headers_queue.empty() &&
-           entry->readers.empty();
-  }
-
-  return true;
-}
-
-bool HttpCache::IsTransactionWritingIncomplete(
-    ActiveEntry* entry,
-    Transaction* transaction,
-    const std::string& method) const {
-  if (transaction == entry->writer)
-    return true;
-
-  if (method == "HEAD" || method == "DELETE")
-    return false;
-
-  // Check if transaction is about to start writing to the cache.
-
-  // Transaction's mode may have been set to NONE if StopCaching was invoked.
-  if (!(transaction->mode() & Transaction::WRITE ||
-        transaction->mode() == Transaction::NONE)) {
-    return false;
-  }
-
-  // If a transaction is completing headers or done with headers phase with
-  // write mode then it should be the future writer. Just checking the front of
-  // done_headers_queue since the rest should anyways be READ mode transactions
-  // as they would be a result of validation match.
-  return transaction == entry->headers_transaction ||
-         transaction == entry->done_headers_queue.front();
-}
-
-bool HttpCache::IsWritingInProgress(ActiveEntry* entry) const {
-  return entry->writer != nullptr;
+  ProcessPendingQueue(entry);
 }
 
 LoadState HttpCache::GetLoadStateForPendingTransaction(
@@ -1117,15 +973,14 @@
 }
 
 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry,
-                                                  Transaction* transaction) {
-  TransactionList& add_to_entry_queue = entry->add_to_entry_queue;
+                                                  Transaction* trans) {
+  TransactionList& pending_queue = entry->pending_queue;
 
-  auto j =
-      find(add_to_entry_queue.begin(), add_to_entry_queue.end(), transaction);
-  if (j == add_to_entry_queue.end())
+  auto j = find(pending_queue.begin(), pending_queue.end(), trans);
+  if (j == pending_queue.end())
     return false;
 
-  add_to_entry_queue.erase(j);
+  pending_queue.erase(j);
   return true;
 }
 
@@ -1147,11 +1002,22 @@
   return false;
 }
 
-void HttpCache::OnProcessQueuedTransactions(ActiveEntry* entry) {
-  entry->will_process_queued_transactions = false;
+void HttpCache::ProcessPendingQueue(ActiveEntry* entry) {
+  // Multiple readers may finish with an entry at once, so we want to batch up
+  // calls to OnProcessPendingQueue.  This flag also tells us that we should
+  // not delete the entry before OnProcessPendingQueue runs.
+  if (entry->will_process_pending_queue)
+    return;
+  entry->will_process_pending_queue = true;
 
-  // Note that this function should only invoke one transaction's IO callback
-  // since its possible for IO callbacks' consumers to destroy the cache/entry.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry));
+}
+
+void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) {
+  entry->will_process_pending_queue = false;
+  DCHECK(!entry->writer);
 
   // If no one is interested in this entry, then we can deactivate it.
   if (entry->HasNoTransactions()) {
@@ -1159,22 +1025,20 @@
     return;
   }
 
-  if (entry->done_headers_queue.empty() && entry->add_to_entry_queue.empty())
+  if (entry->pending_queue.empty())
     return;
 
-  // To maintain FIFO order of transactions, done_headers_queue should be
-  // checked for processing before add_to_entry_queue.
+  // Promote next transaction from the pending queue.
+  Transaction* next = entry->pending_queue.front();
+  if ((next->mode() & Transaction::WRITE) && !entry->readers.empty())
+    return;  // Have to wait.
 
-  // If another transaction is writing the response, let validated transactions
-  // wait till the response is complete. If the response is not yet started, the
-  // done_headers_queue transaction should start writing it.
-  if (!entry->writer && !entry->done_headers_queue.empty()) {
-    ProcessDoneHeadersQueue(entry);
-    return;
+  entry->pending_queue.erase(entry->pending_queue.begin());
+
+  int rv = AddTransactionToEntry(entry, next);
+  if (rv != ERR_IO_PENDING) {
+    next->io_callback().Run(rv);
   }
-
-  if (!entry->add_to_entry_queue.empty())
-    ProcessAddToEntryQueue(entry);
 }
 
 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) {
diff --git a/net/http/http_cache.h b/net/http/http_cache.h
index ca8ba08..635cb92d 100644
--- a/net/http/http_cache.h
+++ b/net/http/http_cache.h
@@ -244,32 +244,10 @@
   friend class ViewCacheHelper;
   struct PendingOp;  // Info for an entry under construction.
 
-  // To help with testing.
-  friend class MockHttpCache;
-
   using TransactionList = std::list<Transaction*>;
   using TransactionSet = std::unordered_set<Transaction*>;
   typedef std::list<std::unique_ptr<WorkItem>> WorkItemList;
 
-  // We implement a basic reader/writer lock for the disk cache entry. If there
-  // is a writer, then all transactions must wait to read the body. But the
-  // waiting transactions can start their headers phase in parallel. Headers
-  // phase is allowed for one transaction at a time so that if it doesn't match
-  // the existing headers, remaining transactions do not also try to match the
-  // existing entry in parallel leading to wasted network requests. If the
-  // headers do not match, this entry will be doomed.
-  //
-  // A transaction goes through these state transitions.
-  //
-  // Write mode transactions:
-  // add_to_entry_queue-> headers_transaction -> writer
-  // add_to_entry_queue-> headers_transaction -> done_headers_queue -> readers
-  // (once the data is written to the cache by another writer)
-  //
-  // Read only transactions:
-  // add_to_entry_queue-> headers_transaction -> done_headers_queue -> readers
-  // (once the data is written to the cache by the writer)
-
   struct ActiveEntry {
     explicit ActiveEntry(disk_cache::Entry* entry);
     ~ActiveEntry();
@@ -278,36 +256,12 @@
     // Returns true if no transactions are associated with this entry.
     bool HasNoTransactions();
 
-    // Returns true if no active readers/writer transactions are associated
-    // with this entry.
-    bool HasNoActiveTransactions();
-
-    disk_cache::Entry* disk_entry = nullptr;
-
-    // Transactions waiting to be added to entry.
-    TransactionList add_to_entry_queue;
-
-    // Transaction currently in the headers phase, either validating the
-    // response or getting new headers. This can exist simultaneously with
-    // writer or readers while validating existing headers.
-    Transaction* headers_transaction = nullptr;
-
-    // Transactions that have completed their headers phase and are waiting
-    // to read the response body or write the response body.
-    TransactionList done_headers_queue;
-
-    // Transaction currently reading from the network and writing to the cache.
-    Transaction* writer = nullptr;
-
-    // Transactions that can only read from the cache. Only one of writer or
-    // readers can exist at a time.
+    disk_cache::Entry* disk_entry;
+    Transaction*       writer;
     TransactionSet readers;
-
-    // The following variables are true if OnProcessQueuedTransactions is posted
-    bool will_process_queued_transactions = false;
-
-    // True if entry is doomed.
-    bool doomed = false;
+    TransactionList    pending_queue;
+    bool               will_process_pending_queue;
+    bool               doomed;
   };
 
   using ActiveEntriesMap =
@@ -388,73 +342,28 @@
   // Destroys an ActiveEntry (active or doomed).
   void DestroyEntry(ActiveEntry* entry);
 
-  // Adds a transaction to an ActiveEntry. This method returns ERR_IO_PENDING
-  // and the transaction will be notified about completion via its IO callback.
-  // In a failure case, the callback will be invoked with ERR_CACHE_RACE.
-  int AddTransactionToEntry(ActiveEntry* entry, Transaction* transaction);
-
-  // Transaction invokes this when its response headers phase is complete
-  // If the transaction is responsible for writing the response body,
-  // it becomes the writer and returns OK. In other cases ERR_IO_PENDING is
-  // returned and the transaction will be notified about completion via its
-  // IO callback. In a failure case, the callback will be invoked with
-  // ERR_CACHE_RACE.
-  int DoneWithResponseHeaders(ActiveEntry* entry, Transaction* transaction);
+  // Adds a transaction to an ActiveEntry. If this method returns ERR_IO_PENDING
+  // the transaction will be notified about completion via its IO callback. This
+  // method returns ERR_CACHE_RACE to signal the transaction that it cannot be
+  // added to the provided entry, and it should retry the process with another
+  // one (in this case, the entry is no longer valid).
+  int AddTransactionToEntry(ActiveEntry* entry, Transaction* trans);
 
   // Called when the transaction has finished working with this entry. |cancel|
   // is true if the operation was cancelled by the caller instead of running
   // to completion.
-  void DoneWithEntry(ActiveEntry* entry, Transaction* transaction, bool cancel);
+  void DoneWithEntry(ActiveEntry* entry, Transaction* trans, bool cancel);
 
   // Called when the transaction has finished writing to this entry. |success|
   // is false if the cache entry should be deleted.
-  void DoneWritingToEntry(ActiveEntry* entry,
-                          bool success,
-                          Transaction* transaction);
+  void DoneWritingToEntry(ActiveEntry* entry, bool success);
 
   // Called when the transaction has finished reading from this entry.
-  void DoneReadingFromEntry(ActiveEntry* entry, Transaction* transaction);
+  void DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans);
 
-  // Removes and returns all queued transactions in |entry| in FIFO order. This
-  // includes transactions that have completed the headers phase and those that
-  // have not been added to the entry yet in that order. |list| is the output
-  // argument.
-  void RemoveAllQueuedTransactions(ActiveEntry* entry, TransactionList* list);
-
-  // Processes either writer's failure to write response body or
-  // headers_transactions's failure to write headers. Also invoked when headers
-  // transaction's validation result is not a match.
-  void ProcessEntryFailure(ActiveEntry* entry);
-
-  // Resumes processing the queued transactions of |entry|.
-  void ProcessQueuedTransactions(ActiveEntry* entry);
-
-  // Checks if a transaction can be added to the entry. If yes, it will
-  // invoke the IO callback of the transaction. This is a helper function for
-  // OnProcessQueuedTransactions. It will take a transaction from
-  // add_to_entry_queue and make it a headers_transaction, if one doesn't exist
-  // already.
-  void ProcessAddToEntryQueue(ActiveEntry* entry);
-
-  // Invoked when a transaction that has already completed the response headers
-  // phase can resume reading/writing the response body. It will invoke the IO
-  // callback of the transaction. This is a helper function for
-  // OnProcessQueuedTransactions.
-  void ProcessDoneHeadersQueue(ActiveEntry* entry);
-
-  // Returns true if this transaction can write headers to the entry.
-  bool CanTransactionWriteResponseHeaders(ActiveEntry* entry,
-                                          Transaction* transaction,
-                                          bool is_match) const;
-
-  // Returns true if |transaction| is about to start writing response body or
-  // already started but not yet finished.
-  bool IsTransactionWritingIncomplete(ActiveEntry* entry,
-                                      Transaction* transaction,
-                                      const std::string& method) const;
-
-  // Returns true if a transaction is currently writing the response body.
-  bool IsWritingInProgress(ActiveEntry* entry) const;
+  // Converts the active writer transaction to a reader so that other
+  // transactions can start reading from this entry.
+  void ConvertWriterToReader(ActiveEntry* entry);
 
   // Returns the LoadState of the provided pending transaction.
   LoadState GetLoadStateForPendingTransaction(const Transaction* trans);
@@ -470,10 +379,12 @@
   // Removes the transaction |trans|, from the pending list of |pending_op|.
   bool RemovePendingTransactionFromPendingOp(PendingOp* pending_op,
                                              Transaction* trans);
+  // Resumes processing the pending list of |entry|.
+  void ProcessPendingQueue(ActiveEntry* entry);
 
   // Events (called via PostTask) ---------------------------------------------
 
-  void OnProcessQueuedTransactions(ActiveEntry* entry);
+  void OnProcessPendingQueue(ActiveEntry* entry);
 
   // Callbacks ----------------------------------------------------------------
 
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index b10bf90..5189446 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -156,7 +156,6 @@
       new_entry_(NULL),
       new_response_(NULL),
       mode_(NONE),
-      original_mode_(NONE),
       reading_(false),
       invalid_range_(false),
       truncated_(false),
@@ -197,12 +196,16 @@
 
   if (cache_) {
     if (entry_) {
-      bool writing_incomplete = cache_->IsTransactionWritingIncomplete(
-          entry_, this, request_->method);
-      if (writing_incomplete && partial_)
-        entry_->disk_entry->CancelSparseIO();
+      bool cancel_request = reading_ && response_.headers.get();
+      if (cancel_request) {
+        if (partial_) {
+          entry_->disk_entry->CancelSparseIO();
+        } else {
+          cancel_request &= (response_.headers->response_code() == 200);
+        }
+      }
 
-      cache_->DoneWithEntry(entry_, this, writing_incomplete);
+      cache_->DoneWithEntry(entry_, this, cancel_request);
     } else if (cache_pending_) {
       cache_->RemovePendingTransaction(this);
     }
@@ -562,12 +565,6 @@
               old_connection_attempts_.end());
 }
 
-void HttpCache::Transaction::SetValidatingCannotProceed() {
-  DCHECK(!reading_);
-  next_state_ = STATE_HEADERS_PHASE_CANNOT_PROCEED;
-  entry_ = nullptr;
-}
-
 size_t HttpCache::Transaction::EstimateMemoryUsage() const {
   // TODO(xunjieli): Consider improving the coverage. crbug.com/669108.
   return 0;
@@ -582,7 +579,7 @@
 //   GetBackend* -> InitEntry -> OpenEntry* -> CreateEntry* -> AddToEntry* ->
 //   SendRequest* -> SuccessfulSendRequest -> OverwriteCachedResponse ->
 //   CacheWriteResponse* -> TruncateCachedData* -> TruncateCachedMetadata* ->
-//   PartialHeadersReceived -> FinishHeaders*
+//   PartialHeadersReceived
 //
 //   Read():
 //   NetworkRead* -> CacheWriteData*
@@ -591,7 +588,7 @@
 //   Start():
 //   GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse*
 //   -> CacheDispatchValidation -> BeginPartialCacheValidation() ->
-//   BeginCacheValidation() -> SetupEntryForRead() -> FinishHeaders*
+//   BeginCacheValidation() -> SetupEntryForRead()
 //
 //   Read():
 //   CacheReadData*
@@ -603,7 +600,7 @@
 //   BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest ->
 //   UpdateCachedResponse -> CacheWriteUpdatedResponse* ->
 //   UpdateCachedResponseComplete -> OverwriteCachedResponse ->
-//   PartialHeadersReceived -> FinishHeaders*
+//   PartialHeadersReceived
 //
 //   Read():
 //   CacheReadData*
@@ -614,7 +611,7 @@
 //   -> CacheDispatchValidation -> BeginPartialCacheValidation() ->
 //   BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest ->
 //   OverwriteCachedResponse -> CacheWriteResponse* -> DoTruncateCachedData* ->
-//   TruncateCachedMetadata* -> PartialHeadersReceived -> FinishHeaders*
+//   TruncateCachedMetadata* -> PartialHeadersReceived
 //
 //   Read():
 //   NetworkRead* -> CacheWriteData*
@@ -628,7 +625,7 @@
 //   BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest ->
 //   UpdateCachedResponse -> CacheWriteUpdatedResponse* ->
 //   UpdateCachedResponseComplete -> OverwriteCachedResponse ->
-//   PartialHeadersReceived -> FinishHeaders*
+//   PartialHeadersReceived
 //
 //   Read() 1:
 //   NetworkRead* -> CacheWriteData*
@@ -669,7 +666,7 @@
 //   GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse*
 //   -> CacheDispatchValidation -> BeginPartialCacheValidation() ->
 //   BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest ->
-//   OverwriteCachedResponse -> FinishHeaders*
+//   OverwriteCachedResponse
 //
 // 10. HEAD. Sparse entry, partially cached:
 //   Serve the request from the cache, as long as it doesn't require
@@ -694,7 +691,7 @@
 //   GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse*
 //   -> CacheToggleUnusedSincePrefetch* -> CacheDispatchValidation ->
 //   BeginPartialCacheValidation() -> BeginCacheValidation() ->
-//   SetupEntryForRead() -> FinishHeaders*
+//   SetupEntryForRead()
 //
 //   Read():
 //   CacheReadData*
@@ -708,9 +705,8 @@
   DCHECK(!in_do_loop_);
 
   int rv = result;
-  State state = next_state_;
   do {
-    state = next_state_;
+    State state = next_state_;
     next_state_ = STATE_UNSET;
     base::AutoReset<bool> scoped_in_do_loop(&in_do_loop_, true);
 
@@ -847,15 +843,6 @@
       case STATE_CACHE_READ_METADATA_COMPLETE:
         rv = DoCacheReadMetadataComplete(rv);
         break;
-      case STATE_HEADERS_PHASE_CANNOT_PROCEED:
-        rv = DoHeadersPhaseCannotProceed();
-        break;
-      case STATE_FINISH_HEADERS:
-        rv = DoFinishHeaders(rv);
-        break;
-      case STATE_FINISH_HEADERS_COMPLETE:
-        rv = DoFinishHeadersComplete(rv);
-        break;
       case STATE_NETWORK_READ:
         DCHECK_EQ(OK, rv);
         rv = DoNetworkRead();
@@ -892,13 +879,8 @@
 
   } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
 
-  // Assert Start() state machine's allowed last state in successful cases when
-  // caching is happening.
-  DCHECK(reading_ || rv != OK || !entry_ ||
-         state == STATE_FINISH_HEADERS_COMPLETE);
-
   if (rv != ERR_IO_PENDING && !callback_.is_null()) {
-    read_buf_ = nullptr;  // Release the buffer before invoking the callback.
+    read_buf_ = NULL;  // Release the buffer before invoking the callback.
     base::ResetAndReturn(&callback_).Run(rv);
   }
 
@@ -925,7 +907,7 @@
     if (effective_load_flags_ & LOAD_ONLY_FROM_CACHE) {
       if (effective_load_flags_ & LOAD_BYPASS_CACHE) {
         // The client has asked for nonsense.
-        TransitionToState(STATE_FINISH_HEADERS);
+        TransitionToState(STATE_NONE);
         return ERR_CACHE_MISS;
       }
       mode_ = READ;
@@ -964,7 +946,7 @@
   // If must use cache, then we must fail.  This can happen for back/forward
   // navigations to a page generated via a form post.
   if (!(mode_ & READ) && effective_load_flags_ & LOAD_ONLY_FROM_CACHE) {
-    TransitionToState(STATE_FINISH_HEADERS);
+    TransitionToState(STATE_NONE);
     return ERR_CACHE_MISS;
   }
 
@@ -981,9 +963,6 @@
   // This is only set if we have something to do with the response.
   range_requested_ = (partial_.get() != NULL);
 
-  // mode_ may change later, save the initial mode in case we need to restart
-  // this request.
-  original_mode_ = mode_;
   return OK;
 }
 
@@ -992,7 +971,7 @@
   DCHECK(!new_entry_);
 
   if (!cache_.get()) {
-    TransitionToState(STATE_FINISH_HEADERS);
+    TransitionToState(STATE_NONE);
     return ERR_UNEXPECTED;
   }
 
@@ -1029,7 +1008,7 @@
   }
 
   if (result == ERR_CACHE_RACE) {
-    TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED);
+    TransitionToState(STATE_INIT_ENTRY);
     return OK;
   }
 
@@ -1055,7 +1034,7 @@
 
   // The entry does not exist, and we are not permitted to create a new entry,
   // so we must fail.
-  TransitionToState(STATE_FINISH_HEADERS);
+  TransitionToState(STATE_NONE);
   return ERR_CACHE_MISS;
 }
 
@@ -1074,9 +1053,8 @@
   net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_DOOM_ENTRY,
                                     result);
   cache_pending_ = false;
-  TransitionToState(result == ERR_CACHE_RACE
-                        ? STATE_HEADERS_PHASE_CANNOT_PROCEED
-                        : STATE_CREATE_ENTRY);
+  TransitionToState(result == ERR_CACHE_RACE ? STATE_INIT_ENTRY
+                                             : STATE_CREATE_ENTRY);
   return OK;
 }
 
@@ -1103,7 +1081,7 @@
       break;
 
     case ERR_CACHE_RACE:
-      TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED);
+      TransitionToState(STATE_INIT_ENTRY);
       break;
 
     default:
@@ -1184,13 +1162,13 @@
   new_entry_ = NULL;
 
   if (result == ERR_CACHE_RACE) {
-    TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED);
+    TransitionToState(STATE_INIT_ENTRY);
     return OK;
   }
 
   if (result == ERR_CACHE_LOCK_TIMEOUT) {
     if (mode_ == READ) {
-      TransitionToState(STATE_FINISH_HEADERS);
+      TransitionToState(STATE_NONE);
       return ERR_CACHE_MISS;
     }
 
@@ -1204,16 +1182,12 @@
     return OK;
   }
 
-  // TODO(crbug.com/713354) Access timestamp for histograms only if entry is
-  // already written, to avoid data race since cache thread can also access
-  // this.
-  if (!cache_->IsWritingInProgress(entry_))
-    open_entry_last_used_ = entry_->disk_entry->GetLastUsed();
+  open_entry_last_used_ = entry_->disk_entry->GetLastUsed();
 
   // TODO(jkarlin): We should either handle the case or DCHECK.
   if (result != OK) {
     NOTREACHED();
-    TransitionToState(STATE_FINISH_HEADERS);
+    TransitionToState(STATE_NONE);
     return result;
   }
 
@@ -1252,37 +1226,29 @@
     return OnCacheReadError(result, true);
   }
 
-  // TODO(crbug.com/713354) Only get data size if there is no other transaction
-  // currently writing the response body due to the data race mentioned in the
-  // associated bug.
-  if (!cache_->IsWritingInProgress(entry_)) {
-    int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex);
-    int64_t full_response_length = response_.headers->GetContentLength();
+  int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex);
+  int64_t full_response_length = response_.headers->GetContentLength();
 
-    // Some resources may have slipped in as truncated when they're not.
-    if (full_response_length == current_size)
-      truncated_ = false;
+  // Some resources may have slipped in as truncated when they're not.
+  if (full_response_length == current_size)
+    truncated_ = false;
 
-    // The state machine's handling of StopCaching unfortunately doesn't deal
-    // well with resources that are larger than 2GB when there is a truncated or
-    // sparse cache entry. While the state machine is reworked to resolve this,
-    // the following logic is put in place to defer such requests to the
-    // network. The cache should not be storing multi gigabyte resources. See
-    // http://crbug.com/89567.
-    if ((truncated_ || response_.headers->response_code() == 206) &&
-        !range_requested_ &&
-        full_response_length > std::numeric_limits<int32_t>::max()) {
-      DCHECK(!partial_);
-
-      // Doom the entry so that no other transaction gets added to this entry
-      // and avoid a race of not being able to check this condition because
-      // writing is in progress.
-      cache_->DoneWritingToEntry(entry_, false, this);
-      entry_ = nullptr;
-      mode_ = NONE;
-      TransitionToState(STATE_SEND_REQUEST);
-      return OK;
-    }
+  // The state machine's handling of StopCaching unfortunately doesn't deal well
+  // with resources that are larger than 2GB when there is a truncated or sparse
+  // cache entry. While the state machine is reworked to resolve this, the
+  // following logic is put in place to defer such requests to the network. The
+  // cache should not be storing multi gigabyte resources. See
+  // http://crbug.com/89567.
+  if ((truncated_ || response_.headers->response_code() == 206) &&
+      !range_requested_ &&
+      full_response_length > std::numeric_limits<int32_t>::max()) {
+    // Does not release the cache entry. If another transaction wants to use
+    // this cache entry while this transaction is active, the second transaction
+    // will fall back to the network after the timeout.
+    DCHECK(!partial_);
+    mode_ = NONE;
+    TransitionToState(STATE_SEND_REQUEST);
+    return OK;
   }
 
   if (response_.unused_since_prefetch !=
@@ -1364,7 +1330,7 @@
 int HttpCache::Transaction::DoCacheQueryDataComplete(int result) {
   DCHECK_EQ(OK, result);
   if (!cache_.get()) {
-    TransitionToState(STATE_FINISH_HEADERS);
+    TransitionToState(STATE_NONE);
     return ERR_UNEXPECTED;
   }
 
@@ -1374,7 +1340,7 @@
 // We may end up here multiple times for a given request.
 int HttpCache::Transaction::DoStartPartialCacheValidation() {
   if (mode_ == NONE) {
-    TransitionToState(STATE_FINISH_HEADERS);
+    TransitionToState(STATE_NONE);
     return OK;
   }
 
@@ -1391,12 +1357,12 @@
       cache_->DoneReadingFromEntry(entry_, this);
       entry_ = NULL;
     }
-    TransitionToState(STATE_FINISH_HEADERS);
+    TransitionToState(STATE_NONE);
     return result;
   }
 
   if (result < 0) {
-    TransitionToState(STATE_FINISH_HEADERS);
+    TransitionToState(STATE_NONE);
     return result;
   }
 
@@ -1422,7 +1388,7 @@
   int rv =
       cache_->network_layer_->CreateTransaction(priority_, &network_trans_);
   if (rv != OK) {
-    TransitionToState(STATE_FINISH_HEADERS);
+    TransitionToState(STATE_NONE);
     return rv;
   }
   network_trans_->SetBeforeNetworkStartCallback(before_network_start_callback_);
@@ -1444,7 +1410,7 @@
 int HttpCache::Transaction::DoSendRequestComplete(int result) {
   TRACE_EVENT0("io", "HttpCacheTransaction::DoSendRequestComplete");
   if (!cache_.get()) {
-    TransitionToState(STATE_FINISH_HEADERS);
+    TransitionToState(STATE_NONE);
     return ERR_UNEXPECTED;
   }
 
@@ -1475,7 +1441,7 @@
     DoneWritingToEntry(true);
   }
 
-  TransitionToState(STATE_FINISH_HEADERS);
+  TransitionToState(STATE_NONE);
   return result;
 }
 
@@ -1489,7 +1455,7 @@
       new_response->headers->response_code() == 407) {
     SetAuthResponse(*new_response);
     if (!reading_) {
-      TransitionToState(STATE_FINISH_HEADERS);
+      TransitionToState(STATE_NONE);
       return OK;
     }
 
@@ -1514,7 +1480,7 @@
     mode_ = NONE;
     partial_.reset();
     ResetNetworkTransaction();
-    TransitionToState(STATE_FINISH_HEADERS);
+    TransitionToState(STATE_NONE);
     return ERR_CACHE_AUTH_FAILURE_AFTER_READ;
   }
 
@@ -1552,7 +1518,7 @@
       int ret = cache_->DoomEntry(cache_key_, NULL);
       DCHECK_EQ(OK, ret);
     }
-    cache_->DoneWritingToEntry(entry_, true, this);
+    cache_->DoneWritingToEntry(entry_, true);
     entry_ = NULL;
     mode_ = NONE;
   }
@@ -1570,7 +1536,7 @@
       (request_->method == "GET" || request_->method == "POST")) {
     // If there is an active entry it may be destroyed with this transaction.
     SetResponse(*new_response_);
-    TransitionToState(STATE_FINISH_HEADERS);
+    TransitionToState(STATE_NONE);
     return OK;
   }
 
@@ -1658,6 +1624,7 @@
   } else if (entry_ && !handling_206_) {
     DCHECK_EQ(READ_WRITE, mode_);
     if (!partial_ || partial_->IsLastRange()) {
+      cache_->ConvertWriterToReader(entry_);
       mode_ = READ;
     }
     // We no longer need the network transaction, so destroy it.
@@ -1695,7 +1662,7 @@
     DoneWritingToEntry(false);
     mode_ = NONE;
     new_response_ = NULL;
-    TransitionToState(STATE_FINISH_HEADERS);
+    TransitionToState(STATE_NONE);
     return OK;
   }
 
@@ -1716,19 +1683,6 @@
 int HttpCache::Transaction::DoCacheWriteResponse() {
   TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponse");
   TransitionToState(STATE_CACHE_WRITE_RESPONSE_COMPLETE);
-
-  // Invalidate any current entry with a successful response if this transaction
-  // cannot write to this entry. This transaction then continues to read from
-  // the network without writing to the backend.
-  bool is_match = response_.headers->response_code() == 304;
-  if (entry_ && response_.headers &&
-      !cache_->CanTransactionWriteResponseHeaders(entry_, this, is_match)) {
-    cache_->DoneWritingToEntry(entry_, false, this);
-    entry_ = nullptr;
-    mode_ = NONE;
-    return OK;
-  }
-
   return WriteResponseInfoToEntry(truncated_);
 }
 
@@ -1790,12 +1744,10 @@
   new_response_ = NULL;
 
   if (!partial_) {
-    if (entry_ && entry_->disk_entry->GetDataSize(kMetadataIndex)) {
+    if (entry_ && entry_->disk_entry->GetDataSize(kMetadataIndex))
       TransitionToState(STATE_CACHE_READ_METADATA);
-    } else {
-      DCHECK(!reading_);
-      TransitionToState(STATE_FINISH_HEADERS);
-    }
+    else
+      TransitionToState(STATE_NONE);
     return OK;
   }
 
@@ -1809,61 +1761,11 @@
     // We are about to return the headers for a byte-range request to the user,
     // so let's fix them.
     partial_->FixResponseHeaders(response_.headers.get(), true);
-    TransitionToState(STATE_FINISH_HEADERS);
-  } else {
-    TransitionToState(STATE_FINISH_HEADERS);
-  }
-  return OK;
-}
-
-int HttpCache::Transaction::DoHeadersPhaseCannotProceed() {
-  // If its the Start state machine and it cannot proceed due to a cache
-  // failure, restart this transaction.
-  DCHECK(!reading_);
-  TransitionToState(STATE_INIT_ENTRY);
-  cache_entry_status_ = CacheEntryStatus::ENTRY_UNDEFINED;
-  entry_ = nullptr;
-  mode_ = original_mode_;
-  if (network_trans_)
-    network_trans_.reset();
-  return OK;
-}
-
-int HttpCache::Transaction::DoFinishHeaders(int result) {
-  if (!entry_ || result != OK) {
     TransitionToState(STATE_NONE);
-    return result;
+  } else {
+    TransitionToState(STATE_NONE);
   }
-
-  TransitionToState(STATE_FINISH_HEADERS_COMPLETE);
-
-  // If it was an auth failure or 416, this transaction should continue to be
-  // headers_transaction till consumer takes an action, so no need to do
-  // anything now.
-  if (auth_response_.headers.get() ||
-      (new_response_ && new_response_->headers &&
-       new_response_->headers->response_code() == 416))
-    return OK;
-
-  // If there is no response body to be written or read, it does not need to
-  // wait.
-  if (request_->method == "HEAD")
-    return OK;
-
-  // If the transaction needs to wait because another transaction is still
-  // writing the response body, it will return ERR_IO_PENDING now and the
-  // io_callback_ will be invoked when the wait is done.
-  return cache_->DoneWithResponseHeaders(entry_, this);
-}
-
-int HttpCache::Transaction::DoFinishHeadersComplete(int rv) {
-  if (rv == ERR_CACHE_RACE) {
-    TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED);
-    return OK;
-  }
-
-  TransitionToState(STATE_NONE);
-  return rv;
+  return OK;
 }
 
 int HttpCache::Transaction::DoCacheReadMetadata() {
@@ -1888,8 +1790,7 @@
                                     result);
   if (result != response_.metadata->size())
     return OnCacheReadError(result, false);
-
-  TransitionToState(STATE_FINISH_HEADERS);
+  TransitionToState(STATE_NONE);
   return OK;
 }
 
@@ -2186,18 +2087,18 @@
   // TODO(jkarlin): Either handle this case or DCHECK.
   if (response_.headers->response_code() == 206 || partial_) {
     NOTREACHED();
-    TransitionToState(STATE_FINISH_HEADERS);
+    TransitionToState(STATE_NONE);
     return ERR_CACHE_MISS;
   }
 
   // We don't have the whole resource.
   if (truncated_) {
-    TransitionToState(STATE_FINISH_HEADERS);
+    TransitionToState(STATE_NONE);
     return ERR_CACHE_MISS;
   }
 
   if (RequiresValidation()) {
-    TransitionToState(STATE_FINISH_HEADERS);
+    TransitionToState(STATE_NONE);
     return ERR_CACHE_MISS;
   }
 
@@ -2207,7 +2108,7 @@
   if (entry_->disk_entry->GetDataSize(kMetadataIndex))
     TransitionToState(STATE_CACHE_READ_METADATA);
   else
-    TransitionToState(STATE_FINISH_HEADERS);
+    TransitionToState(STATE_NONE);
 
   return OK;
 }
@@ -2667,7 +2568,7 @@
       partial_.reset();
     }
   }
-
+  cache_->ConvertWriterToReader(entry_);
   mode_ = READ;
 
   if (request_->method == "HEAD")
@@ -2676,7 +2577,7 @@
   if (entry_->disk_entry->GetDataSize(kMetadataIndex))
     TransitionToState(STATE_CACHE_READ_METADATA);
   else
-    TransitionToState(STATE_FINISH_HEADERS);
+    TransitionToState(STATE_NONE);
   return OK;
 }
 
@@ -2755,7 +2656,7 @@
 
   RecordHistograms();
 
-  cache_->DoneWritingToEntry(entry_, success, this);
+  cache_->DoneWritingToEntry(entry_, success);
   entry_ = NULL;
   mode_ = NONE;  // switch to 'pass through' mode
 }
@@ -2966,14 +2867,10 @@
        cache_entry_status_ == CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE);
   int64_t freshness_periods_since_last_used = 0;
 
-  if (stale_request && !open_entry_last_used_.is_null()) {
-    // Note that we are not able to capture those transactions' histograms which
-    // when added to entry, the response was being written by another
-    // transaction because getting the last used timestamp might lead to a data
-    // race in that case. TODO(crbug.com/713354).
-
+  if (stale_request) {
     // For stale entries, record how many freshness periods have elapsed since
     // the entry was last used.
+    DCHECK(!open_entry_last_used_.is_null());
     DCHECK(!stale_entry_freshness_.is_zero());
     base::TimeDelta time_since_use = base::Time::Now() - open_entry_last_used_;
     freshness_periods_since_last_used =
diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h
index 6811dd4..51c0db7 100644
--- a/net/http/http_cache_transaction.h
+++ b/net/http/http_cache_transaction.h
@@ -164,10 +164,6 @@
   int ResumeNetworkStart() override;
   void GetConnectionAttempts(ConnectionAttempts* out) const override;
 
-  // Invoked when parallel validation cannot proceed due to response failure
-  // and this transaction needs to be restarted.
-  void SetValidatingCannotProceed();
-
   // Returns the estimate of dynamically allocated memory in bytes.
   size_t EstimateMemoryUsage() const;
 
@@ -224,9 +220,6 @@
     STATE_PARTIAL_HEADERS_RECEIVED,
     STATE_CACHE_READ_METADATA,
     STATE_CACHE_READ_METADATA_COMPLETE,
-    STATE_HEADERS_PHASE_CANNOT_PROCEED,
-    STATE_FINISH_HEADERS,
-    STATE_FINISH_HEADERS_COMPLETE,
 
     // These states are entered from Read/AddTruncatedFlag.
     STATE_NETWORK_READ,
@@ -295,9 +288,6 @@
   int DoPartialHeadersReceived();
   int DoCacheReadMetadata();
   int DoCacheReadMetadataComplete(int result);
-  int DoHeadersPhaseCannotProceed();
-  int DoFinishHeaders(int result);
-  int DoFinishHeadersComplete(int result);
   int DoNetworkRead();
   int DoNetworkReadComplete(int result);
   int DoCacheReadData();
@@ -440,12 +430,7 @@
   void SyncCacheEntryStatusToResponse();
   void RecordHistograms();
 
-  // Called to signal completion of asynchronous IO. Note that this callback is
-  // used in the conventional sense where one layer calls the callback of the
-  // layer above it e.g. this callback gets called from the network transaction
-  // layer. In addition, it is also used for HttpCache layer to let this
-  // transaction know when it is out of a queued state in ActiveEntry and can
-  // continue its processing.
+  // Called to signal completion of asynchronous IO.
   void OnIOComplete(int result);
 
   // When in a DoLoop, use this to set the next state as it verifies that the
@@ -471,7 +456,6 @@
   const HttpResponseInfo* new_response_;
   std::string cache_key_;
   Mode mode_;
-  Mode original_mode_;  // Used when restarting the transaction.
   bool reading_;  // We are already reading. Never reverts to false once set.
   bool invalid_range_;  // We may bypass the cache for this request.
   bool truncated_;  // We don't have all the response data.
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index 626f46a..ca9c5d9 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -147,10 +147,6 @@
   EXPECT_TRUE(load_timing_info.receive_headers_end.is_null());
 }
 
-void DeferNetworkStart(bool* defer) {
-  *defer = true;
-}
-
 class DeleteCacheCompletionCallback : public TestCompletionCallbackBase {
  public:
   explicit DeleteCacheCompletionCallback(MockHttpCache* cache)
@@ -1354,12 +1350,12 @@
 
   MockHttpRequest request(kSimpleGET_Transaction);
 
-  std::vector<std::unique_ptr<Context>> context_list;
+  std::vector<Context*> context_list;
   const int kNumTransactions = 5;
 
   for (int i = 0; i < kNumTransactions; ++i) {
-    context_list.push_back(base::MakeUnique<Context>());
-    auto& c = context_list[i];
+    context_list.push_back(new Context());
+    Context* c = context_list[i];
 
     c->result = cache.CreateTransaction(&c->trans);
     ASSERT_THAT(c->result, IsOk());
@@ -1370,19 +1366,16 @@
   }
 
   // All requests are waiting for the active entry.
-  for (auto& context : context_list) {
-    EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, context->trans->GetLoadState());
+  for (int i = 0; i < kNumTransactions; ++i) {
+    Context* c = context_list[i];
+    EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
   }
 
   // Allow all requests to move from the Create queue to the active entry.
   base::RunLoop().RunUntilIdle();
 
   // The first request should be a writer at this point, and the subsequent
-  // requests should have passed the validation phase and waiting for the
-  // response to be written to the cache before they can read.
-  EXPECT_TRUE(cache.IsWriterPresent(kSimpleGET_Transaction.url));
-  EXPECT_EQ(kNumTransactions - 1,
-            cache.GetCountDoneHeadersQueue(kSimpleGET_Transaction.url));
+  // requests should be pending.
 
   EXPECT_EQ(1, cache.network_layer()->transaction_count());
   EXPECT_EQ(0, cache.disk_cache()->open_count());
@@ -1390,21 +1383,15 @@
 
   // All requests depend on the writer, and the writer is between Start and
   // Read, i.e. idle.
-  for (auto& context : context_list) {
-    EXPECT_EQ(LOAD_STATE_IDLE, context->trans->GetLoadState());
+  for (int i = 0; i < kNumTransactions; ++i) {
+    Context* c = context_list[i];
+    EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
   }
 
   for (int i = 0; i < kNumTransactions; ++i) {
-    auto& c = context_list[i];
+    Context* c = context_list[i];
     if (c->result == ERR_IO_PENDING)
       c->result = c->callback.WaitForResult();
-
-    if (i > 0) {
-      EXPECT_FALSE(cache.IsWriterPresent(kSimpleGET_Transaction.url));
-      EXPECT_EQ(kNumTransactions - i,
-                cache.GetCountReaders(kSimpleGET_Transaction.url));
-    }
-
     ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
   }
 
@@ -1413,479 +1400,11 @@
   EXPECT_EQ(1, cache.network_layer()->transaction_count());
   EXPECT_EQ(0, cache.disk_cache()->open_count());
   EXPECT_EQ(1, cache.disk_cache()->create_count());
-}
-
-// Parallel validation results in 200.
-TEST(HttpCache, SimpleGET_ParallelValidationNoMatch) {
-  MockHttpCache cache;
-
-  MockHttpRequest request(kSimpleGET_Transaction);
-  request.load_flags |= LOAD_VALIDATE_CACHE;
-
-  std::vector<std::unique_ptr<Context>> context_list;
-  const int kNumTransactions = 5;
 
   for (int i = 0; i < kNumTransactions; ++i) {
-    context_list.push_back(base::MakeUnique<Context>());
-    auto& c = context_list[i];
-
-    c->result = cache.CreateTransaction(&c->trans);
-    ASSERT_THAT(c->result, IsOk());
-    EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
-
-    c->result =
-        c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
+    Context* c = context_list[i];
+    delete c;
   }
-
-  // All requests are waiting for the active entry.
-  for (auto& context : context_list) {
-    EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, context->trans->GetLoadState());
-  }
-
-  // Allow all requests to move from the Create queue to the active entry.
-  base::RunLoop().RunUntilIdle();
-
-  // The first request should be a writer at this point, and the subsequent
-  // requests should have passed the validation phase and created their own
-  // entries since none of them matched the headers of the earlier one.
-  EXPECT_TRUE(cache.IsWriterPresent(kSimpleGET_Transaction.url));
-
-  // Note that there are only 3 entries created and not 5 since every other
-  // transaction would have gone to the network.
-  EXPECT_EQ(5, cache.network_layer()->transaction_count());
-  EXPECT_EQ(0, cache.disk_cache()->open_count());
-  EXPECT_EQ(3, cache.disk_cache()->create_count());
-
-  // All requests depend on the writer, and the writer is between Start and
-  // Read, i.e. idle.
-  for (auto& context : context_list) {
-    EXPECT_EQ(LOAD_STATE_IDLE, context->trans->GetLoadState());
-  }
-
-  for (auto& context : context_list) {
-    if (context->result == ERR_IO_PENDING)
-      context->result = context->callback.WaitForResult();
-    ReadAndVerifyTransaction(context->trans.get(), kSimpleGET_Transaction);
-  }
-
-  EXPECT_EQ(5, cache.network_layer()->transaction_count());
-  EXPECT_EQ(0, cache.disk_cache()->open_count());
-  EXPECT_EQ(3, cache.disk_cache()->create_count());
-}
-
-// Tests that a GET followed by a DELETE results in DELETE immediately starting
-// the headers phase and the entry is doomed.
-TEST(HttpCache, SimpleGET_ParallelValidationDelete) {
-  MockHttpCache cache;
-
-  MockHttpRequest request(kSimpleGET_Transaction);
-  request.load_flags |= LOAD_VALIDATE_CACHE;
-
-  MockHttpRequest delete_request(kSimpleGET_Transaction);
-  delete_request.method = "DELETE";
-
-  std::vector<std::unique_ptr<Context>> context_list;
-  const int kNumTransactions = 2;
-
-  for (int i = 0; i < kNumTransactions; ++i) {
-    context_list.push_back(base::MakeUnique<Context>());
-    auto& c = context_list[i];
-
-    MockHttpRequest* this_request = &request;
-    if (i == 1)
-      this_request = &delete_request;
-
-    c->result = cache.CreateTransaction(&c->trans);
-    ASSERT_THAT(c->result, IsOk());
-    EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
-
-    c->result = c->trans->Start(this_request, c->callback.callback(),
-                                NetLogWithSource());
-  }
-
-  // All requests are waiting for the active entry.
-  for (auto& context : context_list) {
-    EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, context->trans->GetLoadState());
-  }
-
-  // Allow all requests to move from the Create queue to the active entry.
-  base::RunLoop().RunUntilIdle();
-
-  // The first request should be a writer at this point, and the subsequent
-  // request should have passed the validation phase and doomed the existing
-  // entry.
-  EXPECT_TRUE(
-      cache.disk_cache()->IsDiskEntryDoomed(kSimpleGET_Transaction.url));
-
-  EXPECT_EQ(2, cache.network_layer()->transaction_count());
-  EXPECT_EQ(0, cache.disk_cache()->open_count());
-  EXPECT_EQ(1, cache.disk_cache()->create_count());
-
-  // All requests depend on the writer, and the writer is between Start and
-  // Read, i.e. idle.
-  for (auto& context : context_list) {
-    EXPECT_EQ(LOAD_STATE_IDLE, context->trans->GetLoadState());
-  }
-
-  for (auto& context : context_list) {
-    if (context->result == ERR_IO_PENDING)
-      context->result = context->callback.WaitForResult();
-    ReadAndVerifyTransaction(context->trans.get(), kSimpleGET_Transaction);
-  }
-
-  EXPECT_EQ(2, cache.network_layer()->transaction_count());
-  EXPECT_EQ(0, cache.disk_cache()->open_count());
-  EXPECT_EQ(1, cache.disk_cache()->create_count());
-}
-
-// Tests that a transaction which is in validated queue can be destroyed without
-// any impact to other transactions.
-TEST(HttpCache, SimpleGET_ParallelValidationCancelValidated) {
-  MockHttpCache cache;
-
-  MockHttpRequest request(kSimpleGET_Transaction);
-
-  std::vector<std::unique_ptr<Context>> context_list;
-  const int kNumTransactions = 2;
-
-  for (int i = 0; i < kNumTransactions; ++i) {
-    context_list.push_back(base::MakeUnique<Context>());
-    auto& c = context_list[i];
-
-    c->result = cache.CreateTransaction(&c->trans);
-    ASSERT_THAT(c->result, IsOk());
-
-    c->result =
-        c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
-  }
-
-  // Allow all requests to move from the Create queue to the active entry.
-  base::RunLoop().RunUntilIdle();
-
-  // The first request should be a writer at this point, and the subsequent
-  // requests should have completed validation.
-
-  EXPECT_EQ(1, cache.network_layer()->transaction_count());
-  EXPECT_EQ(0, cache.disk_cache()->open_count());
-  EXPECT_EQ(1, cache.disk_cache()->create_count());
-
-  EXPECT_TRUE(cache.IsWriterPresent(kSimpleGET_Transaction.url));
-  EXPECT_EQ(1, cache.GetCountDoneHeadersQueue(kSimpleGET_Transaction.url));
-
-  context_list[1].reset();
-
-  EXPECT_EQ(0, cache.GetCountDoneHeadersQueue(kSimpleGET_Transaction.url));
-
-  // Complete the rest of the transactions.
-  for (auto& context : context_list) {
-    if (!context)
-      continue;
-    ReadAndVerifyTransaction(context->trans.get(), kSimpleGET_Transaction);
-  }
-
-  EXPECT_EQ(1, cache.network_layer()->transaction_count());
-  EXPECT_EQ(0, cache.disk_cache()->open_count());
-  EXPECT_EQ(1, cache.disk_cache()->create_count());
-}
-
-// Tests that a transaction which is in readers can be destroyed without
-// any impact to other transactions.
-TEST(HttpCache, SimpleGET_ParallelValidationCancelReader) {
-  MockHttpCache cache;
-
-  MockHttpRequest request(kSimpleGET_Transaction);
-
-  MockTransaction transaction(kSimpleGET_Transaction);
-  transaction.load_flags |= LOAD_VALIDATE_CACHE;
-  MockHttpRequest validate_request(transaction);
-
-  int kNumTransactions = 4;
-  std::vector<std::unique_ptr<Context>> context_list;
-
-  for (int i = 0; i < kNumTransactions; ++i) {
-    context_list.push_back(base::MakeUnique<Context>());
-    auto& c = context_list[i];
-
-    c->result = cache.CreateTransaction(&c->trans);
-    ASSERT_THAT(c->result, IsOk());
-
-    MockHttpRequest* this_request = &request;
-    if (i == 3) {
-      this_request = &validate_request;
-      c->trans->SetBeforeNetworkStartCallback(base::Bind(&DeferNetworkStart));
-    }
-
-    c->result = c->trans->Start(this_request, c->callback.callback(),
-                                NetLogWithSource());
-  }
-
-  // Allow all requests to move from the Create queue to the active entry.
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_EQ(2, cache.network_layer()->transaction_count());
-  EXPECT_EQ(0, cache.disk_cache()->open_count());
-  EXPECT_EQ(1, cache.disk_cache()->create_count());
-
-  EXPECT_TRUE(cache.IsWriterPresent(kSimpleGET_Transaction.url));
-  EXPECT_EQ(2, cache.GetCountDoneHeadersQueue(kSimpleGET_Transaction.url));
-  EXPECT_TRUE(cache.IsHeadersTransactionPresent(kSimpleGET_Transaction.url));
-
-  // Complete the response body.
-  auto& c = context_list[0];
-  ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
-
-  // Rest of the transactions should move to readers.
-  EXPECT_FALSE(cache.IsWriterPresent(kSimpleGET_Transaction.url));
-  EXPECT_EQ(2, cache.GetCountReaders(kSimpleGET_Transaction.url));
-  EXPECT_EQ(0, cache.GetCountDoneHeadersQueue(kSimpleGET_Transaction.url));
-  EXPECT_TRUE(cache.IsHeadersTransactionPresent(kSimpleGET_Transaction.url));
-
-  // Add 2 new transactions.
-  kNumTransactions = 6;
-
-  for (int i = 4; i < kNumTransactions; ++i) {
-    context_list.push_back(base::MakeUnique<Context>());
-    auto& c = context_list[i];
-
-    c->result = cache.CreateTransaction(&c->trans);
-    ASSERT_THAT(c->result, IsOk());
-
-    c->result =
-        c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
-  }
-
-  EXPECT_EQ(2, cache.GetCountAddToEntryQueue(kSimpleGET_Transaction.url));
-
-  // Delete a reader.
-  context_list[1].reset();
-
-  // Deleting the reader did not impact any other transaction.
-  EXPECT_EQ(1, cache.GetCountReaders(kSimpleGET_Transaction.url));
-  EXPECT_EQ(2, cache.GetCountAddToEntryQueue(kSimpleGET_Transaction.url));
-  EXPECT_TRUE(cache.IsHeadersTransactionPresent(kSimpleGET_Transaction.url));
-
-  // Resume network start for headers_transaction. It will doom the entry as it
-  // will be a 200 and will go to network for the response body.
-  auto& context = context_list[3];
-  context->trans->ResumeNetworkStart();
-
-  // The pending transactions will be added to a new entry.
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_EQ(1, cache.GetCountDoneHeadersQueue(kSimpleGET_Transaction.url));
-  EXPECT_TRUE(cache.IsWriterPresent(kSimpleGET_Transaction.url));
-
-  // Complete the rest of the transactions.
-  for (int i = 2; i < kNumTransactions; ++i) {
-    auto& c = context_list[i];
-    ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
-  }
-
-  EXPECT_EQ(3, cache.network_layer()->transaction_count());
-  EXPECT_EQ(0, cache.disk_cache()->open_count());
-  EXPECT_EQ(2, cache.disk_cache()->create_count());
-}
-
-// Tests that a transaction is in validated queue and writer is destroyed
-// leading to restarting the validated transaction.
-TEST(HttpCache, SimpleGET_ParallelValidationCancelWriter) {
-  MockHttpCache cache;
-
-  MockHttpRequest request(kSimpleGET_Transaction);
-
-  MockTransaction transaction(kSimpleGET_Transaction);
-  transaction.load_flags |= LOAD_VALIDATE_CACHE;
-  MockHttpRequest validate_request(transaction);
-
-  const int kNumTransactions = 3;
-  std::vector<std::unique_ptr<Context>> context_list;
-
-  for (int i = 0; i < kNumTransactions; ++i) {
-    context_list.push_back(base::MakeUnique<Context>());
-    auto& c = context_list[i];
-
-    c->result = cache.CreateTransaction(&c->trans);
-    ASSERT_THAT(c->result, IsOk());
-
-    MockHttpRequest* this_request = &request;
-    if (i == 2) {
-      this_request = &validate_request;
-      c->trans->SetBeforeNetworkStartCallback(base::Bind(&DeferNetworkStart));
-    }
-
-    c->result = c->trans->Start(this_request, c->callback.callback(),
-                                NetLogWithSource());
-  }
-
-  // Allow all requests to move from the Create queue to the active entry.
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_EQ(2, cache.network_layer()->transaction_count());
-  EXPECT_EQ(0, cache.disk_cache()->open_count());
-  EXPECT_EQ(1, cache.disk_cache()->create_count());
-
-  EXPECT_TRUE(cache.IsWriterPresent(kSimpleGET_Transaction.url));
-  EXPECT_TRUE(cache.IsHeadersTransactionPresent(kSimpleGET_Transaction.url));
-  EXPECT_EQ(1, cache.GetCountDoneHeadersQueue(kSimpleGET_Transaction.url));
-
-  // Deleting the writer at this point will lead to destroying the entry and
-  // restarting the remaining transactions which will then create a new entry.
-  context_list[0].reset();
-
-  // Resume network start for headers_transaction. It should be restarted due to
-  // writer cancellation.
-  auto& c = context_list[2];
-  c->trans->ResumeNetworkStart();
-
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_TRUE(cache.IsWriterPresent(kSimpleGET_Transaction.url));
-  EXPECT_TRUE(cache.IsHeadersTransactionPresent(kSimpleGET_Transaction.url));
-
-  // Resume network start for the transaction the second time.
-  c->trans->ResumeNetworkStart();
-  base::RunLoop().RunUntilIdle();
-
-  // Headers transaction would have doomed the new entry created.
-  EXPECT_TRUE(
-      cache.disk_cache()->IsDiskEntryDoomed(kSimpleGET_Transaction.url));
-
-  // Complete the rest of the transactions.
-  for (auto& context : context_list) {
-    if (!context)
-      continue;
-    ReadAndVerifyTransaction(context->trans.get(), kSimpleGET_Transaction);
-  }
-
-  EXPECT_EQ(4, cache.network_layer()->transaction_count());
-  EXPECT_EQ(0, cache.disk_cache()->open_count());
-  EXPECT_EQ(2, cache.disk_cache()->create_count());
-}
-
-// Tests that a transaction is currently in headers phase and is destroyed
-// leading to destroying the entry.
-TEST(HttpCache, SimpleGET_ParallelValidationCancelHeaders) {
-  MockHttpCache cache;
-
-  MockHttpRequest request(kSimpleGET_Transaction);
-
-  const int kNumTransactions = 2;
-  std::vector<std::unique_ptr<Context>> context_list;
-
-  for (int i = 0; i < kNumTransactions; ++i) {
-    context_list.push_back(base::MakeUnique<Context>());
-    auto& c = context_list[i];
-
-    c->result = cache.CreateTransaction(&c->trans);
-    ASSERT_THAT(c->result, IsOk());
-
-    if (i == 0)
-      c->trans->SetBeforeNetworkStartCallback(base::Bind(&DeferNetworkStart));
-
-    c->result =
-        c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
-  }
-
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_TRUE(cache.IsHeadersTransactionPresent(kSimpleGET_Transaction.url));
-  EXPECT_EQ(1, cache.GetCountAddToEntryQueue(kSimpleGET_Transaction.url));
-
-  EXPECT_EQ(1, cache.network_layer()->transaction_count());
-  EXPECT_EQ(0, cache.disk_cache()->open_count());
-  EXPECT_EQ(1, cache.disk_cache()->create_count());
-
-  // Delete the headers transaction.
-  context_list[0].reset();
-
-  base::RunLoop().RunUntilIdle();
-
-  // Complete the rest of the transactions.
-  for (auto& context : context_list) {
-    if (!context)
-      continue;
-    ReadAndVerifyTransaction(context->trans.get(), kSimpleGET_Transaction);
-  }
-
-  EXPECT_EQ(2, cache.network_layer()->transaction_count());
-  EXPECT_EQ(0, cache.disk_cache()->open_count());
-  EXPECT_EQ(2, cache.disk_cache()->create_count());
-}
-
-// Similar to the above test, except here cache write fails and the
-// validated transactions should be restarted.
-TEST(HttpCache, SimpleGET_ParallelValidationFailWrite) {
-  MockHttpCache cache;
-
-  MockHttpRequest request(kSimpleGET_Transaction);
-
-  const int kNumTransactions = 5;
-  std::vector<std::unique_ptr<Context>> context_list;
-
-  for (int i = 0; i < kNumTransactions; ++i) {
-    context_list.push_back(base::MakeUnique<Context>());
-    auto& c = context_list[i];
-
-    c->result = cache.CreateTransaction(&c->trans);
-    ASSERT_THAT(c->result, IsOk());
-    EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
-
-    c->result =
-        c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
-  }
-
-  // All requests are waiting for the active entry.
-  for (auto& context : context_list) {
-    EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, context->trans->GetLoadState());
-  }
-
-  // Allow all requests to move from the Create queue to the active entry.
-  base::RunLoop().RunUntilIdle();
-
-  // The first request should be a writer at this point, and the subsequent
-  // requests should have passed the validation phase and waiting for the
-  // response to be written to the cache before they can read.
-  EXPECT_TRUE(cache.IsWriterPresent(kSimpleGET_Transaction.url));
-  EXPECT_EQ(4, cache.GetCountDoneHeadersQueue(kSimpleGET_Transaction.url));
-
-  // All requests depend on the writer, and the writer is between Start and
-  // Read, i.e. idle.
-  for (auto& context : context_list) {
-    EXPECT_EQ(LOAD_STATE_IDLE, context->trans->GetLoadState());
-  }
-
-  // The first request should be a writer at this point, and the subsequent
-  // requests should have passed the validation phase and waiting for the
-  // response to be written to the cache before they can read.
-
-  EXPECT_EQ(1, cache.network_layer()->transaction_count());
-  EXPECT_EQ(0, cache.disk_cache()->open_count());
-  EXPECT_EQ(1, cache.disk_cache()->create_count());
-
-  // Fail the request.
-  cache.disk_cache()->set_soft_failures(true);
-  // We have to open the entry again to propagate the failure flag.
-  disk_cache::Entry* en;
-  cache.OpenBackendEntry(kSimpleGET_Transaction.url, &en);
-  en->Close();
-
-  for (int i = 0; i < kNumTransactions; ++i) {
-    auto& c = context_list[i];
-    if (c->result == ERR_IO_PENDING)
-      c->result = c->callback.WaitForResult();
-    if (i == 1) {
-      // The earlier entry must be destroyed and its disk entry doomed.
-      EXPECT_TRUE(
-          cache.disk_cache()->IsDiskEntryDoomed(kSimpleGET_Transaction.url));
-    }
-    ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
-  }
-
-  // Since validated transactions were restarted and new entry read/write
-  // operations would also fail, all requests would have gone to the network.
-  EXPECT_EQ(5, cache.network_layer()->transaction_count());
-  EXPECT_EQ(1, cache.disk_cache()->open_count());
-  EXPECT_EQ(5, cache.disk_cache()->create_count());
 }
 
 // This is a test for http://code.google.com/p/chromium/issues/detail?id=4769.
@@ -1932,12 +1451,11 @@
   c->result = c->callback.WaitForResult();
   ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
 
-  // Now all transactions should be waiting for read to be invoked. Two readers
-  // are because of the load flags and remaining two transactions were converted
-  // to readers after skipping validation. Note that the remaining two went on
-  // to process the headers in parallel with readers present on the entry.
+  // Now we have 2 active readers and two queued transactions.
+
   EXPECT_EQ(LOAD_STATE_IDLE, context_list[2]->trans->GetLoadState());
-  EXPECT_EQ(LOAD_STATE_IDLE, context_list[3]->trans->GetLoadState());
+  EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE,
+            context_list[3]->trans->GetLoadState());
 
   c = context_list[1];
   ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
@@ -2002,16 +1520,12 @@
                                 NetLogWithSource());
   }
 
-  base::RunLoop().RunUntilIdle();
-
   // The first request should be a writer at this point, and the two subsequent
   // requests should be pending. The last request doomed the first entry.
 
   EXPECT_EQ(2, cache.network_layer()->transaction_count());
 
-  // Cancel the second transaction. Note that this and the 3rd transactions
-  // would have completed their headers phase and would be waiting in the
-  // done_headers_queue when the 2nd transaction is cancelled.
+  // Cancel the first queued transaction.
   context_list[1].reset();
 
   for (int i = 0; i < kNumTransactions; ++i) {
@@ -2053,12 +1567,11 @@
   base::RunLoop().RunUntilIdle();
 
   // The first request should be a writer at this point, and the subsequent
-  // requests should have completed validation. Since the validation does not
-  // result in a match, a new entry would be created.
+  // requests should be pending.
 
-  EXPECT_EQ(3, cache.network_layer()->transaction_count());
+  EXPECT_EQ(1, cache.network_layer()->transaction_count());
   EXPECT_EQ(0, cache.disk_cache()->open_count());
-  EXPECT_EQ(2, cache.disk_cache()->create_count());
+  EXPECT_EQ(1, cache.disk_cache()->create_count());
 
   // Now, make sure that the second request asks for the entry not to be stored.
   request_handler.set_no_store(true);
@@ -2112,9 +1625,6 @@
     if (c->result == ERR_IO_PENDING)
       c->result = c->callback.WaitForResult();
     // Destroy only the first transaction.
-    // This should lead to all transactions to restart, even those that have
-    // validated themselves and were waiting for the writer transaction to
-    // complete writing to the cache.
     if (i == 0) {
       delete c;
       context_list[i] = NULL;
@@ -3030,8 +2540,6 @@
 //     be returned.
 // (4) loads |kUrl| from cache only -- expects |cached_response_2| to be
 //     returned.
-// The entry will be created once and will be opened for the 3 subsequent
-// requests.
 static void ConditionalizedRequestUpdatesCacheHelper(
     const Response& net_response_1,
     const Response& net_response_2,
@@ -6607,14 +6115,12 @@
   EXPECT_EQ(5, c->callback.GetResult(rv));
 
   // Cancel the requests.
-  // Since |pending| is currently validating the already written headers
-  // it will be restarted as well.
   delete c;
   delete pending;
 
   EXPECT_EQ(1, cache.network_layer()->transaction_count());
   EXPECT_EQ(1, cache.disk_cache()->open_count());
-  EXPECT_EQ(1, cache.disk_cache()->create_count());
+  EXPECT_EQ(2, cache.disk_cache()->create_count());
 
   base::RunLoop().RunUntilIdle();
   RemoveMockTransaction(&transaction);
@@ -7339,6 +6845,46 @@
   EXPECT_EQ(1, cache.disk_cache()->create_count());
 }
 
+// Tests that if a metadata writer transaction hits cache lock timeout, it will
+// error out.
+TEST(HttpCache, WriteMetadata_CacheLockTimeout) {
+  MockHttpCache cache;
+
+  // Write to the cache
+  HttpResponseInfo response;
+  RunTransactionTestWithResponseInfo(cache.http_cache(), kSimpleGET_Transaction,
+                                     &response);
+  EXPECT_FALSE(response.metadata.get());
+
+  MockHttpRequest request(kSimpleGET_Transaction);
+  Context c1;
+  ASSERT_THAT(cache.CreateTransaction(&c1.trans), IsOk());
+  ASSERT_EQ(ERR_IO_PENDING, c1.trans->Start(&request, c1.callback.callback(),
+                                            NetLogWithSource()));
+
+  cache.SimulateCacheLockTimeout();
+
+  // Write meta data to the same entry.
+  scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(50));
+  memset(buf->data(), 0, buf->size());
+  base::strlcpy(buf->data(), "Hi there", buf->size());
+  cache.http_cache()->WriteMetadata(GURL(kSimpleGET_Transaction.url),
+                                    DEFAULT_PRIORITY, response.response_time,
+                                    buf.get(), buf->size());
+
+  // Release the buffer before the operation takes place.
+  buf = NULL;
+
+  // Makes sure we finish pending operations.
+  base::RunLoop().RunUntilIdle();
+
+  RunTransactionTestWithResponseInfo(cache.http_cache(), kSimpleGET_Transaction,
+                                     &response);
+
+  // The writer transaction should fail due to cache lock timeout.
+  ASSERT_FALSE(response.metadata.get());
+}
+
 // Tests that we ignore VARY checks when writing metadata since the request
 // headers for the WriteMetadata transaction are made up.
 TEST(HttpCache, WriteMetadata_IgnoreVary) {
@@ -7666,6 +7212,10 @@
     EXPECT_THAT(callback.GetResult(rv), IsOk());
 
     trans->StopCaching();
+
+    scoped_refptr<IOBuffer> buf(new IOBuffer(256));
+    rv = trans->Read(buf.get(), 10, callback.callback());
+    EXPECT_EQ(callback.GetResult(rv), 10);
   }
   RemoveMockTransaction(&mock_transaction);
 
diff --git a/net/http/http_transaction_test_util.cc b/net/http/http_transaction_test_util.cc
index fa42dd7..a5b5746 100644
--- a/net/http/http_transaction_test_util.cc
+++ b/net/http/http_transaction_test_util.cc
@@ -409,6 +409,13 @@
   if (!t)
     return ERR_FAILED;
 
+  if (!before_network_start_callback_.is_null()) {
+    bool defer = false;
+    before_network_start_callback_.Run(&defer);
+    if (defer)
+      return net::ERR_IO_PENDING;
+  }
+
   test_mode_ = t->test_mode;
 
   // Return immediately if we're returning an error.
@@ -459,16 +466,6 @@
   if (request_->load_flags & LOAD_PREFETCH)
     response_.unused_since_prefetch = true;
 
-  // Pause and resume.
-  if (!before_network_start_callback_.is_null()) {
-    bool defer = false;
-    before_network_start_callback_.Run(&defer);
-    if (defer) {
-      callback_ = callback;
-      return net::ERR_IO_PENDING;
-    }
-  }
-
   if (test_mode_ & TEST_MODE_SYNC_NET_START)
     return OK;
 
@@ -485,9 +482,8 @@
     const BeforeHeadersSentCallback& callback) {}
 
 int MockNetworkTransaction::ResumeNetworkStart() {
-  DCHECK(!callback_.is_null());
-  CallbackLater(callback_, OK);
-  return ERR_IO_PENDING;
+  // Should not get here.
+  return ERR_FAILED;
 }
 
 void MockNetworkTransaction::GetConnectionAttempts(
diff --git a/net/http/http_transaction_test_util.h b/net/http/http_transaction_test_util.h
index dbd2670..e936ac9d 100644
--- a/net/http/http_transaction_test_util.h
+++ b/net/http/http_transaction_test_util.h
@@ -280,8 +280,6 @@
 
   bool done_reading_called_;
 
-  CompletionCallback callback_;  // used for pause and restart.
-
   base::WeakPtrFactory<MockNetworkTransaction> weak_factory_;
 
 };
diff --git a/net/http/mock_http_cache.cc b/net/http/mock_http_cache.cc
index e676122..47125a30 100644
--- a/net/http/mock_http_cache.cc
+++ b/net/http/mock_http_cache.cc
@@ -534,13 +534,6 @@
       FROM_HERE, base::Bind(&CallbackForwader, callback, result));
 }
 
-bool MockDiskCache::IsDiskEntryDoomed(const std::string& key) {
-  auto it = entries_.find(key);
-  if (it == entries_.end())
-    return false;
-  return it->second->is_doomed();
-}
-
 //-----------------------------------------------------------------------------
 
 int MockBackendFactory::CreateBackend(
@@ -654,41 +647,6 @@
   g_test_mode = test_mode;
 }
 
-bool MockHttpCache::IsWriterPresent(const std::string& key) {
-  HttpCache::ActiveEntry* entry = http_cache_.FindActiveEntry(key);
-  if (entry)
-    return entry->writer;
-  return false;
-}
-
-bool MockHttpCache::IsHeadersTransactionPresent(const std::string& key) {
-  HttpCache::ActiveEntry* entry = http_cache_.FindActiveEntry(key);
-  if (entry)
-    return entry->headers_transaction;
-  return false;
-}
-
-int MockHttpCache::GetCountReaders(const std::string& key) {
-  HttpCache::ActiveEntry* entry = http_cache_.FindActiveEntry(key);
-  if (entry)
-    return entry->readers.size();
-  return false;
-}
-
-int MockHttpCache::GetCountAddToEntryQueue(const std::string& key) {
-  HttpCache::ActiveEntry* entry = http_cache_.FindActiveEntry(key);
-  if (entry)
-    return entry->add_to_entry_queue.size();
-  return false;
-}
-
-int MockHttpCache::GetCountDoneHeadersQueue(const std::string& key) {
-  HttpCache::ActiveEntry* entry = http_cache_.FindActiveEntry(key);
-  if (entry)
-    return entry->done_headers_queue.size();
-  return false;
-}
-
 //-----------------------------------------------------------------------------
 
 int MockDiskCacheNoCB::CreateEntry(const std::string& key,
diff --git a/net/http/mock_http_cache.h b/net/http/mock_http_cache.h
index 7718f351..a24200b 100644
--- a/net/http/mock_http_cache.h
+++ b/net/http/mock_http_cache.h
@@ -158,8 +158,6 @@
 
   void ReleaseAll();
 
-  bool IsDiskEntryDoomed(const std::string& key);
-
  private:
   using EntryMap = std::unordered_map<std::string, MockDiskEntry*>;
   class NotImplementedIterator;
@@ -236,14 +234,6 @@
   // the test! (by setting test_mode to zero).
   static void SetTestMode(int test_mode);
 
-  // Functions to test the state of ActiveEntry.
-
-  bool IsWriterPresent(const std::string& key);
-  bool IsHeadersTransactionPresent(const std::string& key);
-  int GetCountReaders(const std::string& key);
-  int GetCountAddToEntryQueue(const std::string& key);
-  int GetCountDoneHeadersQueue(const std::string& key);
-
  private:
   HttpCache http_cache_;
 };
diff --git a/net/url_request/url_request_quic_unittest.cc b/net/url_request/url_request_quic_unittest.cc
index 8c3f560..ff887060 100644
--- a/net/url_request/url_request_quic_unittest.cc
+++ b/net/url_request/url_request_quic_unittest.cc
@@ -305,14 +305,15 @@
 
   EXPECT_TRUE(entries[0].GetStringValue("push_url", &value));
   EXPECT_EQ(value, push_url_1);
-  EXPECT_TRUE(entries[1].GetStringValue("push_url", &value));
+  // No net error code for this lookup transaction, the push is found.
+  EXPECT_FALSE(entries[1].GetIntegerValue("net_error", &net_error));
+
+  EXPECT_TRUE(entries[2].GetStringValue("push_url", &value));
   EXPECT_EQ(value, push_url_2);
   // Net error code -400 is found for this lookup transaction, the push is not
   // found in the cache.
-  EXPECT_TRUE(entries[2].GetIntegerValue("net_error", &net_error));
+  EXPECT_TRUE(entries[3].GetIntegerValue("net_error", &net_error));
   EXPECT_EQ(net_error, -400);
-  // No net error code for this lookup transaction, the push is found.
-  EXPECT_FALSE(entries[3].GetIntegerValue("net_error", &net_error));
 
   // Verify the reset error count received on the server side.
   EXPECT_LE(1u, GetRstErrorCountReceivedByServer(QUIC_STREAM_CANCELLED));
@@ -391,13 +392,11 @@
 
   EXPECT_TRUE(entries[0].GetStringValue("push_url", &value));
   EXPECT_EQ(value, push_url_1);
-
-  EXPECT_TRUE(entries[1].GetStringValue("push_url", &value));
-  EXPECT_EQ(value, push_url_2);
-
   // No net error code for this lookup transaction, the push is found.
-  EXPECT_FALSE(entries[2].GetIntegerValue("net_error", &net_error));
+  EXPECT_FALSE(entries[1].GetIntegerValue("net_error", &net_error));
 
+  EXPECT_TRUE(entries[2].GetStringValue("push_url", &value));
+  EXPECT_EQ(value, push_url_2);
   // No net error code for this lookup transaction, the push is found.
   EXPECT_FALSE(entries[3].GetIntegerValue("net_error", &net_error));
 
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 341f870..7282a0e5 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -4138,14 +4138,14 @@
         context.CreateRequest(url, DEFAULT_PRIORITY, &d));
     r->Start();
 
-    base::RunLoop().Run();
-
     {
       HttpRequestHeaders headers;
       EXPECT_TRUE(r->GetFullRequestHeaders(&headers));
-      EXPECT_TRUE(headers.HasHeader("Authorization"));
+      EXPECT_FALSE(headers.HasHeader("Authorization"));
     }
 
+    base::RunLoop().Run();
+
     EXPECT_EQ(OK, d.request_status());
     EXPECT_EQ(200, r->GetResponseCode());
     EXPECT_TRUE(d.auth_required_called());