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

Side by Side Diff: net/http/http_cache_shared_writers_unittest.cc

Issue 2519473002: Fixes the cache lock issue. (Closed)
Patch Set: Feedback addressed Created 3 years, 10 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 unified diff | Download patch
« no previous file with comments | « net/http/http_cache_shared_writers.cc ('k') | net/http/http_cache_transaction.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/http/http_cache_transaction.h"
6 #include "net/http/http_transaction.h"
7 #include "net/http/http_transaction_test_util.h"
8 #include "net/http/mock_http_cache.h"
9 #include "net/test/gtest_util.h"
10
11 using net::test::IsError;
12 using net::test::IsOk;
13
14 namespace net {
15
16 namespace {
17
18 // helpers
19 void ReadAndVerifyTransaction(HttpTransaction* transaction,
20 const MockTransaction& transaction_info) {
21 std::string content;
22 int rv = ReadTransaction(transaction, &content);
23
24 EXPECT_THAT(rv, IsOk());
25 std::string expected(transaction_info.data);
26 EXPECT_EQ(expected, content);
27 }
28
29 // The 1st transaction reads from the network and the subsequent transactions
30 // are able to read from the cache even before the complete response is written
31 // to the cache.
32 int ReadSharedWritersCacheRead(std::vector<Context*>& context_list,
33 std::vector<std::string>& results) {
34 int rv;
35
36 size_t i = 0;
37 HttpTransaction* transaction = nullptr;
38 do {
39 Context* c = context_list.at(i);
40 transaction = c->trans.get();
41 scoped_refptr<IOBuffer> buf(new IOBuffer(256));
42 rv = transaction->Read(buf.get(), 256, c->callback.callback());
43 if (rv == ERR_IO_PENDING)
44 rv = c->callback.WaitForResult();
45
46 if (rv > 0)
47 results.at(i).append(buf->data(), rv);
48 else if (rv < 0)
49 return rv;
50
51 i = (i == context_list.size() - 1) ? 0 : i + 1;
52 } while (rv > 0);
53
54 return OK;
55 }
56
57 void ReadAndVerifySharedWritersCacheRead(
58 std::vector<Context*>& context_list,
59 const MockTransaction& transaction_info) {
60 std::vector<std::string> contents(context_list.size());
61 int rv = ReadSharedWritersCacheRead(context_list, contents);
62
63 EXPECT_THAT(rv, IsOk());
64 std::string expected(transaction_info.data);
65 for (size_t i = 0; i < contents.size(); i++) {
66 EXPECT_EQ(expected, contents.at(i));
67 }
68 }
69
70 // The 1st transaction reads from the network and read is invoked on other
71 // transactions even before the 1st one's io callback is invoked. The other
72 // transactions should have data written in their read buffers as part
73 // of the 1st transaction's callback.
74 int ReadSharedWritersJoinedRead(std::vector<Context*>& context_list,
75 std::vector<std::string>& results) {
76 int rv = 0;
77 do {
78 // Invoke Read for all transactions.
79 std::vector<scoped_refptr<IOBuffer>> buffers(context_list.size());
80 for (size_t i = 0; i < context_list.size(); i++) {
81 HttpTransaction* transaction = context_list[i]->trans.get();
82 buffers[i] = new IOBuffer(30);
83 rv = transaction->Read(buffers[i].get(), 30,
84 context_list[i]->callback.callback());
85 // Invoking stop caching here should not have any impact since there are
86 // multiple transactions waiting for this resource.
87 if (i == 0)
88 transaction->StopCaching();
89 }
90 if (rv == ERR_IO_PENDING) {
91 for (size_t i = 0; i < context_list.size(); i++) {
92 Context* ct = context_list[i];
93 rv = ct->callback.WaitForResult();
94 }
95 }
96
97 if (rv > 0) {
98 for (size_t i = 0; i < results.size(); i++) {
99 results[i].append(buffers[i]->data(), rv);
100 }
101 } else if (rv < 0) {
102 return rv;
103 }
104 } while (rv > 0);
105
106 return OK;
107 }
108
109 void ReadAndVerifySharedWritersJoinedRead(
110 const MockTransaction& transaction_info,
111 std::vector<Context*>& context_list) {
112 std::vector<std::string> results(context_list.size());
113 int rv = ReadSharedWritersJoinedRead(context_list, results);
114
115 EXPECT_THAT(rv, IsOk());
116 std::string expected(transaction_info.data);
117 for (size_t i = 0; i < results.size(); i++) {
118 EXPECT_EQ(expected, results[i]);
119 }
120 }
121
122 int ReadSharedWritersJoinedReadDoneReading(std::vector<Context*>& context_list,
123 std::vector<std::string>& results) {
124 int rv = 0;
125 int cnt = 0;
126 do {
127 // Invoke Read for all transactions.
128 std::vector<scoped_refptr<IOBuffer>> buffers(context_list.size());
129 for (size_t i = 0; i < context_list.size(); i++) {
130 HttpTransaction* transaction = context_list[i]->trans.get();
131 buffers[i] = new IOBuffer(30);
132 rv = transaction->Read(buffers[i].get(), 30,
133 context_list[i]->callback.callback());
134 }
135 if (rv == ERR_IO_PENDING) {
136 for (size_t i = 0; i < context_list.size(); i++) {
137 Context* ct = context_list[i];
138 rv = ct->callback.WaitForResult();
139 }
140 }
141
142 if (rv > 0) {
143 for (size_t i = 0; i < results.size(); i++) {
144 results[i].append(buffers[i]->data(), rv);
145 }
146 } else if (rv < 0) {
147 return rv;
148 }
149
150 cnt++;
151 if (cnt == 2) {
152 context_list[0]->trans.get()->DoneReading();
153 }
154 } while (cnt < 2);
155
156 return OK;
157 }
158
159 void ReadAndVerifySharedWritersJoinedReadDoneReading(
160 const MockTransaction& transaction_info,
161 std::vector<Context*>& context_list) {
162 std::vector<std::string> results(context_list.size());
163 int rv = ReadSharedWritersJoinedReadDoneReading(context_list, results);
164
165 EXPECT_THAT(rv, IsOk());
166 std::string expected(transaction_info.data);
167 for (size_t i = 0; i < results.size(); i++) {
168 EXPECT_EQ(expected, results[i]);
169 }
170 }
171
172 // The 1st transaction reads from the network and read is invoked on other
173 // transactions even before the 1st one's io callback is invoked. Also, the
174 // first transaction is deleted before the io callback is invoked. The other
175 // transactions should have data written in their read buffers as part
176 // of the 1st transaction's callback.
177 int ReadSharedWritersJoinedReadDeleteCurrentWriter(
178 std::vector<Context*>& context_list,
179 std::vector<std::string>& results) {
180 int rv = 0;
181 bool first_iter = true;
182 do {
183 // Invoke Read for all transactions.
184 std::vector<scoped_refptr<IOBuffer>> buffers(context_list.size());
185 for (size_t i = 0; i < context_list.size(); i++) {
186 HttpTransaction* transaction = context_list[i]->trans.get();
187 buffers[i] = new IOBuffer(30);
188 rv = transaction->Read(buffers[i].get(), 30,
189 context_list[i]->callback.callback());
190 }
191
192 // Delete the 1st transaction.
193 if (first_iter) {
194 Context* c = context_list[0];
195 context_list.erase(context_list.begin());
196 delete c;
197 buffers.erase(buffers.begin());
198 }
199
200 if (rv == ERR_IO_PENDING) {
201 for (size_t i = 0; i < context_list.size(); i++) {
202 Context* ct = context_list[i];
203 rv = ct->callback.WaitForResult();
204 }
205 }
206
207 if (rv > 0) {
208 for (size_t i = 0; i < context_list.size(); i++) {
209 results[i].append(buffers[i]->data(), rv);
210 }
211 } else if (rv < 0) {
212 return rv;
213 }
214
215 first_iter = false;
216 } while (rv > 0);
217
218 return OK;
219 }
220
221 void ReadAndVerifySharedWritersJoinedReadDeleteCurrentWriter(
222 const MockTransaction& transaction_info,
223 std::vector<Context*>& context_list) {
224 std::vector<std::string> results(context_list.size() - 1);
225 int rv =
226 ReadSharedWritersJoinedReadDeleteCurrentWriter(context_list, results);
227
228 EXPECT_THAT(rv, IsOk());
229 std::string expected(transaction_info.data);
230 for (size_t i = 0; i < results.size(); i++) {
231 EXPECT_EQ(expected, results[i]);
232 }
233 }
234
235 int ReadSharedWritersJoinedReadDeleteWaitingWriter(
236 std::vector<Context*>& context_list,
237 std::vector<std::string>& results) {
238 int rv = 0;
239 bool first_iter = true;
240 do {
241 // Invoke Read for all transactions.
242 std::vector<scoped_refptr<IOBuffer>> buffers(context_list.size());
243 for (size_t i = 0; i < context_list.size(); i++) {
244 HttpTransaction* transaction = context_list[i]->trans.get();
245 buffers[i] = new IOBuffer(30);
246 rv = transaction->Read(buffers[i].get(), 30,
247 context_list[i]->callback.callback());
248 }
249
250 // Remove a waiting writer transaction.
251 if (first_iter) {
252 auto it = context_list.begin();
253 it++;
254 if (it != context_list.end()) {
255 Context* c = *it;
256 context_list.erase(it);
257 delete c;
258 auto it1 = buffers.begin();
259 it1++;
260 buffers.erase(it1);
261 }
262 }
263
264 if (rv == ERR_IO_PENDING) {
265 for (size_t i = 0; i < context_list.size(); i++) {
266 Context* ct = context_list[i];
267 rv = ct->callback.WaitForResult();
268 }
269 }
270
271 if (rv > 0) {
272 for (size_t i = 0; i < context_list.size(); i++) {
273 results[i].append(buffers[i]->data(), rv);
274 }
275 } else if (rv < 0) {
276 return rv;
277 }
278
279 first_iter = false;
280 } while (rv > 0);
281
282 return OK;
283 }
284
285 void ReadAndVerifySharedWritersDeleteWaitingWriter(
286 const MockTransaction& transaction_info,
287 std::vector<Context*>& context_list) {
288 std::vector<std::string> results(context_list.size() - 1);
289 int rv =
290 ReadSharedWritersJoinedReadDeleteWaitingWriter(context_list, results);
291
292 EXPECT_THAT(rv, IsOk());
293 std::string expected(transaction_info.data);
294 for (size_t i = 0; i < results.size(); i++) {
295 EXPECT_EQ(expected, results[i]);
296 }
297 }
298
299 int ReadSharedWritersJoinedReadDeleteIdleWriter(
300 std::vector<Context*>& context_list,
301 std::vector<std::string>& results) {
302 int rv = 0;
303 bool first_iter = true;
304 do {
305 // Invoke Read for all transactions.
306 std::vector<scoped_refptr<IOBuffer>> buffers(context_list.size());
307 for (size_t i = 0; i < context_list.size(); i++) {
308 HttpTransaction* transaction = context_list[i]->trans.get();
309 buffers[i] = new IOBuffer(30);
310 // Do not invoke Read on the first transaction.
311 if (first_iter && i == 0)
312 continue;
313 rv = transaction->Read(buffers[i].get(), 30,
314 context_list[i]->callback.callback());
315 }
316
317 // Remove the idle writer transaction.
318 if (first_iter) {
319 auto it = context_list.begin();
320 Context* c = *it;
321 context_list.erase(it);
322 delete c;
323 auto it1 = buffers.begin();
324 buffers.erase(it1);
325 }
326
327 if (rv == ERR_IO_PENDING) {
328 for (size_t i = 0; i < context_list.size(); i++) {
329 Context* ct = context_list[i];
330 rv = ct->callback.WaitForResult();
331 }
332 }
333
334 if (rv > 0) {
335 for (size_t i = 0; i < context_list.size(); i++) {
336 results[i].append(buffers[i]->data(), rv);
337 }
338 } else if (rv < 0) {
339 return rv;
340 }
341
342 first_iter = false;
343 } while (rv > 0);
344
345 return OK;
346 }
347
348 void ReadAndVerifySharedWritersDeleteIdleWriter(
349 const MockTransaction& transaction_info,
350 std::vector<Context*>& context_list) {
351 std::vector<std::string> results(context_list.size() - 1);
352 int rv = ReadSharedWritersJoinedReadDeleteIdleWriter(context_list, results);
353
354 EXPECT_THAT(rv, IsOk());
355 std::string expected(transaction_info.data);
356 for (size_t i = 0; i < results.size(); i++) {
357 EXPECT_EQ(expected, results[i]);
358 }
359 }
360
361 int ReadSharedWritersJoinedReadCacheWriteFailure(
362 std::vector<Context*>& context_list,
363 std::vector<std::string>& results,
364 MockHttpCache& cache) {
365 int rv = 0;
366 MockHttpRequest request(kSimpleGET_Transaction);
367
368 // Fail the request.
369 cache.disk_cache()->set_soft_failures(true);
370
371 // We have to open the entry again to propagate the failure flag.
372 disk_cache::Entry* en;
373 cache.OpenBackendEntry(kSimpleGET_Transaction.url, &en);
374 en->Close();
375
376 // Invoke Read for two transactions so they become current_writer_ and
377 // waiting_writers_ respectively.
378 std::vector<scoped_refptr<IOBuffer>> buf(2);
379 size_t i = 0, j = 0;
380 do {
381 HttpTransaction* transaction = context_list[i]->trans.get();
382 buf[j] = new IOBuffer(30);
383 rv = transaction->Read(buf[j].get(), 30,
384 context_list[i]->callback.callback());
385 i = context_list.size() - 1;
386 j++;
387 } while (j < buf.size());
388
389 // current_writer_ which is transaction [0] should continue without writing
390 // to the cache, idle writer ([3]) should fail on its next Read call and
391 // waiting_writers_ ([6]) should return a failure back.
392 if (rv == ERR_IO_PENDING) {
393 Context* ct = *(context_list.begin());
394 rv = ct->callback.WaitForResult();
395 }
396
397 // Only [0] should succeed in the Read.
398 results[0].append(buf[0]->data(), 30);
399
400 // Invoke Start on 4 and 5. 4 will fail to read from the cache, doom the
401 // entry and go on to create a new entry. 5 will also get added to that
402 // entry.
403 for (size_t i = 4; i <= 5; i++) {
404 Context* c = context_list[i];
405 c->result =
406 c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
407 }
408
409 base::RunLoop().RunUntilIdle();
410
411 // 3 and 6 failed, delete them.
412 Context* c = context_list[3];
413 scoped_refptr<IOBuffer> buf1 = new IOBuffer(30);
414 int rv_fail = c->trans->Read(buf1.get(), 30, c->callback.callback());
415 EXPECT_THAT(rv_fail, ERR_CACHE_WRITE_FAILURE);
416
417 Context* c6 = context_list[6];
418 for (auto itr = context_list.begin(); itr != context_list.end();) {
419 if (*itr == c || *itr == c6) {
420 Context* ct = *itr;
421 itr = context_list.erase(itr);
422 delete ct;
423 } else {
424 itr++;
425 }
426 }
427
428 cache.disk_cache()->set_soft_failures(false);
429
430 base::RunLoop().RunUntilIdle();
431
432 // Read for the rest of the transactions.
433 Context* c0 = context_list[0];
434 Context* c3 = context_list[3];
435 for (size_t i = 0; i < context_list.size(); i++) {
436 if (i == 1 || i == 2 || i == 4)
437 continue;
438 std::string res;
439 ReadTransaction(context_list[i]->trans.get(), &res);
440 results[i].append(res);
441 }
442
443 base::RunLoop().RunUntilIdle();
444
445 // Delete the done transactions so that pending queue can be processed.
446 // The reader transactions will error out with ERR_CACHE_MISS because of cache
447 // failures.
448 Context* c1 = context_list[1];
449 Context* c2 = context_list[2];
450 auto itr = context_list.begin();
451 for (; itr != context_list.end();) {
452 Context* c = *itr;
453 if (c == c0 || c == c1 || c == c2 || c == c3) {
454 itr = context_list.erase(itr);
455 delete c;
456 } else {
457 itr++;
458 }
459 }
460
461 std::string res;
462 ReadTransaction(context_list[0]->trans.get(), &res);
463 results[4].append(res);
464
465 return OK;
466 }
467
468 void ReadAndVerifySharedWritersJoinedReadCacheWriteFailure(
469 const MockTransaction& transaction_info,
470 std::vector<Context*>& context_list,
471 MockHttpCache& cache) {
472 std::vector<std::string> results(context_list.size());
473 int rv = ReadSharedWritersJoinedReadCacheWriteFailure(context_list, results,
474 cache);
475
476 EXPECT_THAT(rv, IsOk());
477 std::string expected(transaction_info.data);
478 for (size_t i = 0; i < context_list.size(); i++) {
479 EXPECT_EQ(expected, results[i]);
480 }
481 }
482
483 } // namespace
484
485 // Tests.
486
487 TEST(HttpCache, SimpleGET_SharedWritingCacheRead) {
488 MockHttpCache cache;
489
490 MockHttpRequest request(kSimpleGET_Transaction);
491
492 std::vector<Context*> context_list;
493 const int kNumTransactions = 5;
494
495 for (int i = 0; i < kNumTransactions; ++i) {
496 context_list.push_back(new Context());
497 Context* c = context_list[i];
498
499 c->result = cache.CreateTransaction(&c->trans);
500 ASSERT_THAT(c->result, IsOk());
501 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
502
503 c->result =
504 c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
505 }
506
507 // All requests are waiting for the active entry.
508 for (int i = 0; i < kNumTransactions; ++i) {
509 Context* c = context_list[i];
510 EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
511 }
512
513 // Allow all requests to move from the Create queue to the active entry.
514 base::RunLoop().RunUntilIdle();
515
516 // The first request should be a writer at this point, and the subsequent
517 // requests should be pending.
518
519 EXPECT_EQ(1, cache.network_layer()->transaction_count());
520 EXPECT_EQ(0, cache.disk_cache()->open_count());
521 EXPECT_EQ(1, cache.disk_cache()->create_count());
522
523 // All requests depend on the writer, and the writer is between Start and
524 // Read, i.e. idle.
525 for (int i = 0; i < kNumTransactions; ++i) {
526 Context* c = context_list[i];
527 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
528 }
529
530 for (int i = 0; i < kNumTransactions; ++i) {
531 Context* c = context_list[i];
532 if (c->result == ERR_IO_PENDING)
533 c->result = c->callback.WaitForResult();
534 }
535
536 ReadAndVerifySharedWritersCacheRead(context_list, kSimpleGET_Transaction);
537
538 // We should not have had to re-open the disk entry
539
540 EXPECT_EQ(1, cache.network_layer()->transaction_count());
541 EXPECT_EQ(0, cache.disk_cache()->open_count());
542 EXPECT_EQ(1, cache.disk_cache()->create_count());
543
544 for (int i = 0; i < kNumTransactions; ++i) {
545 Context* c = context_list[i];
546 delete c;
547 }
548 }
549
550 TEST(HttpCache, SimpleGET_SharedWritingJoinedRead) {
551 MockHttpCache cache;
552
553 MockHttpRequest request(kSimpleGET_Transaction);
554
555 std::vector<Context*> context_list;
556 const int kNumTransactions = 5;
557
558 for (int i = 0; i < kNumTransactions; ++i) {
559 context_list.push_back(new Context());
560 Context* c = context_list[i];
561
562 c->result = cache.CreateTransaction(&c->trans);
563 ASSERT_THAT(c->result, IsOk());
564 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
565
566 c->result =
567 c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
568 }
569
570 // All requests are waiting for the active entry.
571 for (int i = 0; i < kNumTransactions; ++i) {
572 Context* c = context_list[i];
573 EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
574 }
575
576 // Allow all requests to move from the Create queue to the active entry.
577 base::RunLoop().RunUntilIdle();
578
579 // The first request should be a writer at this point, and the subsequent
580 // requests should be pending.
581
582 EXPECT_EQ(1, cache.network_layer()->transaction_count());
583 EXPECT_EQ(0, cache.disk_cache()->open_count());
584 EXPECT_EQ(1, cache.disk_cache()->create_count());
585 // All requests depend on the writer, and the writer is between Start and
586 // Read, i.e. idle.
587 for (int i = 0; i < kNumTransactions; ++i) {
588 Context* c = context_list[i];
589 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
590 }
591
592 std::vector<HttpTransaction*> transactions;
593 for (int i = 0; i < kNumTransactions; ++i) {
594 Context* c = context_list[i];
595 if (c->result == ERR_IO_PENDING)
596 c->result = c->callback.WaitForResult();
597 transactions.push_back(c->trans.get());
598 }
599
600 ReadAndVerifySharedWritersJoinedRead(kSimpleGET_Transaction, context_list);
601
602 // We should not have had to re-open the disk entry
603
604 EXPECT_EQ(1, cache.network_layer()->transaction_count());
605 EXPECT_EQ(0, cache.disk_cache()->open_count());
606 EXPECT_EQ(1, cache.disk_cache()->create_count());
607
608 for (int i = 0; i < kNumTransactions; ++i) {
609 Context* c = context_list[i];
610 delete c;
611 }
612 }
613
614 TEST(HttpCache, SimpleGET_SharedWritingJoinedReadDoneReading) {
615 MockHttpCache cache;
616
617 MockHttpRequest request(kSimpleGET_Transaction);
618
619 std::vector<Context*> context_list;
620 const int kNumTransactions = 5;
621
622 for (int i = 0; i < kNumTransactions; ++i) {
623 context_list.push_back(new Context());
624 Context* c = context_list[i];
625
626 c->result = cache.CreateTransaction(&c->trans);
627 ASSERT_THAT(c->result, IsOk());
628 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
629
630 c->result =
631 c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
632 }
633
634 // All requests are waiting for the active entry.
635 for (int i = 0; i < kNumTransactions; ++i) {
636 Context* c = context_list[i];
637 EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
638 }
639
640 // Allow all requests to move from the Create queue to the active entry.
641 base::RunLoop().RunUntilIdle();
642
643 // The first request should be a writer at this point, and the subsequent
644 // requests should be pending.
645
646 EXPECT_EQ(1, cache.network_layer()->transaction_count());
647 EXPECT_EQ(0, cache.disk_cache()->open_count());
648 EXPECT_EQ(1, cache.disk_cache()->create_count());
649
650 // All requests depend on the writer, and the writer is between Start and
651 // Read, i.e. idle.
652 for (int i = 0; i < kNumTransactions; ++i) {
653 Context* c = context_list[i];
654 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
655 }
656
657 std::vector<HttpTransaction*> transactions;
658 for (int i = 0; i < kNumTransactions; ++i) {
659 Context* c = context_list[i];
660 if (c->result == ERR_IO_PENDING)
661 c->result = c->callback.WaitForResult();
662 transactions.push_back(c->trans.get());
663 }
664
665 ReadAndVerifySharedWritersJoinedReadDoneReading(kSimpleGET_Transaction,
666 context_list);
667
668 // We should not have had to re-open the disk entry
669
670 EXPECT_EQ(1, cache.network_layer()->transaction_count());
671 EXPECT_EQ(0, cache.disk_cache()->open_count());
672 EXPECT_EQ(1, cache.disk_cache()->create_count());
673
674 for (int i = 0; i < kNumTransactions; ++i) {
675 Context* c = context_list[i];
676 delete c;
677 }
678 }
679
680 // Tests the following:
681 // - A 200 will doom the entry and the transaction will continue to read from
682 // the network.
683 // - Doomed entry's SharedWriters will continue to read and write to the cache.
684 // - Doomed entry's SharedWriters' waiting_for_validation_ will create another
685 // entry.
686 // - The new entry will also have another SharedWriters for subsequent
687 // transactions.
688 TEST(HttpCache, SharedWritingValidation200) {
689 MockHttpCache cache;
690
691 MockHttpRequest request(kSimpleGET_Transaction);
692 request.load_flags |= LOAD_VALIDATE_CACHE;
693 MockHttpRequest reader_request(kSimpleGET_Transaction);
694 reader_request.load_flags = LOAD_ONLY_FROM_CACHE | LOAD_SKIP_CACHE_VALIDATION;
695 MockHttpRequest request_no_validate(kSimpleGET_Transaction);
696
697 std::vector<Context*> context_list;
698 const int kNumTransactions = 6;
699
700 for (int i = 0; i < kNumTransactions; ++i) {
701 context_list.push_back(new Context());
702 Context* c = context_list[i];
703
704 c->result = cache.CreateTransaction(&c->trans);
705 ASSERT_THAT(c->result, IsOk());
706 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
707
708 MockHttpRequest* this_request = &request;
709 if (i == 1 || i == 2)
710 this_request = &reader_request;
711
712 if (i == 5)
713 this_request = &request_no_validate;
714
715 c->result = c->trans->Start(this_request, c->callback.callback(),
716 NetLogWithSource());
717 }
718
719 // All requests are waiting for the active entry.
720 for (int i = 0; i < kNumTransactions; ++i) {
721 Context* c = context_list[i];
722 EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
723 }
724
725 // Allow all requests to move from the Create queue to the active entry.
726 base::RunLoop().RunUntilIdle();
727
728 // The first [0] request should be a writer at this point, and should have
729 // created
730 // SharedWriters, [1] and [2] will be in pending_queue and [3] and [4] should
731 // have validated and [5] will have skipped validation and be ready to read.
732
733 EXPECT_EQ(3, cache.network_layer()->transaction_count());
734 EXPECT_EQ(0, cache.disk_cache()->open_count());
735 EXPECT_EQ(2, cache.disk_cache()->create_count());
736
737 Context* c = context_list[0];
738 ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
739 c->result = c->callback.WaitForResult();
740
741 // First request is done with the headers, now [3] will start validation.
742 Context* c3 = context_list[3];
743 ASSERT_THAT(c3->result, IsError(ERR_IO_PENDING));
744
745 // Let [3] get a 200 , thus leading to dooming the entry, [4] and [5] will
746 // move to entry's pending_queue.
747 c3->result = c3->callback.WaitForResult();
748
749 // [3] will complete reading the response using its own network transaction
750 // and not writing to the cache.
751 ReadAndVerifyTransaction(c3->trans.get(), kSimpleGET_Transaction);
752
753 // [0] will complete reading the response using SharedWriter's network
754 // transaction and then the entry should be finalized.
755 ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
756
757 // [4] should be added to a new entry and should contiue reading and writing
758 // to the cache (also create SharedWriters)
759 for (int i = 4; i <= 5; i++) {
760 Context* c = context_list[i];
761 ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
762 c->result = c->callback.WaitForResult();
763 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
764 // [5] will join SharedWriters at this point when [4] completes validation.
765 ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
766 }
767 // [1] and [2] will become readers and read from the cache.
768 for (int i = 1; i <= 2; i++) {
769 Context* c = context_list[i];
770 ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
771 c->result = c->callback.WaitForResult();
772 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
773 ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
774 }
775
776 // We should not have had to re-open the disk entry
777 EXPECT_EQ(3, cache.network_layer()->transaction_count());
778 EXPECT_EQ(0, cache.disk_cache()->open_count());
779 EXPECT_EQ(2, cache.disk_cache()->create_count());
780
781 for (int i = 0; i < kNumTransactions; ++i) {
782 Context* c = context_list[i];
783 delete c;
784 }
785 }
786
787 // Tests a validating transaction deletion while it is waiting for its callback
788 // to be invoked.
789 TEST(HttpCache, SharedWritingDeleteValidationTrans) {
790 MockHttpCache cache;
791
792 MockHttpRequest request(kSimpleGET_Transaction);
793 request.load_flags |= LOAD_VALIDATE_CACHE;
794 MockHttpRequest reader_request(kSimpleGET_Transaction);
795 reader_request.load_flags = LOAD_ONLY_FROM_CACHE | LOAD_SKIP_CACHE_VALIDATION;
796
797 std::vector<Context*> context_list;
798 const int kNumTransactions = 5;
799
800 for (int i = 0; i < kNumTransactions; ++i) {
801 context_list.push_back(new Context());
802 Context* c = context_list[i];
803
804 c->result = cache.CreateTransaction(&c->trans);
805 ASSERT_THAT(c->result, IsOk());
806 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
807
808 MockHttpRequest* this_request = &request;
809 if (i == 1 || i == 2)
810 this_request = &reader_request;
811
812 if (i == 3 || i == 4)
813 continue;
814
815 c->result = c->trans->Start(this_request, c->callback.callback(),
816 NetLogWithSource());
817 }
818
819 // All requests are waiting for the active entry.
820 for (int i = 0; i < kNumTransactions; ++i) {
821 if (i == 3 || i == 4)
822 continue;
823 Context* c = context_list[i];
824 EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
825 }
826
827 // Allow all requests to move from the Create queue to the active entry.
828 base::RunLoop().RunUntilIdle();
829
830 EXPECT_EQ(1, cache.network_layer()->transaction_count());
831 EXPECT_EQ(0, cache.disk_cache()->open_count());
832 EXPECT_EQ(1, cache.disk_cache()->create_count());
833
834 // Start [3], [4].
835 for (size_t i = 3; i <= 4; i++) {
836 Context* c = context_list[i];
837 c->result =
838 c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
839 ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
840 }
841
842 // Delete [3] as it is the current validating trans.
843 Context* c3 = context_list[3];
844 for (auto it = context_list.begin(); it != context_list.end(); it++) {
845 if (*it == c3) {
846 context_list.erase(it);
847 delete c3;
848 break;
849 }
850 }
851
852 // Complete start state machine for [4].
853 base::RunLoop().RunUntilIdle();
854
855 // [0] will complete reading the response using SharedWriter's network
856 // transaction and then the entry should be finalized.
857 Context* c0 = context_list[0];
858 ReadAndVerifyTransaction(c0->trans.get(), kSimpleGET_Transaction);
859
860 // [4] (now [3]) should doom the entry and continue reading with its network
861 // transaction.
862 Context* c4 = context_list[3];
863 ReadAndVerifyTransaction(c4->trans.get(), kSimpleGET_Transaction);
864
865 // 1st entry will get destroyed and [1] and [2] will being readers will get a
866 // ERR_CACHE_MISS.
867 for (int i = 1; i <= 2; i++) {
868 Context* c = context_list[i];
869 ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
870 c->result = c->callback.WaitForResult();
871 ASSERT_THAT(c->result, IsError(ERR_CACHE_MISS));
872 }
873
874 // We should not have had to re-open the disk entry
875 EXPECT_EQ(2, cache.network_layer()->transaction_count());
876 EXPECT_EQ(0, cache.disk_cache()->open_count());
877 EXPECT_EQ(1, cache.disk_cache()->create_count());
878
879 for (auto i = context_list.begin(); i != context_list.end(); ++i) {
880 Context* c = *i;
881 delete c;
882 }
883 }
884
885 // Tests a transaction deletion while it is waiting for validation.
886 TEST(HttpCache, SharedWritingDeleteWaitingForValidation) {
887 MockHttpCache cache;
888
889 MockHttpRequest request(kSimpleGET_Transaction);
890 request.load_flags |= LOAD_VALIDATE_CACHE;
891 MockHttpRequest reader_request(kSimpleGET_Transaction);
892 reader_request.load_flags = LOAD_ONLY_FROM_CACHE | LOAD_SKIP_CACHE_VALIDATION;
893
894 std::vector<Context*> context_list;
895 const int kNumTransactions = 5;
896
897 for (int i = 0; i < kNumTransactions; ++i) {
898 context_list.push_back(new Context());
899 Context* c = context_list[i];
900
901 c->result = cache.CreateTransaction(&c->trans);
902 ASSERT_THAT(c->result, IsOk());
903 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
904
905 MockHttpRequest* this_request = &request;
906 if (i == 1 || i == 2)
907 this_request = &reader_request;
908
909 if (i == 3 || i == 4)
910 continue;
911
912 c->result = c->trans->Start(this_request, c->callback.callback(),
913 NetLogWithSource());
914 }
915
916 // All requests are waiting for the active entry.
917 for (int i = 0; i < kNumTransactions; ++i) {
918 if (i == 3 || i == 4)
919 continue;
920 Context* c = context_list[i];
921 EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
922 }
923
924 // Allow all requests to move from the Create queue to the active entry.
925 base::RunLoop().RunUntilIdle();
926
927 EXPECT_EQ(1, cache.network_layer()->transaction_count());
928 EXPECT_EQ(0, cache.disk_cache()->open_count());
929 EXPECT_EQ(1, cache.disk_cache()->create_count());
930
931 // Start [3], [4].
932 for (size_t i = 3; i <= 4; i++) {
933 Context* c = context_list[i];
934 c->result =
935 c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
936 ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
937 }
938
939 // Delete [4] as it is the waiting for validation trans.
940 Context* c4 = context_list[4];
941 for (auto it = context_list.begin(); it != context_list.end(); it++) {
942 if (*it == c4) {
943 context_list.erase(it);
944 delete c4;
945 break;
946 }
947 }
948
949 // Complete start state machine for [3].
950 base::RunLoop().RunUntilIdle();
951
952 // [0] will complete reading the response using SharedWriter's network
953 // transaction and then the entry should be finalized.
954 Context* c0 = context_list[0];
955 ReadAndVerifyTransaction(c0->trans.get(), kSimpleGET_Transaction);
956
957 // [3] should doom the entry and continue reading with its network
958 // transaction.
959 Context* c3 = context_list[3];
960 ReadAndVerifyTransaction(c3->trans.get(), kSimpleGET_Transaction);
961
962 // 1st entry will get destroyed and [1] and [2] will being readers will get a
963 // ERR_CACHE_MISS.
964 for (int i = 1; i <= 2; i++) {
965 Context* c = context_list[i];
966 ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
967 c->result = c->callback.WaitForResult();
968 ASSERT_THAT(c->result, IsError(ERR_CACHE_MISS));
969 }
970
971 // We should not have had to re-open the disk entry
972 EXPECT_EQ(2, cache.network_layer()->transaction_count());
973 EXPECT_EQ(0, cache.disk_cache()->open_count());
974 EXPECT_EQ(1, cache.disk_cache()->create_count());
975
976 for (auto i = context_list.begin(); i != context_list.end(); ++i) {
977 Context* c = *i;
978 delete c;
979 }
980 }
981
982 // Tests the impact of cache write failure on Shared Writing.
983 TEST(HttpCache, SharedWritingCacheWriteFailure) {
984 MockHttpCache cache;
985
986 MockHttpRequest request(kSimpleGET_Transaction);
987 request.load_flags |= LOAD_VALIDATE_CACHE;
988 MockHttpRequest reader_request(kSimpleGET_Transaction);
989 reader_request.load_flags = LOAD_ONLY_FROM_CACHE | LOAD_SKIP_CACHE_VALIDATION;
990 MockHttpRequest request_no_validate(kSimpleGET_Transaction);
991
992 std::vector<Context*> context_list;
993 const int kNumTransactions = 7;
994
995 for (int i = 0; i < kNumTransactions; ++i) {
996 context_list.push_back(new Context());
997 Context* c = context_list[i];
998
999 c->result = cache.CreateTransaction(&c->trans);
1000 ASSERT_THAT(c->result, IsOk());
1001 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
1002
1003 MockHttpRequest* this_request = &request;
1004 if (i == 1 || i == 2)
1005 this_request = &reader_request;
1006
1007 if (i == 3 || i == 6)
1008 this_request = &request_no_validate;
1009
1010 if (i == 4 || i == 5)
1011 continue;
1012
1013 c->result = c->trans->Start(this_request, c->callback.callback(),
1014 NetLogWithSource());
1015 }
1016
1017 // All requests are waiting for the active entry.
1018 for (int i = 0; i < kNumTransactions; ++i) {
1019 if (i == 4 || i == 5)
1020 continue;
1021 Context* c = context_list[i];
1022 EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
1023 }
1024
1025 // Allow all requests to move from the Create queue to the active entry.
1026 base::RunLoop().RunUntilIdle();
1027
1028 // At this point, 0,5 and 3 are idle writers, 1 and 2 are pending readers and
1029 // 4
1030 // will now become the validating_trans_.
1031
1032 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1033 EXPECT_EQ(0, cache.disk_cache()->open_count());
1034 EXPECT_EQ(1, cache.disk_cache()->create_count());
1035
1036 ReadAndVerifySharedWritersJoinedReadCacheWriteFailure(kSimpleGET_Transaction,
1037 context_list, cache);
1038
1039 // We should not have had to re-open the disk entry
1040 EXPECT_EQ(3, cache.network_layer()->transaction_count());
1041 EXPECT_EQ(1, cache.disk_cache()->open_count());
1042 EXPECT_EQ(3, cache.disk_cache()->create_count());
1043
1044 for (auto i = context_list.begin(); i != context_list.end(); ++i) {
1045 Context* c = *i;
1046 delete c;
1047 }
1048 }
1049
1050 TEST(HttpCache, SimpleGET_SharedWritingJoinedReadDeleteCurrentWriter) {
1051 MockHttpCache cache;
1052
1053 MockHttpRequest request(kSimpleGET_Transaction);
1054
1055 std::vector<Context*> context_list;
1056 const int kNumTransactions = 5;
1057
1058 for (int i = 0; i < kNumTransactions; ++i) {
1059 context_list.push_back(new Context());
1060 Context* c = context_list[i];
1061
1062 c->result = cache.CreateTransaction(&c->trans);
1063 ASSERT_THAT(c->result, IsOk());
1064 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
1065
1066 c->result =
1067 c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
1068 }
1069
1070 // All requests are waiting for the active entry.
1071 for (int i = 0; i < kNumTransactions; ++i) {
1072 Context* c = context_list[i];
1073 EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
1074 }
1075
1076 // Allow all requests to move from the Create queue to the active entry.
1077 base::RunLoop().RunUntilIdle();
1078
1079 // The first request should be a writer at this point, and the subsequent
1080 // requests should be pending.
1081
1082 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1083 EXPECT_EQ(0, cache.disk_cache()->open_count());
1084 EXPECT_EQ(1, cache.disk_cache()->create_count());
1085
1086 // All requests depend on the writer, and the writer is between Start and
1087 // Read, i.e. idle.
1088 for (int i = 0; i < kNumTransactions; ++i) {
1089 Context* c = context_list[i];
1090 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
1091 }
1092
1093 std::vector<HttpTransaction*> transactions;
1094 for (int i = 0; i < kNumTransactions; ++i) {
1095 Context* c = context_list[i];
1096 if (c->result == ERR_IO_PENDING)
1097 c->result = c->callback.WaitForResult();
1098 transactions.push_back(c->trans.get());
1099 }
1100
1101 ReadAndVerifySharedWritersJoinedReadDeleteCurrentWriter(
1102 kSimpleGET_Transaction, context_list);
1103
1104 // We should not have had to re-open the disk entry
1105 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1106 EXPECT_EQ(0, cache.disk_cache()->open_count());
1107 EXPECT_EQ(1, cache.disk_cache()->create_count());
1108
1109 for (auto i = context_list.begin(); i != context_list.end(); ++i) {
1110 Context* c = *i;
1111 delete c;
1112 }
1113 }
1114
1115 TEST(HttpCache, SimpleGET_SharedWritingJoinedReadDeleteWaitingWriter) {
1116 MockHttpCache cache;
1117
1118 MockHttpRequest request(kSimpleGET_Transaction);
1119
1120 std::vector<Context*> context_list;
1121 const int kNumTransactions = 5;
1122
1123 for (int i = 0; i < kNumTransactions; ++i) {
1124 context_list.push_back(new Context());
1125 Context* c = context_list[i];
1126
1127 c->result = cache.CreateTransaction(&c->trans);
1128 ASSERT_THAT(c->result, IsOk());
1129 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
1130
1131 c->result =
1132 c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
1133 }
1134
1135 // All requests are waiting for the active entry.
1136 for (int i = 0; i < kNumTransactions; ++i) {
1137 Context* c = context_list[i];
1138 EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
1139 }
1140
1141 // Allow all requests to move from the Create queue to the active entry.
1142 base::RunLoop().RunUntilIdle();
1143
1144 // The first request should be a writer at this point, and the subsequent
1145 // requests should be pending.
1146
1147 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1148 EXPECT_EQ(0, cache.disk_cache()->open_count());
1149 EXPECT_EQ(1, cache.disk_cache()->create_count());
1150
1151 // All requests depend on the writer, and the writer is between Start and
1152 // Read, i.e. idle.
1153 for (int i = 0; i < kNumTransactions; ++i) {
1154 Context* c = context_list[i];
1155 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
1156 }
1157
1158 std::vector<HttpTransaction*> transactions;
1159 for (int i = 0; i < kNumTransactions; ++i) {
1160 Context* c = context_list[i];
1161 if (c->result == ERR_IO_PENDING)
1162 c->result = c->callback.WaitForResult();
1163 transactions.push_back(c->trans.get());
1164 }
1165
1166 ReadAndVerifySharedWritersDeleteWaitingWriter(kSimpleGET_Transaction,
1167 context_list);
1168
1169 // We should not have had to re-open the disk entry
1170 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1171 EXPECT_EQ(0, cache.disk_cache()->open_count());
1172 EXPECT_EQ(1, cache.disk_cache()->create_count());
1173
1174 for (auto i = context_list.begin(); i != context_list.end(); ++i) {
1175 Context* c = *i;
1176 delete c;
1177 }
1178 }
1179
1180 TEST(HttpCache, SimpleGET_SharedWritingJoinedReadDeleteIdleWriter) {
1181 MockHttpCache cache;
1182
1183 MockHttpRequest request(kSimpleGET_Transaction);
1184
1185 std::vector<Context*> context_list;
1186 const int kNumTransactions = 5;
1187
1188 for (int i = 0; i < kNumTransactions; ++i) {
1189 context_list.push_back(new Context());
1190 Context* c = context_list[i];
1191
1192 c->result = cache.CreateTransaction(&c->trans);
1193 ASSERT_THAT(c->result, IsOk());
1194 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
1195
1196 c->result =
1197 c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
1198 }
1199
1200 // All requests are waiting for the active entry.
1201 for (int i = 0; i < kNumTransactions; ++i) {
1202 Context* c = context_list[i];
1203 EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
1204 }
1205
1206 // Allow all requests to move from the Create queue to the active entry.
1207 base::RunLoop().RunUntilIdle();
1208
1209 // The first request should be a writer at this point, and the subsequent
1210 // requests should be pending.
1211
1212 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1213 EXPECT_EQ(0, cache.disk_cache()->open_count());
1214 EXPECT_EQ(1, cache.disk_cache()->create_count());
1215
1216 // All requests depend on the writer, and the writer is between Start and
1217 // Read, i.e. idle.
1218 for (int i = 0; i < kNumTransactions; ++i) {
1219 Context* c = context_list[i];
1220 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
1221 }
1222
1223 std::vector<HttpTransaction*> transactions;
1224 for (int i = 0; i < kNumTransactions; ++i) {
1225 Context* c = context_list[i];
1226 if (c->result == ERR_IO_PENDING)
1227 c->result = c->callback.WaitForResult();
1228 transactions.push_back(c->trans.get());
1229 }
1230
1231 ReadAndVerifySharedWritersDeleteIdleWriter(kSimpleGET_Transaction,
1232 context_list);
1233 // We should not have had to re-open the disk entry
1234 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1235 EXPECT_EQ(0, cache.disk_cache()->open_count());
1236 EXPECT_EQ(1, cache.disk_cache()->create_count());
1237
1238 for (auto i = context_list.begin(); i != context_list.end(); ++i) {
1239 Context* c = *i;
1240 delete c;
1241 }
1242 }
1243
1244 } // namespace net
OLDNEW
« no previous file with comments | « net/http/http_cache_shared_writers.cc ('k') | net/http/http_cache_transaction.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698