1 // Copyright 2017 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 "content/browser/indexed_db/indexed_db_pre_close_task_queue.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/threading/sequenced_task_runner_handle.h"
12 #include "third_party/blink/public/common/indexeddb/indexeddb_metadata.h"
13 #include "third_party/leveldatabase/env_chromium.h"
14
15 using blink::IndexedDBDatabaseMetadata;
16
17 namespace content {
18
PreCloseTask(leveldb::DB * database)19 IndexedDBPreCloseTaskQueue::PreCloseTask::PreCloseTask(leveldb::DB* database)
20 : database_(database) {}
21
22 IndexedDBPreCloseTaskQueue::PreCloseTask::~PreCloseTask() = default;
23
RequiresMetadata() const24 bool IndexedDBPreCloseTaskQueue::PreCloseTask::RequiresMetadata() const {
25 return false;
26 }
27
SetMetadata(const std::vector<blink::IndexedDBDatabaseMetadata> * metadata)28 void IndexedDBPreCloseTaskQueue::PreCloseTask::SetMetadata(
29 const std::vector<blink::IndexedDBDatabaseMetadata>* metadata) {}
30
IndexedDBPreCloseTaskQueue(std::list<std::unique_ptr<IndexedDBPreCloseTaskQueue::PreCloseTask>> tasks,base::OnceClosure on_complete,base::TimeDelta max_run_time,std::unique_ptr<base::OneShotTimer> timer)31 IndexedDBPreCloseTaskQueue::IndexedDBPreCloseTaskQueue(
32 std::list<std::unique_ptr<IndexedDBPreCloseTaskQueue::PreCloseTask>> tasks,
33 base::OnceClosure on_complete,
34 base::TimeDelta max_run_time,
35 std::unique_ptr<base::OneShotTimer> timer)
36 : tasks_(std::move(tasks)),
37 on_done_(std::move(on_complete)),
38 timeout_time_(max_run_time),
39 timeout_timer_(std::move(timer)),
40 task_runner_(base::SequencedTaskRunnerHandle::Get()) {}
41 IndexedDBPreCloseTaskQueue::~IndexedDBPreCloseTaskQueue() = default;
42
StopForNewConnection()43 void IndexedDBPreCloseTaskQueue::StopForNewConnection() {
44 if (!started_ || done_)
45 return;
46 DCHECK(!tasks_.empty());
47 while (!tasks_.empty()) {
48 tasks_.front()->Stop(StopReason::NEW_CONNECTION);
49 tasks_.pop_front();
50 }
51 OnComplete();
52 }
53
Start(MetadataFetcher metadata_fetcher)54 void IndexedDBPreCloseTaskQueue::Start(MetadataFetcher metadata_fetcher) {
55 DCHECK(!started_);
56 started_ = true;
57 if (tasks_.empty()) {
58 OnComplete();
59 return;
60 }
61 timeout_timer_->Start(
62 FROM_HERE, timeout_time_,
63 base::BindOnce(&IndexedDBPreCloseTaskQueue::StopForTimout,
64 ptr_factory_.GetWeakPtr()));
65 metadata_fetcher_ = std::move(metadata_fetcher);
66 task_runner_->PostTask(FROM_HERE,
67 base::BindOnce(&IndexedDBPreCloseTaskQueue::RunLoop,
68 ptr_factory_.GetWeakPtr()));
69 }
70
OnComplete()71 void IndexedDBPreCloseTaskQueue::OnComplete() {
72 DCHECK(started_);
73 DCHECK(!done_);
74 ptr_factory_.InvalidateWeakPtrs();
75 timeout_timer_->Stop();
76 done_ = true;
77 std::move(on_done_).Run();
78 }
79
StopForTimout()80 void IndexedDBPreCloseTaskQueue::StopForTimout() {
81 DCHECK(started_);
82 if (done_)
83 return;
84 while (!tasks_.empty()) {
85 tasks_.front()->Stop(StopReason::TIMEOUT);
86 tasks_.pop_front();
87 }
88 OnComplete();
89 }
90
StopForMetadataError(const leveldb::Status & status)91 void IndexedDBPreCloseTaskQueue::StopForMetadataError(
92 const leveldb::Status& status) {
93 if (done_)
94 return;
95
96 LOCAL_HISTOGRAM_ENUMERATION(
97 "WebCore.IndexedDB.IndexedDBPreCloseTaskList.MetadataError",
98 leveldb_env::GetLevelDBStatusUMAValue(status),
99 leveldb_env::LEVELDB_STATUS_MAX);
100 while (!tasks_.empty()) {
101 tasks_.front()->Stop(StopReason::METADATA_ERROR);
102 tasks_.pop_front();
103 }
104 OnComplete();
105 }
106
RunLoop()107 void IndexedDBPreCloseTaskQueue::RunLoop() {
108 if (done_)
109 return;
110
111 if (tasks_.empty()) {
112 OnComplete();
113 return;
114 }
115
116 PreCloseTask* task = tasks_.front().get();
117 if (task->RequiresMetadata() && !task->set_metadata_was_called_) {
118 if (!has_metadata_) {
119 leveldb::Status status = std::move(metadata_fetcher_).Run(&metadata_);
120 has_metadata_ = true;
121 if (!status.ok()) {
122 StopForMetadataError(status);
123 return;
124 }
125 }
126 task->SetMetadata(&metadata_);
127 task->set_metadata_was_called_ = true;
128 }
129 bool done = task->RunRound();
130 if (done) {
131 tasks_.pop_front();
132 if (tasks_.empty()) {
133 OnComplete();
134 return;
135 }
136 }
137 task_runner_->PostTask(FROM_HERE,
138 base::BindOnce(&IndexedDBPreCloseTaskQueue::RunLoop,
139 ptr_factory_.GetWeakPtr()));
140 }
141
142 } // namespace content
143