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 : #include "DatabaseInfo.h"
41 :
42 : #include "nsDataHashtable.h"
43 : #include "nsThreadUtils.h"
44 :
45 : USING_INDEXEDDB_NAMESPACE
46 :
47 : namespace {
48 :
49 : typedef nsDataHashtable<nsISupportsHashKey, DatabaseInfo*>
50 : DatabaseHash;
51 :
52 : DatabaseHash* gDatabaseHash = nsnull;
53 :
54 : PLDHashOperator
55 1716 : EnumerateObjectStoreNames(const nsAString& aKey,
56 : ObjectStoreInfo* aData,
57 : void* aUserArg)
58 : {
59 1716 : nsTArray<nsString>* array = static_cast<nsTArray<nsString>*>(aUserArg);
60 1716 : if (!array->AppendElement(aData->name)) {
61 0 : NS_ERROR("Out of memory?");
62 0 : return PL_DHASH_STOP;
63 : }
64 1716 : return PL_DHASH_NEXT;
65 : }
66 :
67 : PLDHashOperator
68 31 : CloneObjectStoreInfo(const nsAString& aKey,
69 : ObjectStoreInfo* aData,
70 : void* aUserArg)
71 : {
72 31 : ObjectStoreInfoHash* hash = static_cast<ObjectStoreInfoHash*>(aUserArg);
73 :
74 62 : nsRefPtr<ObjectStoreInfo> newInfo(new ObjectStoreInfo(*aData));
75 :
76 31 : if (!hash->Put(aKey, newInfo)) {
77 0 : NS_WARNING("Out of memory?");
78 0 : return PL_DHASH_STOP;
79 : }
80 :
81 31 : return PL_DHASH_NEXT;
82 : }
83 :
84 : }
85 :
86 160 : DatabaseInfo::~DatabaseInfo()
87 : {
88 : // Clones are never in the hash.
89 80 : if (!cloned) {
90 54 : DatabaseInfo::Remove(id);
91 : }
92 80 : }
93 :
94 31 : ObjectStoreInfo::ObjectStoreInfo(ObjectStoreInfo& aOther)
95 : : name(aOther.name),
96 : id(aOther.id),
97 : keyPath(aOther.keyPath),
98 : indexes(aOther.indexes),
99 : nextAutoIncrementId(aOther.nextAutoIncrementId),
100 31 : comittedAutoIncrementId(aOther.comittedAutoIncrementId)
101 : {
102 : // Doesn't copy the refcount
103 31 : MOZ_COUNT_CTOR(ObjectStoreInfo);
104 31 : }
105 :
106 : #ifdef NS_BUILD_REFCNT_LOGGING
107 :
108 103 : IndexInfo::IndexInfo()
109 : : id(LL_MININT),
110 : unique(false),
111 103 : multiEntry(false)
112 : {
113 103 : MOZ_COUNT_CTOR(IndexInfo);
114 103 : }
115 :
116 27 : IndexInfo::IndexInfo(const IndexInfo& aOther)
117 : : id(aOther.id),
118 : name(aOther.name),
119 : keyPath(aOther.keyPath),
120 : keyPathArray(aOther.keyPathArray),
121 : unique(aOther.unique),
122 27 : multiEntry(aOther.multiEntry)
123 : {
124 27 : MOZ_COUNT_CTOR(IndexInfo);
125 27 : }
126 :
127 260 : IndexInfo::~IndexInfo()
128 : {
129 130 : MOZ_COUNT_DTOR(IndexInfo);
130 130 : }
131 :
132 224 : ObjectStoreInfo::ObjectStoreInfo()
133 : : id(0),
134 : nextAutoIncrementId(0),
135 224 : comittedAutoIncrementId(0)
136 : {
137 224 : MOZ_COUNT_CTOR(ObjectStoreInfo);
138 224 : }
139 :
140 510 : ObjectStoreInfo::~ObjectStoreInfo()
141 : {
142 255 : MOZ_COUNT_DTOR(ObjectStoreInfo);
143 255 : }
144 :
145 373 : IndexUpdateInfo::IndexUpdateInfo()
146 : {
147 373 : MOZ_COUNT_CTOR(IndexUpdateInfo);
148 373 : }
149 :
150 746 : IndexUpdateInfo::~IndexUpdateInfo()
151 : {
152 373 : MOZ_COUNT_DTOR(IndexUpdateInfo);
153 373 : }
154 : #endif /* NS_BUILD_REFCNT_LOGGING */
155 :
156 : // static
157 : bool
158 75 : DatabaseInfo::Get(nsIAtom* aId,
159 : DatabaseInfo** aInfo)
160 : {
161 75 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
162 75 : NS_ASSERTION(aId, "Bad id!");
163 :
164 98 : if (gDatabaseHash &&
165 23 : gDatabaseHash->Get(aId, aInfo)) {
166 21 : NS_IF_ADDREF(*aInfo);
167 21 : return true;
168 : }
169 54 : return false;
170 : }
171 :
172 : // static
173 : bool
174 54 : DatabaseInfo::Put(DatabaseInfo* aInfo)
175 : {
176 54 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
177 54 : NS_ASSERTION(aInfo, "Null pointer!");
178 :
179 54 : if (!gDatabaseHash) {
180 104 : nsAutoPtr<DatabaseHash> databaseHash(new DatabaseHash());
181 52 : if (!databaseHash->Init()) {
182 0 : NS_ERROR("Failed to initialize hashtable!");
183 0 : return false;
184 : }
185 :
186 104 : gDatabaseHash = databaseHash.forget();
187 : }
188 :
189 54 : if (gDatabaseHash->Get(aInfo->id, nsnull)) {
190 0 : NS_ERROR("Already know about this database!");
191 0 : return false;
192 : }
193 :
194 54 : if (!gDatabaseHash->Put(aInfo->id, aInfo)) {
195 0 : NS_ERROR("Put failed!");
196 0 : return false;
197 : }
198 :
199 54 : return true;
200 : }
201 :
202 : // static
203 : void
204 55 : DatabaseInfo::Remove(nsIAtom* aId)
205 : {
206 55 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
207 :
208 55 : if (gDatabaseHash) {
209 54 : gDatabaseHash->Remove(aId);
210 :
211 54 : if (!gDatabaseHash->Count()) {
212 52 : delete gDatabaseHash;
213 52 : gDatabaseHash = nsnull;
214 : }
215 : }
216 55 : }
217 :
218 : PLDHashOperator
219 0 : EnumerateDatabasesRemoveOrigin(nsISupports* aId,
220 : DatabaseInfo*& aDatabaseInfo,
221 : void* aUserArg)
222 : {
223 0 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
224 :
225 0 : const nsACString* origin = static_cast<const nsACString*>(aUserArg);
226 0 : return aDatabaseInfo->origin.Equals(*origin) ?
227 : PL_DHASH_REMOVE :
228 0 : PL_DHASH_NEXT;
229 : }
230 :
231 : // static
232 : void
233 8 : DatabaseInfo::RemoveAllForOrigin(const nsACString& aOrigin)
234 : {
235 8 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
236 :
237 8 : if (gDatabaseHash) {
238 : gDatabaseHash->Enumerate(EnumerateDatabasesRemoveOrigin,
239 0 : const_cast<nsACString*>(&aOrigin));
240 : }
241 8 : }
242 :
243 : bool
244 415 : DatabaseInfo::GetObjectStoreNames(nsTArray<nsString>& aNames)
245 : {
246 415 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
247 :
248 415 : aNames.Clear();
249 415 : if (objectStoreHash) {
250 344 : objectStoreHash->EnumerateRead(EnumerateObjectStoreNames, &aNames);
251 : }
252 415 : return true;
253 : }
254 :
255 : bool
256 792 : DatabaseInfo::ContainsStoreName(const nsAString& aName)
257 : {
258 792 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
259 :
260 792 : return objectStoreHash && objectStoreHash->Get(aName, nsnull);
261 : }
262 :
263 : ObjectStoreInfo*
264 747 : DatabaseInfo::GetObjectStore(const nsAString& aName)
265 : {
266 747 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
267 :
268 747 : if (objectStoreHash) {
269 747 : return objectStoreHash->GetWeak(aName);
270 : }
271 :
272 0 : return nsnull;
273 : }
274 :
275 : bool
276 201 : DatabaseInfo::PutObjectStore(ObjectStoreInfo* aInfo)
277 : {
278 201 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
279 201 : NS_ASSERTION(aInfo, "Null pointer!");
280 :
281 201 : if (!objectStoreHash) {
282 94 : nsAutoPtr<ObjectStoreInfoHash> hash(new ObjectStoreInfoHash());
283 47 : if (!hash->Init()) {
284 0 : NS_ERROR("Failed to initialize hashtable!");
285 0 : return false;
286 : }
287 94 : objectStoreHash = hash.forget();
288 : }
289 :
290 201 : if (objectStoreHash->Get(aInfo->name, nsnull)) {
291 0 : NS_ERROR("Already have an entry for this objectstore!");
292 0 : return false;
293 : }
294 :
295 201 : return objectStoreHash->Put(aInfo->name, aInfo);
296 : }
297 :
298 : void
299 123 : DatabaseInfo::RemoveObjectStore(const nsAString& aName)
300 : {
301 123 : NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
302 123 : NS_ASSERTION(GetObjectStore(aName), "Don't know about this one!");
303 :
304 123 : if (objectStoreHash) {
305 123 : objectStoreHash->Remove(aName);
306 : }
307 123 : }
308 :
309 : already_AddRefed<DatabaseInfo>
310 26 : DatabaseInfo::Clone()
311 : {
312 26 : NS_ASSERTION(!cloned, "Should never clone a clone!");
313 :
314 52 : nsRefPtr<DatabaseInfo> dbInfo(new DatabaseInfo());
315 :
316 26 : dbInfo->cloned = true;
317 26 : dbInfo->name = name;
318 26 : dbInfo->version = version;
319 26 : dbInfo->id = id;
320 26 : dbInfo->filePath = filePath;
321 26 : dbInfo->nextObjectStoreId = nextObjectStoreId;
322 26 : dbInfo->nextIndexId = nextIndexId;
323 :
324 26 : if (objectStoreHash) {
325 19 : dbInfo->objectStoreHash = new ObjectStoreInfoHash();
326 19 : if (!dbInfo->objectStoreHash->Init()) {
327 0 : return nsnull;
328 : }
329 :
330 19 : objectStoreHash->EnumerateRead(CloneObjectStoreInfo,
331 38 : dbInfo->objectStoreHash);
332 : }
333 :
334 26 : return dbInfo.forget();
335 : }
|