1 | /* |
2 | * Copyright (C) 2009 Google Inc. All rights reserved. |
3 | * Copyright (C) 2013 Apple 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 are |
7 | * met: |
8 | * |
9 | * * Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * * Redistributions in binary form must reproduce the above |
12 | * copyright notice, this list of conditions and the following disclaimer |
13 | * in the documentation and/or other materials provided with the |
14 | * distribution. |
15 | * * Neither the name of Google Inc. nor the names of its |
16 | * contributors may be used to endorse or promote products derived from |
17 | * this software without specific prior written permission. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
25 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | #include "config.h" |
33 | #include "SQLTransactionCoordinator.h" |
34 | |
35 | #include "Database.h" |
36 | #include "SQLTransaction.h" |
37 | #include "SecurityOrigin.h" |
38 | #include "SecurityOriginData.h" |
39 | #include <wtf/Deque.h> |
40 | #include <wtf/RefPtr.h> |
41 | |
42 | namespace WebCore { |
43 | |
44 | static String getDatabaseIdentifier(SQLTransaction& transaction) |
45 | { |
46 | return transaction.database().securityOrigin().databaseIdentifier(); |
47 | } |
48 | |
49 | SQLTransactionCoordinator::SQLTransactionCoordinator() |
50 | : m_isShuttingDown(false) |
51 | { |
52 | } |
53 | |
54 | void SQLTransactionCoordinator::processPendingTransactions(CoordinationInfo& info) |
55 | { |
56 | if (info.activeWriteTransaction || info.pendingTransactions.isEmpty()) |
57 | return; |
58 | |
59 | RefPtr<SQLTransaction> firstPendingTransaction = info.pendingTransactions.first(); |
60 | if (firstPendingTransaction->isReadOnly()) { |
61 | do { |
62 | firstPendingTransaction = info.pendingTransactions.takeFirst(); |
63 | info.activeReadTransactions.add(firstPendingTransaction); |
64 | firstPendingTransaction->lockAcquired(); |
65 | } while (!info.pendingTransactions.isEmpty() && info.pendingTransactions.first()->isReadOnly()); |
66 | } else if (info.activeReadTransactions.isEmpty()) { |
67 | info.pendingTransactions.removeFirst(); |
68 | info.activeWriteTransaction = firstPendingTransaction; |
69 | firstPendingTransaction->lockAcquired(); |
70 | } |
71 | } |
72 | |
73 | void SQLTransactionCoordinator::acquireLock(SQLTransaction& transaction) |
74 | { |
75 | ASSERT(!m_isShuttingDown); |
76 | |
77 | String dbIdentifier = getDatabaseIdentifier(transaction); |
78 | |
79 | CoordinationInfoMap::iterator coordinationInfoIterator = m_coordinationInfoMap.find(dbIdentifier); |
80 | if (coordinationInfoIterator == m_coordinationInfoMap.end()) { |
81 | // No pending transactions for this DB |
82 | coordinationInfoIterator = m_coordinationInfoMap.add(dbIdentifier, CoordinationInfo()).iterator; |
83 | } |
84 | |
85 | CoordinationInfo& info = coordinationInfoIterator->value; |
86 | info.pendingTransactions.append(&transaction); |
87 | processPendingTransactions(info); |
88 | } |
89 | |
90 | void SQLTransactionCoordinator::releaseLock(SQLTransaction& transaction) |
91 | { |
92 | if (m_isShuttingDown) |
93 | return; |
94 | |
95 | String dbIdentifier = getDatabaseIdentifier(transaction); |
96 | |
97 | CoordinationInfoMap::iterator coordinationInfoIterator = m_coordinationInfoMap.find(dbIdentifier); |
98 | ASSERT(coordinationInfoIterator != m_coordinationInfoMap.end()); |
99 | CoordinationInfo& info = coordinationInfoIterator->value; |
100 | |
101 | if (transaction.isReadOnly()) { |
102 | ASSERT(info.activeReadTransactions.contains(&transaction)); |
103 | info.activeReadTransactions.remove(&transaction); |
104 | } else { |
105 | ASSERT(info.activeWriteTransaction == &transaction); |
106 | info.activeWriteTransaction = nullptr; |
107 | } |
108 | |
109 | processPendingTransactions(info); |
110 | } |
111 | |
112 | void SQLTransactionCoordinator::shutdown() |
113 | { |
114 | // Prevent releaseLock() from accessing / changing the coordinationInfo |
115 | // while we're shutting down. |
116 | m_isShuttingDown = true; |
117 | |
118 | // Notify all transactions in progress that the database thread is shutting down |
119 | for (auto& info : m_coordinationInfoMap.values()) { |
120 | // Clean up transactions that have reached "lockAcquired": |
121 | // Transaction phase 4 cleanup. See comment on "What happens if a |
122 | // transaction is interrupted?" at the top of SQLTransactionBackend.cpp. |
123 | if (info.activeWriteTransaction) |
124 | info.activeWriteTransaction->notifyDatabaseThreadIsShuttingDown(); |
125 | for (auto& transaction : info.activeReadTransactions) |
126 | transaction->notifyDatabaseThreadIsShuttingDown(); |
127 | |
128 | // Clean up transactions that have NOT reached "lockAcquired": |
129 | // Transaction phase 3 cleanup. See comment on "What happens if a |
130 | // transaction is interrupted?" at the top of SQLTransactionBackend.cpp. |
131 | while (!info.pendingTransactions.isEmpty()) { |
132 | RefPtr<SQLTransaction> transaction = info.pendingTransactions.first(); |
133 | transaction->notifyDatabaseThreadIsShuttingDown(); |
134 | } |
135 | } |
136 | |
137 | // Clean up all pending transactions for all databases |
138 | m_coordinationInfoMap.clear(); |
139 | } |
140 | |
141 | } // namespace WebCore |
142 | |