1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=2 et sw=2 tw=80: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Indexed Database.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * The Mozilla Foundation.
20 : * Portions created by the Initial Developer are Copyright (C) 2010
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Ben Turner <bent.mozilla@gmail.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #ifndef mozilla_dom_indexeddb_indexeddatabasemanager_h__
41 : #define mozilla_dom_indexeddb_indexeddatabasemanager_h__
42 :
43 : #include "mozilla/dom/indexedDB/FileManager.h"
44 : #include "mozilla/dom/indexedDB/IndexedDatabase.h"
45 : #include "mozilla/dom/indexedDB/IDBDatabase.h"
46 : #include "mozilla/dom/indexedDB/IDBRequest.h"
47 :
48 : #include "mozilla/Mutex.h"
49 :
50 : #include "nsIIndexedDatabaseManager.h"
51 : #include "nsIObserver.h"
52 : #include "nsIRunnable.h"
53 : #include "nsIThread.h"
54 : #include "nsIURI.h"
55 :
56 : #include "nsClassHashtable.h"
57 : #include "nsRefPtrHashtable.h"
58 : #include "nsHashKeys.h"
59 :
60 : #define INDEXEDDB_MANAGER_CONTRACTID "@mozilla.org/dom/indexeddb/manager;1"
61 :
62 : class mozIStorageQuotaCallback;
63 : class nsITimer;
64 :
65 : BEGIN_INDEXEDDB_NAMESPACE
66 :
67 : class AsyncConnectionHelper;
68 :
69 : class CheckQuotaHelper;
70 :
71 : class IndexedDatabaseManager : public nsIIndexedDatabaseManager,
72 : public nsIObserver
73 : {
74 : friend class IDBDatabase;
75 :
76 : public:
77 : static already_AddRefed<IndexedDatabaseManager> GetOrCreate();
78 :
79 : // Returns a non-owning reference.
80 : static IndexedDatabaseManager* Get();
81 :
82 : // Returns an owning reference! No one should call this but the factory.
83 : static IndexedDatabaseManager* FactoryCreate();
84 :
85 : NS_DECL_ISUPPORTS
86 : NS_DECL_NSIINDEXEDDATABASEMANAGER
87 : NS_DECL_NSIOBSERVER
88 :
89 : // Waits for databases to be cleared and for version change transactions to
90 : // complete before dispatching the given runnable.
91 : nsresult WaitForOpenAllowed(const nsACString& aOrigin,
92 : nsIAtom* aId,
93 : nsIRunnable* aRunnable);
94 :
95 : void AllowNextSynchronizedOp(const nsACString& aOrigin,
96 : nsIAtom* aId);
97 :
98 0 : nsIThread* IOThread()
99 : {
100 0 : NS_ASSERTION(mIOThread, "This should never be null!");
101 0 : return mIOThread;
102 : }
103 :
104 : // Returns true if we've begun the shutdown process.
105 : static bool IsShuttingDown();
106 :
107 : static bool IsClosed();
108 :
109 : typedef void (*WaitingOnDatabasesCallback)(nsTArray<nsRefPtr<IDBDatabase> >&, void*);
110 :
111 : // Acquire exclusive access to the database given (waits for all others to
112 : // close). If databases need to close first, the callback will be invoked
113 : // with an array of said databases.
114 : nsresult AcquireExclusiveAccess(IDBDatabase* aDatabase,
115 : AsyncConnectionHelper* aHelper,
116 : WaitingOnDatabasesCallback aCallback,
117 : void* aClosure)
118 : {
119 : NS_ASSERTION(aDatabase, "Need a DB here!");
120 : return AcquireExclusiveAccess(aDatabase->Origin(), aDatabase, aHelper,
121 : aCallback, aClosure);
122 : }
123 : nsresult AcquireExclusiveAccess(const nsACString& aOrigin,
124 : AsyncConnectionHelper* aHelper,
125 : WaitingOnDatabasesCallback aCallback,
126 : void* aClosure)
127 : {
128 : return AcquireExclusiveAccess(aOrigin, nsnull, aHelper, aCallback,
129 : aClosure);
130 : }
131 :
132 : // Called when a window is being purged from the bfcache or the user leaves
133 : // a page which isn't going into the bfcache. Forces any live database
134 : // objects to close themselves and aborts any running transactions.
135 : void AbortCloseDatabasesForWindow(nsPIDOMWindow* aWindow);
136 :
137 : // Used to check if there are running transactions in a given window.
138 : bool HasOpenTransactions(nsPIDOMWindow* aWindow);
139 :
140 : // Set the Window that the current thread is doing operations for.
141 : // The caller is responsible for ensuring that aWindow is held alive.
142 : static inline void
143 : SetCurrentWindow(nsPIDOMWindow* aWindow)
144 : {
145 : IndexedDatabaseManager* mgr = Get();
146 : NS_ASSERTION(mgr, "Must have a manager here!");
147 :
148 : return mgr->SetCurrentWindowInternal(aWindow);
149 : }
150 :
151 : static PRUint32
152 : GetIndexedDBQuotaMB();
153 :
154 : nsresult EnsureOriginIsInitialized(const nsACString& aOrigin,
155 : nsIFile** aDirectory);
156 :
157 : // Determine if the quota is lifted for the Window the current thread is
158 : // using.
159 : static inline bool
160 0 : QuotaIsLifted()
161 : {
162 0 : IndexedDatabaseManager* mgr = Get();
163 0 : NS_ASSERTION(mgr, "Must have a manager here!");
164 :
165 0 : return mgr->QuotaIsLiftedInternal();
166 : }
167 :
168 : static inline void
169 : CancelPromptsForWindow(nsPIDOMWindow* aWindow)
170 : {
171 : IndexedDatabaseManager* mgr = Get();
172 : NS_ASSERTION(mgr, "Must have a manager here!");
173 :
174 : mgr->CancelPromptsForWindowInternal(aWindow);
175 : }
176 :
177 : static nsresult
178 : GetASCIIOriginFromWindow(nsPIDOMWindow* aWindow, nsCString& aASCIIOrigin);
179 :
180 : already_AddRefed<FileManager>
181 : GetOrCreateFileManager(const nsACString& aOrigin,
182 : const nsAString& aDatabaseName);
183 :
184 : already_AddRefed<FileManager>
185 : GetFileManager(const nsACString& aOrigin,
186 : const nsAString& aDatabaseName);
187 :
188 : void InvalidateFileManagersForOrigin(const nsACString& aOrigin);
189 :
190 : void InvalidateFileManager(const nsACString& aOrigin,
191 : const nsAString& aDatabaseName);
192 :
193 : nsresult AsyncDeleteFile(FileManager* aFileManager,
194 : PRInt64 aFileId);
195 :
196 0 : static mozilla::Mutex& FileMutex()
197 : {
198 0 : IndexedDatabaseManager* mgr = Get();
199 0 : NS_ASSERTION(mgr, "Must have a manager here!");
200 :
201 0 : return mgr->mFileMutex;
202 : }
203 :
204 : private:
205 : IndexedDatabaseManager();
206 : ~IndexedDatabaseManager();
207 :
208 : nsresult AcquireExclusiveAccess(const nsACString& aOrigin,
209 : IDBDatabase* aDatabase,
210 : AsyncConnectionHelper* aHelper,
211 : WaitingOnDatabasesCallback aCallback,
212 : void* aClosure);
213 :
214 : void SetCurrentWindowInternal(nsPIDOMWindow* aWindow);
215 : bool QuotaIsLiftedInternal();
216 : void CancelPromptsForWindowInternal(nsPIDOMWindow* aWindow);
217 :
218 : // Called when a database is created.
219 : bool RegisterDatabase(IDBDatabase* aDatabase);
220 :
221 : // Called when a database is being unlinked or destroyed.
222 : void UnregisterDatabase(IDBDatabase* aDatabase);
223 :
224 : // Called when a database has been closed.
225 : void OnDatabaseClosed(IDBDatabase* aDatabase);
226 :
227 : // Responsible for clearing the database files for a particular origin on the
228 : // IO thread. Created when nsIIDBIndexedDatabaseManager::ClearDatabasesForURI
229 : // is called. Runs three times, first on the main thread, next on the IO
230 : // thread, and then finally again on the main thread. While on the IO thread
231 : // the runnable will actually remove the origin's database files and the
232 : // directory that contains them before dispatching itself back to the main
233 : // thread. When back on the main thread the runnable will notify the
234 : // IndexedDatabaseManager that the job has been completed.
235 : class OriginClearRunnable : public nsIRunnable
236 8 : {
237 : public:
238 : NS_DECL_ISUPPORTS
239 : NS_DECL_NSIRUNNABLE
240 :
241 8 : OriginClearRunnable(const nsACString& aOrigin,
242 : nsIThread* aThread)
243 : : mOrigin(aOrigin),
244 : mThread(aThread),
245 8 : mFirstCallback(true)
246 8 : { }
247 :
248 : nsCString mOrigin;
249 : nsCOMPtr<nsIThread> mThread;
250 : bool mFirstCallback;
251 : };
252 :
253 : bool IsClearOriginPending(const nsACString& origin);
254 :
255 : // Responsible for calculating the amount of space taken up by databases of a
256 : // certain origin. Created when nsIIDBIndexedDatabaseManager::GetUsageForURI
257 : // is called. May be canceled with
258 : // nsIIDBIndexedDatabaseManager::CancelGetUsageForURI. Runs twice, first on
259 : // the IO thread, then again on the main thread. While on the IO thread the
260 : // runnable will calculate the size of all files in the origin's directory
261 : // before dispatching itself back to the main thread. When on the main thread
262 : // the runnable will call the callback and then notify the
263 : // IndexedDatabaseManager that the job has been completed.
264 : class AsyncUsageRunnable : public nsIRunnable
265 0 : {
266 : public:
267 : NS_DECL_ISUPPORTS
268 : NS_DECL_NSIRUNNABLE
269 :
270 : AsyncUsageRunnable(nsIURI* aURI,
271 : const nsACString& aOrigin,
272 : nsIIndexedDatabaseUsageCallback* aCallback);
273 :
274 : // Sets the canceled flag so that the callback is never called.
275 : void Cancel();
276 :
277 : // Run calls the RunInternal method and makes sure that we always dispatch
278 : // to the main thread in case of an error.
279 : inline nsresult RunInternal();
280 :
281 : nsresult GetUsageForDirectory(nsIFile* aDirectory,
282 : PRUint64* aUsage);
283 :
284 : nsCOMPtr<nsIURI> mURI;
285 : nsCString mOrigin;
286 : nsCOMPtr<nsIIndexedDatabaseUsageCallback> mCallback;
287 : PRUint64 mUsage;
288 : PRUint64 mFileUsage;
289 : PRInt32 mCanceled;
290 : };
291 :
292 : // Called when AsyncUsageRunnable has finished its Run() method.
293 : inline void OnUsageCheckComplete(AsyncUsageRunnable* aRunnable);
294 :
295 : // A struct that contains the information corresponding to a pending or
296 : // running operation that requires synchronization (e.g. opening a db,
297 : // clearing dbs for an origin, etc).
298 : struct SynchronizedOp
299 : {
300 : SynchronizedOp(const nsACString& aOrigin, nsIAtom* aId);
301 : ~SynchronizedOp();
302 :
303 : // Test whether the second SynchronizedOp needs to get behind this one.
304 : bool MustWaitFor(const SynchronizedOp& aRhs) const;
305 :
306 : void DelayRunnable(nsIRunnable* aRunnable);
307 : void DispatchDelayedRunnables();
308 :
309 : const nsCString mOrigin;
310 : nsCOMPtr<nsIAtom> mId;
311 : nsRefPtr<AsyncConnectionHelper> mHelper;
312 : nsTArray<nsCOMPtr<nsIRunnable> > mDelayedRunnables;
313 : nsTArray<nsRefPtr<IDBDatabase> > mDatabases;
314 : };
315 :
316 : // A callback runnable used by the TransactionPool when it's safe to proceed
317 : // with a SetVersion/DeleteDatabase/etc.
318 : class WaitForTransactionsToFinishRunnable : public nsIRunnable
319 : {
320 : public:
321 3 : WaitForTransactionsToFinishRunnable(SynchronizedOp* aOp)
322 3 : : mOp(aOp)
323 : {
324 3 : NS_ASSERTION(mOp, "Why don't we have a runnable?");
325 3 : NS_ASSERTION(mOp->mDatabases.IsEmpty(), "We're here too early!");
326 3 : NS_ASSERTION(mOp->mHelper, "What are we supposed to do when we're done?");
327 3 : }
328 :
329 : NS_DECL_ISUPPORTS
330 : NS_DECL_NSIRUNNABLE
331 :
332 : private:
333 : // The IndexedDatabaseManager holds this alive.
334 : SynchronizedOp* mOp;
335 : };
336 :
337 : class AsyncDeleteFileRunnable : public nsIRunnable
338 0 : {
339 : public:
340 : NS_DECL_ISUPPORTS
341 : NS_DECL_NSIRUNNABLE
342 0 : AsyncDeleteFileRunnable(const nsAString& aFilePath)
343 0 : : mFilePath(aFilePath)
344 0 : { }
345 :
346 : private:
347 : nsString mFilePath;
348 : };
349 :
350 : static nsresult DispatchHelper(AsyncConnectionHelper* aHelper);
351 :
352 : // Maintains a list of live databases per origin.
353 : nsClassHashtable<nsCStringHashKey, nsTArray<IDBDatabase*> > mLiveDatabases;
354 :
355 : // TLS storage index for the current thread's window
356 : PRUintn mCurrentWindowIndex;
357 :
358 : // Lock protecting mQuotaHelperHash
359 : mozilla::Mutex mQuotaHelperMutex;
360 :
361 : // A map of Windows to the corresponding quota helper.
362 : nsRefPtrHashtable<nsPtrHashKey<nsPIDOMWindow>, CheckQuotaHelper> mQuotaHelperHash;
363 :
364 : // Maintains a list of all file managers per origin. The list is actually also
365 : // a list of all origins that were successfully initialized. This list
366 : // isn't protected by any mutex but it is only ever touched on the IO thread.
367 : nsClassHashtable<nsCStringHashKey,
368 : nsTArray<nsRefPtr<FileManager> > > mFileManagers;
369 :
370 : // Maintains a list of origins that we're currently enumerating to gather
371 : // usage statistics.
372 : nsAutoTArray<nsRefPtr<AsyncUsageRunnable>, 1> mUsageRunnables;
373 :
374 : // Maintains a list of synchronized operatons that are in progress or queued.
375 : nsAutoTArray<nsAutoPtr<SynchronizedOp>, 5> mSynchronizedOps;
376 :
377 : // Thread on which IO is performed.
378 : nsCOMPtr<nsIThread> mIOThread;
379 :
380 : // A timer that gets activated at shutdown to ensure we close all databases.
381 : nsCOMPtr<nsITimer> mShutdownTimer;
382 :
383 : // A single threadsafe instance of our quota callback. Created on the main
384 : // thread during GetOrCreate().
385 : nsCOMPtr<mozIStorageQuotaCallback> mQuotaCallbackSingleton;
386 :
387 : // Lock protecting FileManager.mFileInfos and nsDOMFileBase.mFileInfos
388 : // It's s also used to atomically update FileInfo.mRefCnt, FileInfo.mDBRefCnt
389 : // and FileInfo.mSliceRefCnt
390 : mozilla::Mutex mFileMutex;
391 : };
392 :
393 : class AutoEnterWindow
394 : {
395 : public:
396 : AutoEnterWindow(nsPIDOMWindow* aWindow)
397 : {
398 : IndexedDatabaseManager::SetCurrentWindow(aWindow);
399 : }
400 :
401 : ~AutoEnterWindow()
402 : {
403 : IndexedDatabaseManager::SetCurrentWindow(nsnull);
404 : }
405 : };
406 :
407 : END_INDEXEDDB_NAMESPACE
408 :
409 : #endif /* mozilla_dom_indexeddb_indexeddatabasemanager_h__ */
|