OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/browser/indexed_db/indexed_db_database_impl.h" | |
6 | |
7 #include <math.h> | |
8 #include <vector> | |
9 | |
10 #include "base/auto_reset.h" | |
11 #include "base/logging.h" | |
12 #include "base/memory/scoped_ptr.h" | |
13 #include "base/strings/string_number_conversions.h" | |
14 #include "base/utf_string_conversions.h" | |
15 #include "content/browser/indexed_db/indexed_db_backing_store.h" | |
16 #include "content/browser/indexed_db/indexed_db_cursor_impl.h" | |
17 #include "content/browser/indexed_db/indexed_db_factory_impl.h" | |
18 #include "content/browser/indexed_db/indexed_db_index_writer.h" | |
19 #include "content/browser/indexed_db/indexed_db_tracing.h" | |
20 #include "content/browser/indexed_db/indexed_db_transaction.h" | |
21 #include "content/common/indexed_db/indexed_db_key_path.h" | |
22 #include "content/common/indexed_db/indexed_db_key_range.h" | |
23 #include "third_party/WebKit/Source/Platform/chromium/public/WebIDBDatabaseExcep
tion.h" | |
24 | |
25 using base::Int64ToString16; | |
26 using WebKit::WebIDBKey; | |
27 | |
28 namespace content { | |
29 | |
30 class CreateObjectStoreOperation : public IndexedDBTransaction::Operation { | |
31 public: | |
32 CreateObjectStoreOperation( | |
33 scoped_refptr<IndexedDBBackingStore> backing_store, | |
34 const IndexedDBObjectStoreMetadata& object_store_metadata) | |
35 : backing_store_(backing_store), | |
36 object_store_metadata_(object_store_metadata) {} | |
37 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
38 | |
39 private: | |
40 const scoped_refptr<IndexedDBBackingStore> backing_store_; | |
41 const IndexedDBObjectStoreMetadata object_store_metadata_; | |
42 }; | |
43 | |
44 class DeleteObjectStoreOperation : public IndexedDBTransaction::Operation { | |
45 public: | |
46 DeleteObjectStoreOperation( | |
47 scoped_refptr<IndexedDBBackingStore> backing_store, | |
48 const IndexedDBObjectStoreMetadata& object_store_metadata) | |
49 : backing_store_(backing_store), | |
50 object_store_metadata_(object_store_metadata) {} | |
51 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
52 | |
53 private: | |
54 const scoped_refptr<IndexedDBBackingStore> backing_store_; | |
55 const IndexedDBObjectStoreMetadata object_store_metadata_; | |
56 }; | |
57 | |
58 class IndexedDBDatabaseImpl::VersionChangeOperation | |
59 : public IndexedDBTransaction::Operation { | |
60 public: | |
61 VersionChangeOperation( | |
62 scoped_refptr<IndexedDBDatabaseImpl> database, | |
63 int64 transaction_id, | |
64 int64 version, | |
65 scoped_refptr<IndexedDBCallbacksWrapper> callbacks, | |
66 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks) | |
67 : database_(database), | |
68 transaction_id_(transaction_id), | |
69 version_(version), | |
70 callbacks_(callbacks), | |
71 database_callbacks_(database_callbacks) {} | |
72 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
73 | |
74 private: | |
75 scoped_refptr<IndexedDBDatabaseImpl> database_; | |
76 int64 transaction_id_; | |
77 int64 version_; | |
78 scoped_refptr<IndexedDBCallbacksWrapper> callbacks_; | |
79 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks_; | |
80 }; | |
81 | |
82 class CreateObjectStoreAbortOperation : public IndexedDBTransaction::Operation { | |
83 public: | |
84 CreateObjectStoreAbortOperation(scoped_refptr<IndexedDBDatabaseImpl> database, | |
85 int64 object_store_id) | |
86 : database_(database), object_store_id_(object_store_id) {} | |
87 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
88 | |
89 private: | |
90 const scoped_refptr<IndexedDBDatabaseImpl> database_; | |
91 const int64 object_store_id_; | |
92 }; | |
93 | |
94 class DeleteObjectStoreAbortOperation : public IndexedDBTransaction::Operation { | |
95 public: | |
96 DeleteObjectStoreAbortOperation( | |
97 scoped_refptr<IndexedDBDatabaseImpl> database, | |
98 const IndexedDBObjectStoreMetadata& object_store_metadata) | |
99 : database_(database), object_store_metadata_(object_store_metadata) {} | |
100 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
101 | |
102 private: | |
103 scoped_refptr<IndexedDBDatabaseImpl> database_; | |
104 IndexedDBObjectStoreMetadata object_store_metadata_; | |
105 }; | |
106 | |
107 class IndexedDBDatabaseImpl::VersionChangeAbortOperation | |
108 : public IndexedDBTransaction::Operation { | |
109 public: | |
110 VersionChangeAbortOperation(scoped_refptr<IndexedDBDatabaseImpl> database, | |
111 const string16& previous_version, | |
112 int64 previous_int_version) | |
113 : database_(database), | |
114 previous_version_(previous_version), | |
115 previous_int_version_(previous_int_version) {} | |
116 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
117 | |
118 private: | |
119 scoped_refptr<IndexedDBDatabaseImpl> database_; | |
120 string16 previous_version_; | |
121 int64 previous_int_version_; | |
122 }; | |
123 | |
124 class CreateIndexOperation : public IndexedDBTransaction::Operation { | |
125 public: | |
126 CreateIndexOperation(scoped_refptr<IndexedDBBackingStore> backing_store, | |
127 int64 object_store_id, | |
128 const IndexedDBIndexMetadata& index_metadata) | |
129 : backing_store_(backing_store), | |
130 object_store_id_(object_store_id), | |
131 index_metadata_(index_metadata) {} | |
132 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
133 | |
134 private: | |
135 const scoped_refptr<IndexedDBBackingStore> backing_store_; | |
136 const int64 object_store_id_; | |
137 const IndexedDBIndexMetadata index_metadata_; | |
138 }; | |
139 | |
140 class DeleteIndexOperation : public IndexedDBTransaction::Operation { | |
141 public: | |
142 DeleteIndexOperation(scoped_refptr<IndexedDBBackingStore> backing_store, | |
143 int64 object_store_id, | |
144 const IndexedDBIndexMetadata& index_metadata) | |
145 : backing_store_(backing_store), | |
146 object_store_id_(object_store_id), | |
147 index_metadata_(index_metadata) {} | |
148 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
149 | |
150 private: | |
151 const scoped_refptr<IndexedDBBackingStore> backing_store_; | |
152 const int64 object_store_id_; | |
153 const IndexedDBIndexMetadata index_metadata_; | |
154 }; | |
155 | |
156 class CreateIndexAbortOperation : public IndexedDBTransaction::Operation { | |
157 public: | |
158 CreateIndexAbortOperation(scoped_refptr<IndexedDBDatabaseImpl> database, | |
159 int64 object_store_id, | |
160 int64 index_id) | |
161 : database_(database), | |
162 object_store_id_(object_store_id), | |
163 index_id_(index_id) {} | |
164 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
165 | |
166 private: | |
167 const scoped_refptr<IndexedDBDatabaseImpl> database_; | |
168 const int64 object_store_id_; | |
169 const int64 index_id_; | |
170 }; | |
171 | |
172 class DeleteIndexAbortOperation : public IndexedDBTransaction::Operation { | |
173 public: | |
174 DeleteIndexAbortOperation(scoped_refptr<IndexedDBDatabaseImpl> database, | |
175 int64 object_store_id, | |
176 const IndexedDBIndexMetadata& index_metadata) | |
177 : database_(database), | |
178 object_store_id_(object_store_id), | |
179 index_metadata_(index_metadata) {} | |
180 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
181 | |
182 private: | |
183 const scoped_refptr<IndexedDBDatabaseImpl> database_; | |
184 const int64 object_store_id_; | |
185 const IndexedDBIndexMetadata index_metadata_; | |
186 }; | |
187 | |
188 class GetOperation : public IndexedDBTransaction::Operation { | |
189 public: | |
190 GetOperation(scoped_refptr<IndexedDBBackingStore> backing_store, | |
191 const IndexedDBDatabaseMetadata& metadata, | |
192 int64 object_store_id, | |
193 int64 index_id, | |
194 scoped_ptr<IndexedDBKeyRange> key_range, | |
195 indexed_db::CursorType cursor_type, | |
196 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) | |
197 : backing_store_(backing_store), | |
198 database_id_(metadata.id), | |
199 object_store_id_(object_store_id), | |
200 index_id_(index_id), | |
201 key_path_(metadata.object_stores.find(object_store_id) | |
202 ->second.key_path), | |
203 auto_increment_(metadata.object_stores.find(object_store_id) | |
204 ->second.auto_increment), | |
205 key_range_(key_range.Pass()), | |
206 cursor_type_(cursor_type), | |
207 callbacks_(callbacks) { | |
208 DCHECK(metadata.object_stores.find(object_store_id) != | |
209 metadata.object_stores.end()); | |
210 DCHECK(metadata.object_stores.find(object_store_id)->second.id == | |
211 object_store_id); | |
212 } | |
213 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
214 | |
215 private: | |
216 const scoped_refptr<IndexedDBBackingStore> backing_store_; | |
217 const int64 database_id_; | |
218 const int64 object_store_id_; | |
219 const int64 index_id_; | |
220 const IndexedDBKeyPath key_path_; | |
221 const bool auto_increment_; | |
222 const scoped_ptr<IndexedDBKeyRange> key_range_; | |
223 const indexed_db::CursorType cursor_type_; | |
224 const scoped_refptr<IndexedDBCallbacksWrapper> callbacks_; | |
225 }; | |
226 | |
227 class PutOperation : public IndexedDBTransaction::Operation { | |
228 public: | |
229 PutOperation(scoped_refptr<IndexedDBBackingStore> backing_store, | |
230 int64 database_id, | |
231 const IndexedDBObjectStoreMetadata& object_store, | |
232 std::vector<char>* value, | |
233 scoped_ptr<IndexedDBKey> key, | |
234 IndexedDBDatabase::PutMode put_mode, | |
235 scoped_refptr<IndexedDBCallbacksWrapper> callbacks, | |
236 const std::vector<int64>& index_ids, | |
237 const std::vector<IndexedDBDatabase::IndexKeys>& index_keys) | |
238 : backing_store_(backing_store), | |
239 database_id_(database_id), | |
240 object_store_(object_store), | |
241 key_(key.Pass()), | |
242 put_mode_(put_mode), | |
243 callbacks_(callbacks), | |
244 index_ids_(index_ids), | |
245 index_keys_(index_keys) { | |
246 value_.swap(*value); | |
247 } | |
248 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
249 | |
250 private: | |
251 const scoped_refptr<IndexedDBBackingStore> backing_store_; | |
252 const int64 database_id_; | |
253 const IndexedDBObjectStoreMetadata object_store_; | |
254 std::vector<char> value_; | |
255 scoped_ptr<IndexedDBKey> key_; | |
256 const IndexedDBDatabase::PutMode put_mode_; | |
257 const scoped_refptr<IndexedDBCallbacksWrapper> callbacks_; | |
258 const std::vector<int64> index_ids_; | |
259 const std::vector<IndexedDBDatabase::IndexKeys> index_keys_; | |
260 }; | |
261 | |
262 class SetIndexesReadyOperation : public IndexedDBTransaction::Operation { | |
263 public: | |
264 explicit SetIndexesReadyOperation(size_t index_count) | |
265 : index_count_(index_count) {} | |
266 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
267 | |
268 private: | |
269 const size_t index_count_; | |
270 }; | |
271 | |
272 class OpenCursorOperation : public IndexedDBTransaction::Operation { | |
273 public: | |
274 OpenCursorOperation(scoped_refptr<IndexedDBBackingStore> backing_store, | |
275 int64 database_id, | |
276 int64 object_store_id, | |
277 int64 index_id, | |
278 scoped_ptr<IndexedDBKeyRange> key_range, | |
279 indexed_db::CursorDirection direction, | |
280 indexed_db::CursorType cursor_type, | |
281 IndexedDBDatabase::TaskType task_type, | |
282 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) | |
283 : backing_store_(backing_store), | |
284 database_id_(database_id), | |
285 object_store_id_(object_store_id), | |
286 index_id_(index_id), | |
287 key_range_(key_range.Pass()), | |
288 direction_(direction), | |
289 cursor_type_(cursor_type), | |
290 task_type_(task_type), | |
291 callbacks_(callbacks) {} | |
292 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
293 | |
294 private: | |
295 const scoped_refptr<IndexedDBBackingStore> backing_store_; | |
296 const int64 database_id_; | |
297 const int64 object_store_id_; | |
298 const int64 index_id_; | |
299 const scoped_ptr<IndexedDBKeyRange> key_range_; | |
300 const indexed_db::CursorDirection direction_; | |
301 const indexed_db::CursorType cursor_type_; | |
302 const IndexedDBDatabase::TaskType task_type_; | |
303 const scoped_refptr<IndexedDBCallbacksWrapper> callbacks_; | |
304 }; | |
305 | |
306 class CountOperation : public IndexedDBTransaction::Operation { | |
307 public: | |
308 CountOperation(scoped_refptr<IndexedDBBackingStore> backing_store, | |
309 int64 database_id, | |
310 int64 object_store_id, | |
311 int64 index_id, | |
312 scoped_ptr<IndexedDBKeyRange> key_range, | |
313 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) | |
314 : backing_store_(backing_store), | |
315 database_id_(database_id), | |
316 object_store_id_(object_store_id), | |
317 index_id_(index_id), | |
318 key_range_(key_range.Pass()), | |
319 callbacks_(callbacks) {} | |
320 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
321 | |
322 private: | |
323 const scoped_refptr<IndexedDBBackingStore> backing_store_; | |
324 const int64 database_id_; | |
325 const int64 object_store_id_; | |
326 const int64 index_id_; | |
327 const scoped_ptr<IndexedDBKeyRange> key_range_; | |
328 const scoped_refptr<IndexedDBCallbacksWrapper> callbacks_; | |
329 }; | |
330 | |
331 class DeleteRangeOperation : public IndexedDBTransaction::Operation { | |
332 public: | |
333 DeleteRangeOperation(scoped_refptr<IndexedDBBackingStore> backing_store, | |
334 int64 database_id, | |
335 int64 object_store_id, | |
336 scoped_ptr<IndexedDBKeyRange> key_range, | |
337 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) | |
338 : backing_store_(backing_store), | |
339 database_id_(database_id), | |
340 object_store_id_(object_store_id), | |
341 key_range_(key_range.Pass()), | |
342 callbacks_(callbacks) {} | |
343 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
344 | |
345 private: | |
346 const scoped_refptr<IndexedDBBackingStore> backing_store_; | |
347 const int64 database_id_; | |
348 const int64 object_store_id_; | |
349 const scoped_ptr<IndexedDBKeyRange> key_range_; | |
350 const scoped_refptr<IndexedDBCallbacksWrapper> callbacks_; | |
351 }; | |
352 | |
353 class ClearOperation : public IndexedDBTransaction::Operation { | |
354 public: | |
355 ClearOperation(scoped_refptr<IndexedDBBackingStore> backing_store, | |
356 int64 database_id, | |
357 int64 object_store_id, | |
358 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) | |
359 : backing_store_(backing_store), | |
360 database_id_(database_id), | |
361 object_store_id_(object_store_id), | |
362 callbacks_(callbacks) {} | |
363 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
364 | |
365 private: | |
366 const scoped_refptr<IndexedDBBackingStore> backing_store_; | |
367 const int64 database_id_; | |
368 const int64 object_store_id_; | |
369 const scoped_refptr<IndexedDBCallbacksWrapper> callbacks_; | |
370 }; | |
371 | |
372 class IndexedDBDatabaseImpl::PendingOpenCall { | |
373 public: | |
374 PendingOpenCall( | |
375 scoped_refptr<IndexedDBCallbacksWrapper> callbacks, | |
376 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks, | |
377 int64 transaction_id, | |
378 int64 version) | |
379 : callbacks_(callbacks), | |
380 database_callbacks_(database_callbacks), | |
381 version_(version), | |
382 transaction_id_(transaction_id) {} | |
383 scoped_refptr<IndexedDBCallbacksWrapper> Callbacks() { return callbacks_; } | |
384 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> DatabaseCallbacks() { | |
385 return database_callbacks_; | |
386 } | |
387 int64 Version() { return version_; } | |
388 int64 TransactionId() const { return transaction_id_; } | |
389 | |
390 private: | |
391 scoped_refptr<IndexedDBCallbacksWrapper> callbacks_; | |
392 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks_; | |
393 int64 version_; | |
394 const int64 transaction_id_; | |
395 }; | |
396 | |
397 class IndexedDBDatabaseImpl::PendingDeleteCall { | |
398 public: | |
399 explicit PendingDeleteCall(scoped_refptr<IndexedDBCallbacksWrapper> callbacks) | |
400 : callbacks_(callbacks) {} | |
401 scoped_refptr<IndexedDBCallbacksWrapper> Callbacks() { return callbacks_; } | |
402 | |
403 private: | |
404 scoped_refptr<IndexedDBCallbacksWrapper> callbacks_; | |
405 }; | |
406 | |
407 scoped_refptr<IndexedDBDatabaseImpl> IndexedDBDatabaseImpl::Create( | |
408 const string16& name, | |
409 IndexedDBBackingStore* database, | |
410 IndexedDBFactoryImpl* factory, | |
411 const string16& unique_identifier) { | |
412 scoped_refptr<IndexedDBDatabaseImpl> backend = | |
413 new IndexedDBDatabaseImpl(name, database, factory, unique_identifier); | |
414 if (!backend->OpenInternal()) | |
415 return 0; | |
416 return backend; | |
417 } | |
418 | |
419 namespace { | |
420 const base::string16::value_type kNoStringVersion[] = {0}; | |
421 } | |
422 | |
423 IndexedDBDatabaseImpl::IndexedDBDatabaseImpl( | |
424 const string16& name, | |
425 IndexedDBBackingStore* backing_store, | |
426 IndexedDBFactoryImpl* factory, | |
427 const string16& unique_identifier) | |
428 : backing_store_(backing_store), | |
429 metadata_(name, | |
430 kInvalidId, | |
431 kNoStringVersion, | |
432 IndexedDBDatabaseMetadata::NO_INT_VERSION, | |
433 kInvalidId), | |
434 identifier_(unique_identifier), | |
435 factory_(factory), | |
436 running_version_change_transaction_(NULL), | |
437 closing_connection_(false) { | |
438 DCHECK(!metadata_.name.empty()); | |
439 } | |
440 | |
441 void IndexedDBDatabaseImpl::AddObjectStore( | |
442 const IndexedDBObjectStoreMetadata& object_store, | |
443 int64 new_max_object_store_id) { | |
444 DCHECK(metadata_.object_stores.find(object_store.id) == | |
445 metadata_.object_stores.end()); | |
446 if (new_max_object_store_id != IndexedDBObjectStoreMetadata::kInvalidId) { | |
447 DCHECK_LT(metadata_.max_object_store_id, new_max_object_store_id); | |
448 metadata_.max_object_store_id = new_max_object_store_id; | |
449 } | |
450 metadata_.object_stores[object_store.id] = object_store; | |
451 } | |
452 | |
453 void IndexedDBDatabaseImpl::RemoveObjectStore(int64 object_store_id) { | |
454 DCHECK(metadata_.object_stores.find(object_store_id) != | |
455 metadata_.object_stores.end()); | |
456 metadata_.object_stores.erase(object_store_id); | |
457 } | |
458 | |
459 void IndexedDBDatabaseImpl::AddIndex(int64 object_store_id, | |
460 const IndexedDBIndexMetadata& index, | |
461 int64 new_max_index_id) { | |
462 DCHECK(metadata_.object_stores.find(object_store_id) != | |
463 metadata_.object_stores.end()); | |
464 IndexedDBObjectStoreMetadata object_store = | |
465 metadata_.object_stores[object_store_id]; | |
466 | |
467 DCHECK(object_store.indexes.find(index.id) == object_store.indexes.end()); | |
468 object_store.indexes[index.id] = index; | |
469 if (new_max_index_id != IndexedDBIndexMetadata::kInvalidId) { | |
470 DCHECK_LT(object_store.max_index_id, new_max_index_id); | |
471 object_store.max_index_id = new_max_index_id; | |
472 } | |
473 metadata_.object_stores[object_store_id] = object_store; | |
474 } | |
475 | |
476 void IndexedDBDatabaseImpl::RemoveIndex(int64 object_store_id, int64 index_id) { | |
477 DCHECK(metadata_.object_stores.find(object_store_id) != | |
478 metadata_.object_stores.end()); | |
479 IndexedDBObjectStoreMetadata object_store = | |
480 metadata_.object_stores[object_store_id]; | |
481 | |
482 DCHECK(object_store.indexes.find(index_id) != object_store.indexes.end()); | |
483 object_store.indexes.erase(index_id); | |
484 metadata_.object_stores[object_store_id] = object_store; | |
485 } | |
486 | |
487 bool IndexedDBDatabaseImpl::OpenInternal() { | |
488 bool success = false; | |
489 bool ok = backing_store_->GetIDBDatabaseMetaData( | |
490 metadata_.name, &metadata_, success); | |
491 DCHECK(success == (metadata_.id != kInvalidId)) << "success = " << success | |
492 << " id_ = " << metadata_.id; | |
493 if (!ok) | |
494 return false; | |
495 if (success) | |
496 return backing_store_->GetObjectStores(metadata_.id, | |
497 &metadata_.object_stores); | |
498 | |
499 return backing_store_->CreateIDBDatabaseMetaData( | |
500 metadata_.name, metadata_.version, metadata_.int_version, metadata_.id); | |
501 } | |
502 | |
503 IndexedDBDatabaseImpl::~IndexedDBDatabaseImpl() { | |
504 DCHECK(transactions_.empty()); | |
505 DCHECK(pending_open_calls_.empty()); | |
506 DCHECK(pending_delete_calls_.empty()); | |
507 } | |
508 | |
509 scoped_refptr<IndexedDBBackingStore> IndexedDBDatabaseImpl::BackingStore() | |
510 const { | |
511 return backing_store_; | |
512 } | |
513 | |
514 void IndexedDBDatabaseImpl::CreateObjectStore(int64 transaction_id, | |
515 int64 object_store_id, | |
516 const string16& name, | |
517 const IndexedDBKeyPath& key_path, | |
518 bool auto_increment) { | |
519 IDB_TRACE("IndexedDBDatabaseImpl::create_object_store"); | |
520 TransactionMap::const_iterator trans_iterator = | |
521 transactions_.find(transaction_id); | |
522 if (trans_iterator == transactions_.end()) | |
523 return; | |
524 IndexedDBTransaction* transaction = trans_iterator->second; | |
525 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); | |
526 | |
527 DCHECK(metadata_.object_stores.find(object_store_id) == | |
528 metadata_.object_stores.end()); | |
529 IndexedDBObjectStoreMetadata object_store_metadata( | |
530 name, | |
531 object_store_id, | |
532 key_path, | |
533 auto_increment, | |
534 IndexedDBDatabase::kMinimumIndexId); | |
535 | |
536 transaction->ScheduleTask( | |
537 new CreateObjectStoreOperation(backing_store_, object_store_metadata), | |
538 new CreateObjectStoreAbortOperation(this, object_store_id)); | |
539 | |
540 AddObjectStore(object_store_metadata, object_store_id); | |
541 } | |
542 | |
543 void CreateObjectStoreOperation::Perform(IndexedDBTransaction* transaction) { | |
544 IDB_TRACE("CreateObjectStoreOperation"); | |
545 if (!backing_store_->CreateObjectStore( | |
546 transaction->BackingStoreTransaction(), | |
547 transaction->database()->id(), | |
548 object_store_metadata_.id, | |
549 object_store_metadata_.name, | |
550 object_store_metadata_.key_path, | |
551 object_store_metadata_.auto_increment)) { | |
552 string16 error_string = | |
553 ASCIIToUTF16("Internal error creating object store '") + | |
554 object_store_metadata_.name + ASCIIToUTF16("'."); | |
555 | |
556 scoped_refptr<IndexedDBDatabaseError> error = | |
557 IndexedDBDatabaseError::Create( | |
558 WebKit::WebIDBDatabaseExceptionUnknownError, error_string); | |
559 transaction->Abort(error); | |
560 return; | |
561 } | |
562 } | |
563 | |
564 void IndexedDBDatabaseImpl::DeleteObjectStore(int64 transaction_id, | |
565 int64 object_store_id) { | |
566 IDB_TRACE("IndexedDBDatabaseImpl::delete_object_store"); | |
567 TransactionMap::const_iterator trans_iterator = | |
568 transactions_.find(transaction_id); | |
569 if (trans_iterator == transactions_.end()) | |
570 return; | |
571 IndexedDBTransaction* transaction = trans_iterator->second; | |
572 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); | |
573 | |
574 DCHECK(metadata_.object_stores.find(object_store_id) != | |
575 metadata_.object_stores.end()); | |
576 const IndexedDBObjectStoreMetadata& object_store_metadata = | |
577 metadata_.object_stores[object_store_id]; | |
578 | |
579 transaction->ScheduleTask( | |
580 new DeleteObjectStoreOperation(backing_store_, object_store_metadata), | |
581 new DeleteObjectStoreAbortOperation(this, object_store_metadata)); | |
582 RemoveObjectStore(object_store_id); | |
583 } | |
584 | |
585 void IndexedDBDatabaseImpl::CreateIndex(int64 transaction_id, | |
586 int64 object_store_id, | |
587 int64 index_id, | |
588 const string16& name, | |
589 const IndexedDBKeyPath& key_path, | |
590 bool unique, | |
591 bool multi_entry) { | |
592 IDB_TRACE("IndexedDBDatabaseImpl::create_index"); | |
593 TransactionMap::const_iterator trans_iterator = | |
594 transactions_.find(transaction_id); | |
595 if (trans_iterator == transactions_.end()) | |
596 return; | |
597 IndexedDBTransaction* transaction = trans_iterator->second; | |
598 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); | |
599 | |
600 DCHECK(metadata_.object_stores.find(object_store_id) != | |
601 metadata_.object_stores.end()); | |
602 const IndexedDBObjectStoreMetadata object_store = | |
603 metadata_.object_stores[object_store_id]; | |
604 | |
605 DCHECK(object_store.indexes.find(index_id) == object_store.indexes.end()); | |
606 const IndexedDBIndexMetadata index_metadata( | |
607 name, index_id, key_path, unique, multi_entry); | |
608 | |
609 transaction->ScheduleTask( | |
610 new CreateIndexOperation(backing_store_, object_store_id, index_metadata), | |
611 new CreateIndexAbortOperation(this, object_store_id, index_id)); | |
612 | |
613 AddIndex(object_store_id, index_metadata, index_id); | |
614 } | |
615 | |
616 void CreateIndexOperation::Perform(IndexedDBTransaction* transaction) { | |
617 IDB_TRACE("CreateIndexOperation"); | |
618 if (!backing_store_->CreateIndex(transaction->BackingStoreTransaction(), | |
619 transaction->database()->id(), | |
620 object_store_id_, | |
621 index_metadata_.id, | |
622 index_metadata_.name, | |
623 index_metadata_.key_path, | |
624 index_metadata_.unique, | |
625 index_metadata_.multi_entry)) { | |
626 string16 error_string = ASCIIToUTF16("Internal error creating index '") + | |
627 index_metadata_.name + ASCIIToUTF16("'."); | |
628 transaction->Abort(IndexedDBDatabaseError::Create( | |
629 WebKit::WebIDBDatabaseExceptionUnknownError, error_string)); | |
630 return; | |
631 } | |
632 } | |
633 | |
634 void CreateIndexAbortOperation::Perform(IndexedDBTransaction* transaction) { | |
635 IDB_TRACE("CreateIndexAbortOperation"); | |
636 DCHECK(!transaction); | |
637 database_->RemoveIndex(object_store_id_, index_id_); | |
638 } | |
639 | |
640 void IndexedDBDatabaseImpl::DeleteIndex(int64 transaction_id, | |
641 int64 object_store_id, | |
642 int64 index_id) { | |
643 IDB_TRACE("IndexedDBDatabaseImpl::delete_index"); | |
644 TransactionMap::const_iterator trans_iterator = | |
645 transactions_.find(transaction_id); | |
646 if (trans_iterator == transactions_.end()) | |
647 return; | |
648 IndexedDBTransaction* transaction = trans_iterator->second; | |
649 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); | |
650 | |
651 DCHECK(metadata_.object_stores.find(object_store_id) != | |
652 metadata_.object_stores.end()); | |
653 IndexedDBObjectStoreMetadata object_store = | |
654 metadata_.object_stores[object_store_id]; | |
655 | |
656 DCHECK(object_store.indexes.find(index_id) != object_store.indexes.end()); | |
657 const IndexedDBIndexMetadata& index_metadata = object_store.indexes[index_id]; | |
658 | |
659 transaction->ScheduleTask( | |
660 new DeleteIndexOperation(backing_store_, object_store_id, index_metadata), | |
661 new DeleteIndexAbortOperation(this, object_store_id, index_metadata)); | |
662 | |
663 RemoveIndex(object_store_id, index_id); | |
664 } | |
665 | |
666 void DeleteIndexOperation::Perform(IndexedDBTransaction* transaction) { | |
667 IDB_TRACE("DeleteIndexOperation"); | |
668 bool ok = backing_store_->DeleteIndex(transaction->BackingStoreTransaction(), | |
669 transaction->database()->id(), | |
670 object_store_id_, | |
671 index_metadata_.id); | |
672 if (!ok) { | |
673 string16 error_string = ASCIIToUTF16("Internal error deleting index '") + | |
674 index_metadata_.name + ASCIIToUTF16("'."); | |
675 scoped_refptr<IndexedDBDatabaseError> error = | |
676 IndexedDBDatabaseError::Create( | |
677 WebKit::WebIDBDatabaseExceptionUnknownError, error_string); | |
678 transaction->Abort(error); | |
679 } | |
680 } | |
681 | |
682 void DeleteIndexAbortOperation::Perform(IndexedDBTransaction* transaction) { | |
683 IDB_TRACE("DeleteIndexAbortOperation"); | |
684 DCHECK(!transaction); | |
685 database_->AddIndex( | |
686 object_store_id_, index_metadata_, IndexedDBIndexMetadata::kInvalidId); | |
687 } | |
688 | |
689 void IndexedDBDatabaseImpl::Commit(int64 transaction_id) { | |
690 // The frontend suggests that we commit, but we may have previously initiated | |
691 // an abort, and so have disposed of the transaction. on_abort has already | |
692 // been dispatched to the frontend, so it will find out about that | |
693 // asynchronously. | |
694 if (transactions_.find(transaction_id) != transactions_.end()) | |
695 transactions_[transaction_id]->Commit(); | |
696 } | |
697 | |
698 void IndexedDBDatabaseImpl::Abort(int64 transaction_id) { | |
699 // If the transaction is unknown, then it has already been aborted by the | |
700 // backend before this call so it is safe to ignore it. | |
701 if (transactions_.find(transaction_id) != transactions_.end()) | |
702 transactions_[transaction_id]->Abort(); | |
703 } | |
704 | |
705 void IndexedDBDatabaseImpl::Abort(int64 transaction_id, | |
706 scoped_refptr<IndexedDBDatabaseError> error) { | |
707 // If the transaction is unknown, then it has already been aborted by the | |
708 // backend before this call so it is safe to ignore it. | |
709 if (transactions_.find(transaction_id) != transactions_.end()) | |
710 transactions_[transaction_id]->Abort(error); | |
711 } | |
712 | |
713 void IndexedDBDatabaseImpl::Get( | |
714 int64 transaction_id, | |
715 int64 object_store_id, | |
716 int64 index_id, | |
717 scoped_ptr<IndexedDBKeyRange> key_range, | |
718 bool key_only, | |
719 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
720 IDB_TRACE("IndexedDBDatabaseImpl::get"); | |
721 TransactionMap::const_iterator trans_iterator = | |
722 transactions_.find(transaction_id); | |
723 if (trans_iterator == transactions_.end()) | |
724 return; | |
725 IndexedDBTransaction* transaction = trans_iterator->second; | |
726 | |
727 transaction->ScheduleTask(new GetOperation( | |
728 backing_store_, | |
729 metadata_, | |
730 object_store_id, | |
731 index_id, | |
732 key_range.Pass(), | |
733 key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE, | |
734 callbacks)); | |
735 } | |
736 | |
737 void GetOperation::Perform(IndexedDBTransaction* transaction) { | |
738 IDB_TRACE("GetOperation"); | |
739 | |
740 const IndexedDBKey* key; | |
741 | |
742 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor; | |
743 if (key_range_->IsOnlyKey()) { | |
744 key = &key_range_->lower(); | |
745 } else { | |
746 if (index_id_ == IndexedDBIndexMetadata::kInvalidId) { | |
747 DCHECK_NE(cursor_type_, indexed_db::CURSOR_KEY_ONLY); | |
748 // ObjectStore Retrieval Operation | |
749 backing_store_cursor = backing_store_->OpenObjectStoreCursor( | |
750 transaction->BackingStoreTransaction(), | |
751 database_id_, | |
752 object_store_id_, | |
753 *key_range_, | |
754 indexed_db::CURSOR_NEXT); | |
755 } else if (cursor_type_ == indexed_db::CURSOR_KEY_ONLY) { | |
756 // Index Value Retrieval Operation | |
757 backing_store_cursor = backing_store_->OpenIndexKeyCursor( | |
758 transaction->BackingStoreTransaction(), | |
759 database_id_, | |
760 object_store_id_, | |
761 index_id_, | |
762 *key_range_, | |
763 indexed_db::CURSOR_NEXT); | |
764 } else { | |
765 // Index Referenced Value Retrieval Operation | |
766 backing_store_cursor = backing_store_->OpenIndexCursor( | |
767 transaction->BackingStoreTransaction(), | |
768 database_id_, | |
769 object_store_id_, | |
770 index_id_, | |
771 *key_range_, | |
772 indexed_db::CURSOR_NEXT); | |
773 } | |
774 | |
775 if (!backing_store_cursor) { | |
776 callbacks_->OnSuccess(); | |
777 return; | |
778 } | |
779 | |
780 key = &backing_store_cursor->key(); | |
781 } | |
782 | |
783 scoped_ptr<IndexedDBKey> primary_key; | |
784 bool ok; | |
785 if (index_id_ == IndexedDBIndexMetadata::kInvalidId) { | |
786 // Object Store Retrieval Operation | |
787 std::vector<char> value; | |
788 ok = backing_store_->GetRecord(transaction->BackingStoreTransaction(), | |
789 database_id_, | |
790 object_store_id_, | |
791 *key, | |
792 value); | |
793 if (!ok) { | |
794 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
795 WebKit::WebIDBDatabaseExceptionUnknownError, | |
796 ASCIIToUTF16("Internal error in get_record."))); | |
797 return; | |
798 } | |
799 | |
800 if (value.empty()) { | |
801 callbacks_->OnSuccess(); | |
802 return; | |
803 } | |
804 | |
805 if (auto_increment_ && !key_path_.IsNull()) { | |
806 callbacks_->OnSuccess(&value, *key, key_path_); | |
807 return; | |
808 } | |
809 | |
810 callbacks_->OnSuccess(&value); | |
811 return; | |
812 } | |
813 | |
814 // From here we are dealing only with indexes. | |
815 ok = backing_store_->GetPrimaryKeyViaIndex( | |
816 transaction->BackingStoreTransaction(), | |
817 database_id_, | |
818 object_store_id_, | |
819 index_id_, | |
820 *key, | |
821 &primary_key); | |
822 if (!ok) { | |
823 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
824 WebKit::WebIDBDatabaseExceptionUnknownError, | |
825 ASCIIToUTF16("Internal error in get_primary_key_via_index."))); | |
826 return; | |
827 } | |
828 if (!primary_key) { | |
829 callbacks_->OnSuccess(); | |
830 return; | |
831 } | |
832 if (cursor_type_ == indexed_db::CURSOR_KEY_ONLY) { | |
833 // Index Value Retrieval Operation | |
834 callbacks_->OnSuccess(*primary_key); | |
835 return; | |
836 } | |
837 | |
838 // Index Referenced Value Retrieval Operation | |
839 std::vector<char> value; | |
840 ok = backing_store_->GetRecord(transaction->BackingStoreTransaction(), | |
841 database_id_, | |
842 object_store_id_, | |
843 *primary_key, | |
844 value); | |
845 if (!ok) { | |
846 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
847 WebKit::WebIDBDatabaseExceptionUnknownError, | |
848 ASCIIToUTF16("Internal error in get_record."))); | |
849 return; | |
850 } | |
851 | |
852 if (value.empty()) { | |
853 callbacks_->OnSuccess(); | |
854 return; | |
855 } | |
856 if (auto_increment_ && !key_path_.IsNull()) { | |
857 callbacks_->OnSuccess(&value, *primary_key, key_path_); | |
858 return; | |
859 } | |
860 callbacks_->OnSuccess(&value); | |
861 } | |
862 | |
863 static scoped_ptr<IndexedDBKey> GenerateKey( | |
864 scoped_refptr<IndexedDBBackingStore> backing_store, | |
865 scoped_refptr<IndexedDBTransaction> transaction, | |
866 int64 database_id, | |
867 int64 object_store_id) { | |
868 const int64 max_generator_value = | |
869 9007199254740992LL; // Maximum integer storable as ECMAScript number. | |
870 int64 current_number; | |
871 bool ok = backing_store->GetKeyGeneratorCurrentNumber( | |
872 transaction->BackingStoreTransaction(), | |
873 database_id, | |
874 object_store_id, | |
875 current_number); | |
876 if (!ok) { | |
877 LOG(ERROR) << "Failed to get_key_generator_current_number"; | |
878 return make_scoped_ptr(new IndexedDBKey()); | |
879 } | |
880 if (current_number < 0 || current_number > max_generator_value) | |
881 return make_scoped_ptr(new IndexedDBKey()); | |
882 | |
883 return make_scoped_ptr( | |
884 new IndexedDBKey(current_number, WebIDBKey::NumberType)); | |
885 } | |
886 | |
887 static bool UpdateKeyGenerator( | |
888 scoped_refptr<IndexedDBBackingStore> backing_store, | |
889 scoped_refptr<IndexedDBTransaction> transaction, | |
890 int64 database_id, | |
891 int64 object_store_id, | |
892 const IndexedDBKey* key, | |
893 bool check_current) { | |
894 DCHECK(key && key->type() == WebIDBKey::NumberType); | |
895 return backing_store->MaybeUpdateKeyGeneratorCurrentNumber( | |
896 transaction->BackingStoreTransaction(), | |
897 database_id, | |
898 object_store_id, | |
899 static_cast<int64>(floor(key->number())) + 1, | |
900 check_current); | |
901 } | |
902 | |
903 void IndexedDBDatabaseImpl::Put( | |
904 int64 transaction_id, | |
905 int64 object_store_id, | |
906 std::vector<char>* value, | |
907 scoped_ptr<IndexedDBKey> key, | |
908 PutMode put_mode, | |
909 scoped_refptr<IndexedDBCallbacksWrapper> callbacks, | |
910 const std::vector<int64>& index_ids, | |
911 const std::vector<IndexKeys>& index_keys) { | |
912 IDB_TRACE("IndexedDBDatabaseImpl::put"); | |
913 TransactionMap::const_iterator trans_iterator = | |
914 transactions_.find(transaction_id); | |
915 if (trans_iterator == transactions_.end()) | |
916 return; | |
917 IndexedDBTransaction* transaction = trans_iterator->second; | |
918 DCHECK_NE(transaction->mode(), indexed_db::TRANSACTION_READ_ONLY); | |
919 | |
920 const IndexedDBObjectStoreMetadata object_store_metadata = | |
921 metadata_.object_stores[object_store_id]; | |
922 | |
923 DCHECK(key); | |
924 DCHECK(object_store_metadata.auto_increment || key->IsValid()); | |
925 transaction->ScheduleTask(new PutOperation(backing_store_, | |
926 id(), | |
927 object_store_metadata, | |
928 value, | |
929 key.Pass(), | |
930 put_mode, | |
931 callbacks, | |
932 index_ids, | |
933 index_keys)); | |
934 } | |
935 | |
936 void PutOperation::Perform(IndexedDBTransaction* transaction) { | |
937 IDB_TRACE("PutOperation"); | |
938 DCHECK_NE(transaction->mode(), indexed_db::TRANSACTION_READ_ONLY); | |
939 DCHECK_EQ(index_ids_.size(), index_keys_.size()); | |
940 bool key_was_generated = false; | |
941 | |
942 scoped_ptr<IndexedDBKey> key; | |
943 if (put_mode_ != IndexedDBDatabase::CURSOR_UPDATE && | |
944 object_store_.auto_increment && !key_->IsValid()) { | |
945 scoped_ptr<IndexedDBKey> auto_inc_key = GenerateKey( | |
946 backing_store_, transaction, database_id_, object_store_.id); | |
947 key_was_generated = true; | |
948 if (!auto_inc_key->IsValid()) { | |
949 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
950 WebKit::WebIDBDatabaseExceptionConstraintError, | |
951 ASCIIToUTF16("Maximum key generator value reached."))); | |
952 return; | |
953 } | |
954 key = auto_inc_key.Pass(); | |
955 } else { | |
956 key = key_.Pass(); | |
957 } | |
958 | |
959 DCHECK(key->IsValid()); | |
960 | |
961 IndexedDBBackingStore::RecordIdentifier record_identifier; | |
962 if (put_mode_ == IndexedDBDatabase::ADD_ONLY) { | |
963 bool found = false; | |
964 bool ok = backing_store_->KeyExistsInObjectStore( | |
965 transaction->BackingStoreTransaction(), | |
966 database_id_, | |
967 object_store_.id, | |
968 *key.get(), | |
969 &record_identifier, | |
970 found); | |
971 if (!ok) { | |
972 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
973 WebKit::WebIDBDatabaseExceptionUnknownError, | |
974 ASCIIToUTF16("Internal error checking key existence."))); | |
975 return; | |
976 } | |
977 if (found) { | |
978 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
979 WebKit::WebIDBDatabaseExceptionConstraintError, | |
980 ASCIIToUTF16("Key already exists in the object store."))); | |
981 return; | |
982 } | |
983 } | |
984 | |
985 ScopedVector<IndexedDBObjectStoreImpl::IndexWriter> index_writers; | |
986 string16 error_message; | |
987 bool obeys_constraints = false; | |
988 bool backing_store_success = | |
989 IndexedDBObjectStoreImpl::MakeIndexWriters(transaction, | |
990 backing_store_.get(), | |
991 database_id_, | |
992 object_store_, | |
993 *key, | |
994 key_was_generated, | |
995 index_ids_, | |
996 index_keys_, | |
997 &index_writers, | |
998 &error_message, | |
999 &obeys_constraints); | |
1000 if (!backing_store_success) { | |
1001 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
1002 WebKit::WebIDBDatabaseExceptionUnknownError, | |
1003 ASCIIToUTF16( | |
1004 "Internal error: backing store error updating index keys."))); | |
1005 return; | |
1006 } | |
1007 if (!obeys_constraints) { | |
1008 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
1009 WebKit::WebIDBDatabaseExceptionConstraintError, error_message)); | |
1010 return; | |
1011 } | |
1012 | |
1013 // Before this point, don't do any mutation. After this point, rollback the | |
1014 // transaction in case of error. | |
1015 backing_store_success = | |
1016 backing_store_->PutRecord(transaction->BackingStoreTransaction(), | |
1017 database_id_, | |
1018 object_store_.id, | |
1019 *key.get(), | |
1020 value_, | |
1021 &record_identifier); | |
1022 if (!backing_store_success) { | |
1023 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
1024 WebKit::WebIDBDatabaseExceptionUnknownError, | |
1025 ASCIIToUTF16( | |
1026 "Internal error: backing store error performing put/add."))); | |
1027 return; | |
1028 } | |
1029 | |
1030 for (size_t i = 0; i < index_writers.size(); ++i) { | |
1031 IndexedDBObjectStoreImpl::IndexWriter* index_writer = index_writers[i]; | |
1032 index_writer->WriteIndexKeys(record_identifier, | |
1033 backing_store_, | |
1034 transaction->BackingStoreTransaction(), | |
1035 database_id_, | |
1036 object_store_.id); | |
1037 } | |
1038 | |
1039 if (object_store_.auto_increment && | |
1040 put_mode_ != IndexedDBDatabase::CURSOR_UPDATE && | |
1041 key->type() == WebIDBKey::NumberType) { | |
1042 bool ok = UpdateKeyGenerator(backing_store_, | |
1043 transaction, | |
1044 database_id_, | |
1045 object_store_.id, | |
1046 key.get(), | |
1047 !key_was_generated); | |
1048 if (!ok) { | |
1049 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
1050 WebKit::WebIDBDatabaseExceptionUnknownError, | |
1051 ASCIIToUTF16("Internal error updating key generator."))); | |
1052 return; | |
1053 } | |
1054 } | |
1055 | |
1056 callbacks_->OnSuccess(*key); | |
1057 } | |
1058 | |
1059 void IndexedDBDatabaseImpl::SetIndexKeys( | |
1060 int64 transaction_id, | |
1061 int64 object_store_id, | |
1062 scoped_ptr<IndexedDBKey> primary_key, | |
1063 const std::vector<int64>& index_ids, | |
1064 const std::vector<IndexKeys>& index_keys) { | |
1065 IDB_TRACE("IndexedDBDatabaseImpl::set_index_keys"); | |
1066 TransactionMap::const_iterator trans_iterator = | |
1067 transactions_.find(transaction_id); | |
1068 if (trans_iterator == transactions_.end()) | |
1069 return; | |
1070 IndexedDBTransaction* transaction = trans_iterator->second; | |
1071 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); | |
1072 | |
1073 scoped_refptr<IndexedDBBackingStore> store = BackingStore(); | |
1074 // TODO(jsbell): This method could be asynchronous, but we need to | |
1075 // evaluate if it's worth the extra complexity. | |
1076 IndexedDBBackingStore::RecordIdentifier record_identifier; | |
1077 bool found = false; | |
1078 bool ok = | |
1079 store->KeyExistsInObjectStore(transaction->BackingStoreTransaction(), | |
1080 metadata_.id, | |
1081 object_store_id, | |
1082 *primary_key, | |
1083 &record_identifier, | |
1084 found); | |
1085 if (!ok) { | |
1086 transaction->Abort(IndexedDBDatabaseError::Create( | |
1087 WebKit::WebIDBDatabaseExceptionUnknownError, | |
1088 ASCIIToUTF16("Internal error setting index keys."))); | |
1089 return; | |
1090 } | |
1091 if (!found) { | |
1092 scoped_refptr<IndexedDBDatabaseError> error = | |
1093 IndexedDBDatabaseError::Create( | |
1094 WebKit::WebIDBDatabaseExceptionUnknownError, | |
1095 ASCIIToUTF16( | |
1096 "Internal error setting index keys for object store.")); | |
1097 transaction->Abort(error); | |
1098 return; | |
1099 } | |
1100 | |
1101 ScopedVector<IndexedDBObjectStoreImpl::IndexWriter> index_writers; | |
1102 string16 error_message; | |
1103 bool obeys_constraints = false; | |
1104 DCHECK(metadata_.object_stores.find(object_store_id) != | |
1105 metadata_.object_stores.end()); | |
1106 const IndexedDBObjectStoreMetadata& object_store_metadata = | |
1107 metadata_.object_stores[object_store_id]; | |
1108 bool backing_store_success = | |
1109 IndexedDBObjectStoreImpl::MakeIndexWriters(transaction, | |
1110 store.get(), | |
1111 id(), | |
1112 object_store_metadata, | |
1113 *primary_key, | |
1114 false, | |
1115 index_ids, | |
1116 index_keys, | |
1117 &index_writers, | |
1118 &error_message, | |
1119 &obeys_constraints); | |
1120 if (!backing_store_success) { | |
1121 transaction->Abort(IndexedDBDatabaseError::Create( | |
1122 WebKit::WebIDBDatabaseExceptionUnknownError, | |
1123 ASCIIToUTF16( | |
1124 "Internal error: backing store error updating index keys."))); | |
1125 return; | |
1126 } | |
1127 if (!obeys_constraints) { | |
1128 transaction->Abort(IndexedDBDatabaseError::Create( | |
1129 WebKit::WebIDBDatabaseExceptionConstraintError, error_message)); | |
1130 return; | |
1131 } | |
1132 | |
1133 for (size_t i = 0; i < index_writers.size(); ++i) { | |
1134 IndexedDBObjectStoreImpl::IndexWriter* index_writer = index_writers[i]; | |
1135 index_writer->WriteIndexKeys(record_identifier, | |
1136 store.get(), | |
1137 transaction->BackingStoreTransaction(), | |
1138 id(), | |
1139 object_store_id); | |
1140 } | |
1141 } | |
1142 | |
1143 void IndexedDBDatabaseImpl::SetIndexesReady( | |
1144 int64 transaction_id, | |
1145 int64, | |
1146 const std::vector<int64>& index_ids) { | |
1147 IDB_TRACE("IndexedDBObjectStoreImpl::set_indexes_ready"); | |
1148 | |
1149 TransactionMap::const_iterator trans_iterator = | |
1150 transactions_.find(transaction_id); | |
1151 if (trans_iterator == transactions_.end()) | |
1152 return; | |
1153 IndexedDBTransaction* transaction = trans_iterator->second; | |
1154 | |
1155 transaction->ScheduleTask(IndexedDBDatabase::PREEMPTIVE_TASK, | |
1156 new SetIndexesReadyOperation(index_ids.size())); | |
1157 } | |
1158 | |
1159 void SetIndexesReadyOperation::Perform(IndexedDBTransaction* transaction) { | |
1160 IDB_TRACE("SetIndexesReadyOperation"); | |
1161 for (size_t i = 0; i < index_count_; ++i) | |
1162 transaction->DidCompletePreemptiveEvent(); | |
1163 } | |
1164 | |
1165 void IndexedDBDatabaseImpl::OpenCursor( | |
1166 int64 transaction_id, | |
1167 int64 object_store_id, | |
1168 int64 index_id, | |
1169 scoped_ptr<IndexedDBKeyRange> key_range, | |
1170 indexed_db::CursorDirection direction, | |
1171 bool key_only, | |
1172 TaskType task_type, | |
1173 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
1174 IDB_TRACE("IndexedDBDatabaseImpl::open_cursor"); | |
1175 TransactionMap::const_iterator trans_iterator = | |
1176 transactions_.find(transaction_id); | |
1177 if (trans_iterator == transactions_.end()) | |
1178 return; | |
1179 IndexedDBTransaction* transaction = trans_iterator->second; | |
1180 | |
1181 transaction->ScheduleTask(new OpenCursorOperation( | |
1182 backing_store_, | |
1183 id(), | |
1184 object_store_id, | |
1185 index_id, | |
1186 key_range.Pass(), | |
1187 direction, | |
1188 key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE, | |
1189 task_type, | |
1190 callbacks)); | |
1191 } | |
1192 | |
1193 void OpenCursorOperation::Perform(IndexedDBTransaction* transaction) { | |
1194 IDB_TRACE("OpenCursorOperation"); | |
1195 | |
1196 // The frontend has begun indexing, so this pauses the transaction | |
1197 // until the indexing is complete. This can't happen any earlier | |
1198 // because we don't want to switch to early mode in case multiple | |
1199 // indexes are being created in a row, with Put()'s in between. | |
1200 if (task_type_ == IndexedDBDatabase::PREEMPTIVE_TASK) | |
1201 transaction->AddPreemptiveEvent(); | |
1202 | |
1203 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor; | |
1204 if (index_id_ == IndexedDBIndexMetadata::kInvalidId) { | |
1205 DCHECK_NE(cursor_type_, indexed_db::CURSOR_KEY_ONLY); | |
1206 backing_store_cursor = backing_store_->OpenObjectStoreCursor( | |
1207 transaction->BackingStoreTransaction(), | |
1208 database_id_, | |
1209 object_store_id_, | |
1210 *key_range_, | |
1211 direction_); | |
1212 } else { | |
1213 DCHECK_EQ(task_type_, IndexedDBDatabase::NORMAL_TASK); | |
1214 if (cursor_type_ == indexed_db::CURSOR_KEY_ONLY) { | |
1215 backing_store_cursor = backing_store_->OpenIndexKeyCursor( | |
1216 transaction->BackingStoreTransaction(), | |
1217 database_id_, | |
1218 object_store_id_, | |
1219 index_id_, | |
1220 *key_range_, | |
1221 direction_); | |
1222 } else { | |
1223 backing_store_cursor = backing_store_->OpenIndexCursor( | |
1224 transaction->BackingStoreTransaction(), | |
1225 database_id_, | |
1226 object_store_id_, | |
1227 index_id_, | |
1228 *key_range_, | |
1229 direction_); | |
1230 } | |
1231 } | |
1232 | |
1233 if (!backing_store_cursor) { | |
1234 callbacks_->OnSuccess(static_cast<std::vector<char>*>(NULL)); | |
1235 return; | |
1236 } | |
1237 | |
1238 IndexedDBDatabase::TaskType task_type( | |
1239 static_cast<IndexedDBDatabase::TaskType>(task_type_)); | |
1240 scoped_refptr<IndexedDBCursorImpl> cursor = | |
1241 IndexedDBCursorImpl::Create(backing_store_cursor.Pass(), | |
1242 cursor_type_, | |
1243 task_type, | |
1244 transaction, | |
1245 object_store_id_); | |
1246 callbacks_->OnSuccess( | |
1247 cursor, cursor->key(), cursor->primary_key(), cursor->Value()); | |
1248 } | |
1249 | |
1250 void IndexedDBDatabaseImpl::Count( | |
1251 int64 transaction_id, | |
1252 int64 object_store_id, | |
1253 int64 index_id, | |
1254 scoped_ptr<IndexedDBKeyRange> key_range, | |
1255 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
1256 IDB_TRACE("IndexedDBDatabaseImpl::count"); | |
1257 TransactionMap::const_iterator trans_iterator = | |
1258 transactions_.find(transaction_id); | |
1259 if (trans_iterator == transactions_.end()) | |
1260 return; | |
1261 IndexedDBTransaction* transaction = trans_iterator->second; | |
1262 | |
1263 DCHECK(metadata_.object_stores.find(object_store_id) != | |
1264 metadata_.object_stores.end()); | |
1265 transaction->ScheduleTask(new CountOperation(backing_store_, | |
1266 id(), | |
1267 object_store_id, | |
1268 index_id, | |
1269 key_range.Pass(), | |
1270 callbacks)); | |
1271 } | |
1272 | |
1273 void CountOperation::Perform(IndexedDBTransaction* transaction) { | |
1274 IDB_TRACE("CountOperation"); | |
1275 uint32 count = 0; | |
1276 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor; | |
1277 | |
1278 if (index_id_ == IndexedDBIndexMetadata::kInvalidId) { | |
1279 backing_store_cursor = backing_store_->OpenObjectStoreKeyCursor( | |
1280 transaction->BackingStoreTransaction(), | |
1281 database_id_, | |
1282 object_store_id_, | |
1283 *key_range_, | |
1284 indexed_db::CURSOR_NEXT); | |
1285 } else { | |
1286 backing_store_cursor = backing_store_->OpenIndexKeyCursor( | |
1287 transaction->BackingStoreTransaction(), | |
1288 database_id_, | |
1289 object_store_id_, | |
1290 index_id_, | |
1291 *key_range_, | |
1292 indexed_db::CURSOR_NEXT); | |
1293 } | |
1294 if (!backing_store_cursor) { | |
1295 callbacks_->OnSuccess(count); | |
1296 return; | |
1297 } | |
1298 | |
1299 do { | |
1300 ++count; | |
1301 } while (backing_store_cursor->ContinueFunction(0)); | |
1302 | |
1303 callbacks_->OnSuccess(count); | |
1304 } | |
1305 | |
1306 void IndexedDBDatabaseImpl::DeleteRange( | |
1307 int64 transaction_id, | |
1308 int64 object_store_id, | |
1309 scoped_ptr<IndexedDBKeyRange> key_range, | |
1310 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
1311 IDB_TRACE("IndexedDBDatabaseImpl::delete_range"); | |
1312 TransactionMap::const_iterator trans_iterator = | |
1313 transactions_.find(transaction_id); | |
1314 if (trans_iterator == transactions_.end()) | |
1315 return; | |
1316 IndexedDBTransaction* transaction = trans_iterator->second; | |
1317 | |
1318 transaction->ScheduleTask(new DeleteRangeOperation( | |
1319 backing_store_, id(), object_store_id, key_range.Pass(), callbacks)); | |
1320 } | |
1321 | |
1322 void DeleteRangeOperation::Perform(IndexedDBTransaction* transaction) { | |
1323 IDB_TRACE("DeleteRangeOperation"); | |
1324 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor = | |
1325 backing_store_->OpenObjectStoreCursor( | |
1326 transaction->BackingStoreTransaction(), | |
1327 database_id_, | |
1328 object_store_id_, | |
1329 *key_range_, | |
1330 indexed_db::CURSOR_NEXT); | |
1331 if (backing_store_cursor) { | |
1332 do { | |
1333 if (!backing_store_->DeleteRecord( | |
1334 transaction->BackingStoreTransaction(), | |
1335 database_id_, | |
1336 object_store_id_, | |
1337 backing_store_cursor->record_identifier())) { | |
1338 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
1339 WebKit::WebIDBDatabaseExceptionUnknownError, | |
1340 ASCIIToUTF16("Internal error deleting data in range"))); | |
1341 return; | |
1342 } | |
1343 } while (backing_store_cursor->ContinueFunction(0)); | |
1344 } | |
1345 | |
1346 callbacks_->OnSuccess(); | |
1347 } | |
1348 | |
1349 void IndexedDBDatabaseImpl::Clear( | |
1350 int64 transaction_id, | |
1351 int64 object_store_id, | |
1352 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
1353 IDB_TRACE("IndexedDBDatabaseImpl::clear"); | |
1354 TransactionMap::const_iterator trans_iterator = | |
1355 transactions_.find(transaction_id); | |
1356 if (trans_iterator == transactions_.end()) | |
1357 return; | |
1358 IndexedDBTransaction* transaction = trans_iterator->second; | |
1359 DCHECK_NE(transaction->mode(), indexed_db::TRANSACTION_READ_ONLY); | |
1360 | |
1361 transaction->ScheduleTask( | |
1362 new ClearOperation(backing_store_, id(), object_store_id, callbacks)); | |
1363 } | |
1364 | |
1365 void ClearOperation::Perform(IndexedDBTransaction* transaction) { | |
1366 IDB_TRACE("ObjectStoreClearOperation"); | |
1367 if (!backing_store_->ClearObjectStore(transaction->BackingStoreTransaction(), | |
1368 database_id_, | |
1369 object_store_id_)) { | |
1370 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
1371 WebKit::WebIDBDatabaseExceptionUnknownError, | |
1372 ASCIIToUTF16("Internal error clearing object store"))); | |
1373 return; | |
1374 } | |
1375 callbacks_->OnSuccess(); | |
1376 } | |
1377 | |
1378 void DeleteObjectStoreOperation::Perform(IndexedDBTransaction* transaction) { | |
1379 IDB_TRACE("DeleteObjectStoreOperation"); | |
1380 bool ok = | |
1381 backing_store_->DeleteObjectStore(transaction->BackingStoreTransaction(), | |
1382 transaction->database()->id(), | |
1383 object_store_metadata_.id); | |
1384 if (!ok) { | |
1385 string16 error_string = | |
1386 ASCIIToUTF16("Internal error deleting object store '") + | |
1387 object_store_metadata_.name + ASCIIToUTF16("'."); | |
1388 scoped_refptr<IndexedDBDatabaseError> error = | |
1389 IndexedDBDatabaseError::Create( | |
1390 WebKit::WebIDBDatabaseExceptionUnknownError, error_string); | |
1391 transaction->Abort(error); | |
1392 } | |
1393 } | |
1394 | |
1395 void IndexedDBDatabaseImpl::VersionChangeOperation::Perform( | |
1396 IndexedDBTransaction* transaction) { | |
1397 IDB_TRACE("VersionChangeOperation"); | |
1398 int64 database_id = database_->id(); | |
1399 int64 old_version = database_->metadata_.int_version; | |
1400 DCHECK_GT(version_, old_version); | |
1401 database_->metadata_.int_version = version_; | |
1402 if (!database_->backing_store_->UpdateIDBDatabaseIntVersion( | |
1403 transaction->BackingStoreTransaction(), | |
1404 database_id, | |
1405 database_->metadata_.int_version)) { | |
1406 scoped_refptr<IndexedDBDatabaseError> error = | |
1407 IndexedDBDatabaseError::Create( | |
1408 WebKit::WebIDBDatabaseExceptionUnknownError, | |
1409 ASCIIToUTF16("Internal error writing data to stable storage when " | |
1410 "updating version.")); | |
1411 callbacks_->OnError(error); | |
1412 transaction->Abort(error); | |
1413 return; | |
1414 } | |
1415 DCHECK(!database_->pending_second_half_open_); | |
1416 database_->pending_second_half_open_.reset(new PendingOpenCall( | |
1417 callbacks_, database_callbacks_, transaction_id_, version_)); | |
1418 callbacks_->OnUpgradeNeeded(old_version, database_, database_->metadata()); | |
1419 } | |
1420 | |
1421 void IndexedDBDatabaseImpl::TransactionStarted( | |
1422 IndexedDBTransaction* transaction) { | |
1423 | |
1424 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) { | |
1425 DCHECK(!running_version_change_transaction_); | |
1426 running_version_change_transaction_ = transaction; | |
1427 } | |
1428 } | |
1429 | |
1430 void IndexedDBDatabaseImpl::TransactionFinished( | |
1431 IndexedDBTransaction* transaction) { | |
1432 | |
1433 DCHECK(transactions_.find(transaction->id()) != transactions_.end()); | |
1434 DCHECK_EQ(transactions_[transaction->id()], transaction); | |
1435 transactions_.erase(transaction->id()); | |
1436 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) { | |
1437 DCHECK_EQ(transaction, running_version_change_transaction_); | |
1438 running_version_change_transaction_ = NULL; | |
1439 } | |
1440 } | |
1441 | |
1442 void IndexedDBDatabaseImpl::TransactionFinishedAndAbortFired( | |
1443 IndexedDBTransaction* transaction) { | |
1444 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) { | |
1445 if (pending_second_half_open_) { | |
1446 pending_second_half_open_->Callbacks() | |
1447 ->OnError(IndexedDBDatabaseError::Create( | |
1448 WebKit::WebIDBDatabaseExceptionAbortError, | |
1449 ASCIIToUTF16("Version change transaction was aborted in " | |
1450 "upgradeneeded event handler."))); | |
1451 pending_second_half_open_.reset(); | |
1452 } | |
1453 ProcessPendingCalls(); | |
1454 } | |
1455 } | |
1456 | |
1457 void IndexedDBDatabaseImpl::TransactionFinishedAndCompleteFired( | |
1458 IndexedDBTransaction* transaction) { | |
1459 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) { | |
1460 DCHECK(pending_second_half_open_); | |
1461 if (pending_second_half_open_) { | |
1462 DCHECK_EQ(pending_second_half_open_->Version(), metadata_.int_version); | |
1463 DCHECK(metadata_.id != kInvalidId); | |
1464 pending_second_half_open_->Callbacks()->OnSuccess(this, this->metadata()); | |
1465 pending_second_half_open_.reset(); | |
1466 } | |
1467 ProcessPendingCalls(); | |
1468 } | |
1469 } | |
1470 | |
1471 size_t IndexedDBDatabaseImpl::ConnectionCount() const { | |
1472 // This does not include pending open calls, as those should not block version | |
1473 // changes and deletes. | |
1474 return database_callbacks_set_.size(); | |
1475 } | |
1476 | |
1477 void IndexedDBDatabaseImpl::ProcessPendingCalls() { | |
1478 if (pending_second_half_open_) { | |
1479 DCHECK_EQ(pending_second_half_open_->Version(), metadata_.int_version); | |
1480 DCHECK(metadata_.id != kInvalidId); | |
1481 scoped_ptr<PendingOpenCall> pending_call = pending_second_half_open_.Pass(); | |
1482 pending_call->Callbacks()->OnSuccess(this, this->metadata()); | |
1483 // Fall through when complete, as pending opens may be unblocked. | |
1484 } | |
1485 | |
1486 if (pending_run_version_change_transaction_call_ && ConnectionCount() == 1) { | |
1487 DCHECK(pending_run_version_change_transaction_call_->Version() > | |
1488 metadata_.int_version); | |
1489 scoped_ptr<PendingOpenCall> pending_call = | |
1490 pending_run_version_change_transaction_call_.Pass(); | |
1491 RunVersionChangeTransactionFinal(pending_call->Callbacks(), | |
1492 pending_call->DatabaseCallbacks(), | |
1493 pending_call->TransactionId(), | |
1494 pending_call->Version()); | |
1495 DCHECK_EQ(static_cast<size_t>(1), ConnectionCount()); | |
1496 // Fall through would be a no-op, since transaction must complete | |
1497 // asynchronously. | |
1498 DCHECK(IsDeleteDatabaseBlocked()); | |
1499 DCHECK(IsOpenConnectionBlocked()); | |
1500 return; | |
1501 } | |
1502 | |
1503 if (!IsDeleteDatabaseBlocked()) { | |
1504 PendingDeleteCallList pending_delete_calls; | |
1505 pending_delete_calls_.swap(pending_delete_calls); | |
1506 while (!pending_delete_calls.empty()) { | |
1507 // Only the first delete call will delete the database, but each must fire | |
1508 // callbacks. | |
1509 scoped_ptr<PendingDeleteCall> pending_delete_call( | |
1510 pending_delete_calls.front()); | |
1511 pending_delete_calls.pop_front(); | |
1512 DeleteDatabaseFinal(pending_delete_call->Callbacks()); | |
1513 } | |
1514 // delete_database_final should never re-queue calls. | |
1515 DCHECK(pending_delete_calls_.empty()); | |
1516 // Fall through when complete, as pending opens may be unblocked. | |
1517 } | |
1518 | |
1519 if (!IsOpenConnectionBlocked()) { | |
1520 PendingOpenCallList pending_open_calls; | |
1521 pending_open_calls_.swap(pending_open_calls); | |
1522 while (!pending_open_calls.empty()) { | |
1523 scoped_ptr<PendingOpenCall> pending_open_call(pending_open_calls.front()); | |
1524 pending_open_calls.pop_front(); | |
1525 OpenConnection(pending_open_call->Callbacks(), | |
1526 pending_open_call->DatabaseCallbacks(), | |
1527 pending_open_call->TransactionId(), | |
1528 pending_open_call->Version()); | |
1529 } | |
1530 } | |
1531 } | |
1532 | |
1533 void IndexedDBDatabaseImpl::CreateTransaction( | |
1534 int64 transaction_id, | |
1535 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> callbacks, | |
1536 const std::vector<int64>& object_store_ids, | |
1537 uint16 mode) { | |
1538 | |
1539 DCHECK(database_callbacks_set_.has(callbacks)); | |
1540 | |
1541 scoped_refptr<IndexedDBTransaction> transaction = | |
1542 IndexedDBTransaction::Create( | |
1543 transaction_id, | |
1544 callbacks, | |
1545 object_store_ids, | |
1546 static_cast<indexed_db::TransactionMode>(mode), | |
1547 this); | |
1548 DCHECK(transactions_.find(transaction_id) == transactions_.end()); | |
1549 transactions_[transaction_id] = transaction; | |
1550 } | |
1551 | |
1552 bool IndexedDBDatabaseImpl::IsOpenConnectionBlocked() const { | |
1553 return !pending_delete_calls_.empty() || | |
1554 running_version_change_transaction_ || | |
1555 pending_run_version_change_transaction_call_; | |
1556 } | |
1557 | |
1558 void IndexedDBDatabaseImpl::OpenConnection( | |
1559 scoped_refptr<IndexedDBCallbacksWrapper> callbacks, | |
1560 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks, | |
1561 int64 transaction_id, | |
1562 int64 version) { | |
1563 DCHECK(backing_store_.get()); | |
1564 | |
1565 // TODO(jsbell): Should have a priority queue so that higher version | |
1566 // requests are processed first. http://crbug.com/225850 | |
1567 if (IsOpenConnectionBlocked()) { | |
1568 pending_open_calls_.push_back(new PendingOpenCall( | |
1569 callbacks, database_callbacks, transaction_id, version)); | |
1570 return; | |
1571 } | |
1572 | |
1573 if (metadata_.id == kInvalidId) { | |
1574 // The database was deleted then immediately re-opened; OpenInternal() | |
1575 // recreates it in the backing store. | |
1576 if (OpenInternal()) { | |
1577 DCHECK_EQ(metadata_.int_version, | |
1578 IndexedDBDatabaseMetadata::NO_INT_VERSION); | |
1579 } else { | |
1580 string16 message; | |
1581 scoped_refptr<IndexedDBDatabaseError> error; | |
1582 if (version == IndexedDBDatabaseMetadata::NO_INT_VERSION) | |
1583 message = ASCIIToUTF16( | |
1584 "Internal error opening database with no version specified."); | |
1585 else | |
1586 message = | |
1587 ASCIIToUTF16("Internal error opening database with version ") + | |
1588 Int64ToString16(version); | |
1589 callbacks->OnError(IndexedDBDatabaseError::Create( | |
1590 WebKit::WebIDBDatabaseExceptionUnknownError, message)); | |
1591 return; | |
1592 } | |
1593 } | |
1594 | |
1595 // We infer that the database didn't exist from its lack of either type of | |
1596 // version. | |
1597 bool is_new_database = | |
1598 metadata_.version == kNoStringVersion && | |
1599 metadata_.int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION; | |
1600 | |
1601 if (version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) { | |
1602 // For unit tests only - skip upgrade steps. Calling from script with | |
1603 // DEFAULT_INT_VERSION throws exception. | |
1604 // TODO(jsbell): Assert that we're executing a unit test. | |
1605 DCHECK(is_new_database); | |
1606 database_callbacks_set_.insert(database_callbacks); | |
1607 callbacks->OnSuccess(this, this->metadata()); | |
1608 return; | |
1609 } | |
1610 | |
1611 if (version == IndexedDBDatabaseMetadata::NO_INT_VERSION) { | |
1612 if (!is_new_database) { | |
1613 database_callbacks_set_.insert(database_callbacks); | |
1614 callbacks->OnSuccess(this, this->metadata()); | |
1615 return; | |
1616 } | |
1617 // Spec says: If no version is specified and no database exists, set | |
1618 // database version to 1. | |
1619 version = 1; | |
1620 } | |
1621 | |
1622 if (version > metadata_.int_version) { | |
1623 database_callbacks_set_.insert(database_callbacks); | |
1624 RunVersionChangeTransaction( | |
1625 callbacks, database_callbacks, transaction_id, version); | |
1626 return; | |
1627 } | |
1628 if (version < metadata_.int_version) { | |
1629 callbacks->OnError(IndexedDBDatabaseError::Create( | |
1630 WebKit::WebIDBDatabaseExceptionVersionError, | |
1631 ASCIIToUTF16("The requested version (") + Int64ToString16(version) + | |
1632 ASCIIToUTF16(") is less than the existing version (") + | |
1633 Int64ToString16(metadata_.int_version) + ASCIIToUTF16(")."))); | |
1634 return; | |
1635 } | |
1636 DCHECK_EQ(version, metadata_.int_version); | |
1637 database_callbacks_set_.insert(database_callbacks); | |
1638 callbacks->OnSuccess(this, this->metadata()); | |
1639 } | |
1640 | |
1641 void IndexedDBDatabaseImpl::RunVersionChangeTransaction( | |
1642 scoped_refptr<IndexedDBCallbacksWrapper> callbacks, | |
1643 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks, | |
1644 int64 transaction_id, | |
1645 int64 requested_version) { | |
1646 | |
1647 DCHECK(callbacks); | |
1648 DCHECK(database_callbacks_set_.has(database_callbacks)); | |
1649 if (ConnectionCount() > 1) { | |
1650 // Front end ensures the event is not fired at connections that have | |
1651 // close_pending set. | |
1652 for (DatabaseCallbacksSet::const_iterator it = | |
1653 database_callbacks_set_.begin(); | |
1654 it != database_callbacks_set_.end(); | |
1655 ++it) { | |
1656 if (*it != database_callbacks.get()) | |
1657 (*it)->OnVersionChange(metadata_.int_version, requested_version); | |
1658 } | |
1659 // TODO(jsbell): Remove the call to on_blocked and instead wait | |
1660 // until the frontend tells us that all the "versionchange" events | |
1661 // have been delivered. http://crbug.com/100123 | |
1662 callbacks->OnBlocked(metadata_.int_version); | |
1663 | |
1664 DCHECK(!pending_run_version_change_transaction_call_); | |
1665 pending_run_version_change_transaction_call_.reset(new PendingOpenCall( | |
1666 callbacks, database_callbacks, transaction_id, requested_version)); | |
1667 return; | |
1668 } | |
1669 RunVersionChangeTransactionFinal( | |
1670 callbacks, database_callbacks, transaction_id, requested_version); | |
1671 } | |
1672 | |
1673 void IndexedDBDatabaseImpl::RunVersionChangeTransactionFinal( | |
1674 scoped_refptr<IndexedDBCallbacksWrapper> callbacks, | |
1675 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks, | |
1676 int64 transaction_id, | |
1677 int64 requested_version) { | |
1678 | |
1679 std::vector<int64> object_store_ids; | |
1680 CreateTransaction(transaction_id, | |
1681 database_callbacks, | |
1682 object_store_ids, | |
1683 indexed_db::TRANSACTION_VERSION_CHANGE); | |
1684 scoped_refptr<IndexedDBTransaction> transaction = | |
1685 transactions_[transaction_id]; | |
1686 | |
1687 transaction->ScheduleTask( | |
1688 new VersionChangeOperation(this, | |
1689 transaction_id, | |
1690 requested_version, | |
1691 callbacks, | |
1692 database_callbacks), | |
1693 new VersionChangeAbortOperation( | |
1694 this, metadata_.version, metadata_.int_version)); | |
1695 | |
1696 DCHECK(!pending_second_half_open_); | |
1697 } | |
1698 | |
1699 void IndexedDBDatabaseImpl::DeleteDatabase( | |
1700 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
1701 | |
1702 if (IsDeleteDatabaseBlocked()) { | |
1703 for (DatabaseCallbacksSet::const_iterator it = | |
1704 database_callbacks_set_.begin(); | |
1705 it != database_callbacks_set_.end(); | |
1706 ++it) { | |
1707 // Front end ensures the event is not fired at connections that have | |
1708 // close_pending set. | |
1709 (*it)->OnVersionChange(metadata_.int_version, | |
1710 IndexedDBDatabaseMetadata::NO_INT_VERSION); | |
1711 } | |
1712 // TODO(jsbell): Only fire on_blocked if there are open | |
1713 // connections after the VersionChangeEvents are received, not | |
1714 // just set up to fire. http://crbug.com/100123 | |
1715 callbacks->OnBlocked(metadata_.int_version); | |
1716 pending_delete_calls_.push_back(new PendingDeleteCall(callbacks)); | |
1717 return; | |
1718 } | |
1719 DeleteDatabaseFinal(callbacks); | |
1720 } | |
1721 | |
1722 bool IndexedDBDatabaseImpl::IsDeleteDatabaseBlocked() const { | |
1723 return !!ConnectionCount(); | |
1724 } | |
1725 | |
1726 void IndexedDBDatabaseImpl::DeleteDatabaseFinal( | |
1727 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
1728 DCHECK(!IsDeleteDatabaseBlocked()); | |
1729 DCHECK(backing_store_); | |
1730 if (!backing_store_->DeleteDatabase(metadata_.name)) { | |
1731 callbacks->OnError(IndexedDBDatabaseError::Create( | |
1732 WebKit::WebIDBDatabaseExceptionUnknownError, | |
1733 ASCIIToUTF16("Internal error deleting database."))); | |
1734 return; | |
1735 } | |
1736 metadata_.version = kNoStringVersion; | |
1737 metadata_.id = kInvalidId; | |
1738 metadata_.int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION; | |
1739 metadata_.object_stores.clear(); | |
1740 callbacks->OnSuccess(); | |
1741 } | |
1742 | |
1743 void IndexedDBDatabaseImpl::Close( | |
1744 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> callbacks) { | |
1745 DCHECK(callbacks); | |
1746 DCHECK(database_callbacks_set_.has(callbacks)); | |
1747 | |
1748 // Close outstanding transactions from the closing connection. This | |
1749 // can not happen if the close is requested by the connection itself | |
1750 // as the front-end defers the close until all transactions are | |
1751 // complete, so something unusual has happened e.g. unexpected | |
1752 // process termination. | |
1753 { | |
1754 TransactionMap transactions(transactions_); | |
1755 for (TransactionMap::const_iterator it = transactions.begin(), | |
1756 end = transactions.end(); | |
1757 it != end; | |
1758 ++it) { | |
1759 if (it->second->connection() == callbacks) | |
1760 it->second->Abort(IndexedDBDatabaseError::Create( | |
1761 WebKit::WebIDBDatabaseExceptionUnknownError, | |
1762 ASCIIToUTF16("Connection is closing."))); | |
1763 } | |
1764 } | |
1765 | |
1766 database_callbacks_set_.erase(callbacks); | |
1767 if (pending_second_half_open_ && | |
1768 pending_second_half_open_->DatabaseCallbacks() == callbacks) { | |
1769 pending_second_half_open_->Callbacks() | |
1770 ->OnError(IndexedDBDatabaseError::Create( | |
1771 WebKit::WebIDBDatabaseExceptionAbortError, | |
1772 ASCIIToUTF16("The connection was closed."))); | |
1773 pending_second_half_open_.reset(); | |
1774 } | |
1775 | |
1776 // process_pending_calls allows the inspector to process a pending open call | |
1777 // and call close, reentering IndexedDBDatabaseImpl::close. Then the | |
1778 // backend would be removed both by the inspector closing its connection, and | |
1779 // by the connection that first called close. | |
1780 // To avoid that situation, don't proceed in case of reentrancy. | |
1781 if (closing_connection_) | |
1782 return; | |
1783 base::AutoReset<bool> ClosingConnection(&closing_connection_, true); | |
1784 ProcessPendingCalls(); | |
1785 | |
1786 // TODO(jsbell): Add a test for the pending_open_calls_ cases below. | |
1787 if (!ConnectionCount() && !pending_open_calls_.size() && | |
1788 !pending_delete_calls_.size()) { | |
1789 DCHECK(transactions_.empty()); | |
1790 | |
1791 backing_store_ = NULL; | |
1792 | |
1793 // This check should only be false in unit tests. | |
1794 // TODO(jsbell): Assert factory_ || we're executing a unit test. | |
1795 if (factory_) | |
1796 factory_->RemoveIDBDatabaseBackend(identifier_); | |
1797 } | |
1798 } | |
1799 | |
1800 void CreateObjectStoreAbortOperation::Perform( | |
1801 IndexedDBTransaction* transaction) { | |
1802 IDB_TRACE("CreateObjectStoreAbortOperation"); | |
1803 DCHECK(!transaction); | |
1804 database_->RemoveObjectStore(object_store_id_); | |
1805 } | |
1806 | |
1807 void DeleteObjectStoreAbortOperation::Perform( | |
1808 IndexedDBTransaction* transaction) { | |
1809 IDB_TRACE("DeleteObjectStoreAbortOperation"); | |
1810 DCHECK(!transaction); | |
1811 database_->AddObjectStore(object_store_metadata_, | |
1812 IndexedDBObjectStoreMetadata::kInvalidId); | |
1813 } | |
1814 | |
1815 void IndexedDBDatabaseImpl::VersionChangeAbortOperation::Perform( | |
1816 IndexedDBTransaction* transaction) { | |
1817 IDB_TRACE("VersionChangeAbortOperation"); | |
1818 DCHECK(!transaction); | |
1819 database_->metadata_.version = previous_version_; | |
1820 database_->metadata_.int_version = previous_int_version_; | |
1821 } | |
1822 | |
1823 } // namespace content | |
OLD | NEW |