| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/indexed_db/indexed_db_database.h" | 5 #include "content/browser/indexed_db/indexed_db_database.h" |
| 6 | 6 |
| 7 #include <math.h> | 7 #include <math.h> |
| 8 #include <set> | 8 #include <set> |
| 9 | 9 |
| 10 #include "base/auto_reset.h" | 10 #include "base/auto_reset.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
| 13 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
| 14 #include "base/strings/string_number_conversions.h" | 14 #include "base/strings/string_number_conversions.h" |
| 15 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
| 16 #include "content/browser/indexed_db/indexed_db_connection.h" | 16 #include "content/browser/indexed_db/indexed_db_connection.h" |
| 17 #include "content/browser/indexed_db/indexed_db_cursor.h" | 17 #include "content/browser/indexed_db/indexed_db_cursor.h" |
| 18 #include "content/browser/indexed_db/indexed_db_factory.h" | 18 #include "content/browser/indexed_db/indexed_db_factory.h" |
| 19 #include "content/browser/indexed_db/indexed_db_index_writer.h" | 19 #include "content/browser/indexed_db/indexed_db_index_writer.h" |
| 20 #include "content/browser/indexed_db/indexed_db_pending_connection.h" |
| 20 #include "content/browser/indexed_db/indexed_db_tracing.h" | 21 #include "content/browser/indexed_db/indexed_db_tracing.h" |
| 21 #include "content/browser/indexed_db/indexed_db_transaction.h" | 22 #include "content/browser/indexed_db/indexed_db_transaction.h" |
| 22 #include "content/common/indexed_db/indexed_db_key_path.h" | 23 #include "content/common/indexed_db/indexed_db_key_path.h" |
| 23 #include "content/common/indexed_db/indexed_db_key_range.h" | 24 #include "content/common/indexed_db/indexed_db_key_range.h" |
| 24 #include "third_party/WebKit/public/platform/WebIDBDatabaseException.h" | 25 #include "third_party/WebKit/public/platform/WebIDBDatabaseException.h" |
| 25 | 26 |
| 26 using base::ASCIIToUTF16; | 27 using base::ASCIIToUTF16; |
| 27 using base::Int64ToString16; | 28 using base::Int64ToString16; |
| 28 using blink::WebIDBKeyTypeNumber; | 29 using blink::WebIDBKeyTypeNumber; |
| 29 | 30 |
| 30 namespace content { | 31 namespace content { |
| 31 | 32 |
| 32 // PendingOpenCall has a scoped_refptr<IndexedDBDatabaseCallbacks> because it | |
| 33 // isn't a connection yet. | |
| 34 class IndexedDBDatabase::PendingOpenCall { | |
| 35 public: | |
| 36 PendingOpenCall(scoped_refptr<IndexedDBCallbacks> callbacks, | |
| 37 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks, | |
| 38 int64 transaction_id, | |
| 39 int64 version) | |
| 40 : callbacks_(callbacks), | |
| 41 database_callbacks_(database_callbacks), | |
| 42 version_(version), | |
| 43 transaction_id_(transaction_id) {} | |
| 44 scoped_refptr<IndexedDBCallbacks> callbacks() const { return callbacks_; } | |
| 45 scoped_refptr<IndexedDBDatabaseCallbacks> const database_callbacks() { | |
| 46 return database_callbacks_; | |
| 47 } | |
| 48 int64 version() const { return version_; } | |
| 49 int64 transaction_id() const { return transaction_id_; } | |
| 50 | |
| 51 private: | |
| 52 scoped_refptr<IndexedDBCallbacks> callbacks_; | |
| 53 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks_; | |
| 54 int64 version_; | |
| 55 const int64 transaction_id_; | |
| 56 }; | |
| 57 | |
| 58 // PendingUpgradeCall has a scoped_ptr<IndexedDBConnection> because it owns the | 33 // PendingUpgradeCall has a scoped_ptr<IndexedDBConnection> because it owns the |
| 59 // in-progress connection. | 34 // in-progress connection. |
| 60 class IndexedDBDatabase::PendingUpgradeCall { | 35 class IndexedDBDatabase::PendingUpgradeCall { |
| 61 public: | 36 public: |
| 62 PendingUpgradeCall(scoped_refptr<IndexedDBCallbacks> callbacks, | 37 PendingUpgradeCall(scoped_refptr<IndexedDBCallbacks> callbacks, |
| 63 scoped_ptr<IndexedDBConnection> connection, | 38 scoped_ptr<IndexedDBConnection> connection, |
| 64 int64 transaction_id, | 39 int64 transaction_id, |
| 65 int64 version) | 40 int64 version) |
| 66 : callbacks_(callbacks), | 41 : callbacks_(callbacks), |
| 67 connection_(connection.Pass()), | 42 connection_(connection.Pass()), |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 202 return backing_store_->CreateIDBDatabaseMetaData( | 177 return backing_store_->CreateIDBDatabaseMetaData( |
| 203 metadata_.name, metadata_.version, metadata_.int_version, &metadata_.id); | 178 metadata_.name, metadata_.version, metadata_.int_version, &metadata_.id); |
| 204 } | 179 } |
| 205 | 180 |
| 206 IndexedDBDatabase::~IndexedDBDatabase() { | 181 IndexedDBDatabase::~IndexedDBDatabase() { |
| 207 DCHECK(transactions_.empty()); | 182 DCHECK(transactions_.empty()); |
| 208 DCHECK(pending_open_calls_.empty()); | 183 DCHECK(pending_open_calls_.empty()); |
| 209 DCHECK(pending_delete_calls_.empty()); | 184 DCHECK(pending_delete_calls_.empty()); |
| 210 } | 185 } |
| 211 | 186 |
| 187 scoped_ptr<IndexedDBConnection> IndexedDBDatabase::CreateConnection( |
| 188 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks, |
| 189 int child_process_id) { |
| 190 scoped_ptr<IndexedDBConnection> connection( |
| 191 new IndexedDBConnection(this, database_callbacks)); |
| 192 connections_.insert(connection.get()); |
| 193 /* TODO(ericu): Grant child process permissions here so that the connection |
| 194 * can create Blobs. |
| 195 */ |
| 196 return connection.Pass(); |
| 197 } |
| 198 |
| 212 IndexedDBTransaction* IndexedDBDatabase::GetTransaction( | 199 IndexedDBTransaction* IndexedDBDatabase::GetTransaction( |
| 213 int64 transaction_id) const { | 200 int64 transaction_id) const { |
| 214 TransactionMap::const_iterator trans_iterator = | 201 TransactionMap::const_iterator trans_iterator = |
| 215 transactions_.find(transaction_id); | 202 transactions_.find(transaction_id); |
| 216 if (trans_iterator == transactions_.end()) | 203 if (trans_iterator == transactions_.end()) |
| 217 return NULL; | 204 return NULL; |
| 218 return trans_iterator->second; | 205 return trans_iterator->second; |
| 219 } | 206 } |
| 220 | 207 |
| 221 bool IndexedDBDatabase::ValidateObjectStoreId(int64 object_store_id) const { | 208 bool IndexedDBDatabase::ValidateObjectStoreId(int64 object_store_id) const { |
| (...skipping 1119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1341 } | 1328 } |
| 1342 // delete_database_final should never re-queue calls. | 1329 // delete_database_final should never re-queue calls. |
| 1343 DCHECK(pending_delete_calls_.empty()); | 1330 DCHECK(pending_delete_calls_.empty()); |
| 1344 // Fall through when complete, as pending opens may be unblocked. | 1331 // Fall through when complete, as pending opens may be unblocked. |
| 1345 } | 1332 } |
| 1346 | 1333 |
| 1347 if (!IsOpenConnectionBlocked()) { | 1334 if (!IsOpenConnectionBlocked()) { |
| 1348 PendingOpenCallList pending_open_calls; | 1335 PendingOpenCallList pending_open_calls; |
| 1349 pending_open_calls_.swap(pending_open_calls); | 1336 pending_open_calls_.swap(pending_open_calls); |
| 1350 while (!pending_open_calls.empty()) { | 1337 while (!pending_open_calls.empty()) { |
| 1351 scoped_ptr<PendingOpenCall> pending_open_call(pending_open_calls.front()); | 1338 OpenConnection(pending_open_calls.front()); |
| 1352 pending_open_calls.pop_front(); | 1339 pending_open_calls.pop_front(); |
| 1353 OpenConnection(pending_open_call->callbacks(), | |
| 1354 pending_open_call->database_callbacks(), | |
| 1355 pending_open_call->transaction_id(), | |
| 1356 pending_open_call->version()); | |
| 1357 } | 1340 } |
| 1358 } | 1341 } |
| 1359 } | 1342 } |
| 1360 | 1343 |
| 1361 void IndexedDBDatabase::CreateTransaction( | 1344 void IndexedDBDatabase::CreateTransaction( |
| 1362 int64 transaction_id, | 1345 int64 transaction_id, |
| 1363 IndexedDBConnection* connection, | 1346 IndexedDBConnection* connection, |
| 1364 const std::vector<int64>& object_store_ids, | 1347 const std::vector<int64>& object_store_ids, |
| 1365 uint16 mode) { | 1348 uint16 mode) { |
| 1366 | 1349 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1384 transactions_[transaction->id()] = transaction; | 1367 transactions_[transaction->id()] = transaction; |
| 1385 } | 1368 } |
| 1386 | 1369 |
| 1387 bool IndexedDBDatabase::IsOpenConnectionBlocked() const { | 1370 bool IndexedDBDatabase::IsOpenConnectionBlocked() const { |
| 1388 return !pending_delete_calls_.empty() || | 1371 return !pending_delete_calls_.empty() || |
| 1389 transaction_coordinator_.IsRunningVersionChangeTransaction() || | 1372 transaction_coordinator_.IsRunningVersionChangeTransaction() || |
| 1390 pending_run_version_change_transaction_call_; | 1373 pending_run_version_change_transaction_call_; |
| 1391 } | 1374 } |
| 1392 | 1375 |
| 1393 void IndexedDBDatabase::OpenConnection( | 1376 void IndexedDBDatabase::OpenConnection( |
| 1394 scoped_refptr<IndexedDBCallbacks> callbacks, | 1377 const IndexedDBPendingConnection& connection) { |
| 1395 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks, | |
| 1396 int64 transaction_id, | |
| 1397 int64 version) { | |
| 1398 DCHECK(backing_store_); | 1378 DCHECK(backing_store_); |
| 1399 | 1379 |
| 1400 // TODO(jsbell): Should have a priority queue so that higher version | 1380 // TODO(jsbell): Should have a priority queue so that higher version |
| 1401 // requests are processed first. http://crbug.com/225850 | 1381 // requests are processed first. http://crbug.com/225850 |
| 1402 if (IsOpenConnectionBlocked()) { | 1382 if (IsOpenConnectionBlocked()) { |
| 1403 // The backing store only detects data loss when it is first opened. The | 1383 // The backing store only detects data loss when it is first opened. The |
| 1404 // presence of existing connections means we didn't even check for data loss | 1384 // presence of existing connections means we didn't even check for data loss |
| 1405 // so there'd better not be any. | 1385 // so there'd better not be any. |
| 1406 DCHECK_NE(blink::WebIDBDataLossTotal, callbacks->data_loss()); | 1386 DCHECK_NE(blink::WebIDBDataLossTotal, connection.callbacks->data_loss()); |
| 1407 pending_open_calls_.push_back(new PendingOpenCall( | 1387 pending_open_calls_.push_back(connection); |
| 1408 callbacks, database_callbacks, transaction_id, version)); | |
| 1409 return; | 1388 return; |
| 1410 } | 1389 } |
| 1411 | 1390 |
| 1412 if (metadata_.id == kInvalidId) { | 1391 if (metadata_.id == kInvalidId) { |
| 1413 // The database was deleted then immediately re-opened; OpenInternal() | 1392 // The database was deleted then immediately re-opened; OpenInternal() |
| 1414 // recreates it in the backing store. | 1393 // recreates it in the backing store. |
| 1415 if (OpenInternal().ok()) { | 1394 if (OpenInternal().ok()) { |
| 1416 DCHECK_EQ(IndexedDBDatabaseMetadata::NO_INT_VERSION, | 1395 DCHECK_EQ(IndexedDBDatabaseMetadata::NO_INT_VERSION, |
| 1417 metadata_.int_version); | 1396 metadata_.int_version); |
| 1418 } else { | 1397 } else { |
| 1419 base::string16 message; | 1398 base::string16 message; |
| 1420 if (version == IndexedDBDatabaseMetadata::NO_INT_VERSION) { | 1399 if (connection.version == IndexedDBDatabaseMetadata::NO_INT_VERSION) { |
| 1421 message = ASCIIToUTF16( | 1400 message = ASCIIToUTF16( |
| 1422 "Internal error opening database with no version specified."); | 1401 "Internal error opening database with no version specified."); |
| 1423 } else { | 1402 } else { |
| 1424 message = | 1403 message = |
| 1425 ASCIIToUTF16("Internal error opening database with version ") + | 1404 ASCIIToUTF16("Internal error opening database with version ") + |
| 1426 Int64ToString16(version); | 1405 Int64ToString16(connection.version); |
| 1427 } | 1406 } |
| 1428 callbacks->OnError(IndexedDBDatabaseError( | 1407 connection.callbacks->OnError(IndexedDBDatabaseError( |
| 1429 blink::WebIDBDatabaseExceptionUnknownError, message)); | 1408 blink::WebIDBDatabaseExceptionUnknownError, message)); |
| 1430 return; | 1409 return; |
| 1431 } | 1410 } |
| 1432 } | 1411 } |
| 1433 | 1412 |
| 1434 // We infer that the database didn't exist from its lack of either type of | 1413 // We infer that the database didn't exist from its lack of either type of |
| 1435 // version. | 1414 // version. |
| 1436 bool is_new_database = | 1415 bool is_new_database = |
| 1437 metadata_.version == kNoStringVersion && | 1416 metadata_.version == kNoStringVersion && |
| 1438 metadata_.int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION; | 1417 metadata_.int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION; |
| 1439 | 1418 |
| 1440 scoped_ptr<IndexedDBConnection> connection( | 1419 if (connection.version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) { |
| 1441 new IndexedDBConnection(this, database_callbacks)); | |
| 1442 | |
| 1443 if (version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) { | |
| 1444 // For unit tests only - skip upgrade steps. Calling from script with | 1420 // For unit tests only - skip upgrade steps. Calling from script with |
| 1445 // DEFAULT_INT_VERSION throws exception. | 1421 // DEFAULT_INT_VERSION throws exception. |
| 1446 // TODO(jsbell): DCHECK that not in unit tests. | 1422 // TODO(jsbell): DCHECK that not in unit tests. |
| 1447 DCHECK(is_new_database); | 1423 DCHECK(is_new_database); |
| 1448 connections_.insert(connection.get()); | 1424 connection.callbacks->OnSuccess( |
| 1449 callbacks->OnSuccess(connection.Pass(), this->metadata()); | 1425 CreateConnection(connection.database_callbacks, |
| 1426 connection.child_process_id), |
| 1427 this->metadata()); |
| 1450 return; | 1428 return; |
| 1451 } | 1429 } |
| 1452 | 1430 |
| 1453 if (version == IndexedDBDatabaseMetadata::NO_INT_VERSION) { | 1431 // We may need to change the version. |
| 1432 int64 local_version = connection.version; |
| 1433 if (local_version == IndexedDBDatabaseMetadata::NO_INT_VERSION) { |
| 1454 if (!is_new_database) { | 1434 if (!is_new_database) { |
| 1455 connections_.insert(connection.get()); | 1435 connection.callbacks->OnSuccess( |
| 1456 callbacks->OnSuccess(connection.Pass(), this->metadata()); | 1436 CreateConnection(connection.database_callbacks, |
| 1437 connection.child_process_id), |
| 1438 this->metadata()); |
| 1457 return; | 1439 return; |
| 1458 } | 1440 } |
| 1459 // Spec says: If no version is specified and no database exists, set | 1441 // Spec says: If no version is specified and no database exists, set |
| 1460 // database version to 1. | 1442 // database version to 1. |
| 1461 version = 1; | 1443 local_version = 1; |
| 1462 } | 1444 } |
| 1463 | 1445 |
| 1464 if (version > metadata_.int_version) { | 1446 if (local_version > metadata_.int_version) { |
| 1465 connections_.insert(connection.get()); | 1447 RunVersionChangeTransaction(connection.callbacks, |
| 1466 RunVersionChangeTransaction( | 1448 CreateConnection(connection.database_callbacks, |
| 1467 callbacks, connection.Pass(), transaction_id, version); | 1449 connection.child_process_id), |
| 1450 connection.transaction_id, |
| 1451 local_version); |
| 1468 return; | 1452 return; |
| 1469 } | 1453 } |
| 1470 if (version < metadata_.int_version) { | 1454 if (local_version < metadata_.int_version) { |
| 1471 callbacks->OnError(IndexedDBDatabaseError( | 1455 connection.callbacks->OnError(IndexedDBDatabaseError( |
| 1472 blink::WebIDBDatabaseExceptionVersionError, | 1456 blink::WebIDBDatabaseExceptionVersionError, |
| 1473 ASCIIToUTF16("The requested version (") + Int64ToString16(version) + | 1457 ASCIIToUTF16("The requested version (") + |
| 1458 Int64ToString16(local_version) + |
| 1474 ASCIIToUTF16(") is less than the existing version (") + | 1459 ASCIIToUTF16(") is less than the existing version (") + |
| 1475 Int64ToString16(metadata_.int_version) + ASCIIToUTF16(")."))); | 1460 Int64ToString16(metadata_.int_version) + ASCIIToUTF16(")."))); |
| 1476 return; | 1461 return; |
| 1477 } | 1462 } |
| 1478 DCHECK_EQ(version, metadata_.int_version); | 1463 DCHECK_EQ(local_version, metadata_.int_version); |
| 1479 connections_.insert(connection.get()); | 1464 connection.callbacks->OnSuccess( |
| 1480 callbacks->OnSuccess(connection.Pass(), this->metadata()); | 1465 CreateConnection(connection.database_callbacks, |
| 1466 connection.child_process_id), |
| 1467 this->metadata()); |
| 1481 } | 1468 } |
| 1482 | 1469 |
| 1483 void IndexedDBDatabase::RunVersionChangeTransaction( | 1470 void IndexedDBDatabase::RunVersionChangeTransaction( |
| 1484 scoped_refptr<IndexedDBCallbacks> callbacks, | 1471 scoped_refptr<IndexedDBCallbacks> callbacks, |
| 1485 scoped_ptr<IndexedDBConnection> connection, | 1472 scoped_ptr<IndexedDBConnection> connection, |
| 1486 int64 transaction_id, | 1473 int64 transaction_id, |
| 1487 int64 requested_version) { | 1474 int64 requested_version) { |
| 1488 | 1475 |
| 1489 DCHECK(callbacks); | 1476 DCHECK(callbacks); |
| 1490 DCHECK(connections_.count(connection.get())); | 1477 DCHECK(connections_.count(connection.get())); |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1667 const base::string16& previous_version, | 1654 const base::string16& previous_version, |
| 1668 int64 previous_int_version, | 1655 int64 previous_int_version, |
| 1669 IndexedDBTransaction* transaction) { | 1656 IndexedDBTransaction* transaction) { |
| 1670 IDB_TRACE("IndexedDBDatabase::VersionChangeAbortOperation"); | 1657 IDB_TRACE("IndexedDBDatabase::VersionChangeAbortOperation"); |
| 1671 DCHECK(!transaction); | 1658 DCHECK(!transaction); |
| 1672 metadata_.version = previous_version; | 1659 metadata_.version = previous_version; |
| 1673 metadata_.int_version = previous_int_version; | 1660 metadata_.int_version = previous_int_version; |
| 1674 } | 1661 } |
| 1675 | 1662 |
| 1676 } // namespace content | 1663 } // namespace content |
| OLD | NEW |