0d1ddb0dfebc05dce507be09d421c26d268b4e0e
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / IDBDatabaseBackendImpl.cpp
1 /*
2  * Copyright (C) 2011 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 "IDBDatabaseBackendImpl.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "IDBBackingStore.h"
32 #include "IDBCursorBackendImpl.h"
33 #include "IDBDatabaseException.h"
34 #include "IDBFactoryBackendImpl.h"
35 #include "IDBIndexBackendImpl.h"
36 #include "IDBObjectStoreBackendImpl.h"
37 #include "IDBTracing.h"
38 #include "IDBTransactionBackendImpl.h"
39 #include "IDBTransactionCoordinator.h"
40
41 namespace WebCore {
42
43 class IDBDatabaseBackendImpl::CreateObjectStoreOperation : public IDBTransactionBackendImpl::Operation {
44 public:
45     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBDatabaseBackendImpl> database, PassRefPtr<IDBObjectStoreBackendImpl> objectStore)
46     {
47         return adoptPtr(new CreateObjectStoreOperation(database, objectStore));
48     }
49     virtual void perform(IDBTransactionBackendImpl*);
50 private:
51     CreateObjectStoreOperation(PassRefPtr<IDBDatabaseBackendImpl> database, PassRefPtr<IDBObjectStoreBackendImpl> objectStore)
52         : m_database(database)
53         , m_objectStore(objectStore)
54     {
55     }
56
57     RefPtr<IDBDatabaseBackendImpl> m_database;
58     RefPtr<IDBObjectStoreBackendImpl> m_objectStore;
59 };
60
61 class IDBDatabaseBackendImpl::DeleteObjectStoreOperation : public IDBTransactionBackendImpl::Operation {
62 public:
63     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBDatabaseBackendImpl> database, PassRefPtr<IDBObjectStoreBackendImpl> objectStore)
64     {
65         return adoptPtr(new DeleteObjectStoreOperation(database, objectStore));
66     }
67     virtual void perform(IDBTransactionBackendImpl*);
68 private:
69     DeleteObjectStoreOperation(PassRefPtr<IDBDatabaseBackendImpl> database, PassRefPtr<IDBObjectStoreBackendImpl> objectStore)
70         : m_database(database)
71         , m_objectStore(objectStore)
72     {
73     }
74
75     RefPtr<IDBDatabaseBackendImpl> m_database;
76     RefPtr<IDBObjectStoreBackendImpl> m_objectStore;
77 };
78
79 class IDBDatabaseBackendImpl::VersionChangeOperation : public IDBTransactionBackendImpl::Operation {
80 public:
81     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBDatabaseBackendImpl> database, int64_t transactionId, int64_t version, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks)
82     {
83         return adoptPtr(new VersionChangeOperation(database, transactionId, version, callbacks, databaseCallbacks));
84     }
85     virtual void perform(IDBTransactionBackendImpl*);
86 private:
87     VersionChangeOperation(PassRefPtr<IDBDatabaseBackendImpl> database, int64_t transactionId, int64_t version, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks)
88         : m_database(database)
89         , m_transactionId(transactionId)
90         , m_version(version)
91         , m_callbacks(callbacks)
92         , m_databaseCallbacks(databaseCallbacks)
93     {
94     }
95
96     RefPtr<IDBDatabaseBackendImpl> m_database;
97     int64_t m_transactionId;
98     int64_t m_version;
99     RefPtr<IDBCallbacks> m_callbacks;
100     RefPtr<IDBDatabaseCallbacks> m_databaseCallbacks;
101 };
102
103 class IDBDatabaseBackendImpl::CreateObjectStoreAbortOperation : public IDBTransactionBackendImpl::Operation {
104 public:
105     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBDatabaseBackendImpl> database, PassRefPtr<IDBObjectStoreBackendImpl> objectStore)
106     {
107         return adoptPtr(new CreateObjectStoreAbortOperation(database, objectStore));
108     }
109     virtual void perform(IDBTransactionBackendImpl*);
110 private:
111     CreateObjectStoreAbortOperation(PassRefPtr<IDBDatabaseBackendImpl> database, PassRefPtr<IDBObjectStoreBackendImpl> objectStore)
112         : m_database(database)
113         , m_objectStore(objectStore)
114     {
115     }
116
117     RefPtr<IDBDatabaseBackendImpl> m_database;
118     RefPtr<IDBObjectStoreBackendImpl> m_objectStore;
119 };
120
121 class IDBDatabaseBackendImpl::DeleteObjectStoreAbortOperation : public IDBTransactionBackendImpl::Operation {
122 public:
123     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBDatabaseBackendImpl> database, PassRefPtr<IDBObjectStoreBackendImpl> objectStore)
124     {
125         return adoptPtr(new DeleteObjectStoreAbortOperation(database, objectStore));
126     }
127     virtual void perform(IDBTransactionBackendImpl*);
128 private:
129     DeleteObjectStoreAbortOperation(PassRefPtr<IDBDatabaseBackendImpl> database, PassRefPtr<IDBObjectStoreBackendImpl> objectStore)
130         : m_database(database)
131         , m_objectStore(objectStore)
132     {
133     }
134
135     RefPtr<IDBDatabaseBackendImpl> m_database;
136     RefPtr<IDBObjectStoreBackendImpl> m_objectStore;
137 };
138
139 class IDBDatabaseBackendImpl::VersionChangeAbortOperation : public IDBTransactionBackendImpl::Operation {
140 public:
141     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBDatabaseBackendImpl> database, const String& previousVersion, int64_t previousIntVersion)
142     {
143         return adoptPtr(new VersionChangeAbortOperation(database, previousVersion, previousIntVersion));
144     }
145     virtual void perform(IDBTransactionBackendImpl*);
146 private:
147     VersionChangeAbortOperation(PassRefPtr<IDBDatabaseBackendImpl> database, const String& previousVersion, int64_t previousIntVersion)
148         : m_database(database)
149         , m_previousVersion(previousVersion)
150         , m_previousIntVersion(previousIntVersion)
151     {
152     }
153
154     RefPtr<IDBDatabaseBackendImpl> m_database;
155     String m_previousVersion;
156     int64_t m_previousIntVersion;
157 };
158
159 class GetOperation : public IDBTransactionBackendImpl::Operation {
160 public:
161     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, const IDBDatabaseMetadata& metadata, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, IDBCursorBackendInterface::CursorType cursorType, PassRefPtr<IDBCallbacks> callbacks)
162     {
163         return adoptPtr(new GetOperation(backingStore, metadata, objectStoreId, indexId, keyRange, cursorType, callbacks));
164     }
165     virtual void perform(IDBTransactionBackendImpl*);
166 private:
167     GetOperation(PassRefPtr<IDBBackingStore> backingStore, const IDBDatabaseMetadata& metadata, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, IDBCursorBackendInterface::CursorType cursorType, PassRefPtr<IDBCallbacks> callbacks)
168         : m_backingStore(backingStore)
169         , m_databaseId(metadata.id)
170         , m_objectStoreId(objectStoreId)
171         , m_indexId(indexId)
172         , m_keyPath(metadata.objectStores.get(objectStoreId).keyPath)
173         , m_autoIncrement(metadata.objectStores.get(objectStoreId).autoIncrement)
174         , m_keyRange(keyRange)
175         , m_cursorType(cursorType)
176         , m_callbacks(callbacks)
177     {
178         ASSERT(metadata.objectStores.get(objectStoreId).id == objectStoreId);
179     }
180
181     const RefPtr<IDBBackingStore> m_backingStore;
182     const int64_t m_databaseId;
183     const int64_t m_objectStoreId;
184     const int64_t m_indexId;
185     const IDBKeyPath m_keyPath;
186     const bool m_autoIncrement;
187     const RefPtr<IDBKeyRange> m_keyRange;
188     const IDBCursorBackendInterface::CursorType m_cursorType;
189     const RefPtr<IDBCallbacks> m_callbacks;
190 };
191
192 class PutOperation : public IDBTransactionBackendImpl::Operation {
193 public:
194     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, const IDBObjectStoreMetadata& objectStore, Vector<uint8_t>& value, PassRefPtr<IDBKey> key, IDBDatabaseBackendInterface::PutMode putMode, PassRefPtr<IDBCallbacks> callbacks, const Vector<int64_t>& indexIds, const Vector<IDBDatabaseBackendInterface::IndexKeys>& indexKeys)
195     {
196         return adoptPtr(new PutOperation(backingStore, databaseId, objectStore, value, key, putMode, callbacks, indexIds, indexKeys));
197     }
198     virtual void perform(IDBTransactionBackendImpl*);
199 private:
200     PutOperation(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, const IDBObjectStoreMetadata& objectStore, Vector<uint8_t>& value, PassRefPtr<IDBKey> key, IDBDatabaseBackendInterface::PutMode putMode, PassRefPtr<IDBCallbacks> callbacks, const Vector<int64_t>& indexIds, const Vector<IDBDatabaseBackendInterface::IndexKeys>& indexKeys)
201         : m_backingStore(backingStore)
202         , m_databaseId(databaseId)
203         , m_objectStore(objectStore)
204         , m_key(key)
205         , m_putMode(putMode)
206         , m_callbacks(callbacks)
207         , m_indexIds(indexIds)
208         , m_indexKeys(indexKeys)
209     {
210         m_value.swap(value);
211     }
212
213     const RefPtr<IDBBackingStore> m_backingStore;
214     const int64_t m_databaseId;
215     const IDBObjectStoreMetadata m_objectStore;
216     Vector<uint8_t> m_value;
217     const RefPtr<IDBKey> m_key;
218     const IDBDatabaseBackendInterface::PutMode m_putMode;
219     const RefPtr<IDBCallbacks> m_callbacks;
220     const Vector<int64_t> m_indexIds;
221     const Vector<IDBDatabaseBackendInterface::IndexKeys> m_indexKeys;
222 };
223
224 class SetIndexesReadyOperation : public IDBTransactionBackendImpl::Operation {
225 public:
226     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(size_t indexCount)
227     {
228         return adoptPtr(new SetIndexesReadyOperation(indexCount));
229     }
230     virtual void perform(IDBTransactionBackendImpl*);
231 private:
232     SetIndexesReadyOperation(size_t indexCount)
233         : m_indexCount(indexCount)
234     {
235     }
236
237     const size_t m_indexCount;
238 };
239
240 class OpenCursorOperation : public IDBTransactionBackendImpl::Operation {
241 public:
242     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, unsigned short direction, IDBCursorBackendInterface::CursorType cursorType, IDBDatabaseBackendInterface::TaskType taskType, PassRefPtr<IDBCallbacks> callbacks)
243     {
244         return adoptPtr(new OpenCursorOperation(backingStore, databaseId, objectStoreId, indexId, keyRange, direction, cursorType, taskType, callbacks));
245     }
246     virtual void perform(IDBTransactionBackendImpl*);
247 private:
248     OpenCursorOperation(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, unsigned short direction, IDBCursorBackendInterface::CursorType cursorType, IDBDatabaseBackendInterface::TaskType taskType, PassRefPtr<IDBCallbacks> callbacks)
249         : m_backingStore(backingStore)
250         , m_databaseId(databaseId)
251         , m_objectStoreId(objectStoreId)
252         , m_indexId(indexId)
253         , m_keyRange(keyRange)
254         , m_direction(direction)
255         , m_cursorType(cursorType)
256         , m_taskType(taskType)
257         , m_callbacks(callbacks)
258     {
259     }
260
261     const RefPtr<IDBBackingStore> m_backingStore;
262     const int64_t m_databaseId;
263     const int64_t m_objectStoreId;
264     const int64_t m_indexId;
265     const PassRefPtr<IDBKeyRange> m_keyRange;
266     const unsigned short m_direction;
267     const IDBCursorBackendInterface::CursorType m_cursorType;
268     const IDBDatabaseBackendInterface::TaskType m_taskType;
269     const RefPtr<IDBCallbacks> m_callbacks;
270 };
271
272 class CountOperation : public IDBTransactionBackendImpl::Operation {
273 public:
274     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
275     {
276         return adoptPtr(new CountOperation(backingStore, databaseId, objectStoreId, indexId, keyRange, callbacks));
277     }
278     virtual void perform(IDBTransactionBackendImpl*);
279 private:
280     CountOperation(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
281         : m_backingStore(backingStore)
282         , m_databaseId(databaseId)
283         , m_objectStoreId(objectStoreId)
284         , m_indexId(indexId)
285         , m_keyRange(keyRange)
286         , m_callbacks(callbacks)
287     {
288     }
289
290     const RefPtr<IDBBackingStore> m_backingStore;
291     const int64_t m_databaseId;
292     const int64_t m_objectStoreId;
293     const int64_t m_indexId;
294     const RefPtr<IDBKeyRange> m_keyRange;
295     const RefPtr<IDBCallbacks> m_callbacks;
296 };
297
298 class DeleteRangeOperation : public IDBTransactionBackendImpl::Operation {
299 public:
300     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
301     {
302         return adoptPtr(new DeleteRangeOperation(backingStore, databaseId, objectStoreId, keyRange, callbacks));
303     }
304     virtual void perform(IDBTransactionBackendImpl*);
305 private:
306     DeleteRangeOperation(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
307         : m_backingStore(backingStore)
308         , m_databaseId(databaseId)
309         , m_objectStoreId(objectStoreId)
310         , m_keyRange(keyRange)
311         , m_callbacks(callbacks)
312     {
313     }
314
315     const RefPtr<IDBBackingStore> m_backingStore;
316     const int64_t m_databaseId;
317     const int64_t m_objectStoreId;
318     const RefPtr<IDBKeyRange> m_keyRange;
319     const RefPtr<IDBCallbacks> m_callbacks;
320 };
321
322 class ClearOperation : public IDBTransactionBackendImpl::Operation {
323 public:
324     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBCallbacks> callbacks)
325     {
326         return adoptPtr(new ClearOperation(backingStore, databaseId, objectStoreId, callbacks));
327     }
328     virtual void perform(IDBTransactionBackendImpl*);
329 private:
330     ClearOperation(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBCallbacks> callbacks)
331         : m_backingStore(backingStore)
332         , m_databaseId(databaseId)
333         , m_objectStoreId(objectStoreId)
334         , m_callbacks(callbacks)
335     {
336     }
337
338     const RefPtr<IDBBackingStore> m_backingStore;
339     const int64_t m_databaseId;
340     const int64_t m_objectStoreId;
341     const RefPtr<IDBCallbacks> m_callbacks;
342 };
343
344 class IDBDatabaseBackendImpl::PendingOpenCall {
345 public:
346     static PassOwnPtr<PendingOpenCall> create(PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks, int64_t transactionId, int64_t version)
347     {
348         return adoptPtr(new PendingOpenCall(callbacks, databaseCallbacks, transactionId, version));
349     }
350     PassRefPtr<IDBCallbacks> callbacks() { return m_callbacks; }
351     PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks() { return m_databaseCallbacks; }
352     int64_t version() { return m_version; }
353     int64_t transactionId() const { return m_transactionId; }
354
355 private:
356     PendingOpenCall(PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks, int64_t transactionId, int64_t version)
357         : m_callbacks(callbacks)
358         , m_databaseCallbacks(databaseCallbacks)
359         , m_version(version)
360         , m_transactionId(transactionId)
361     {
362     }
363     RefPtr<IDBCallbacks> m_callbacks;
364     RefPtr<IDBDatabaseCallbacks> m_databaseCallbacks;
365     int64_t m_version;
366     const int64_t m_transactionId;
367 };
368
369 class IDBDatabaseBackendImpl::PendingDeleteCall {
370 public:
371     static PassOwnPtr<PendingDeleteCall> create(PassRefPtr<IDBCallbacks> callbacks)
372     {
373         return adoptPtr(new PendingDeleteCall(callbacks));
374     }
375     PassRefPtr<IDBCallbacks> callbacks() { return m_callbacks; }
376
377 private:
378     PendingDeleteCall(PassRefPtr<IDBCallbacks> callbacks)
379         : m_callbacks(callbacks)
380     {
381     }
382     RefPtr<IDBCallbacks> m_callbacks;
383 };
384
385 PassRefPtr<IDBDatabaseBackendImpl> IDBDatabaseBackendImpl::create(const String& name, IDBBackingStore* database, IDBFactoryBackendImpl* factory, const String& uniqueIdentifier)
386 {
387     RefPtr<IDBDatabaseBackendImpl> backend = adoptRef(new IDBDatabaseBackendImpl(name, database, factory, uniqueIdentifier));
388     if (!backend->openInternal())
389         return 0;
390     return backend.release();
391 }
392
393 namespace {
394 const char* NoStringVersion = "";
395 }
396
397 IDBDatabaseBackendImpl::IDBDatabaseBackendImpl(const String& name, IDBBackingStore* backingStore, IDBFactoryBackendImpl* factory, const String& uniqueIdentifier)
398     : m_backingStore(backingStore)
399     , m_metadata(name, InvalidId, NoStringVersion, IDBDatabaseMetadata::NoIntVersion, InvalidId)
400     , m_identifier(uniqueIdentifier)
401     , m_factory(factory)
402     , m_transactionCoordinator(IDBTransactionCoordinator::create())
403     , m_closingConnection(false)
404 {
405     ASSERT(!m_metadata.name.isNull());
406 }
407
408 bool IDBDatabaseBackendImpl::openInternal()
409 {
410     bool success = false;
411     bool ok = m_backingStore->getIDBDatabaseMetaData(m_metadata.name, &m_metadata, success);
412     ASSERT_WITH_MESSAGE(success == (m_metadata.id != InvalidId), "success = %s, m_id = %lld", success ? "true" : "false", static_cast<long long>(m_metadata.id));
413     if (!ok)
414         return false;
415     if (success) {
416         loadObjectStores();
417         return true;
418     }
419     return m_backingStore->createIDBDatabaseMetaData(m_metadata.name, m_metadata.version, m_metadata.intVersion, m_metadata.id);
420 }
421
422 IDBDatabaseBackendImpl::~IDBDatabaseBackendImpl()
423 {
424 }
425
426 PassRefPtr<IDBBackingStore> IDBDatabaseBackendImpl::backingStore() const
427 {
428     return m_backingStore;
429 }
430
431 IDBDatabaseMetadata IDBDatabaseBackendImpl::metadata() const
432 {
433     // FIXME: Figure out a way to keep m_metadata.objectStores.get(N).indexes up to date rather than regenerating this every time.
434     IDBDatabaseMetadata metadata(m_metadata);
435     for (ObjectStoreMap::const_iterator it = m_objectStores.begin(); it != m_objectStores.end(); ++it)
436         metadata.objectStores.set(it->value->id(), it->value->metadata());
437     return metadata;
438 }
439
440 PassRefPtr<IDBObjectStoreBackendInterface> IDBDatabaseBackendImpl::createObjectStore(int64_t id, const String& name, const IDBKeyPath& keyPath, bool autoIncrement, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
441 {
442     ASSERT(!m_objectStores.contains(id));
443
444     RefPtr<IDBObjectStoreBackendImpl> objectStore = IDBObjectStoreBackendImpl::create(this, IDBObjectStoreMetadata(name, id, keyPath, autoIncrement, IDBObjectStoreBackendInterface::MinimumIndexId));
445     ASSERT(objectStore->name() == name);
446
447     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
448     ASSERT(transaction->mode() == IDBTransaction::VERSION_CHANGE);
449
450     // FIXME: Fix edge cases around transaction aborts that prevent this from just being ASSERT(id == m_metadata.maxObjectStoreId + 1)
451     ASSERT(id > m_metadata.maxObjectStoreId);
452     m_metadata.maxObjectStoreId = id;
453
454     if (!transaction->scheduleTask(CreateObjectStoreOperation::create(this, objectStore), CreateObjectStoreAbortOperation::create(this, objectStore))) {
455         ec = IDBDatabaseException::TransactionInactiveError;
456         return 0;
457     }
458
459     m_objectStores.set(id, objectStore);
460     return objectStore.release();
461 }
462
463 void IDBDatabaseBackendImpl::CreateObjectStoreOperation::perform(IDBTransactionBackendImpl* transaction)
464 {
465     IDB_TRACE("CreateObjectStoreOperation");
466     if (!m_database->m_backingStore->createObjectStore(transaction->backingStoreTransaction(), m_database->id(), m_objectStore->id(), m_objectStore->name(), m_objectStore->keyPath(), m_objectStore->autoIncrement())) {
467         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error creating object store '%s'.", m_objectStore->name().utf8().data()));
468         transaction->abort(error.release());
469         return;
470     }
471 }
472
473 PassRefPtr<IDBObjectStoreBackendImpl> IDBDatabaseBackendImpl::objectStore(int64_t id)
474 {
475     return m_objectStores.get(id);
476 }
477
478 void IDBDatabaseBackendImpl::deleteObjectStore(int64_t id, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
479 {
480     ASSERT(m_objectStores.contains(id));
481
482     RefPtr<IDBObjectStoreBackendImpl> objectStore = m_objectStores.get(id);
483     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
484     ASSERT(transaction->mode() == IDBTransaction::VERSION_CHANGE);
485
486     if (!transaction->scheduleTask(DeleteObjectStoreOperation::create(this, objectStore), DeleteObjectStoreAbortOperation::create(this, objectStore))) {
487         ec = IDBDatabaseException::TransactionInactiveError;
488         return;
489     }
490     m_objectStores.remove(id);
491 }
492
493 void IDBDatabaseBackendImpl::commit(int64_t transactionId)
494 {
495     ASSERT(m_transactions.contains(transactionId));
496     m_transactions.get(transactionId)->commit();
497 }
498
499 void IDBDatabaseBackendImpl::abort(int64_t transactionId)
500 {
501     ASSERT(m_transactions.contains(transactionId));
502     m_transactions.get(transactionId)->abort();
503 }
504
505 void IDBDatabaseBackendImpl::get(int64_t transactionId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, bool keyOnly, PassRefPtr<IDBCallbacks> callbacks)
506 {
507     IDB_TRACE("IDBDatabaseBackendImpl::get");
508     ASSERT(m_transactions.contains(transactionId));
509     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
510
511     transaction->scheduleTask(GetOperation::create(m_backingStore, metadata(), objectStoreId, indexId, keyRange, keyOnly ? IDBCursorBackendInterface::KeyOnly : IDBCursorBackendInterface::KeyAndValue, callbacks));
512 }
513
514 void GetOperation::perform(IDBTransactionBackendImpl* transaction)
515 {
516     IDB_TRACE("GetOperation");
517
518     RefPtr<IDBKey> key;
519
520     if (m_keyRange->isOnlyKey())
521         key = m_keyRange->lower();
522     else {
523         RefPtr<IDBBackingStore::Cursor> backingStoreCursor;
524         if (m_indexId == IDBIndexMetadata::InvalidId) {
525             ASSERT(m_cursorType != IDBCursorBackendInterface::KeyOnly);
526             // ObjectStore Retrieval Operation
527             backingStoreCursor = m_backingStore->openObjectStoreCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), IDBCursor::NEXT);
528         } else {
529             if (m_cursorType == IDBCursorBackendInterface::KeyOnly)
530                 // Index Value Retrieval Operation
531                 backingStoreCursor = m_backingStore->openIndexKeyCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), IDBCursor::NEXT);
532             else
533                 // Index Referenced Value Retrieval Operation
534                 backingStoreCursor = m_backingStore->openIndexCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), IDBCursor::NEXT);
535         }
536
537         if (!backingStoreCursor) {
538             m_callbacks->onSuccess();
539             return;
540         }
541
542         key = backingStoreCursor->key();
543     }
544
545     RefPtr<IDBKey> primaryKey;
546     bool ok;
547     if (m_indexId == IDBIndexMetadata::InvalidId) {
548         // Object Store Retrieval Operation
549         Vector<uint8_t> value;
550         ok = m_backingStore->getRecord(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, *key, value);
551         if (!ok) {
552             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getRecord."));
553             return;
554         }
555
556         if (value.isEmpty()) {
557             m_callbacks->onSuccess();
558             return;
559         }
560
561         if (m_autoIncrement && !m_keyPath.isNull()) {
562             m_callbacks->onSuccess(SerializedScriptValue::createFromWireBytes(value), key, m_keyPath);
563             return;
564         }
565
566         m_callbacks->onSuccess(SerializedScriptValue::createFromWireBytes(value));
567         return;
568
569     }
570
571     // From here we are dealing only with indexes.
572     ok = m_backingStore->getPrimaryKeyViaIndex(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, *key, primaryKey);
573     if (!ok) {
574         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getPrimaryKeyViaIndex."));
575         return;
576     }
577     if (m_cursorType == IDBCursorBackendInterface::KeyOnly) {
578         // Index Value Retrieval Operation
579         m_callbacks->onSuccess(primaryKey.get());
580         return;
581     }
582
583     // Index Referenced Value Retrieval Operation
584     Vector<uint8_t> value;
585     ok = m_backingStore->getRecord(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, *primaryKey, value);
586     if (!ok) {
587         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getRecord."));
588         return;
589     }
590
591     if (value.isEmpty()) {
592         m_callbacks->onSuccess();
593         return;
594     }
595     if (m_autoIncrement && !m_keyPath.isNull()) {
596         m_callbacks->onSuccess(SerializedScriptValue::createFromWireBytes(value), primaryKey, m_keyPath);
597         return;
598     }
599     m_callbacks->onSuccess(SerializedScriptValue::createFromWireBytes(value));
600 }
601
602 void IDBDatabaseBackendImpl::put(int64_t transactionId, int64_t objectStoreId, Vector<uint8_t>* value, PassRefPtr<IDBKey> key, PutMode putMode, PassRefPtr<IDBCallbacks> callbacks, const Vector<int64_t>& indexIds, const Vector<IndexKeys>& indexKeys)
603 {
604     IDB_TRACE("IDBDatabaseBackendImpl::put");
605
606     ASSERT(m_transactions.contains(transactionId));
607     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
608     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
609
610     const IDBObjectStoreMetadata objectStoreMetadata = metadata().objectStores.get(objectStoreId);
611
612     ASSERT(objectStoreMetadata.autoIncrement || key.get());
613
614     transaction->scheduleTask(PutOperation::create(m_backingStore, id(), objectStoreMetadata, *value, key, putMode, callbacks, indexIds, indexKeys));
615 }
616
617 void PutOperation::perform(IDBTransactionBackendImpl* transaction)
618 {
619     IDB_TRACE("PutOperation");
620     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
621     ASSERT(m_indexIds.size() == m_indexKeys.size());
622     bool keyWasGenerated = false;
623
624     RefPtr<IDBKey> key;
625     if (m_putMode != IDBDatabaseBackendInterface::CursorUpdate && m_objectStore.autoIncrement && !m_key) {
626         RefPtr<IDBKey> autoIncKey = IDBObjectStoreBackendImpl::generateKey(m_backingStore, transaction, m_databaseId, m_objectStore.id);
627         keyWasGenerated = true;
628         if (!autoIncKey->isValid()) {
629             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, "Maximum key generator value reached."));
630             return;
631         }
632         key = autoIncKey;
633     } else
634         key = m_key;
635
636     ASSERT(key && key->isValid());
637
638     IDBBackingStore::RecordIdentifier recordIdentifier;
639     if (m_putMode == IDBDatabaseBackendInterface::AddOnly) {
640         bool found = false;
641         bool ok = m_backingStore->keyExistsInObjectStore(transaction->backingStoreTransaction(), m_databaseId, m_objectStore.id, *key, &recordIdentifier, found);
642         if (!ok) {
643             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error checking key existence."));
644             return;
645         }
646         if (found) {
647             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, "Key already exists in the object store."));
648             return;
649         }
650     }
651
652     Vector<OwnPtr<IDBObjectStoreBackendImpl::IndexWriter> > indexWriters;
653     String errorMessage;
654     bool obeysConstraints = false;
655     bool backingStoreSuccess = IDBObjectStoreBackendImpl::makeIndexWriters(transaction, m_backingStore.get(), m_databaseId, m_objectStore, key, keyWasGenerated, m_indexIds, m_indexKeys, &indexWriters, &errorMessage, obeysConstraints);
656     if (!backingStoreSuccess) {
657         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error updating index keys."));
658         return;
659     }
660     if (!obeysConstraints) {
661         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, errorMessage));
662         return;
663     }
664
665     // Before this point, don't do any mutation. After this point, rollback the transaction in case of error.
666     backingStoreSuccess = m_backingStore->putRecord(transaction->backingStoreTransaction(), m_databaseId, m_objectStore.id, *key, m_value, &recordIdentifier);
667     if (!backingStoreSuccess) {
668         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error performing put/add."));
669         return;
670     }
671
672     for (size_t i = 0; i < indexWriters.size(); ++i) {
673         IDBObjectStoreBackendImpl::IndexWriter* indexWriter = indexWriters[i].get();
674         indexWriter->writeIndexKeys(recordIdentifier, *m_backingStore, transaction->backingStoreTransaction(), m_databaseId, m_objectStore.id);
675     }
676
677     if (m_objectStore.autoIncrement && m_putMode != IDBDatabaseBackendInterface::CursorUpdate && key->type() == IDBKey::NumberType) {
678         bool ok = IDBObjectStoreBackendImpl::updateKeyGenerator(m_backingStore, transaction, m_databaseId, m_objectStore.id, key.get(), !keyWasGenerated);
679         if (!ok) {
680             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error updating key generator."));
681             return;
682         }
683     }
684
685     m_callbacks->onSuccess(key.release());
686 }
687
688
689 void IDBDatabaseBackendImpl::setIndexKeys(int64_t transactionId, int64_t objectStoreId, PassRefPtr<IDBKey> prpPrimaryKey, const Vector<int64_t>& indexIds, const Vector<IndexKeys>& indexKeys)
690 {
691     IDB_TRACE("IDBDatabaseBackendImpl::setIndexKeys");
692     if (!m_transactions.contains(transactionId))
693         return;
694
695     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
696     if (transaction->isFinished())
697         return;
698
699     RefPtr<IDBKey> primaryKey = prpPrimaryKey;
700     RefPtr<IDBBackingStore> store = backingStore();
701     // FIXME: This method could be asynchronous, but we need to evaluate if it's worth the extra complexity.
702     IDBBackingStore::RecordIdentifier recordIdentifier;
703     bool found = false;
704     bool ok = store->keyExistsInObjectStore(transaction->backingStoreTransaction(), m_metadata.id, objectStoreId, *primaryKey, &recordIdentifier, found);
705     if (!ok) {
706         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error setting index keys."));
707         return;
708     }
709     if (!found) {
710         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error setting index keys for object store."));
711         transaction->abort(error.release());
712         return;
713     }
714
715     Vector<OwnPtr<IDBObjectStoreBackendImpl::IndexWriter> > indexWriters;
716     String errorMessage;
717     bool obeysConstraints = false;
718     ASSERT(metadata().objectStores.contains(objectStoreId));
719     const IDBObjectStoreMetadata& objectStoreMetadata = metadata().objectStores.get(objectStoreId);
720     bool backingStoreSuccess = IDBObjectStoreBackendImpl::makeIndexWriters(transaction, store.get(), id(), objectStoreMetadata, primaryKey, false, indexIds, indexKeys, &indexWriters, &errorMessage, obeysConstraints);
721     if (!backingStoreSuccess) {
722         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error updating index keys."));
723         return;
724     }
725     if (!obeysConstraints) {
726         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, errorMessage));
727         return;
728     }
729
730     for (size_t i = 0; i < indexWriters.size(); ++i) {
731         IDBObjectStoreBackendImpl::IndexWriter* indexWriter = indexWriters[i].get();
732         indexWriter->writeIndexKeys(recordIdentifier, *store.get(), transaction->backingStoreTransaction(), id(), objectStoreId);
733     }
734 }
735
736 void IDBDatabaseBackendImpl::setIndexesReady(int64_t transactionId, int64_t objectStoreId, const Vector<int64_t>& indexIds)
737 {
738     IDB_TRACE("IDBObjectStoreBackendImpl::setIndexesReady");
739
740     if (!m_transactions.contains(transactionId))
741         return;
742
743     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
744     if (transaction->isFinished())
745         return;
746
747     if (!transaction->scheduleTask(IDBTransactionBackendInterface::PreemptiveTask, SetIndexesReadyOperation::create(indexIds.size())))
748         ASSERT_NOT_REACHED();
749 }
750
751 void SetIndexesReadyOperation::perform(IDBTransactionBackendImpl* transaction)
752 {
753     IDB_TRACE("SetIndexesReadyOperation");
754     for (size_t i = 0; i < m_indexCount; ++i)
755         transaction->didCompletePreemptiveEvent();
756 }
757
758 void IDBDatabaseBackendImpl::openCursor(int64_t transactionId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, unsigned short direction, bool keyOnly, TaskType taskType, PassRefPtr<IDBCallbacks> callbacks)
759 {
760     IDB_TRACE("IDBDatabaseBackendImpl::openCursor");
761     ASSERT(m_transactions.contains(transactionId));
762     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
763
764     transaction->scheduleTask(OpenCursorOperation::create(m_backingStore, id(), objectStoreId, indexId, keyRange, direction, keyOnly ? IDBCursorBackendInterface::KeyOnly : IDBCursorBackendInterface::KeyAndValue, taskType, callbacks));
765 }
766
767 void OpenCursorOperation::perform(IDBTransactionBackendImpl* transaction)
768 {
769     IDB_TRACE("OpenCursorOperation");
770
771     // The frontend has begun indexing, so this pauses the transaction
772     // until the indexing is complete. This can't happen any earlier
773     // because we don't want to switch to early mode in case multiple
774     // indexes are being created in a row, with put()'s in between.
775     if (m_taskType == IDBDatabaseBackendInterface::PreemptiveTask)
776         transaction->addPreemptiveEvent();
777
778     IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(m_direction);
779     RefPtr<IDBBackingStore::Cursor> backingStoreCursor;
780     if (m_indexId == IDBIndexMetadata::InvalidId) {
781         ASSERT(m_cursorType != IDBCursorBackendInterface::KeyOnly);
782         backingStoreCursor = m_backingStore->openObjectStoreCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), direction);
783     } else {
784         ASSERT(m_taskType == IDBDatabaseBackendInterface::NormalTask);
785         if (m_cursorType == IDBCursorBackendInterface::KeyOnly)
786             backingStoreCursor = m_backingStore->openIndexKeyCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), direction);
787         else
788             backingStoreCursor = m_backingStore->openIndexCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), direction);
789     }
790
791     if (!backingStoreCursor) {
792         m_callbacks->onSuccess(static_cast<SerializedScriptValue*>(0));
793         return;
794     }
795
796     IDBTransactionBackendInterface::TaskType taskType(static_cast<IDBTransactionBackendInterface::TaskType>(m_taskType));
797     RefPtr<IDBCursorBackendImpl> cursor = IDBCursorBackendImpl::create(backingStoreCursor.get(), m_cursorType, taskType, transaction, m_objectStoreId);
798     m_callbacks->onSuccess(cursor, cursor->key(), cursor->primaryKey(), cursor->value());
799 }
800
801 void IDBDatabaseBackendImpl::count(int64_t transactionId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
802 {
803     IDB_TRACE("IDBDatabaseBackendImpl::count");
804     ASSERT(m_transactions.contains(transactionId));
805     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
806     ASSERT(metadata().objectStores.contains(objectStoreId));
807     transaction->scheduleTask(CountOperation::create(m_backingStore, id(), objectStoreId, indexId, keyRange, callbacks));
808 }
809
810 void CountOperation::perform(IDBTransactionBackendImpl* transaction)
811 {
812     IDB_TRACE("CountOperation");
813     uint32_t count = 0;
814     RefPtr<IDBBackingStore::Cursor> backingStoreCursor;
815
816     if (m_indexId == IDBIndexMetadata::InvalidId)
817         backingStoreCursor = m_backingStore->openObjectStoreKeyCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), IDBCursor::NEXT);
818     else
819         backingStoreCursor = m_backingStore->openIndexKeyCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), IDBCursor::NEXT);
820     if (!backingStoreCursor) {
821         m_callbacks->onSuccess(count);
822         return;
823     }
824
825     do {
826         ++count;
827     } while (backingStoreCursor->continueFunction(0));
828
829     m_callbacks->onSuccess(count);
830 }
831
832 void IDBDatabaseBackendImpl::deleteRange(int64_t transactionId, int64_t objectStoreId, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
833 {
834     IDB_TRACE("IDBDatabaseBackendImpl::deleteRange");
835
836     ASSERT(m_transactions.contains(transactionId));
837     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
838     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
839
840     transaction->scheduleTask(DeleteRangeOperation::create(m_backingStore, id(), objectStoreId, keyRange, callbacks));
841 }
842
843 void DeleteRangeOperation::perform(IDBTransactionBackendImpl* transaction)
844 {
845     IDB_TRACE("DeleteRangeOperation");
846
847     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = m_backingStore->openObjectStoreCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), IDBCursor::NEXT);
848     if (backingStoreCursor) {
849         do {
850             m_backingStore->deleteRecord(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, backingStoreCursor->recordIdentifier());
851         } while (backingStoreCursor->continueFunction(0));
852     }
853
854     m_callbacks->onSuccess();
855 }
856
857 void IDBDatabaseBackendImpl::clear(int64_t transactionId, int64_t objectStoreId, PassRefPtr<IDBCallbacks> callbacks)
858 {
859     IDB_TRACE("IDBDatabaseBackendImpl::clear");
860
861     ASSERT(m_transactions.contains(transactionId));
862     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
863     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
864
865     transaction->scheduleTask(ClearOperation::create(m_backingStore, id(), objectStoreId, callbacks));
866 }
867
868 void ClearOperation::perform(IDBTransactionBackendImpl* transaction)
869 {
870     IDB_TRACE("ObjectStoreClearOperation");
871     m_backingStore->clearObjectStore(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId);
872     m_callbacks->onSuccess();
873 }
874
875 void IDBDatabaseBackendImpl::DeleteObjectStoreOperation::perform(IDBTransactionBackendImpl* transaction)
876 {
877     IDB_TRACE("DeleteObjectStoreOperation");
878     bool ok = m_database->m_backingStore->deleteObjectStore(transaction->backingStoreTransaction(), m_database->id(), m_objectStore->id());
879     if (!ok) {
880         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error deleting object store '%s'.", m_objectStore->name().utf8().data()));
881         transaction->abort(error);
882     }
883 }
884
885 void IDBDatabaseBackendImpl::VersionChangeOperation::perform(IDBTransactionBackendImpl* transaction)
886 {
887     IDB_TRACE("VersionChangeOperation");
888     int64_t databaseId = m_database->id();
889     int64_t oldVersion = m_database->m_metadata.intVersion;
890     ASSERT(m_version > oldVersion);
891     m_database->m_metadata.intVersion = m_version;
892     if (!m_database->m_backingStore->updateIDBDatabaseIntVersion(transaction->backingStoreTransaction(), databaseId, m_database->m_metadata.intVersion)) {
893         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Error writing data to stable storage when updating version.");
894         m_callbacks->onError(error);
895         transaction->abort(error);
896         return;
897     }
898     ASSERT(!m_database->m_pendingSecondHalfOpen);
899     m_database->m_pendingSecondHalfOpen = PendingOpenCall::create(m_callbacks, m_databaseCallbacks, m_transactionId, m_version);
900     m_callbacks->onUpgradeNeeded(oldVersion, transaction, m_database);
901 }
902
903 void IDBDatabaseBackendImpl::transactionStarted(PassRefPtr<IDBTransactionBackendImpl> prpTransaction)
904 {
905     RefPtr<IDBTransactionBackendImpl> transaction = prpTransaction;
906     if (transaction->mode() == IDBTransaction::VERSION_CHANGE) {
907         ASSERT(!m_runningVersionChangeTransaction);
908         m_runningVersionChangeTransaction = transaction;
909     }
910 }
911
912 void IDBDatabaseBackendImpl::transactionFinished(PassRefPtr<IDBTransactionBackendImpl> prpTransaction)
913 {
914     RefPtr<IDBTransactionBackendImpl> transaction = prpTransaction;
915     ASSERT(m_transactions.contains(transaction->id()));
916     ASSERT(m_transactions.get(transaction->id()) == transaction.get());
917     m_transactions.remove(transaction->id());
918     if (transaction->mode() == IDBTransaction::VERSION_CHANGE) {
919         ASSERT(transaction.get() == m_runningVersionChangeTransaction.get());
920         m_runningVersionChangeTransaction.clear();
921     }
922 }
923
924 void IDBDatabaseBackendImpl::transactionFinishedAndAbortFired(PassRefPtr<IDBTransactionBackendImpl> prpTransaction)
925 {
926     RefPtr<IDBTransactionBackendImpl> transaction = prpTransaction;
927     if (transaction->mode() == IDBTransaction::VERSION_CHANGE) {
928         // If this was an open-with-version call, there will be a "second
929         // half" open call waiting for us in processPendingCalls.
930         // FIXME: When we no longer support setVersion, assert such a thing.
931         if (m_pendingSecondHalfOpen) {
932             m_pendingSecondHalfOpen->callbacks()->onError(IDBDatabaseError::create(IDBDatabaseException::AbortError, "Version change transaction was aborted in upgradeneeded event handler."));
933             m_pendingSecondHalfOpen.release();
934         }
935         processPendingCalls();
936     }
937 }
938
939 void IDBDatabaseBackendImpl::transactionFinishedAndCompleteFired(PassRefPtr<IDBTransactionBackendImpl> prpTransaction)
940 {
941     RefPtr<IDBTransactionBackendImpl> transaction = prpTransaction;
942     if (transaction->mode() == IDBTransaction::VERSION_CHANGE)
943         processPendingCalls();
944 }
945
946 size_t IDBDatabaseBackendImpl::connectionCount()
947 {
948     // This does not include pending open calls, as those should not block version changes and deletes.
949     return m_databaseCallbacksSet.size();
950 }
951
952 void IDBDatabaseBackendImpl::processPendingCalls()
953 {
954     if (m_pendingSecondHalfOpen) {
955         ASSERT(m_pendingSecondHalfOpen->version() == m_metadata.intVersion);
956         ASSERT(m_metadata.id != InvalidId);
957         m_pendingSecondHalfOpen->callbacks()->onSuccess(this);
958         m_pendingSecondHalfOpen.release();
959         // Fall through when complete, as pending deletes may be (partially) unblocked.
960     }
961
962     // Note that this check is only an optimization to reduce queue-churn and
963     // not necessary for correctness; deleteDatabase and openConnection will
964     // requeue their calls if this condition is true.
965     if (m_runningVersionChangeTransaction)
966         return;
967
968     if (!m_pendingDeleteCalls.isEmpty() && isDeleteDatabaseBlocked())
969         return;
970     while (!m_pendingDeleteCalls.isEmpty()) {
971         OwnPtr<PendingDeleteCall> pendingDeleteCall = m_pendingDeleteCalls.takeFirst();
972         deleteDatabaseFinal(pendingDeleteCall->callbacks());
973     }
974     // deleteDatabaseFinal should never re-queue calls.
975     ASSERT(m_pendingDeleteCalls.isEmpty());
976
977     // This check is also not really needed, openConnection would just requeue its calls.
978     if (m_runningVersionChangeTransaction)
979         return;
980
981     // Open calls can be requeued if an open call started a version change transaction.
982     Deque<OwnPtr<PendingOpenCall> > pendingOpenCalls;
983     m_pendingOpenCalls.swap(pendingOpenCalls);
984     while (!pendingOpenCalls.isEmpty()) {
985         OwnPtr<PendingOpenCall> pendingOpenCall = pendingOpenCalls.takeFirst();
986         openConnection(pendingOpenCall->callbacks(), pendingOpenCall->databaseCallbacks(), pendingOpenCall->transactionId(), pendingOpenCall->version());
987     }
988 }
989
990 // FIXME: Remove this method in https://bugs.webkit.org/show_bug.cgi?id=103923.
991 PassRefPtr<IDBTransactionBackendInterface> IDBDatabaseBackendImpl::createTransaction(int64_t transactionId, const Vector<int64_t>& objectStoreIds, IDBTransaction::Mode mode)
992 {
993     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::create(transactionId, objectStoreIds, mode, this);
994     ASSERT(!m_transactions.contains(transactionId));
995     m_transactions.add(transactionId, transaction.get());
996     return transaction.release();
997 }
998
999 void IDBDatabaseBackendImpl::createTransaction(int64_t transactionId, PassRefPtr<IDBDatabaseCallbacks> callbacks, const Vector<int64_t>& objectStoreIds, unsigned short mode)
1000 {
1001     ASSERT_NOT_REACHED();
1002 }
1003
1004 void IDBDatabaseBackendImpl::openConnection(PassRefPtr<IDBCallbacks> prpCallbacks, PassRefPtr<IDBDatabaseCallbacks> prpDatabaseCallbacks, int64_t transactionId, int64_t version)
1005 {
1006     ASSERT(m_backingStore.get());
1007     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
1008     RefPtr<IDBDatabaseCallbacks> databaseCallbacks = prpDatabaseCallbacks;
1009
1010     if (!m_pendingDeleteCalls.isEmpty() || m_runningVersionChangeTransaction) {
1011         m_pendingOpenCalls.append(PendingOpenCall::create(callbacks, databaseCallbacks, transactionId, version));
1012         return;
1013     }
1014
1015     if (m_metadata.id == InvalidId) {
1016         // The database was deleted then immediately re-opened; openInternal() recreates it in the backing store.
1017         if (openInternal())
1018             ASSERT(m_metadata.intVersion == IDBDatabaseMetadata::NoIntVersion);
1019         else {
1020             String message;
1021             RefPtr<IDBDatabaseError> error;
1022             if (version == IDBDatabaseMetadata::NoIntVersion)
1023                 message = "Internal error opening database with no version specified.";
1024             else
1025                 message = String::format("Internal error opening database with version %lld", static_cast<long long>(version));
1026             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, message));
1027             return;
1028         }
1029     }
1030
1031     // We infer that the database didn't exist from its lack of either type of version.
1032     bool isNewDatabase = m_metadata.version == NoStringVersion && m_metadata.intVersion == IDBDatabaseMetadata::NoIntVersion;
1033
1034     if (version == IDBDatabaseMetadata::DefaultIntVersion) {
1035         // For unit tests only - skip upgrade steps. Calling from script with DefaultIntVersion throws exception.
1036         ASSERT(isNewDatabase);
1037         m_databaseCallbacksSet.add(databaseCallbacks);
1038         callbacks->onSuccess(this);
1039         return;
1040     }
1041
1042     if (version == IDBDatabaseMetadata::NoIntVersion) {
1043         if (!isNewDatabase) {
1044             m_databaseCallbacksSet.add(RefPtr<IDBDatabaseCallbacks>(databaseCallbacks));
1045             callbacks->onSuccess(this);
1046             return;
1047         }
1048         // Spec says: If no version is specified and no database exists, set database version to 1.
1049         version = 1;
1050     }
1051
1052     if (version > m_metadata.intVersion) {
1053         runIntVersionChangeTransaction(callbacks, databaseCallbacks, transactionId, version);
1054         return;
1055     }
1056     if (version < m_metadata.intVersion) {
1057         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::VersionError, String::format("The requested version (%lld) is less than the existing version (%lld).", static_cast<long long>(version), static_cast<long long>(m_metadata.intVersion))));
1058         return;
1059     }
1060     ASSERT(version == m_metadata.intVersion);
1061     m_databaseCallbacksSet.add(databaseCallbacks);
1062     callbacks->onSuccess(this);
1063 }
1064
1065 void IDBDatabaseBackendImpl::runIntVersionChangeTransaction(PassRefPtr<IDBCallbacks> prpCallbacks, PassRefPtr<IDBDatabaseCallbacks> prpDatabaseCallbacks, int64_t transactionId, int64_t requestedVersion)
1066 {
1067     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
1068     RefPtr<IDBDatabaseCallbacks> databaseCallbacks = prpDatabaseCallbacks;
1069     ASSERT(callbacks);
1070     for (DatabaseCallbacksSet::const_iterator it = m_databaseCallbacksSet.begin(); it != m_databaseCallbacksSet.end(); ++it) {
1071         // Front end ensures the event is not fired at connections that have closePending set.
1072         if (*it != databaseCallbacks)
1073             (*it)->onVersionChange(m_metadata.intVersion, requestedVersion);
1074     }
1075     // The spec dictates we wait until all the version change events are
1076     // delivered and then check m_databaseCallbacks.empty() before proceeding
1077     // or firing a blocked event, but instead we should be consistent with how
1078     // the old setVersion (incorrectly) did it.
1079     // FIXME: Remove the call to onBlocked and instead wait until the frontend
1080     // tells us that all the blocked events have been delivered. See
1081     // https://bugs.webkit.org/show_bug.cgi?id=71130
1082     if (connectionCount())
1083         callbacks->onBlocked(m_metadata.intVersion);
1084     // FIXME: Add test for m_runningVersionChangeTransaction.
1085     if (m_runningVersionChangeTransaction || connectionCount()) {
1086         m_pendingOpenCalls.append(PendingOpenCall::create(callbacks, databaseCallbacks, transactionId, requestedVersion));
1087         return;
1088     }
1089
1090     Vector<int64_t> objectStoreIds;
1091     RefPtr<IDBTransactionBackendInterface> transactionInterface = createTransaction(transactionId, objectStoreIds, IDBTransaction::VERSION_CHANGE);
1092     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionInterface.get());
1093
1094     if (!transaction->scheduleTask(VersionChangeOperation::create(this, transactionId, requestedVersion, callbacks, databaseCallbacks), VersionChangeAbortOperation::create(this, m_metadata.version, m_metadata.intVersion))) {
1095         ASSERT_NOT_REACHED();
1096     }
1097     ASSERT(!m_pendingSecondHalfOpen);
1098     m_databaseCallbacksSet.add(databaseCallbacks);
1099 }
1100
1101 void IDBDatabaseBackendImpl::deleteDatabase(PassRefPtr<IDBCallbacks> prpCallbacks)
1102 {
1103     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
1104     if (isDeleteDatabaseBlocked()) {
1105         for (DatabaseCallbacksSet::const_iterator it = m_databaseCallbacksSet.begin(); it != m_databaseCallbacksSet.end(); ++it) {
1106             // Front end ensures the event is not fired at connections that have closePending set.
1107             (*it)->onVersionChange(NoStringVersion);
1108         }
1109         // FIXME: Only fire onBlocked if there are open connections after the
1110         // VersionChangeEvents are received, not just set up to fire.
1111         // https://bugs.webkit.org/show_bug.cgi?id=71130
1112         callbacks->onBlocked();
1113         m_pendingDeleteCalls.append(PendingDeleteCall::create(callbacks.release()));
1114         return;
1115     }
1116     deleteDatabaseFinal(callbacks.release());
1117 }
1118
1119 bool IDBDatabaseBackendImpl::isDeleteDatabaseBlocked()
1120 {
1121     return connectionCount();
1122 }
1123
1124 void IDBDatabaseBackendImpl::deleteDatabaseFinal(PassRefPtr<IDBCallbacks> callbacks)
1125 {
1126     ASSERT(!isDeleteDatabaseBlocked());
1127     ASSERT(m_backingStore);
1128     if (!m_backingStore->deleteDatabase(m_metadata.name)) {
1129         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error deleting database."));
1130         return;
1131     }
1132     m_metadata.version = NoStringVersion;
1133     m_metadata.id = InvalidId;
1134     m_metadata.intVersion = IDBDatabaseMetadata::NoIntVersion;
1135     m_objectStores.clear();
1136     callbacks->onSuccess();
1137 }
1138
1139 void IDBDatabaseBackendImpl::close(PassRefPtr<IDBDatabaseCallbacks> prpCallbacks)
1140 {
1141     RefPtr<IDBDatabaseCallbacks> callbacks = prpCallbacks;
1142     ASSERT(m_databaseCallbacksSet.contains(callbacks));
1143
1144     m_databaseCallbacksSet.remove(callbacks);
1145     if (m_pendingSecondHalfOpen && m_pendingSecondHalfOpen->databaseCallbacks() == callbacks) {
1146         m_pendingSecondHalfOpen->callbacks()->onError(IDBDatabaseError::create(IDBDatabaseException::AbortError, "The connection was closed."));
1147         m_pendingSecondHalfOpen.release();
1148     }
1149
1150     if (connectionCount() > 1)
1151         return;
1152
1153     // processPendingCalls allows the inspector to process a pending open call
1154     // and call close, reentering IDBDatabaseBackendImpl::close. Then the
1155     // backend would be removed both by the inspector closing its connection, and
1156     // by the connection that first called close.
1157     // To avoid that situation, don't proceed in case of reentrancy.
1158     if (m_closingConnection)
1159         return;
1160     m_closingConnection = true;
1161     processPendingCalls();
1162
1163     // FIXME: Add a test for the m_pendingOpenCalls cases below.
1164     if (!connectionCount() && !m_pendingOpenCalls.size() && !m_pendingDeleteCalls.size()) {
1165         TransactionMap transactions(m_transactions);
1166         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Connection is closing.");
1167         for (TransactionMap::const_iterator::Values it = transactions.values().begin(), end = transactions.values().end(); it != end; ++it)
1168             (*it)->abort(error);
1169
1170         ASSERT(m_transactions.isEmpty());
1171
1172         m_backingStore.clear();
1173         // This check should only be false in tests.
1174         if (m_factory)
1175             m_factory->removeIDBDatabaseBackend(m_identifier);
1176     }
1177     m_closingConnection = false;
1178 }
1179
1180 void IDBDatabaseBackendImpl::loadObjectStores()
1181 {
1182     Vector<int64_t> ids;
1183     Vector<String> names;
1184     Vector<IDBKeyPath> keyPaths;
1185     Vector<bool> autoIncrementFlags;
1186     Vector<int64_t> maxIndexIds;
1187     Vector<IDBObjectStoreMetadata> objectStores = m_backingStore->getObjectStores(m_metadata.id);
1188
1189     for (size_t i = 0; i < objectStores.size(); i++)
1190         m_objectStores.set(objectStores[i].id, IDBObjectStoreBackendImpl::create(this, objectStores[i]));
1191 }
1192
1193 void IDBDatabaseBackendImpl::CreateObjectStoreAbortOperation::perform(IDBTransactionBackendImpl* transaction)
1194 {
1195     ASSERT(!transaction);
1196     ASSERT(m_database->m_objectStores.contains(m_objectStore->id()));
1197     m_database->m_objectStores.remove(m_objectStore->id());
1198 }
1199
1200 void IDBDatabaseBackendImpl::DeleteObjectStoreAbortOperation::perform(IDBTransactionBackendImpl* transaction)
1201 {
1202     ASSERT(!transaction);
1203     ASSERT(!m_database->m_objectStores.contains(m_objectStore->id()));
1204     m_database->m_objectStores.set(m_objectStore->id(), m_objectStore);
1205 }
1206
1207 void IDBDatabaseBackendImpl::VersionChangeAbortOperation::perform(IDBTransactionBackendImpl* transaction)
1208 {
1209     ASSERT(!transaction);
1210     m_database->m_metadata.version = m_previousVersion;
1211     m_database->m_metadata.intVersion = m_previousIntVersion;
1212 }
1213
1214 } // namespace WebCore
1215
1216 #endif // ENABLE(INDEXED_DATABASE)