1 /*
2 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3 * Copyright (C) 2011 Google, Inc. All Rights Reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 */
27
28 #include "third_party/blink/renderer/modules/webdatabase/database_context.h"
29
30 #include "third_party/blink/renderer/core/dom/document.h"
31 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
32 #include "third_party/blink/renderer/modules/webdatabase/database.h"
33 #include "third_party/blink/renderer/modules/webdatabase/database_manager.h"
34 #include "third_party/blink/renderer/modules/webdatabase/database_task.h"
35 #include "third_party/blink/renderer/modules/webdatabase/database_thread.h"
36 #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
37 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
38 #include "third_party/blink/renderer/platform/wtf/assertions.h"
39
40 namespace blink {
41
42 // How the DatabaseContext Life-Cycle works?
43 // ========================================
44 // ... in other words, who's keeping the DatabaseContext alive and how long does
45 // it need to stay alive?
46 //
47 // The DatabaseContext is referenced from:
48 // 1. DatabaseManager
49 // 2. Database
50 //
51 // At Birth:
52 // ========
53 // We create a DatabaseContext only when there is a need i.e. the script tries
54 // to open a Database via DatabaseManager::openDatabase().
55 //
56 // The DatabaseContext constructor will register itself to DatabaseManager. This
57 // lets DatabaseContext keep itself alive until it is unregisterd in
58 // contextDestroyed().
59 //
60 // Once a DatabaseContext is associated with a ExecutionContext, it will
61 // live until after the ExecutionContext destructs. This is true even if
62 // we don't succeed in opening any Databases for that context. When we do
63 // succeed in opening Databases for this ExecutionContext, the Database
64 // will re-use the same DatabaseContext.
65 //
66 // At Shutdown:
67 // ===========
68 // During shutdown, the DatabaseContext needs to:
69 // 1. "outlive" the ExecutionContext.
70 // - This is needed because the DatabaseContext needs to remove itself from
71 // the
72 // ExecutionContext's ExecutionContextLifecycleObserver list and
73 // ExecutionContextLifecycleObserver
74 // list. This removal needs to be executed on the script's thread. Hence,
75 // we
76 // rely on the ExecutionContext's shutdown process to call
77 // stop() and contextDestroyed() to give us a chance to clean these up from
78 // the script thread.
79 //
80 // 2. "outlive" the Databases.
81 // - This is because they may make use of the DatabaseContext to execute a
82 // close task and shutdown in an orderly manner. When the Databases are
83 // destructed, they will release the DatabaseContext reference from the
84 // DatabaseThread.
85 //
86 // During shutdown, the ExecutionContext is shutting down on the script thread
87 // while the Databases are shutting down on the DatabaseThread. Hence, there can
88 // be a race condition as to whether the ExecutionContext or the Databases
89 // destruct first.
90 //
91 // The Members in the Databases and DatabaseManager will ensure that the
92 // DatabaseContext will outlive Database and ExecutionContext regardless of
93 // which of the 2 destructs first.
94
Create(ExecutionContext * context)95 DatabaseContext* DatabaseContext::Create(ExecutionContext* context) {
96 DatabaseContext* self = MakeGarbageCollected<DatabaseContext>(context);
97 DatabaseManager::Manager().RegisterDatabaseContext(self);
98 return self;
99 }
100
DatabaseContext(ExecutionContext * context)101 DatabaseContext::DatabaseContext(ExecutionContext* context)
102 : ExecutionContextLifecycleObserver(context),
103 has_open_databases_(false),
104 has_requested_termination_(false) {
105 DCHECK(IsMainThread());
106
107 // For debug accounting only. We must do this before we register the
108 // instance. The assertions assume this.
109 DatabaseManager::Manager().DidConstructDatabaseContext();
110 }
111
~DatabaseContext()112 DatabaseContext::~DatabaseContext() {
113 // For debug accounting only. We must call this last. The assertions assume
114 // this.
115 DatabaseManager::Manager().DidDestructDatabaseContext();
116 }
117
Trace(Visitor * visitor)118 void DatabaseContext::Trace(Visitor* visitor) {
119 visitor->Trace(database_thread_);
120 ExecutionContextLifecycleObserver::Trace(visitor);
121 }
122
123 // This is called if the associated ExecutionContext is destructing while
124 // we're still associated with it. That's our cue to disassociate and shutdown.
125 // To do this, we stop the database and let everything shutdown naturally
126 // because the database closing process may still make use of this context.
127 // It is not safe to just delete the context here.
ContextDestroyed()128 void DatabaseContext::ContextDestroyed() {
129 StopDatabases();
130 DatabaseManager::Manager().UnregisterDatabaseContext(this);
131 }
132
Backend()133 DatabaseContext* DatabaseContext::Backend() {
134 return this;
135 }
136
GetDatabaseThread()137 DatabaseThread* DatabaseContext::GetDatabaseThread() {
138 if (!database_thread_ && !has_open_databases_) {
139 // It's OK to ask for the m_databaseThread after we've requested
140 // termination because we're still using it to execute the closing
141 // of the database. However, it is NOT OK to create a new thread
142 // after we've requested termination.
143 DCHECK(!has_requested_termination_);
144
145 // Create the database thread on first request - but not if at least one
146 // database was already opened, because in that case we already had a
147 // database thread and terminated it and should not create another.
148 database_thread_ = MakeGarbageCollected<DatabaseThread>();
149 database_thread_->Start();
150 }
151
152 return database_thread_.Get();
153 }
154
DatabaseThreadAvailable()155 bool DatabaseContext::DatabaseThreadAvailable() {
156 return GetDatabaseThread() && !has_requested_termination_;
157 }
158
StopDatabases()159 void DatabaseContext::StopDatabases() {
160 // Though we initiate termination of the DatabaseThread here in
161 // stopDatabases(), we can't clear the m_databaseThread ref till we get to
162 // the destructor. This is because the Databases that are managed by
163 // DatabaseThread still rely on this ref between the context and the thread
164 // to execute the task for closing the database. By the time we get to the
165 // destructor, we're guaranteed that the databases are destructed (which is
166 // why our ref count is 0 then and we're destructing). Then, the
167 // m_databaseThread RefPtr destructor will deref and delete the
168 // DatabaseThread.
169
170 if (DatabaseThreadAvailable()) {
171 has_requested_termination_ = true;
172 // This blocks until the database thread finishes the cleanup task.
173 database_thread_->Terminate();
174 }
175 }
176
AllowDatabaseAccess() const177 bool DatabaseContext::AllowDatabaseAccess() const {
178 return Document::From(GetExecutionContext())->IsActive();
179 }
180
GetSecurityOrigin() const181 const SecurityOrigin* DatabaseContext::GetSecurityOrigin() const {
182 return GetExecutionContext()->GetSecurityOrigin();
183 }
184
IsContextThread() const185 bool DatabaseContext::IsContextThread() const {
186 return GetExecutionContext()->IsContextThread();
187 }
188
189 } // namespace blink
190