xref: /aosp_15_r20/external/cronet/net/http/http_cache_writers.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef NET_HTTP_HTTP_CACHE_WRITERS_H_
6 #define NET_HTTP_HTTP_CACHE_WRITERS_H_
7 
8 #include <map>
9 #include <memory>
10 
11 #include "base/memory/raw_ptr.h"
12 #include "base/memory/weak_ptr.h"
13 #include "net/base/completion_once_callback.h"
14 #include "net/http/http_cache.h"
15 #include "net/http/http_response_info.h"
16 
17 namespace net {
18 
19 class HttpResponseInfo;
20 class IOBuffer;
21 class PartialData;
22 
23 // If multiple HttpCache::Transactions are accessing the same cache entry
24 // simultaneously, their access to the data read from network is synchronized
25 // by HttpCache::Writers. This enables each of those transactions to drive
26 // reading the response body from the network ensuring a slow consumer does not
27 // starve other consumers of the same resource.
28 //
29 // Writers represents the set of all HttpCache::Transactions that are reading
30 // from the network using the same network transaction and writing to the same
31 // cache entry. It is owned by the ActiveEntry. The writers object must be
32 // deleted when HttpCache::WritersDoneWritingToEntry is called as it doesn't
33 // expect any of its ongoing IO transactions (e.g., network reads or cache
34 // writers) to complete after that point and won't know what to do with them.
35 class NET_EXPORT_PRIVATE HttpCache::Writers {
36  public:
37   // This is the information maintained by Writers in the context of each
38   // transaction.
39   // |partial| is owned by the transaction and to be sure there are no
40   // dangling pointers, it must be ensured that transaction's reference and
41   // this information will be removed from writers once the transaction is
42   // deleted.
43   struct NET_EXPORT_PRIVATE TransactionInfo {
44     TransactionInfo(PartialData* partial,
45                     bool truncated,
46                     HttpResponseInfo info);
47     ~TransactionInfo();
48     TransactionInfo& operator=(const TransactionInfo&);
49     TransactionInfo(const TransactionInfo&);
50 
51     raw_ptr<PartialData> partial;
52     bool truncated;
53     HttpResponseInfo response_info;
54   };
55 
56   // |cache| and |entry| must outlive this object.
57   Writers(HttpCache* cache, scoped_refptr<HttpCache::ActiveEntry> entry);
58 
59   Writers(const Writers&) = delete;
60   Writers& operator=(const Writers&) = delete;
61 
62   ~Writers();
63 
64   // Retrieves data from the network transaction associated with the Writers
65   // object. This may be done directly (via a network read into |*buf->data()|)
66   // or indirectly (by copying from another transactions buffer into
67   // |*buf->data()| on network read completion) depending on whether or not a
68   // read is currently in progress. May return the result synchronously or
69   // return ERR_IO_PENDING: if ERR_IO_PENDING is returned, |callback| will be
70   // run to inform the consumer of the result of the Read().
71   // |transaction| may be removed while Read() is ongoing. In that case Writers
72   // will still complete the Read() processing but will not invoke the
73   // |callback|.
74   int Read(scoped_refptr<IOBuffer> buf,
75            int buf_len,
76            CompletionOnceCallback callback,
77            Transaction* transaction);
78 
79   // Invoked when StopCaching is called on a member transaction.
80   // It stops caching only if there are no other transactions. Returns true if
81   // caching can be stopped.
82   // |keep_entry| should be true if the entry needs to be preserved after
83   // truncation.
84   bool StopCaching(bool keep_entry);
85 
86   // Membership functions like AddTransaction and RemoveTransaction are invoked
87   // by HttpCache on behalf of the HttpCache::Transaction.
88 
89   // Adds an HttpCache::Transaction to Writers.
90   // Should only be invoked if CanAddWriters() returns true.
91   // |parallel_writing_pattern| governs whether writing is an exclusive
92   // operation implying that Writers can contain at most one transaction till
93   // the completion of the response body. It is illegal to invoke with
94   // |parallel_writing_pattern| as PARALLEL_WRITING_NOT_JOIN*  if there is
95   // already a transaction present.
96   // |transaction| can be destroyed at any point and it should invoke
97   // HttpCache::DoneWithEntry() during its destruction. This will also ensure
98   // any pointers in |info| are not accessed after the transaction is destroyed.
99   void AddTransaction(Transaction* transaction,
100                       ParallelWritingPattern initial_writing_pattern,
101                       RequestPriority priority,
102                       const TransactionInfo& info);
103 
104   // Invoked when the transaction is done working with the entry.
105   void RemoveTransaction(Transaction* transaction, bool success);
106 
107   // Invoked when there is a change in a member transaction's priority or a
108   // member transaction is removed.
109   void UpdatePriority();
110 
111   // Returns true if this object is empty.
IsEmpty()112   bool IsEmpty() const { return all_writers_.empty(); }
113 
114   // Returns true if |transaction| is part of writers.
HasTransaction(const Transaction * transaction)115   bool HasTransaction(const Transaction* transaction) const {
116     return all_writers_.count(const_cast<Transaction*>(transaction)) > 0;
117   }
118 
119   // Returns true if more writers can be added for shared writing. Also fills in
120   // the |reason| for why a transaction cannot be added.
121   bool CanAddWriters(ParallelWritingPattern* reason);
122 
123   // Returns if only one transaction can be a member of writers.
IsExclusive()124   bool IsExclusive() const { return is_exclusive_; }
125 
126   // Returns the network transaction which may be nullptr for range requests.
network_transaction()127   const HttpTransaction* network_transaction() const {
128     return network_transaction_.get();
129   }
130 
131   void CloseConnectionOnDestruction();
132 
133   // Returns the load state of the |network_transaction_| if present else
134   // returns LOAD_STATE_IDLE.
135   LoadState GetLoadState() const;
136 
137   // Sets the network transaction argument to |network_transaction_|. Must be
138   // invoked before Read can be invoked.
139   void SetNetworkTransaction(
140       Transaction* transaction,
141       std::unique_ptr<HttpTransaction> network_transaction);
142 
143   // Resets the network transaction to nullptr. Required for range requests as
144   // they might use the current network transaction only for part of the
145   // request. Must only be invoked for range requests.
146   void ResetNetworkTransaction();
147 
148   // Returns if response is only being read from the network.
network_read_only()149   bool network_read_only() const { return network_read_only_; }
150 
GetTransactionsCount()151   int GetTransactionsCount() const { return all_writers_.size(); }
152 
153  private:
154   friend class WritersTest;
155 
156   enum class State {
157     UNSET,
158     NONE,
159     NETWORK_READ,
160     NETWORK_READ_COMPLETE,
161     CACHE_WRITE_DATA,
162     CACHE_WRITE_DATA_COMPLETE,
163   };
164 
165   // These transactions are waiting on Read. After the active transaction
166   // completes writing the data to the cache, their buffer would be filled with
167   // the data and their callback will be invoked.
168   struct WaitingForRead {
169     scoped_refptr<IOBuffer> read_buf;
170     int read_buf_len;
171     int write_len = 0;
172     CompletionOnceCallback callback;
173     WaitingForRead(scoped_refptr<IOBuffer> read_buf,
174                    int len,
175                    CompletionOnceCallback consumer_callback);
176     ~WaitingForRead();
177     WaitingForRead(WaitingForRead&&);
178   };
179   using WaitingForReadMap = std::map<Transaction*, WaitingForRead>;
180 
181   using TransactionMap = std::map<Transaction*, TransactionInfo>;
182 
183   // Runs the state transition loop. Resets and calls |callback_| on exit,
184   // unless the return value is ERR_IO_PENDING.
185   int DoLoop(int result);
186 
187   // State machine functions.
188   int DoNetworkRead();
189   int DoNetworkReadComplete(int result);
190   int DoCacheWriteData(int num_bytes);
191   int DoCacheWriteDataComplete(int result);
192 
193   // Helper functions for callback.
194   void OnNetworkReadFailure(int result);
195   void OnCacheWriteFailure();
196   void OnDataReceived(int result);
197 
198   // Completes any pending IO_PENDING read operations by copying any received
199   // bytes from read_buf_ to the given buffer and posts a task to run the
200   // callback with |result|.
201   void CompleteWaitingForReadTransactions(int result);
202 
203   // Removes idle writers, passing |result| which is to be used for any
204   // subsequent read transaction.
205   void RemoveIdleWriters(int result);
206 
207   // Invoked when |active_transaction_| fails to read from network or write to
208   // cache. |error| indicates network read error code or cache write error.
209   void ProcessFailure(int error);
210 
211   // Returns true if |this| only contains idle writers. Idle writers are those
212   // that are waiting for Read to be invoked by the consumer.
213   bool ContainsOnlyIdleWriters() const;
214 
215   // Returns true if its worth marking the entry as truncated.
216   // TODO(shivanisha): Refactor this so that it could be const.
217   bool ShouldTruncate();
218 
219   // Enqueues a truncation operation to the entry. Ignores the response.
220   void TruncateEntry();
221 
222   // Remove the transaction.
223   void EraseTransaction(Transaction* transaction, int result);
224   TransactionMap::iterator EraseTransaction(TransactionMap::iterator it,
225                                             int result);
226   void SetCacheCallback(bool success, const TransactionSet& make_readers);
227 
228   // IO Completion callback function.
229   void OnIOComplete(int result);
230 
231   State next_state_ = State::NONE;
232 
233   // True if only reading from network and not writing to cache.
234   bool network_read_only_ = false;
235 
236   raw_ptr<HttpCache> const cache_ = nullptr;
237 
238   // Owner of |this|.
239   scoped_refptr<HttpCache::ActiveEntry> entry_;
240 
241   std::unique_ptr<HttpTransaction> network_transaction_;
242 
243   scoped_refptr<IOBuffer> read_buf_;
244 
245   int io_buf_len_ = 0;
246   int write_len_ = 0;
247 
248   // The cache transaction that is the current consumer of network_transaction_
249   // ::Read or writing to the entry and is waiting for the operation to be
250   // completed. This is used to ensure there is at most one consumer of
251   // network_transaction_ at a time.
252   raw_ptr<Transaction> active_transaction_ = nullptr;
253 
254   // Transactions whose consumers have invoked Read, but another transaction is
255   // currently the |active_transaction_|. After the network read and cache write
256   // is complete, the waiting transactions will be notified.
257   WaitingForReadMap waiting_for_read_;
258 
259   // Includes all transactions. ResetStateForEmptyWriters should be invoked
260   // whenever all_writers_ becomes empty.
261   TransactionMap all_writers_;
262 
263   // True if multiple transactions are not allowed e.g. for partial requests.
264   bool is_exclusive_ = false;
265   ParallelWritingPattern parallel_writing_pattern_ = PARALLEL_WRITING_NONE;
266 
267   // Current priority of the request. It is always the maximum of all the writer
268   // transactions.
269   RequestPriority priority_ = MINIMUM_PRIORITY;
270 
271   // Response info of the most recent transaction added to Writers will be used
272   // to write back the headers along with the truncated bit set. This is done so
273   // that we don't overwrite headers written by a more recent transaction with
274   // older headers while truncating.
275   HttpResponseInfo response_info_truncation_;
276 
277   // Do not mark a partial request as truncated if it is not already a truncated
278   // entry to start with.
279   bool partial_do_not_truncate_ = false;
280 
281   // True if the entry should be kept, even if the response was not completely
282   // written.
283   bool should_keep_entry_ = true;
284 
285   // The latest time `this` starts writing data to the disk cache.
286   base::TimeTicks last_disk_cache_access_start_time_;
287 
288   CompletionOnceCallback callback_;  // Callback for active_transaction_.
289 
290   // Since cache_ can destroy |this|, |cache_callback_| is only invoked at the
291   // end of DoLoop().
292   base::OnceClosure cache_callback_;  // Callback for cache_.
293 
294   base::WeakPtrFactory<Writers> weak_factory_{this};
295 };
296 
297 }  // namespace net
298 
299 #endif  // NET_HTTP_HTTP_CACHE_WRITERS_H_
300