Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(406)

Unified Diff: net/http/http_cache_shared_writers.h

Issue 2519473002: Fixes the cache lock issue. (Closed)
Patch Set: Redesigned the fix using DataAccess class for eliminating Orphan API.(Rebased till refs/heads/master@{#442607}) Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/http/http_cache_shared_writers.h
diff --git a/net/http/http_cache_shared_writers.h b/net/http/http_cache_shared_writers.h
new file mode 100644
index 0000000000000000000000000000000000000000..f91f8195b2a28714f4b2fa9b78edc28d120027ac
--- /dev/null
+++ b/net/http/http_cache_shared_writers.h
@@ -0,0 +1,307 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_HTTP_HTTP_CACHE_SHARED_WRITERS_H_
+#define NET_HTTP_HTTP_CACHE_SHARED_WRITERS_H_
+
+#include <list>
+#include <memory>
+#include "base/memory/weak_ptr.h"
+#include "net/base/completion_callback.h"
+#include "net/http/http_cache.h"
+
+namespace net {
+
+class DataAccess;
+
+// SharedWriters represents the set of all HttpCache::Transactions that are
+// reading from the network using the same network transaction and writing to
+// the same cache entry. It is owned by the ActiveEntry.
+//
+// An instance of SharedWriters will be created when the first writer has
+// written the new response headers in the cache.
+// At creation:
+// - The writer’s network transaction’s ownership will be transferred to the new
+// DataAccess object owned by SharedWriters and thus can be used by any of the
+// HttpCache::Transactions for subsequent reading from the network.
+// - The pending_queue will be traversed to see if there are other
+// transactions that can be added to SharedWriters.
+//
+// Destroyed when any of the following happen:
+// - All the data has been read from the network and written to cache.
+// - ActiveEntry is destroyed.
+// - Last transaction part of SharedWriters is destroyed.
+// - Response writing is terminated due to a failure.
+// - StopCaching API is invoked and caching was successfully stopped.
Randy Smith (Not in Mondays) 2017/01/19 00:53:43 Suggestion: My model for class documentation is th
shivanisha 2017/01/25 19:46:13 Agree, thanks. Updated the comments in this file t
+class HttpCache::SharedWriters {
+ public:
+ // Creates a new SharedWriters object, transfers the ownership of network
+ // transaction to SharedWriters, and adds the cache transaction to
+ // all_writers_.
+ SharedWriters(HttpCache* cache,
+ ActiveEntry* entry,
+ Transaction* cache_transaction,
+ RequestPriority priority,
+ std::unique_ptr<HttpTransaction> network_transaction);
Randy Smith (Not in Mondays) 2017/01/19 00:53:43 Recommend documenting lifetimes for raw pointers (
shivanisha 2017/01/25 19:46:13 done.
+ ~SharedWriters();
+
+ // Adds a transaction to SharedWriters. Invokes SetShared on the transaction
+ // and either assigns the transaction to validating_transaction_ or inserts it
+ // in waiting_for_validation_. Return value is true if it is the current
+ // validating_transaction_ and false if its waiting.
+ bool AddTransaction(Transaction* transaction);
+
+ // Invokes Read on data_access_, assigns this transaction to
+ // current_writer_ and returns what data_access_->Read() returns.
+ // In case a read is already in progress then this transaction is instead
+ // added to waiting_writers_, read_in_progress is set to true and
+ // ERR_IO_PENDING is returned.
+ int Read(scoped_refptr<IOBuffer> buf,
+ int buf_len,
+ const CompletionCallback& callback,
+ Transaction* transaction,
+ bool* read_in_progress);
+
+ // Invokes CacheWrite on data_access_ and returns the return value returned
+ // from it. Current_writer_ should be equal to transaction.
+ int CacheWrite(scoped_refptr<IOBuffer> buf,
+ int write_len,
+ const CompletionCallback& callback,
+ Transaction* transaction);
+
+ // Callback to be invoked when validating_transaction_ wants to continue with
+ // the entry as the validation successfully matched it.
+ void OnValidationMatch(Transaction* transaction, RequestPriority priority);
+
+ // Callback to be invoked when validating_transaction_ cannot continue with
+ // the entry as the validation did not return a 304.
+ // Its ok to continue writing to cache if this is the only transaction in
+ // SharedWriters, so network_transaction ownership is transferred to
+ // SharedWriters. But if there are other transactions, entry will be doomed
+ // and this transaction will continue reading from the network so the return
+ // value will pass the ownership of the network transaction back to the
+ // transaction.
+ std::unique_ptr<HttpTransaction> OnValidationNoMatch(
+ Transaction* transaction,
+ std::unique_ptr<HttpTransaction> network_transaction,
+ RequestPriority priority);
+
+ // Invoked when DoneReading is invoked on a shared transaction. If
+ // current_writer_ is set, do nothing, else consider it a read completion
+ // and process accordingly.
+ void DoneReading(Transaction* transaction);
+
+ // Invoked when StopCaching is called for a shared writer transaction.
+ // It stops caching only if there are no other transactions in
+ // all_writers_.
+ bool StopCaching(Transaction* transaction);
+
+ // Moves all transactions eligible for shared writing from entry's
+ // pending_queue to waiting_for_validation_.
+ void MoveFromPendingQueue();
+
+ // Posts a task for invoking the io callback of the first transaction in
+ // waiting_for_validation_.
+ void ProcessFirstWaitingValidation();
+
+ // Removes a transaction from waiting_for_validation_ and invokes
+ // ResetShared on it.
+ bool RemoveWaitingTransaction(Transaction* transaction);
+
+ // Removes a transaction which is in all_writers_ but not currently waiting
+ // on Read.
+ void RemoveIdleWriter(Transaction* transaction);
+
+ // Removes a waiting_writer_ transaction.
+ void RemoveWaitingWriter(Transaction* transaction);
+
+ // Removes the currently validating transaction.
+ void RemoveValidatingTransaction(Transaction* transaction);
+
+ // Removes the transaction that is currently accessing data_access_.
+ void RemoveCurrentWriter(Transaction* transaction);
+
+ // Should the owner be able to reset this object? Returns false if
+ // SharedWriters is in a flow where it is about to destroy itself at the end
+ // of the flow.
+ bool CanReset();
+
+ // Returns true if this object is empty: no transactions in all_writers and
+ // waiting_for_validation_ and validating_transaction_.
+ bool empty();
+
+ friend class Transaction;
+
+ private:
+ // Runs the state transition loop. Resets and calls |callback_| on exit,
+ // unless the return value is ERR_IO_PENDING.
+ int DoLoop(int result);
+
+ // IO Completion callback function. May destroy this object if needed at the
+ // end of the processing.
+ void OnIOComplete(int result);
+
+ // State machine functions.
+ int DoNetworkRead();
+ int DoNetworkReadComplete(int result);
+ int DoCacheWriteData(int num_bytes);
+ int DoCacheWriteDataComplete(int result);
+ int DoCacheWriteTruncatedResponse();
+ int DoCacheWriteTruncatedResponseComplete(int result);
+
+ // Helper functions for callback.
+ //
+ // current_writer_ successfully read from the network.
+ void OnNetworkReadSuccess(int len);
+
+ // current_writer_ successfully wrote to the cache.
+ void OnCacheWriteSuccess(int result);
+
+ // current_writer_ fails to write data to the cache.
+ // It transfers the ownership of data_access_ to the transaction since shared
+ // writing can no longer continue, but current_writer_ can continue to read
+ // the remaning data from the network. Any waiting_writers_ will be
+ // notified of the failure. Any idle transactions or validating_transaction_
+ // will be set to a state so that they can fail any subsequent Read calls.
+ // Any transactions in waiting_for_validation_ will move to pending_queue.
+ void OnCacheWriteFailure();
+
+ // current_writer_ fails to read from the network. Both this transaction and
+ // any waiting_writers_ will return the failure code to their consumers.
+ // Any idle transactions or validating_transaction_ will be set to a
+ // state so that they can fail any subsequent Read calls.
+ // Any transactions in waiting_for_validation_ will move to pending_queue.
+ // Marking the entry as truncated will be attempted.
+ void OnNetworkReadFailure(int result);
+
+ // Helper function for doing the cleanup for failure scenarios such as those
+ // mentioned above.
+ void FailureCleanup(int error, bool continue_network_reading);
+
+ // Moves all transactions in waiting_for_validation_ to entry's
+ // pending_queue.
+ void MoveToPendingQueue();
+
+ // Notifies the waiting_writers_ of the result, by posting a task for each
+ // of them. While processing the task for a transaction, it's IO callback
+ // will be invoked.
+ void ProcessWaitingWriters(int result);
+
+ // First waiting_for_validation transaction's callback will be invoked.
+ void OnProcessFirstWaitingValidation();
+
+ // Removes the current_writer_ transaction from this object.
+ void ResetCurrentWriter(bool continue_network_reading = false);
+
+ // Sets the state of idle writers so that they can fail any subsequent
+ // Read.
+ void SetIdleWritersFailState(int result);
+
+ // When response is completely written, any idle writers are moved to
+ // entry_->readers.
+ void MoveIdleWritersToReaders();
+
+ // Helper function to let the validating_transaction_ continue being a part of
+ // SharedWriters.
+ void ValidationDoneContinue(Transaction* transaction,
+ RequestPriority priority);
+
+ // Helper function invoked when response is successfully written to the cache.
+ void ResponseDataComplete();
+
+ // Deletes itself. This is needed for callback scenarios where we no longer
+ // need shared writing. Entry will release ownership in the flow and
+ // SharedWriters will delete itself in the end of the flow.
+ void SelfDestroy();
+
+ enum State {
+ STATE_NONE,
+ STATE_NETWORK_READ,
+ STATE_NETWORK_READ_COMPLETE,
+ STATE_CACHE_WRITE_DATA,
+ STATE_CACHE_WRITE_DATA_COMPLETE,
+ STATE_CACHE_WRITE_TRUNCATED_RESPONSE,
+ STATE_CACHE_WRITE_TRUNCATED_RESPONSE_COMPLETE
+ };
+
+ State next_state_ = STATE_NONE;
Randy Smith (Not in Mondays) 2017/01/19 00:53:43 I think it's good to use either all in-declaration
shivanisha 2017/01/25 19:46:13 I have tried to keep all simple initializations he
+
+ // Http Cache.
+ base::WeakPtr<HttpCache> cache_;
+
+ // Owner of this object.
+ ActiveEntry* entry_ = nullptr;
+
+ std::unique_ptr<DataAccess> data_access_;
+
+ scoped_refptr<IOBuffer> read_buf_;
+ int io_buf_len_ = 0;
+ int write_len_ = 0;
+
+ // The cache transaction that is the current consumer of data_access_::Read
+ // or data_access_->CacheWrite and is waiting for the operation to be
+ // completed. This is used to ensure there is at most one consumer of
+ // data_access_. After the network read and cache write is successful and data
+ // written to cache, other waiting writers will be notified.
+ Transaction* current_writer_ = nullptr;
+
+ // This will point to the currently validating transaction.
+ // After the validation stage is successfully done, this transaction is
+ // added to all_writers_.
+ Transaction* validating_transaction_ = nullptr;
+
+ // If a transaction is currently set in validating_transaction_, these
+ // transactions will wait for that to complete and then the first of these
+ // will be assigned to validating_transaction_.
+ TransactionList waiting_for_validation_;
+
+ // These transactions are waiting on their Read calls when current_writer_
+ // is not null. After current_writer_ completes writing the data to the
+ // cache, their buffer would be filled with the data and their callback
+ // invoked.
+ struct WaitingWriter {
+ Transaction* transaction;
+ scoped_refptr<IOBuffer> read_buf;
+ int read_buf_len;
+ int write_len;
+ WaitingWriter(Transaction* transaction,
+ scoped_refptr<IOBuffer> read_buf,
+ int len);
+ ~WaitingWriter();
+ WaitingWriter(const WaitingWriter&);
+ };
+ typedef std::list<WaitingWriter> WaitingWritersList;
+ WaitingWritersList waiting_writers_;
Randy Smith (Not in Mondays) 2017/01/19 00:53:43 Suggestion: I'm finding the reader/writer nomencla
shivanisha 2017/01/20 16:00:09 active_transaction_ and waiting_for_read_ sound go
shivanisha 2017/01/25 19:46:13 Done.
+
+ // Includes a transaction if it is one of the following:
+ // 1. current_writer_ or,
+ // 2. member of waiting_writers_ or,
+ // 3. Waiting for Read to be invoked from the consumer.
+ TransactionSet all_writers_;
+
+ // Current priority of the request. If a higher priority transaction is
+ // added to all_writers_, the priority of data_access_->network_transaction_
+ // will be increased.
+ // todo (shivanisha@): If the higher priority request dies, we do not change
+ // the priority back to a lower one. Fix this. The priority should be the
+ // highest of the existing requests.
+ RequestPriority priority_ = DEFAULT_PRIORITY;
+
+ CompletionCallback callback_; // Consumer's callback.
+ CompletionCallback io_callback_;
+
+ bool destroy_ = false; // Should be destroyed at the end of this flow.
+
+ // Return value from network read. Saved so it could be returned to the
+ // consumer after marking the entry as truncated, if needed.
+ int network_read_rv_ = 0;
+
+ base::WeakPtrFactory<SharedWriters> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SharedWriters);
+};
+
+} // namespace net
+
+#endif // NET_HTTP_HTTP_CACHE_SHARED_WRITERS_H_

Powered by Google App Engine
This is Rietveld 408576698