1 /*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
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 AND ITS CONTRIBUTORS "AS IS" AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "modules/indexeddb/IDBPendingTransactionMonitor.h"
28
29 #include "modules/indexeddb/IDBCursor.h"
30 #include "modules/indexeddb/IDBRequest.h"
31 #include "modules/indexeddb/IDBTransaction.h"
32
33 namespace blink {
34
IDBPendingTransactionMonitor()35 IDBPendingTransactionMonitor::IDBPendingTransactionMonitor()
36 {
37 }
38
~IDBPendingTransactionMonitor()39 IDBPendingTransactionMonitor::~IDBPendingTransactionMonitor()
40 {
41 }
42
addNewTransaction(IDBTransaction & transaction)43 void IDBPendingTransactionMonitor::addNewTransaction(IDBTransaction& transaction)
44 {
45 m_transactions.append(&transaction);
46 }
47
deactivateNewTransactions()48 void IDBPendingTransactionMonitor::deactivateNewTransactions()
49 {
50 for (size_t i = 0; i < m_transactions.size(); ++i)
51 m_transactions[i]->setActive(false);
52 // FIXME: Exercise this call to clear() in a layout test.
53 m_transactions.clear();
54 }
55
56 // IDBDisposerDispatcher should be RefCounted because it should outlive all of
57 // target objects.
58 class IDBDisposerDispatcher: public RefCounted<IDBDisposerDispatcher> {
59 public:
create()60 static PassRefPtr<IDBDisposerDispatcher> create() { return adoptRef(new IDBDisposerDispatcher()); }
61
62 private:
IDBDisposerDispatcher()63 IDBDisposerDispatcher() { }
64
65 template<typename Owner, typename Target>
66 class Disposer {
67 public:
create(Owner & owner,Target & target)68 static PassOwnPtr<Disposer> create(Owner& owner, Target& target) { return adoptPtr(new Disposer(owner, target)); }
~Disposer()69 ~Disposer()
70 {
71 if (!m_isDisabled)
72 m_target.dispose();
73 }
setDisabled()74 void setDisabled() { m_isDisabled = true; }
75
76 private:
Disposer(Owner & owner,Target & target)77 Disposer(Owner& owner, Target& target)
78 : m_owner(owner)
79 , m_target(target)
80 , m_isDisabled(false)
81 {
82 }
83
84 RefPtr<Owner> m_owner;
85 Target& m_target;
86 bool m_isDisabled;
87 };
88
89 template<typename Target>
90 class DisposerMap {
91 DISALLOW_ALLOCATION();
92 public:
registerTarget(IDBDisposerDispatcher & dispatcher,Target & target)93 void registerTarget(IDBDisposerDispatcher& dispatcher, Target& target)
94 {
95 ASSERT(!m_disposerMap.contains(&target));
96 m_disposerMap.add(&target, Disposer<IDBDisposerDispatcher, Target>::create(dispatcher, target));
97 }
98
unregisterTarget(IDBDisposerDispatcher & dispatcher,Target & target)99 void unregisterTarget(IDBDisposerDispatcher& dispatcher, Target& target)
100 {
101 // Skip this function if this is called in Target::dispose().
102 if (ThreadState::current()->isSweepInProgress())
103 return;
104 auto it = m_disposerMap.find(&target);
105 ASSERT(it != m_disposerMap.end());
106 if (it == m_disposerMap.end())
107 return;
108 // m_disposerMap.remove() will trigger ~Disposer. We should not call
109 // Target::dispose() in ~Disposer in this case.
110 it->value->setDisabled();
111 m_disposerMap.remove(it);
112 }
113
114 private:
115 PersistentHeapHashMap<WeakMember<Target>, OwnPtr<Disposer<IDBDisposerDispatcher, Target>>> m_disposerMap;
116 };
117
118 DisposerMap<IDBRequest> m_requests;
119 DisposerMap<IDBCursor> m_cursors;
120 friend class IDBPendingTransactionMonitor;
121 };
122
registerRequest(IDBRequest & request)123 void IDBPendingTransactionMonitor::registerRequest(IDBRequest& request)
124 {
125 if (!m_dispatcher)
126 m_dispatcher = IDBDisposerDispatcher::create();
127 m_dispatcher->m_requests.registerTarget(*m_dispatcher, request);
128 }
129
unregisterRequest(IDBRequest & request)130 void IDBPendingTransactionMonitor::unregisterRequest(IDBRequest& request)
131 {
132 // We should not unregister without registeration.
133 ASSERT(m_dispatcher);
134 m_dispatcher->m_requests.unregisterTarget(*m_dispatcher, request);
135 }
136
registerCursor(IDBCursor & cursor)137 void IDBPendingTransactionMonitor::registerCursor(IDBCursor& cursor)
138 {
139 if (!m_dispatcher)
140 m_dispatcher = IDBDisposerDispatcher::create();
141 m_dispatcher->m_cursors.registerTarget(*m_dispatcher, cursor);
142 }
143
unregisterCursor(IDBCursor & cursor)144 void IDBPendingTransactionMonitor::unregisterCursor(IDBCursor& cursor)
145 {
146 // We should not unregister without registeration.
147 ASSERT(m_dispatcher);
148 m_dispatcher->m_cursors.unregisterTarget(*m_dispatcher, cursor);
149 }
150
151 } // namespace blink
152