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_t transaction_id, | |
64 int64_t 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_t transaction_id_; | |
77 int64_t 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_t 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_t 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_t 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_t previous_int_version_; | |
122 }; | |
123 | |
124 class CreateIndexOperation : public IndexedDBTransaction::Operation { | |
125 public: | |
126 CreateIndexOperation(scoped_refptr<IndexedDBBackingStore> backing_store, | |
127 int64_t 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_t 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_t 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_t 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_t object_store_id, | |
160 int64_t 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_t object_store_id_; | |
169 const int64_t index_id_; | |
170 }; | |
171 | |
172 class DeleteIndexAbortOperation : public IndexedDBTransaction::Operation { | |
173 public: | |
174 DeleteIndexAbortOperation(scoped_refptr<IndexedDBDatabaseImpl> database, | |
175 int64_t 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_t 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_t object_store_id, | |
193 int64_t 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_t database_id_; | |
218 const int64_t object_store_id_; | |
219 const int64_t 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_t 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_t>& 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_t 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_t> 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_t database_id, | |
276 int64_t object_store_id, | |
277 int64_t 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_t database_id_; | |
297 const int64_t object_store_id_; | |
298 const int64_t 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_t database_id, | |
310 int64_t object_store_id, | |
311 int64_t 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_t database_id_; | |
325 const int64_t object_store_id_; | |
326 const int64_t 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_t database_id, | |
335 int64_t 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_t database_id_; | |
348 const int64_t 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_t database_id, | |
357 int64_t 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_t database_id_; | |
368 const int64_t 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_t transaction_id, | |
378 int64_t 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_t Version() { return version_; } | |
388 int64_t TransactionId() const { return transaction_id_; } | |
389 | |
390 private: | |
391 scoped_refptr<IndexedDBCallbacksWrapper> callbacks_; | |
392 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks_; | |
393 int64_t version_; | |
394 const int64_t 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_t 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(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_t 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_t object_store_id, | |
460 const IndexedDBIndexMetadata& index, | |
461 int64_t 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(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_t object_store_id, | |
477 int64_t index_id) { | |
478 DCHECK(metadata_.object_stores.find(object_store_id) != | |
479 metadata_.object_stores.end()); | |
480 IndexedDBObjectStoreMetadata object_store = | |
481 metadata_.object_stores[object_store_id]; | |
482 | |
483 DCHECK(object_store.indexes.find(index_id) != object_store.indexes.end()); | |
484 object_store.indexes.erase(index_id); | |
485 metadata_.object_stores[object_store_id] = object_store; | |
486 } | |
487 | |
488 bool IndexedDBDatabaseImpl::OpenInternal() { | |
489 bool success = false; | |
490 bool ok = backing_store_->GetIDBDatabaseMetaData( | |
491 metadata_.name, &metadata_, success); | |
492 DCHECK(success == (metadata_.id != kInvalidId)) << "success = " << success | |
493 << " id_ = " << metadata_.id; | |
494 if (!ok) | |
495 return false; | |
496 if (success) | |
497 return backing_store_->GetObjectStores(metadata_.id, | |
498 &metadata_.object_stores); | |
499 | |
500 return backing_store_->CreateIDBDatabaseMetaData( | |
501 metadata_.name, metadata_.version, metadata_.int_version, metadata_.id); | |
502 } | |
503 | |
504 IndexedDBDatabaseImpl::~IndexedDBDatabaseImpl() { | |
505 DCHECK(transactions_.empty()); | |
506 DCHECK(pending_open_calls_.empty()); | |
507 DCHECK(pending_delete_calls_.empty()); | |
508 } | |
509 | |
510 scoped_refptr<IndexedDBBackingStore> IndexedDBDatabaseImpl::BackingStore() | |
511 const { | |
512 return backing_store_; | |
513 } | |
514 | |
515 void IndexedDBDatabaseImpl::CreateObjectStore(int64_t transaction_id, | |
516 int64_t object_store_id, | |
517 const string16& name, | |
518 const IndexedDBKeyPath& key_path, | |
519 bool auto_increment) { | |
520 IDB_TRACE("IndexedDBDatabaseImpl::create_object_store"); | |
521 TransactionMap::const_iterator trans_iterator = | |
522 transactions_.find(transaction_id); | |
523 if (trans_iterator == transactions_.end()) | |
524 return; | |
525 IndexedDBTransaction* transaction = trans_iterator->second; | |
526 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); | |
527 | |
528 DCHECK(metadata_.object_stores.find(object_store_id) == | |
529 metadata_.object_stores.end()); | |
530 IndexedDBObjectStoreMetadata object_store_metadata( | |
531 name, | |
532 object_store_id, | |
533 key_path, | |
534 auto_increment, | |
535 IndexedDBDatabase::kMinimumIndexId); | |
536 | |
537 transaction->ScheduleTask( | |
538 new CreateObjectStoreOperation(backing_store_, object_store_metadata), | |
539 new CreateObjectStoreAbortOperation(this, object_store_id)); | |
540 | |
541 AddObjectStore(object_store_metadata, object_store_id); | |
542 } | |
543 | |
544 void CreateObjectStoreOperation::Perform(IndexedDBTransaction* transaction) { | |
545 IDB_TRACE("CreateObjectStoreOperation"); | |
546 if (!backing_store_->CreateObjectStore( | |
547 transaction->BackingStoreTransaction(), | |
548 transaction->database()->id(), | |
549 object_store_metadata_.id, | |
550 object_store_metadata_.name, | |
551 object_store_metadata_.key_path, | |
552 object_store_metadata_.auto_increment)) { | |
553 string16 error_string = | |
554 ASCIIToUTF16("Internal error creating object store '") + | |
555 object_store_metadata_.name + ASCIIToUTF16("'."); | |
556 | |
557 scoped_refptr<IndexedDBDatabaseError> error = | |
558 IndexedDBDatabaseError::Create( | |
559 WebKit::WebIDBDatabaseExceptionUnknownError, error_string); | |
560 transaction->Abort(error); | |
561 return; | |
562 } | |
563 } | |
564 | |
565 void IndexedDBDatabaseImpl::DeleteObjectStore(int64_t transaction_id, | |
566 int64_t object_store_id) { | |
567 IDB_TRACE("IndexedDBDatabaseImpl::delete_object_store"); | |
568 TransactionMap::const_iterator trans_iterator = | |
569 transactions_.find(transaction_id); | |
570 if (trans_iterator == transactions_.end()) | |
571 return; | |
572 IndexedDBTransaction* transaction = trans_iterator->second; | |
573 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); | |
574 | |
575 DCHECK(metadata_.object_stores.find(object_store_id) != | |
576 metadata_.object_stores.end()); | |
577 const IndexedDBObjectStoreMetadata& object_store_metadata = | |
578 metadata_.object_stores[object_store_id]; | |
579 | |
580 transaction->ScheduleTask( | |
581 new DeleteObjectStoreOperation(backing_store_, object_store_metadata), | |
582 new DeleteObjectStoreAbortOperation(this, object_store_metadata)); | |
583 RemoveObjectStore(object_store_id); | |
584 } | |
585 | |
586 void IndexedDBDatabaseImpl::CreateIndex(int64_t transaction_id, | |
587 int64_t object_store_id, | |
588 int64_t index_id, | |
589 const string16& name, | |
590 const IndexedDBKeyPath& key_path, | |
591 bool unique, | |
592 bool multi_entry) { | |
593 IDB_TRACE("IndexedDBDatabaseImpl::create_index"); | |
594 TransactionMap::const_iterator trans_iterator = | |
595 transactions_.find(transaction_id); | |
596 if (trans_iterator == transactions_.end()) | |
597 return; | |
598 IndexedDBTransaction* transaction = trans_iterator->second; | |
599 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); | |
600 | |
601 DCHECK(metadata_.object_stores.find(object_store_id) != | |
602 metadata_.object_stores.end()); | |
603 const IndexedDBObjectStoreMetadata object_store = | |
604 metadata_.object_stores[object_store_id]; | |
605 | |
606 DCHECK(object_store.indexes.find(index_id) == object_store.indexes.end()); | |
607 const IndexedDBIndexMetadata index_metadata( | |
608 name, index_id, key_path, unique, multi_entry); | |
609 | |
610 transaction->ScheduleTask( | |
611 new CreateIndexOperation(backing_store_, object_store_id, index_metadata), | |
612 new CreateIndexAbortOperation(this, object_store_id, index_id)); | |
613 | |
614 AddIndex(object_store_id, index_metadata, index_id); | |
615 } | |
616 | |
617 void CreateIndexOperation::Perform(IndexedDBTransaction* transaction) { | |
618 IDB_TRACE("CreateIndexOperation"); | |
619 if (!backing_store_->CreateIndex(transaction->BackingStoreTransaction(), | |
620 transaction->database()->id(), | |
621 object_store_id_, | |
622 index_metadata_.id, | |
623 index_metadata_.name, | |
624 index_metadata_.key_path, | |
625 index_metadata_.unique, | |
626 index_metadata_.multi_entry)) { | |
627 string16 error_string = ASCIIToUTF16("Internal error creating index '") + | |
628 index_metadata_.name + ASCIIToUTF16("'."); | |
629 transaction->Abort(IndexedDBDatabaseError::Create( | |
630 WebKit::WebIDBDatabaseExceptionUnknownError, error_string)); | |
631 return; | |
632 } | |
633 } | |
634 | |
635 void CreateIndexAbortOperation::Perform(IndexedDBTransaction* transaction) { | |
636 IDB_TRACE("CreateIndexAbortOperation"); | |
637 DCHECK(!transaction); | |
638 database_->RemoveIndex(object_store_id_, index_id_); | |
639 } | |
640 | |
641 void IndexedDBDatabaseImpl::DeleteIndex(int64_t transaction_id, | |
642 int64_t object_store_id, | |
643 int64_t index_id) { | |
644 IDB_TRACE("IndexedDBDatabaseImpl::delete_index"); | |
645 TransactionMap::const_iterator trans_iterator = | |
646 transactions_.find(transaction_id); | |
647 if (trans_iterator == transactions_.end()) | |
648 return; | |
649 IndexedDBTransaction* transaction = trans_iterator->second; | |
650 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); | |
651 | |
652 DCHECK(metadata_.object_stores.find(object_store_id) != | |
653 metadata_.object_stores.end()); | |
654 IndexedDBObjectStoreMetadata object_store = | |
655 metadata_.object_stores[object_store_id]; | |
656 | |
657 DCHECK(object_store.indexes.find(index_id) != object_store.indexes.end()); | |
658 const IndexedDBIndexMetadata& index_metadata = object_store.indexes[index_id]; | |
659 | |
660 transaction->ScheduleTask( | |
661 new DeleteIndexOperation(backing_store_, object_store_id, index_metadata), | |
662 new DeleteIndexAbortOperation(this, object_store_id, index_metadata)); | |
663 | |
664 RemoveIndex(object_store_id, index_id); | |
665 } | |
666 | |
667 void DeleteIndexOperation::Perform(IndexedDBTransaction* transaction) { | |
668 IDB_TRACE("DeleteIndexOperation"); | |
669 bool ok = backing_store_->DeleteIndex(transaction->BackingStoreTransaction(), | |
670 transaction->database()->id(), | |
671 object_store_id_, | |
672 index_metadata_.id); | |
673 if (!ok) { | |
674 string16 error_string = ASCIIToUTF16("Internal error deleting index '") + | |
675 index_metadata_.name + ASCIIToUTF16("'."); | |
676 scoped_refptr<IndexedDBDatabaseError> error = | |
677 IndexedDBDatabaseError::Create( | |
678 WebKit::WebIDBDatabaseExceptionUnknownError, error_string); | |
679 transaction->Abort(error); | |
680 } | |
681 } | |
682 | |
683 void DeleteIndexAbortOperation::Perform(IndexedDBTransaction* transaction) { | |
684 IDB_TRACE("DeleteIndexAbortOperation"); | |
685 DCHECK(!transaction); | |
686 database_->AddIndex( | |
687 object_store_id_, index_metadata_, IndexedDBIndexMetadata::kInvalidId); | |
688 } | |
689 | |
690 void IndexedDBDatabaseImpl::Commit(int64_t transaction_id) { | |
691 // The frontend suggests that we commit, but we may have previously initiated | |
692 // an abort, and so have disposed of the transaction. on_abort has already | |
693 // been dispatched to the frontend, so it will find out about that | |
694 // asynchronously. | |
695 if (transactions_.find(transaction_id) != transactions_.end()) | |
696 transactions_[transaction_id]->Commit(); | |
697 } | |
698 | |
699 void IndexedDBDatabaseImpl::Abort(int64_t transaction_id) { | |
700 // If the transaction is unknown, then it has already been aborted by the | |
701 // backend before this call so it is safe to ignore it. | |
702 if (transactions_.find(transaction_id) != transactions_.end()) | |
703 transactions_[transaction_id]->Abort(); | |
704 } | |
705 | |
706 void IndexedDBDatabaseImpl::Abort(int64_t transaction_id, | |
707 scoped_refptr<IndexedDBDatabaseError> error) { | |
708 // If the transaction is unknown, then it has already been aborted by the | |
709 // backend before this call so it is safe to ignore it. | |
710 if (transactions_.find(transaction_id) != transactions_.end()) | |
711 transactions_[transaction_id]->Abort(error); | |
712 } | |
713 | |
714 void IndexedDBDatabaseImpl::Get( | |
715 int64_t transaction_id, | |
716 int64_t object_store_id, | |
717 int64_t index_id, | |
718 scoped_ptr<IndexedDBKeyRange> key_range, | |
719 bool key_only, | |
720 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
721 IDB_TRACE("IndexedDBDatabaseImpl::get"); | |
722 TransactionMap::const_iterator trans_iterator = | |
723 transactions_.find(transaction_id); | |
724 if (trans_iterator == transactions_.end()) | |
725 return; | |
726 IndexedDBTransaction* transaction = trans_iterator->second; | |
727 | |
728 transaction->ScheduleTask(new GetOperation( | |
729 backing_store_, | |
730 metadata_, | |
731 object_store_id, | |
732 index_id, | |
733 key_range.Pass(), | |
734 key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE, | |
735 callbacks)); | |
736 } | |
737 | |
738 void GetOperation::Perform(IndexedDBTransaction* transaction) { | |
739 IDB_TRACE("GetOperation"); | |
740 | |
741 const IndexedDBKey* key; | |
742 | |
743 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor; | |
744 if (key_range_->IsOnlyKey()) { | |
745 key = &key_range_->lower(); | |
746 } else { | |
747 if (index_id_ == IndexedDBIndexMetadata::kInvalidId) { | |
748 DCHECK(cursor_type_ != indexed_db::CURSOR_KEY_ONLY); | |
749 // ObjectStore Retrieval Operation | |
750 backing_store_cursor = backing_store_->OpenObjectStoreCursor( | |
751 transaction->BackingStoreTransaction(), | |
752 database_id_, | |
753 object_store_id_, | |
754 *key_range_, | |
755 indexed_db::CURSOR_NEXT); | |
756 } else if (cursor_type_ == indexed_db::CURSOR_KEY_ONLY) { | |
757 // Index Value Retrieval Operation | |
758 backing_store_cursor = backing_store_->OpenIndexKeyCursor( | |
759 transaction->BackingStoreTransaction(), | |
760 database_id_, | |
761 object_store_id_, | |
762 index_id_, | |
763 *key_range_, | |
764 indexed_db::CURSOR_NEXT); | |
765 } else { | |
766 // Index Referenced Value Retrieval Operation | |
767 backing_store_cursor = backing_store_->OpenIndexCursor( | |
768 transaction->BackingStoreTransaction(), | |
769 database_id_, | |
770 object_store_id_, | |
771 index_id_, | |
772 *key_range_, | |
773 indexed_db::CURSOR_NEXT); | |
774 } | |
775 | |
776 if (!backing_store_cursor) { | |
777 callbacks_->OnSuccess(); | |
778 return; | |
779 } | |
780 | |
781 key = &backing_store_cursor->key(); | |
782 } | |
783 | |
784 scoped_ptr<IndexedDBKey> primary_key; | |
785 bool ok; | |
786 if (index_id_ == IndexedDBIndexMetadata::kInvalidId) { | |
787 // Object Store Retrieval Operation | |
788 std::vector<char> value; | |
789 ok = backing_store_->GetRecord(transaction->BackingStoreTransaction(), | |
790 database_id_, | |
791 object_store_id_, | |
792 *key, | |
793 value); | |
794 if (!ok) { | |
795 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
796 WebKit::WebIDBDatabaseExceptionUnknownError, | |
797 ASCIIToUTF16("Internal error in get_record."))); | |
798 return; | |
799 } | |
800 | |
801 if (value.empty()) { | |
802 callbacks_->OnSuccess(); | |
803 return; | |
804 } | |
805 | |
806 if (auto_increment_ && !key_path_.IsNull()) { | |
807 callbacks_->OnSuccess(&value, *key, key_path_); | |
808 return; | |
809 } | |
810 | |
811 callbacks_->OnSuccess(&value); | |
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_t database_id, | |
867 int64_t object_store_id) { | |
868 const int64_t max_generator_value = | |
869 9007199254740992LL; // Maximum integer storable as ECMAScript number. | |
870 int64_t 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_t database_id, | |
891 int64_t object_store_id, | |
892 const IndexedDBKey* key, | |
893 bool check_current) { | |
894 DCHECK_EQ(key && key->type(), WebIDBKey::NumberType); | |
895 return backing_store->MaybeUpdateKeyGeneratorCurrentNumber( | |
896 transaction->BackingStoreTransaction(), | |
897 database_id, | |
898 object_store_id, | |
899 static_cast<int64_t>(floor(key->number())) + 1, | |
900 check_current); | |
901 } | |
902 | |
903 void IndexedDBDatabaseImpl::Put( | |
904 int64_t transaction_id, | |
905 int64_t 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_t>& 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(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(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_t transaction_id, | |
1061 int64_t object_store_id, | |
1062 scoped_ptr<IndexedDBKey> primary_key, | |
1063 const std::vector<int64_t>& 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 evaluate if | |
1075 // it's | |
1076 // worth the extra complexity. | |
1077 IndexedDBBackingStore::RecordIdentifier record_identifier; | |
1078 bool found = false; | |
1079 bool ok = | |
1080 store->KeyExistsInObjectStore(transaction->BackingStoreTransaction(), | |
1081 metadata_.id, | |
1082 object_store_id, | |
1083 *primary_key, | |
1084 &record_identifier, | |
1085 found); | |
1086 if (!ok) { | |
1087 transaction->Abort(IndexedDBDatabaseError::Create( | |
1088 WebKit::WebIDBDatabaseExceptionUnknownError, | |
1089 ASCIIToUTF16("Internal error setting index keys."))); | |
1090 return; | |
1091 } | |
1092 if (!found) { | |
1093 scoped_refptr<IndexedDBDatabaseError> error = | |
1094 IndexedDBDatabaseError::Create( | |
1095 WebKit::WebIDBDatabaseExceptionUnknownError, | |
1096 ASCIIToUTF16( | |
1097 "Internal error setting index keys for object store.")); | |
1098 transaction->Abort(error); | |
1099 return; | |
1100 } | |
1101 | |
1102 ScopedVector<IndexedDBObjectStoreImpl::IndexWriter> index_writers; | |
1103 string16 error_message; | |
1104 bool obeys_constraints = false; | |
1105 DCHECK(metadata_.object_stores.find(object_store_id) != | |
1106 metadata_.object_stores.end()); | |
1107 const IndexedDBObjectStoreMetadata& object_store_metadata = | |
1108 metadata_.object_stores[object_store_id]; | |
1109 bool backing_store_success = | |
1110 IndexedDBObjectStoreImpl::MakeIndexWriters(transaction, | |
1111 store.get(), | |
1112 id(), | |
1113 object_store_metadata, | |
1114 *primary_key, | |
1115 false, | |
1116 index_ids, | |
1117 index_keys, | |
1118 &index_writers, | |
1119 &error_message, | |
1120 &obeys_constraints); | |
1121 if (!backing_store_success) { | |
1122 transaction->Abort(IndexedDBDatabaseError::Create( | |
1123 WebKit::WebIDBDatabaseExceptionUnknownError, | |
1124 ASCIIToUTF16( | |
1125 "Internal error: backing store error updating index keys."))); | |
1126 return; | |
1127 } | |
1128 if (!obeys_constraints) { | |
1129 transaction->Abort(IndexedDBDatabaseError::Create( | |
1130 WebKit::WebIDBDatabaseExceptionConstraintError, error_message)); | |
1131 return; | |
1132 } | |
1133 | |
1134 for (size_t i = 0; i < index_writers.size(); ++i) { | |
1135 IndexedDBObjectStoreImpl::IndexWriter* index_writer = index_writers[i]; | |
1136 index_writer->WriteIndexKeys(record_identifier, | |
1137 store.get(), | |
1138 transaction->BackingStoreTransaction(), | |
1139 id(), | |
1140 object_store_id); | |
1141 } | |
1142 } | |
1143 | |
1144 void IndexedDBDatabaseImpl::SetIndexesReady( | |
1145 int64_t transaction_id, | |
1146 int64_t, | |
1147 const std::vector<int64_t>& index_ids) { | |
1148 IDB_TRACE("IndexedDBObjectStoreImpl::set_indexes_ready"); | |
1149 | |
1150 TransactionMap::const_iterator trans_iterator = | |
1151 transactions_.find(transaction_id); | |
1152 if (trans_iterator == transactions_.end()) | |
1153 return; | |
1154 IndexedDBTransaction* transaction = trans_iterator->second; | |
1155 | |
1156 transaction->ScheduleTask(IndexedDBDatabase::PREEMPTIVE_TASK, | |
1157 new SetIndexesReadyOperation(index_ids.size())); | |
1158 } | |
1159 | |
1160 void SetIndexesReadyOperation::Perform(IndexedDBTransaction* transaction) { | |
1161 IDB_TRACE("SetIndexesReadyOperation"); | |
1162 for (size_t i = 0; i < index_count_; ++i) | |
1163 transaction->DidCompletePreemptiveEvent(); | |
1164 } | |
1165 | |
1166 void IndexedDBDatabaseImpl::OpenCursor( | |
1167 int64_t transaction_id, | |
1168 int64_t object_store_id, | |
1169 int64_t index_id, | |
1170 scoped_ptr<IndexedDBKeyRange> key_range, | |
1171 indexed_db::CursorDirection direction, | |
1172 bool key_only, | |
1173 TaskType task_type, | |
1174 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
1175 IDB_TRACE("IndexedDBDatabaseImpl::open_cursor"); | |
1176 TransactionMap::const_iterator trans_iterator = | |
1177 transactions_.find(transaction_id); | |
1178 if (trans_iterator == transactions_.end()) | |
1179 return; | |
1180 IndexedDBTransaction* transaction = trans_iterator->second; | |
1181 | |
1182 transaction->ScheduleTask(new OpenCursorOperation( | |
1183 backing_store_, | |
1184 id(), | |
1185 object_store_id, | |
1186 index_id, | |
1187 key_range.Pass(), | |
1188 direction, | |
1189 key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE, | |
1190 task_type, | |
1191 callbacks)); | |
1192 } | |
1193 | |
1194 void OpenCursorOperation::Perform(IndexedDBTransaction* transaction) { | |
1195 IDB_TRACE("OpenCursorOperation"); | |
1196 | |
1197 // The frontend has begun indexing, so this pauses the transaction | |
1198 // until the indexing is complete. This can't happen any earlier | |
1199 // because we don't want to switch to early mode in case multiple | |
1200 // indexes are being created in a row, with Put()'s in between. | |
1201 if (task_type_ == IndexedDBDatabase::PREEMPTIVE_TASK) | |
1202 transaction->AddPreemptiveEvent(); | |
1203 | |
1204 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor; | |
1205 if (index_id_ == IndexedDBIndexMetadata::kInvalidId) { | |
1206 DCHECK(cursor_type_ != indexed_db::CURSOR_KEY_ONLY); | |
1207 backing_store_cursor = backing_store_->OpenObjectStoreCursor( | |
1208 transaction->BackingStoreTransaction(), | |
1209 database_id_, | |
1210 object_store_id_, | |
1211 *key_range_, | |
1212 direction_); | |
1213 } else { | |
1214 DCHECK_EQ(task_type_, IndexedDBDatabase::NORMAL_TASK); | |
1215 if (cursor_type_ == indexed_db::CURSOR_KEY_ONLY) { | |
1216 backing_store_cursor = backing_store_->OpenIndexKeyCursor( | |
1217 transaction->BackingStoreTransaction(), | |
1218 database_id_, | |
1219 object_store_id_, | |
1220 index_id_, | |
1221 *key_range_, | |
1222 direction_); | |
1223 } else { | |
1224 backing_store_cursor = backing_store_->OpenIndexCursor( | |
1225 transaction->BackingStoreTransaction(), | |
1226 database_id_, | |
1227 object_store_id_, | |
1228 index_id_, | |
1229 *key_range_, | |
1230 direction_); | |
1231 } | |
1232 } | |
1233 | |
1234 if (!backing_store_cursor) { | |
1235 callbacks_->OnSuccess(static_cast<std::vector<char>*>(NULL)); | |
1236 return; | |
1237 } | |
1238 | |
1239 IndexedDBDatabase::TaskType task_type( | |
1240 static_cast<IndexedDBDatabase::TaskType>(task_type_)); | |
1241 scoped_refptr<IndexedDBCursorImpl> cursor = | |
1242 IndexedDBCursorImpl::Create(backing_store_cursor.Pass(), | |
1243 cursor_type_, | |
1244 task_type, | |
1245 transaction, | |
1246 object_store_id_); | |
1247 callbacks_->OnSuccess( | |
1248 cursor, cursor->key(), cursor->primary_key(), cursor->Value()); | |
1249 } | |
1250 | |
1251 void IndexedDBDatabaseImpl::Count( | |
1252 int64_t transaction_id, | |
1253 int64_t object_store_id, | |
1254 int64_t index_id, | |
1255 scoped_ptr<IndexedDBKeyRange> key_range, | |
1256 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
1257 IDB_TRACE("IndexedDBDatabaseImpl::count"); | |
1258 TransactionMap::const_iterator trans_iterator = | |
1259 transactions_.find(transaction_id); | |
1260 if (trans_iterator == transactions_.end()) | |
1261 return; | |
1262 IndexedDBTransaction* transaction = trans_iterator->second; | |
1263 | |
1264 DCHECK(metadata_.object_stores.find(object_store_id) != | |
1265 metadata_.object_stores.end()); | |
1266 transaction->ScheduleTask(new CountOperation(backing_store_, | |
1267 id(), | |
1268 object_store_id, | |
1269 index_id, | |
1270 key_range.Pass(), | |
1271 callbacks)); | |
1272 } | |
1273 | |
1274 void CountOperation::Perform(IndexedDBTransaction* transaction) { | |
1275 IDB_TRACE("CountOperation"); | |
1276 uint32_t count = 0; | |
1277 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor; | |
1278 | |
1279 if (index_id_ == IndexedDBIndexMetadata::kInvalidId) { | |
1280 backing_store_cursor = backing_store_->OpenObjectStoreKeyCursor( | |
1281 transaction->BackingStoreTransaction(), | |
1282 database_id_, | |
1283 object_store_id_, | |
1284 *key_range_, | |
1285 indexed_db::CURSOR_NEXT); | |
1286 } else { | |
1287 backing_store_cursor = backing_store_->OpenIndexKeyCursor( | |
1288 transaction->BackingStoreTransaction(), | |
1289 database_id_, | |
1290 object_store_id_, | |
1291 index_id_, | |
1292 *key_range_, | |
1293 indexed_db::CURSOR_NEXT); | |
1294 } | |
1295 if (!backing_store_cursor) { | |
1296 callbacks_->OnSuccess(count); | |
1297 return; | |
1298 } | |
1299 | |
1300 do { | |
1301 ++count; | |
1302 } while (backing_store_cursor->ContinueFunction(0)); | |
1303 | |
1304 callbacks_->OnSuccess(count); | |
1305 } | |
1306 | |
1307 void IndexedDBDatabaseImpl::DeleteRange( | |
1308 int64_t transaction_id, | |
1309 int64_t object_store_id, | |
1310 scoped_ptr<IndexedDBKeyRange> key_range, | |
1311 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
1312 IDB_TRACE("IndexedDBDatabaseImpl::delete_range"); | |
1313 TransactionMap::const_iterator trans_iterator = | |
1314 transactions_.find(transaction_id); | |
1315 if (trans_iterator == transactions_.end()) | |
1316 return; | |
1317 IndexedDBTransaction* transaction = trans_iterator->second; | |
1318 | |
1319 transaction->ScheduleTask(new DeleteRangeOperation( | |
1320 backing_store_, id(), object_store_id, key_range.Pass(), callbacks)); | |
1321 } | |
1322 | |
1323 void DeleteRangeOperation::Perform(IndexedDBTransaction* transaction) { | |
1324 IDB_TRACE("DeleteRangeOperation"); | |
1325 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor = | |
1326 backing_store_->OpenObjectStoreCursor( | |
1327 transaction->BackingStoreTransaction(), | |
1328 database_id_, | |
1329 object_store_id_, | |
1330 *key_range_, | |
1331 indexed_db::CURSOR_NEXT); | |
1332 if (backing_store_cursor) { | |
1333 do { | |
1334 if (!backing_store_->DeleteRecord( | |
1335 transaction->BackingStoreTransaction(), | |
1336 database_id_, | |
1337 object_store_id_, | |
1338 backing_store_cursor->record_identifier())) { | |
1339 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
1340 WebKit::WebIDBDatabaseExceptionUnknownError, | |
1341 ASCIIToUTF16("Internal error deleting data in range"))); | |
1342 return; | |
1343 } | |
1344 } while (backing_store_cursor->ContinueFunction(0)); | |
1345 } | |
1346 | |
1347 callbacks_->OnSuccess(); | |
1348 } | |
1349 | |
1350 void IndexedDBDatabaseImpl::Clear( | |
1351 int64_t transaction_id, | |
1352 int64_t object_store_id, | |
1353 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
1354 IDB_TRACE("IndexedDBDatabaseImpl::clear"); | |
1355 TransactionMap::const_iterator trans_iterator = | |
1356 transactions_.find(transaction_id); | |
1357 if (trans_iterator == transactions_.end()) | |
1358 return; | |
1359 IndexedDBTransaction* transaction = trans_iterator->second; | |
1360 DCHECK(transaction->mode() != indexed_db::TRANSACTION_READ_ONLY); | |
1361 | |
1362 transaction->ScheduleTask( | |
1363 new ClearOperation(backing_store_, id(), object_store_id, callbacks)); | |
1364 } | |
1365 | |
1366 void ClearOperation::Perform(IndexedDBTransaction* transaction) { | |
1367 IDB_TRACE("ObjectStoreClearOperation"); | |
1368 if (!backing_store_->ClearObjectStore(transaction->BackingStoreTransaction(), | |
1369 database_id_, | |
1370 object_store_id_)) { | |
1371 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
1372 WebKit::WebIDBDatabaseExceptionUnknownError, | |
1373 ASCIIToUTF16("Internal error clearing object store"))); | |
1374 return; | |
1375 } | |
1376 callbacks_->OnSuccess(); | |
1377 } | |
1378 | |
1379 void DeleteObjectStoreOperation::Perform(IndexedDBTransaction* transaction) { | |
1380 IDB_TRACE("DeleteObjectStoreOperation"); | |
1381 bool ok = | |
1382 backing_store_->DeleteObjectStore(transaction->BackingStoreTransaction(), | |
1383 transaction->database()->id(), | |
1384 object_store_metadata_.id); | |
1385 if (!ok) { | |
1386 string16 error_string = | |
1387 ASCIIToUTF16("Internal error deleting object store '") + | |
1388 object_store_metadata_.name + ASCIIToUTF16("'."); | |
1389 scoped_refptr<IndexedDBDatabaseError> error = | |
1390 IndexedDBDatabaseError::Create( | |
1391 WebKit::WebIDBDatabaseExceptionUnknownError, error_string); | |
1392 transaction->Abort(error); | |
1393 } | |
1394 } | |
1395 | |
1396 void IndexedDBDatabaseImpl::VersionChangeOperation::Perform( | |
1397 IndexedDBTransaction* transaction) { | |
1398 IDB_TRACE("VersionChangeOperation"); | |
1399 int64_t database_id = database_->id(); | |
1400 int64_t old_version = database_->metadata_.int_version; | |
1401 DCHECK(version_ > old_version); | |
1402 database_->metadata_.int_version = version_; | |
1403 if (!database_->backing_store_->UpdateIDBDatabaseIntVersion( | |
1404 transaction->BackingStoreTransaction(), | |
1405 database_id, | |
1406 database_->metadata_.int_version)) { | |
1407 scoped_refptr<IndexedDBDatabaseError> error = | |
1408 IndexedDBDatabaseError::Create( | |
1409 WebKit::WebIDBDatabaseExceptionUnknownError, | |
1410 ASCIIToUTF16("Internal error writing data to stable storage when " | |
1411 "updating version.")); | |
1412 callbacks_->OnError(error); | |
1413 transaction->Abort(error); | |
1414 return; | |
1415 } | |
1416 DCHECK(!database_->pending_second_half_open_); | |
1417 database_->pending_second_half_open_.reset(new PendingOpenCall( | |
1418 callbacks_, database_callbacks_, transaction_id_, version_)); | |
1419 callbacks_->OnUpgradeNeeded(old_version, database_, database_->metadata()); | |
1420 } | |
1421 | |
1422 void IndexedDBDatabaseImpl::TransactionStarted( | |
1423 IndexedDBTransaction* transaction) { | |
1424 | |
1425 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) { | |
1426 DCHECK(!running_version_change_transaction_); | |
1427 running_version_change_transaction_ = transaction; | |
1428 } | |
1429 } | |
1430 | |
1431 void IndexedDBDatabaseImpl::TransactionFinished( | |
1432 IndexedDBTransaction* transaction) { | |
1433 | |
1434 DCHECK(transactions_.find(transaction->id()) != transactions_.end()); | |
1435 DCHECK_EQ(transactions_[transaction->id()], transaction); | |
1436 transactions_.erase(transaction->id()); | |
1437 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) { | |
1438 DCHECK_EQ(transaction, running_version_change_transaction_); | |
1439 running_version_change_transaction_ = NULL; | |
1440 } | |
1441 } | |
1442 | |
1443 void IndexedDBDatabaseImpl::TransactionFinishedAndAbortFired( | |
1444 IndexedDBTransaction* transaction) { | |
1445 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) { | |
1446 if (pending_second_half_open_) { | |
1447 pending_second_half_open_->Callbacks() | |
1448 ->OnError(IndexedDBDatabaseError::Create( | |
1449 WebKit::WebIDBDatabaseExceptionAbortError, | |
1450 ASCIIToUTF16("Version change transaction was aborted in " | |
1451 "upgradeneeded event handler."))); | |
1452 pending_second_half_open_.reset(); | |
1453 } | |
1454 ProcessPendingCalls(); | |
1455 } | |
1456 } | |
1457 | |
1458 void IndexedDBDatabaseImpl::TransactionFinishedAndCompleteFired( | |
1459 IndexedDBTransaction* transaction) { | |
1460 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) { | |
1461 DCHECK(pending_second_half_open_); | |
1462 if (pending_second_half_open_) { | |
1463 DCHECK_EQ(pending_second_half_open_->Version(), metadata_.int_version); | |
1464 DCHECK(metadata_.id != kInvalidId); | |
1465 pending_second_half_open_->Callbacks()->OnSuccess(this, this->metadata()); | |
1466 pending_second_half_open_.reset(); | |
1467 } | |
1468 ProcessPendingCalls(); | |
1469 } | |
1470 } | |
1471 | |
1472 size_t IndexedDBDatabaseImpl::ConnectionCount() const { | |
1473 // This does not include pending open calls, as those should not block version | |
1474 // changes and deletes. | |
1475 return database_callbacks_set_.size(); | |
1476 } | |
1477 | |
1478 void IndexedDBDatabaseImpl::ProcessPendingCalls() { | |
1479 if (pending_second_half_open_) { | |
1480 DCHECK_EQ(pending_second_half_open_->Version(), metadata_.int_version); | |
1481 DCHECK(metadata_.id != kInvalidId); | |
1482 scoped_ptr<PendingOpenCall> pending_call = pending_second_half_open_.Pass(); | |
1483 pending_call->Callbacks()->OnSuccess(this, this->metadata()); | |
1484 // Fall through when complete, as pending opens may be unblocked. | |
1485 } | |
1486 | |
1487 if (pending_run_version_change_transaction_call_ && ConnectionCount() == 1) { | |
1488 DCHECK(pending_run_version_change_transaction_call_->Version() > | |
1489 metadata_.int_version); | |
1490 scoped_ptr<PendingOpenCall> pending_call = | |
1491 pending_run_version_change_transaction_call_.Pass(); | |
1492 RunVersionChangeTransactionFinal(pending_call->Callbacks(), | |
1493 pending_call->DatabaseCallbacks(), | |
1494 pending_call->TransactionId(), | |
1495 pending_call->Version()); | |
1496 DCHECK(ConnectionCount() == 1); | |
1497 // Fall through would be a no-op, since transaction must complete | |
1498 // asynchronously. | |
1499 DCHECK(IsDeleteDatabaseBlocked()); | |
1500 DCHECK(IsOpenConnectionBlocked()); | |
1501 return; | |
1502 } | |
1503 | |
1504 if (!IsDeleteDatabaseBlocked()) { | |
1505 PendingDeleteCallList pending_delete_calls; | |
1506 pending_delete_calls_.swap(pending_delete_calls); | |
1507 while (!pending_delete_calls.empty()) { | |
1508 // Only the first delete call will delete the database, but each must fire | |
1509 // callbacks. | |
1510 scoped_ptr<PendingDeleteCall> pending_delete_call( | |
1511 pending_delete_calls.front()); | |
1512 pending_delete_calls.pop_front(); | |
1513 DeleteDatabaseFinal(pending_delete_call->Callbacks()); | |
1514 } | |
1515 // delete_database_final should never re-queue calls. | |
1516 DCHECK(pending_delete_calls_.empty()); | |
1517 // Fall through when complete, as pending opens may be unblocked. | |
1518 } | |
1519 | |
1520 if (!IsOpenConnectionBlocked()) { | |
1521 PendingOpenCallList pending_open_calls; | |
1522 pending_open_calls_.swap(pending_open_calls); | |
1523 while (!pending_open_calls.empty()) { | |
1524 scoped_ptr<PendingOpenCall> pending_open_call(pending_open_calls.front()); | |
1525 pending_open_calls.pop_front(); | |
1526 OpenConnection(pending_open_call->Callbacks(), | |
1527 pending_open_call->DatabaseCallbacks(), | |
1528 pending_open_call->TransactionId(), | |
1529 pending_open_call->Version()); | |
1530 } | |
1531 } | |
1532 } | |
1533 | |
1534 void IndexedDBDatabaseImpl::CreateTransaction( | |
1535 int64_t transaction_id, | |
1536 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> callbacks, | |
1537 const std::vector<int64_t>& object_store_ids, | |
1538 unsigned short mode) { | |
1539 | |
1540 DCHECK(database_callbacks_set_.has(callbacks)); | |
1541 | |
1542 scoped_refptr<IndexedDBTransaction> transaction = | |
1543 IndexedDBTransaction::Create( | |
1544 transaction_id, | |
1545 callbacks, | |
1546 object_store_ids, | |
1547 static_cast<indexed_db::TransactionMode>(mode), | |
1548 this); | |
1549 DCHECK(transactions_.find(transaction_id) == transactions_.end()); | |
1550 transactions_[transaction_id] = transaction; | |
1551 } | |
1552 | |
1553 bool IndexedDBDatabaseImpl::IsOpenConnectionBlocked() const { | |
1554 return !pending_delete_calls_.empty() || | |
1555 running_version_change_transaction_ || | |
1556 pending_run_version_change_transaction_call_; | |
1557 } | |
1558 | |
1559 void IndexedDBDatabaseImpl::OpenConnection( | |
1560 scoped_refptr<IndexedDBCallbacksWrapper> callbacks, | |
1561 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks, | |
1562 int64_t transaction_id, | |
1563 int64_t version) { | |
1564 DCHECK(backing_store_.get()); | |
1565 | |
1566 // TODO(jsbell): Should have a priority queue so that higher version requests | |
1567 // are | |
dgrogan
2013/05/22 18:22:06
There are a few of these bad comment wraps.
jsbell
2013/05/22 22:21:14
Done.
| |
1568 // processed first. http://crbug.com/225850 | |
1569 if (IsOpenConnectionBlocked()) { | |
1570 pending_open_calls_.push_back(new PendingOpenCall( | |
1571 callbacks, database_callbacks, transaction_id, version)); | |
1572 return; | |
1573 } | |
1574 | |
1575 if (metadata_.id == kInvalidId) { | |
1576 // The database was deleted then immediately re-opened; OpenInternal() | |
1577 // recreates it in the backing store. | |
1578 if (OpenInternal()) { | |
1579 DCHECK_EQ(metadata_.int_version, | |
1580 IndexedDBDatabaseMetadata::NO_INT_VERSION); | |
1581 } else { | |
1582 string16 message; | |
1583 scoped_refptr<IndexedDBDatabaseError> error; | |
1584 if (version == IndexedDBDatabaseMetadata::NO_INT_VERSION) | |
1585 message = ASCIIToUTF16( | |
1586 "Internal error opening database with no version specified."); | |
1587 else | |
1588 message = | |
1589 ASCIIToUTF16("Internal error opening database with version ") + | |
1590 Int64ToString16(version); | |
1591 callbacks->OnError(IndexedDBDatabaseError::Create( | |
1592 WebKit::WebIDBDatabaseExceptionUnknownError, message)); | |
1593 return; | |
1594 } | |
1595 } | |
1596 | |
1597 // We infer that the database didn't exist from its lack of either type of | |
1598 // version. | |
1599 bool is_new_database = | |
1600 metadata_.version == kNoStringVersion && | |
1601 metadata_.int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION; | |
1602 | |
1603 if (version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) { | |
1604 // For unit tests only - skip upgrade steps. Calling from script with | |
1605 // DEFAULT_INT_VERSION throws exception. | |
1606 // TODO(jsbell): Assert that we're executing a unit test. | |
1607 DCHECK(is_new_database); | |
1608 database_callbacks_set_.insert(database_callbacks); | |
1609 callbacks->OnSuccess(this, this->metadata()); | |
1610 return; | |
1611 } | |
1612 | |
1613 if (version == IndexedDBDatabaseMetadata::NO_INT_VERSION) { | |
1614 if (!is_new_database) { | |
1615 database_callbacks_set_.insert(database_callbacks); | |
1616 callbacks->OnSuccess(this, this->metadata()); | |
1617 return; | |
1618 } | |
1619 // Spec says: If no version is specified and no database exists, set | |
1620 // database version to 1. | |
1621 version = 1; | |
1622 } | |
1623 | |
1624 if (version > metadata_.int_version) { | |
1625 database_callbacks_set_.insert(database_callbacks); | |
1626 RunVersionChangeTransaction( | |
1627 callbacks, database_callbacks, transaction_id, version); | |
1628 return; | |
1629 } | |
1630 if (version < metadata_.int_version) { | |
1631 callbacks->OnError(IndexedDBDatabaseError::Create( | |
1632 WebKit::WebIDBDatabaseExceptionVersionError, | |
1633 ASCIIToUTF16("The requested version (") + Int64ToString16(version) + | |
1634 ASCIIToUTF16(") is less than the existing version (") + | |
1635 Int64ToString16(metadata_.int_version) + ASCIIToUTF16(")."))); | |
1636 return; | |
1637 } | |
1638 DCHECK_EQ(version, metadata_.int_version); | |
1639 database_callbacks_set_.insert(database_callbacks); | |
1640 callbacks->OnSuccess(this, this->metadata()); | |
1641 } | |
1642 | |
1643 void IndexedDBDatabaseImpl::RunVersionChangeTransaction( | |
1644 scoped_refptr<IndexedDBCallbacksWrapper> callbacks, | |
1645 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks, | |
1646 int64_t transaction_id, | |
1647 int64_t requested_version) { | |
1648 | |
1649 DCHECK(callbacks); | |
1650 DCHECK(database_callbacks_set_.has(database_callbacks)); | |
1651 if (ConnectionCount() > 1) { | |
1652 // Front end ensures the event is not fired at connections that have | |
1653 // close_pending set. | |
1654 for (DatabaseCallbacksSet::const_iterator it = | |
1655 database_callbacks_set_.begin(); | |
1656 it != database_callbacks_set_.end(); | |
1657 ++it) { | |
1658 if (*it != database_callbacks.get()) | |
1659 (*it)->OnVersionChange(metadata_.int_version, requested_version); | |
1660 } | |
1661 // TODO(jsbell): Remove the call to on_blocked and instead wait until the | |
1662 // frontend | |
dgrogan
2013/05/22 18:22:06
comment wrapping
jsbell
2013/05/22 19:13:04
Done.
| |
1663 // tells us that all the "versionchange" events have been delivered. | |
1664 // http://crbug.com/100123 | |
1665 callbacks->OnBlocked(metadata_.int_version); | |
1666 | |
1667 DCHECK(!pending_run_version_change_transaction_call_); | |
1668 pending_run_version_change_transaction_call_.reset(new PendingOpenCall( | |
1669 callbacks, database_callbacks, transaction_id, requested_version)); | |
1670 return; | |
1671 } | |
1672 RunVersionChangeTransactionFinal( | |
1673 callbacks, database_callbacks, transaction_id, requested_version); | |
1674 } | |
1675 | |
1676 void IndexedDBDatabaseImpl::RunVersionChangeTransactionFinal( | |
1677 scoped_refptr<IndexedDBCallbacksWrapper> callbacks, | |
1678 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks, | |
1679 int64_t transaction_id, | |
1680 int64_t requested_version) { | |
1681 | |
1682 std::vector<int64_t> object_store_ids; | |
1683 CreateTransaction(transaction_id, | |
1684 database_callbacks, | |
1685 object_store_ids, | |
1686 indexed_db::TRANSACTION_VERSION_CHANGE); | |
1687 scoped_refptr<IndexedDBTransaction> transaction = | |
1688 transactions_[transaction_id]; | |
1689 | |
1690 transaction->ScheduleTask( | |
1691 new VersionChangeOperation(this, | |
1692 transaction_id, | |
1693 requested_version, | |
1694 callbacks, | |
1695 database_callbacks), | |
1696 new VersionChangeAbortOperation( | |
1697 this, metadata_.version, metadata_.int_version)); | |
1698 | |
1699 DCHECK(!pending_second_half_open_); | |
1700 } | |
1701 | |
1702 void IndexedDBDatabaseImpl::DeleteDatabase( | |
1703 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
1704 | |
1705 if (IsDeleteDatabaseBlocked()) { | |
1706 for (DatabaseCallbacksSet::const_iterator it = | |
1707 database_callbacks_set_.begin(); | |
1708 it != database_callbacks_set_.end(); | |
1709 ++it) { | |
1710 // Front end ensures the event is not fired at connections that have | |
1711 // close_pending set. | |
1712 (*it)->OnVersionChange(metadata_.int_version, | |
1713 IndexedDBDatabaseMetadata::NO_INT_VERSION); | |
1714 } | |
1715 // TODO(jsbell): Only fire on_blocked if there are open connections after | |
1716 // the | |
dgrogan
2013/05/22 18:22:06
comment wrapping
jsbell
2013/05/22 19:13:04
Done.
| |
1717 // VersionChangeEvents are received, not just set up to fire. | |
1718 // http://crbug.com/100123 | |
1719 callbacks->OnBlocked(metadata_.int_version); | |
1720 pending_delete_calls_.push_back(new PendingDeleteCall(callbacks)); | |
1721 return; | |
1722 } | |
1723 DeleteDatabaseFinal(callbacks); | |
1724 } | |
1725 | |
1726 bool IndexedDBDatabaseImpl::IsDeleteDatabaseBlocked() const { | |
1727 return ConnectionCount(); | |
1728 } | |
1729 | |
1730 void IndexedDBDatabaseImpl::DeleteDatabaseFinal( | |
1731 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
1732 DCHECK(!IsDeleteDatabaseBlocked()); | |
1733 DCHECK(backing_store_); | |
1734 if (!backing_store_->DeleteDatabase(metadata_.name)) { | |
1735 callbacks->OnError(IndexedDBDatabaseError::Create( | |
1736 WebKit::WebIDBDatabaseExceptionUnknownError, | |
1737 ASCIIToUTF16("Internal error deleting database."))); | |
1738 return; | |
1739 } | |
1740 metadata_.version = kNoStringVersion; | |
1741 metadata_.id = kInvalidId; | |
1742 metadata_.int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION; | |
1743 metadata_.object_stores.clear(); | |
1744 callbacks->OnSuccess(); | |
1745 } | |
1746 | |
1747 void IndexedDBDatabaseImpl::Close( | |
1748 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> callbacks) { | |
1749 DCHECK(callbacks); | |
1750 DCHECK(database_callbacks_set_.has(callbacks)); | |
1751 | |
1752 // Close outstanding transactions from the closing connection. This | |
1753 // can not happen if the close is requested by the connection itself | |
1754 // as the front-end defers the close until all transactions are | |
1755 // complete, so something unusual has happened e.g. unexpected | |
1756 // process termination. | |
1757 { | |
1758 TransactionMap transactions(transactions_); | |
1759 for (TransactionMap::const_iterator it = transactions.begin(), | |
1760 end = transactions.end(); | |
1761 it != end; | |
1762 ++it) { | |
1763 if (it->second->connection() == callbacks) | |
1764 it->second->Abort(IndexedDBDatabaseError::Create( | |
1765 WebKit::WebIDBDatabaseExceptionUnknownError, | |
1766 ASCIIToUTF16("Connection is closing."))); | |
1767 } | |
1768 } | |
1769 | |
1770 database_callbacks_set_.erase(callbacks); | |
1771 if (pending_second_half_open_ && | |
1772 pending_second_half_open_->DatabaseCallbacks() == callbacks) { | |
1773 pending_second_half_open_->Callbacks() | |
1774 ->OnError(IndexedDBDatabaseError::Create( | |
1775 WebKit::WebIDBDatabaseExceptionAbortError, | |
1776 ASCIIToUTF16("The connection was closed."))); | |
1777 pending_second_half_open_.reset(); | |
1778 } | |
1779 | |
1780 // process_pending_calls allows the inspector to process a pending open call | |
1781 // and call close, reentering IndexedDBDatabaseImpl::close. Then the | |
1782 // backend would be removed both by the inspector closing its connection, and | |
1783 // by the connection that first called close. | |
1784 // To avoid that situation, don't proceed in case of reentrancy. | |
1785 if (closing_connection_) | |
1786 return; | |
1787 base::AutoReset<bool> ClosingConnection(&closing_connection_, true); | |
1788 ProcessPendingCalls(); | |
1789 | |
1790 // TODO(jsbell): Add a test for the pending_open_calls_ cases below. | |
1791 if (!ConnectionCount() && !pending_open_calls_.size() && | |
1792 !pending_delete_calls_.size()) { | |
1793 DCHECK(transactions_.empty()); | |
1794 | |
1795 backing_store_ = NULL; | |
1796 | |
1797 // This check should only be false in unit tests. | |
1798 // TODO(jsbell): Assert factory_ || we're executing a unit test. | |
1799 if (factory_) | |
1800 factory_->RemoveIDBDatabaseBackend(identifier_); | |
1801 } | |
1802 } | |
1803 | |
1804 void CreateObjectStoreAbortOperation::Perform( | |
1805 IndexedDBTransaction* transaction) { | |
1806 IDB_TRACE("CreateObjectStoreAbortOperation"); | |
1807 DCHECK(!transaction); | |
1808 database_->RemoveObjectStore(object_store_id_); | |
1809 } | |
1810 | |
1811 void DeleteObjectStoreAbortOperation::Perform( | |
1812 IndexedDBTransaction* transaction) { | |
1813 IDB_TRACE("DeleteObjectStoreAbortOperation"); | |
1814 DCHECK(!transaction); | |
1815 database_->AddObjectStore(object_store_metadata_, | |
1816 IndexedDBObjectStoreMetadata::kInvalidId); | |
1817 } | |
1818 | |
1819 void IndexedDBDatabaseImpl::VersionChangeAbortOperation::Perform( | |
1820 IndexedDBTransaction* transaction) { | |
1821 IDB_TRACE("VersionChangeAbortOperation"); | |
1822 DCHECK(!transaction); | |
1823 database_->metadata_.version = previous_version_; | |
1824 database_->metadata_.int_version = previous_int_version_; | |
1825 } | |
1826 | |
1827 } // namespace content | |
OLD | NEW |