Make IDBDatabaseBackendLevelDB.cpp be cross platform
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / leveldb / IDBTransactionBackendLevelDBOperations.cpp
1 /*
2  * Copyright (C) 2013 Apple 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "IDBTransactionBackendLevelDBOperations.h"
28
29 #include "IDBCursorBackendLevelDB.h"
30 #include "IDBDatabaseCallbacks.h"
31 #include "IDBIndexWriter.h"
32 #include "IDBKeyRange.h"
33 #include "Logging.h"
34 #include <wtf/text/CString.h>
35
36 #if ENABLE(INDEXED_DATABASE) && USE(LEVELDB)
37
38 namespace WebCore {
39
40 void CreateObjectStoreOperation::perform()
41 {
42     LOG(StorageAPI, "CreateObjectStoreOperation");
43     if (!m_backingStore->createObjectStore(m_transaction->backingStoreTransaction(), m_transaction->database()->id(), m_objectStoreMetadata.id, m_objectStoreMetadata.name, m_objectStoreMetadata.keyPath, m_objectStoreMetadata.autoIncrement)) {
44         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error creating object store '%s'.", m_objectStoreMetadata.name.utf8().data()));
45         m_transaction->abort(error.release());
46         return;
47     }
48 }
49
50 void CreateIndexOperation::perform()
51 {
52     LOG(StorageAPI, "CreateIndexOperation");
53     if (!m_backingStore->createIndex(m_transaction->backingStoreTransaction(), m_transaction->database()->id(), m_objectStoreId, m_indexMetadata.id, m_indexMetadata.name, m_indexMetadata.keyPath, m_indexMetadata.unique, m_indexMetadata.multiEntry)) {
54         m_transaction->abort(IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error when trying to create index '%s'.", m_indexMetadata.name.utf8().data())));
55         return;
56     }
57 }
58
59 void CreateIndexAbortOperation::perform()
60 {
61     LOG(StorageAPI, "CreateIndexAbortOperation");
62     m_transaction->database()->removeIndex(m_objectStoreId, m_indexId);
63 }
64
65 void DeleteIndexOperation::perform()
66 {
67     LOG(StorageAPI, "DeleteIndexOperation");
68     bool ok = m_backingStore->deleteIndex(m_transaction->backingStoreTransaction(), m_transaction->database()->id(), m_objectStoreId, m_indexMetadata.id);
69     if (!ok) {
70         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error deleting index '%s'.", m_indexMetadata.name.utf8().data()));
71         m_transaction->abort(error);
72     }
73 }
74
75 void DeleteIndexAbortOperation::perform()
76 {
77     LOG(StorageAPI, "DeleteIndexAbortOperation");
78     m_transaction->database()->addIndex(m_objectStoreId, m_indexMetadata, IDBIndexMetadata::InvalidId);
79 }
80
81 void GetOperation::perform()
82 {
83     LOG(StorageAPI, "GetOperation");
84
85     RefPtr<IDBKey> key;
86
87     if (m_keyRange->isOnlyKey())
88         key = m_keyRange->lower();
89     else {
90         RefPtr<IDBBackingStoreInterface::Cursor> backingStoreCursor;
91         if (m_indexId == IDBIndexMetadata::InvalidId) {
92             ASSERT(m_cursorType != IndexedDB::CursorKeyOnly);
93             // ObjectStore Retrieval Operation
94             backingStoreCursor = m_backingStore->openObjectStoreCursor(m_transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), IndexedDB::CursorNext);
95         } else {
96             if (m_cursorType == IndexedDB::CursorKeyOnly) {
97                 // Index Value Retrieval Operation
98                 backingStoreCursor = m_backingStore->openIndexKeyCursor(m_transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), IndexedDB::CursorNext);
99             } else {
100                 // Index Referenced Value Retrieval Operation
101                 backingStoreCursor = m_backingStore->openIndexCursor(m_transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), IndexedDB::CursorNext);
102             }
103         }
104
105         if (!backingStoreCursor) {
106             m_callbacks->onSuccess();
107             return;
108         }
109
110         key = backingStoreCursor->key();
111     }
112
113     RefPtr<IDBKey> primaryKey;
114     bool ok;
115     if (m_indexId == IDBIndexMetadata::InvalidId) {
116         // Object Store Retrieval Operation
117         Vector<char> value;
118         ok = m_backingStore->getRecord(m_transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, *key, value);
119         if (!ok) {
120             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getRecord."));
121             return;
122         }
123
124         if (value.isEmpty()) {
125             m_callbacks->onSuccess();
126             return;
127         }
128
129         if (m_autoIncrement && !m_keyPath.isNull()) {
130             m_callbacks->onSuccess(SharedBuffer::adoptVector(value), key, m_keyPath);
131             return;
132         }
133
134         m_callbacks->onSuccess(SharedBuffer::adoptVector(value));
135         return;
136
137     }
138
139     // From here we are dealing only with indexes.
140     ok = m_backingStore->getPrimaryKeyViaIndex(m_transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, *key, primaryKey);
141     if (!ok) {
142         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getPrimaryKeyViaIndex."));
143         return;
144     }
145     if (!primaryKey) {
146         m_callbacks->onSuccess();
147         return;
148     }
149     if (m_cursorType == IndexedDB::CursorKeyOnly) {
150         // Index Value Retrieval Operation
151         m_callbacks->onSuccess(primaryKey.get());
152         return;
153     }
154
155     // Index Referenced Value Retrieval Operation
156     Vector<char> value;
157     ok = m_backingStore->getRecord(m_transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, *primaryKey, value);
158     if (!ok) {
159         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getRecord."));
160         return;
161     }
162
163     if (value.isEmpty()) {
164         m_callbacks->onSuccess();
165         return;
166     }
167     if (m_autoIncrement && !m_keyPath.isNull()) {
168         m_callbacks->onSuccess(SharedBuffer::adoptVector(value), primaryKey, m_keyPath);
169         return;
170     }
171     m_callbacks->onSuccess(SharedBuffer::adoptVector(value));
172 }
173
174 void PutOperation::perform()
175 {
176     LOG(StorageAPI, "PutOperation");
177     ASSERT(m_transaction->mode() != IndexedDB::TransactionReadOnly);
178     ASSERT(m_indexIds.size() == m_indexKeys.size());
179     bool keyWasGenerated = false;
180
181     RefPtr<IDBKey> key;
182     if (m_putMode != IDBDatabaseBackendInterface::CursorUpdate && m_objectStore.autoIncrement && !m_key) {
183         RefPtr<IDBKey> autoIncKey = m_backingStore->generateKey(*m_transaction, m_databaseId, m_objectStore.id);
184         keyWasGenerated = true;
185         if (!autoIncKey->isValid()) {
186             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, "Maximum key generator value reached."));
187             return;
188         }
189         key = autoIncKey;
190     } else
191         key = m_key;
192
193     ASSERT(key);
194     ASSERT(key->isValid());
195
196     RefPtr<IDBRecordIdentifier> recordIdentifier;
197     if (m_putMode == IDBDatabaseBackendInterface::AddOnly) {
198         bool ok = m_backingStore->keyExistsInObjectStore(m_transaction->backingStoreTransaction(), m_databaseId, m_objectStore.id, *key, recordIdentifier);
199         if (!ok) {
200             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error checking key existence."));
201             return;
202         }
203         if (recordIdentifier) {
204             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, "Key already exists in the object store."));
205             return;
206         }
207     }
208
209     Vector<RefPtr<IDBIndexWriter>> indexWriters;
210     String errorMessage;
211     bool obeysConstraints = false;
212     bool backingStoreSuccess = m_backingStore->makeIndexWriters(*m_transaction, m_databaseId, m_objectStore, *key, keyWasGenerated, m_indexIds, m_indexKeys, indexWriters, &errorMessage, obeysConstraints);
213     if (!backingStoreSuccess) {
214         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error updating index keys."));
215         return;
216     }
217     if (!obeysConstraints) {
218         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, errorMessage));
219         return;
220     }
221
222     // Before this point, don't do any mutation. After this point, rollback the transaction in case of error.
223     backingStoreSuccess = m_backingStore->putRecord(m_transaction->backingStoreTransaction(), m_databaseId, m_objectStore.id, *key, m_value, recordIdentifier.get());
224     if (!backingStoreSuccess) {
225         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error performing put/add."));
226         return;
227     }
228
229     for (size_t i = 0; i < indexWriters.size(); ++i) {
230         IDBIndexWriter* indexWriter = indexWriters[i].get();
231         indexWriter->writeIndexKeys(recordIdentifier.get(), *m_backingStore, m_transaction->backingStoreTransaction(), m_databaseId, m_objectStore.id);
232     }
233
234     if (m_objectStore.autoIncrement && m_putMode != IDBDatabaseBackendInterface::CursorUpdate && key->type() == IDBKey::NumberType) {
235         bool ok = m_backingStore->updateKeyGenerator(*m_transaction, m_databaseId, m_objectStore.id, *key, !keyWasGenerated);
236         if (!ok) {
237             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error updating key generator."));
238             return;
239         }
240     }
241
242     m_callbacks->onSuccess(key.release());
243 }
244
245 void SetIndexesReadyOperation::perform()
246 {
247     LOG(StorageAPI, "SetIndexesReadyOperation");
248     for (size_t i = 0; i < m_indexCount; ++i)
249         m_transaction->didCompletePreemptiveEvent();
250 }
251
252 void OpenCursorOperation::perform()
253 {
254     LOG(StorageAPI, "OpenCursorOperation");
255
256     // The frontend has begun indexing, so this pauses the transaction
257     // until the indexing is complete. This can't happen any earlier
258     // because we don't want to switch to early mode in case multiple
259     // indexes are being created in a row, with put()'s in between.
260     if (m_taskType == IDBDatabaseBackendInterface::PreemptiveTask)
261         m_transaction->addPreemptiveEvent();
262
263     RefPtr<IDBBackingStoreInterface::Cursor> backingStoreCursor;
264     if (m_indexId == IDBIndexMetadata::InvalidId) {
265         ASSERT(m_cursorType != IndexedDB::CursorKeyOnly);
266         backingStoreCursor = m_backingStore->openObjectStoreCursor(m_transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), m_direction);
267     } else {
268         ASSERT(m_taskType == IDBDatabaseBackendInterface::NormalTask);
269         if (m_cursorType == IndexedDB::CursorKeyOnly)
270             backingStoreCursor = m_backingStore->openIndexKeyCursor(m_transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), m_direction);
271         else
272             backingStoreCursor = m_backingStore->openIndexCursor(m_transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), m_direction);
273     }
274
275     if (!backingStoreCursor) {
276         m_callbacks->onSuccess(static_cast<SharedBuffer*>(0));
277         return;
278     }
279
280     IDBDatabaseBackendInterface::TaskType taskType(static_cast<IDBDatabaseBackendInterface::TaskType>(m_taskType));
281     RefPtr<IDBCursorBackendLevelDB> cursor = IDBCursorBackendLevelDB::create(backingStoreCursor.get(), m_cursorType, taskType, m_transaction.get(), m_objectStoreId);
282     m_callbacks->onSuccess(cursor, cursor->key(), cursor->primaryKey(), cursor->value());
283 }
284
285 void CountOperation::perform()
286 {
287     LOG(StorageAPI, "CountOperation");
288     uint32_t count = 0;
289     RefPtr<IDBBackingStoreInterface::Cursor> backingStoreCursor;
290
291     if (m_indexId == IDBIndexMetadata::InvalidId)
292         backingStoreCursor = m_backingStore->openObjectStoreKeyCursor(m_transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), IndexedDB::CursorNext);
293     else
294         backingStoreCursor = m_backingStore->openIndexKeyCursor(m_transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), IndexedDB::CursorNext);
295     if (!backingStoreCursor) {
296         m_callbacks->onSuccess(count);
297         return;
298     }
299
300     do {
301         ++count;
302     } while (backingStoreCursor->continueFunction(0));
303
304     m_callbacks->onSuccess(count);
305 }
306
307 void DeleteRangeOperation::perform()
308 {
309     LOG(StorageAPI, "DeleteRangeOperation");
310     RefPtr<IDBBackingStoreInterface::Cursor> backingStoreCursor = m_backingStore->openObjectStoreCursor(m_transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), IndexedDB::CursorNext);
311     if (backingStoreCursor) {
312         do {
313             if (!m_backingStore->deleteRecord(m_transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, backingStoreCursor->recordIdentifier())) {
314                 m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Error deleting data in range"));
315                 return;
316             }
317         } while (backingStoreCursor->continueFunction(0));
318     }
319
320     m_callbacks->onSuccess();
321 }
322
323 void ClearOperation::perform()
324 {
325     LOG(StorageAPI, "ObjectStoreClearOperation");
326     if (!m_backingStore->clearObjectStore(m_transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId)) {
327         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Error clearing object store"));
328         return;
329     }
330     m_callbacks->onSuccess();
331 }
332
333 void DeleteObjectStoreOperation::perform()
334 {
335     LOG(StorageAPI, "DeleteObjectStoreOperation");
336     bool ok = m_backingStore->deleteObjectStore(m_transaction->backingStoreTransaction(), m_transaction->database()->id(), m_objectStoreMetadata.id);
337     if (!ok) {
338         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error deleting object store '%s'.", m_objectStoreMetadata.name.utf8().data()));
339         m_transaction->abort(error);
340     }
341 }
342
343 void IDBDatabaseBackendImpl::VersionChangeOperation::perform()
344 {
345     LOG(StorageAPI, "VersionChangeOperation");
346     IDBDatabaseBackendImpl* database = m_transaction->database();
347     int64_t databaseId = database->id();
348     uint64_t oldVersion = database->m_metadata.version;
349
350     // FIXME: Database versions are now of type uint64_t, but this code expected int64_t.
351     ASSERT(m_version > (int64_t)oldVersion);
352     database->m_metadata.version = m_version;
353     if (!database->m_backingStore->updateIDBDatabaseIntVersion(m_transaction->backingStoreTransaction(), databaseId, database->m_metadata.version)) {
354         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Error writing data to stable storage when updating version.");
355         m_callbacks->onError(error);
356         m_transaction->abort(error);
357         return;
358     }
359     ASSERT(!database->m_pendingSecondHalfOpen);
360     database->m_pendingSecondHalfOpen = PendingOpenCall::create(m_callbacks, m_databaseCallbacks, m_transactionId, m_version);
361     m_callbacks->onUpgradeNeeded(oldVersion, database, database->metadata());
362 }
363
364 void CreateObjectStoreAbortOperation::perform()
365 {
366     LOG(StorageAPI, "CreateObjectStoreAbortOperation");
367     m_transaction->database()->removeObjectStore(m_objectStoreId);
368 }
369
370 void DeleteObjectStoreAbortOperation::perform()
371 {
372     LOG(StorageAPI, "DeleteObjectStoreAbortOperation");
373     m_transaction->database()->addObjectStore(m_objectStoreMetadata, IDBObjectStoreMetadata::InvalidId);
374 }
375
376 void IDBDatabaseBackendImpl::VersionChangeAbortOperation::perform()
377 {
378     LOG(StorageAPI, "VersionChangeAbortOperation");
379     m_transaction->database()->m_metadata.version = m_previousIntVersion;
380 }
381
382 } // namespace WebCore
383
384 #endif // ENABLE(INDEXED_DATABASE) && USE(LEVELDB)