| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/browser/indexed_db/indexed_db_connection.h" |
| |
| #include "base/logging.h" |
| #include "base/stl_util.h" |
| #include "content/browser/indexed_db/indexed_db_class_factory.h" |
| #include "content/browser/indexed_db/indexed_db_database_callbacks.h" |
| #include "content/browser/indexed_db/indexed_db_database_error.h" |
| #include "content/browser/indexed_db/indexed_db_observer.h" |
| #include "content/browser/indexed_db/indexed_db_tracing.h" |
| #include "content/browser/indexed_db/indexed_db_transaction.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| static int32_t g_next_indexed_db_connection_id; |
| |
| } // namespace |
| |
| IndexedDBConnection::IndexedDBConnection( |
| int child_process_id, |
| scoped_refptr<IndexedDBDatabase> database, |
| scoped_refptr<IndexedDBDatabaseCallbacks> callbacks) |
| : id_(g_next_indexed_db_connection_id++), |
| child_process_id_(child_process_id), |
| database_(database), |
| callbacks_(callbacks), |
| weak_factory_(this) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| } |
| |
| IndexedDBConnection::~IndexedDBConnection() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| } |
| |
| void IndexedDBConnection::Close() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| if (!callbacks_.get()) |
| return; |
| base::WeakPtr<IndexedDBConnection> this_obj = weak_factory_.GetWeakPtr(); |
| database_->Close(this, false /* forced */); |
| if (this_obj) { |
| database_ = nullptr; |
| callbacks_ = nullptr; |
| active_observers_.clear(); |
| } |
| } |
| |
| void IndexedDBConnection::ForceClose() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| if (!callbacks_.get()) |
| return; |
| |
| // IndexedDBDatabase::Close() can delete this instance. |
| base::WeakPtr<IndexedDBConnection> this_obj = weak_factory_.GetWeakPtr(); |
| scoped_refptr<IndexedDBDatabaseCallbacks> callbacks(callbacks_); |
| database_->Close(this, true /* forced */); |
| if (this_obj) { |
| database_ = nullptr; |
| callbacks_ = nullptr; |
| active_observers_.clear(); |
| } |
| callbacks->OnForcedClose(); |
| } |
| |
| void IndexedDBConnection::VersionChangeIgnored() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| if (!database_.get()) |
| return; |
| database_->VersionChangeIgnored(); |
| } |
| |
| bool IndexedDBConnection::IsConnected() { |
| return database_.get() != nullptr; |
| } |
| |
| // The observers begin listening to changes only once they are activated. |
| void IndexedDBConnection::ActivatePendingObservers( |
| std::vector<std::unique_ptr<IndexedDBObserver>> pending_observers) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| for (auto& observer : pending_observers) { |
| active_observers_.push_back(std::move(observer)); |
| } |
| pending_observers.clear(); |
| } |
| |
| void IndexedDBConnection::RemoveObservers( |
| const std::vector<int32_t>& observer_ids_to_remove) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| std::vector<int32_t> pending_observer_ids; |
| for (int32_t id_to_remove : observer_ids_to_remove) { |
| const auto& it = std::find_if( |
| active_observers_.begin(), active_observers_.end(), |
| [&id_to_remove](const std::unique_ptr<IndexedDBObserver>& o) { |
| return o->id() == id_to_remove; |
| }); |
| if (it != active_observers_.end()) |
| active_observers_.erase(it); |
| else |
| pending_observer_ids.push_back(id_to_remove); |
| } |
| if (pending_observer_ids.empty()) |
| return; |
| |
| for (const auto& it : transactions_) { |
| it.second->RemovePendingObservers(pending_observer_ids); |
| } |
| } |
| |
| IndexedDBTransaction* IndexedDBConnection::CreateTransaction( |
| int64_t id, |
| const std::set<int64_t>& scope, |
| blink::mojom::IDBTransactionMode mode, |
| IndexedDBBackingStore::Transaction* backing_store_transaction) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| CHECK_EQ(GetTransaction(id), nullptr) << "Duplicate transaction id." << id; |
| std::unique_ptr<IndexedDBTransaction> transaction = |
| IndexedDBClassFactory::Get()->CreateIndexedDBTransaction( |
| id, this, scope, mode, backing_store_transaction); |
| IndexedDBTransaction* transaction_ptr = transaction.get(); |
| transactions_[id] = std::move(transaction); |
| return transaction_ptr; |
| } |
| |
| void IndexedDBConnection::AbortTransaction( |
| IndexedDBTransaction* transaction, |
| const IndexedDBDatabaseError& error) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| IDB_TRACE1("IndexedDBDatabase::Abort(error)", "txn.id", transaction->id()); |
| transaction->Abort(error); |
| } |
| |
| void IndexedDBConnection::FinishAllTransactions( |
| const IndexedDBDatabaseError& error) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| std::unordered_map<int64_t, std::unique_ptr<IndexedDBTransaction>> temp_map; |
| std::swap(temp_map, transactions_); |
| for (const auto& pair : temp_map) { |
| auto& transaction = pair.second; |
| if (transaction->is_commit_pending()) { |
| IDB_TRACE1("IndexedDBDatabase::Commit", "transaction.id", |
| transaction->id()); |
| transaction->ForcePendingCommit(); |
| } else { |
| IDB_TRACE1("IndexedDBDatabase::Abort(error)", "transaction.id", |
| transaction->id()); |
| transaction->Abort(error); |
| } |
| } |
| } |
| |
| IndexedDBTransaction* IndexedDBConnection::GetTransaction(int64_t id) const { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| auto it = transactions_.find(id); |
| if (it == transactions_.end()) |
| return nullptr; |
| return it->second.get(); |
| } |
| |
| base::WeakPtr<IndexedDBTransaction> |
| IndexedDBConnection::AddTransactionForTesting( |
| std::unique_ptr<IndexedDBTransaction> transaction) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| DCHECK(!base::ContainsKey(transactions_, transaction->id())); |
| base::WeakPtr<IndexedDBTransaction> transaction_ptr = |
| transaction->ptr_factory_.GetWeakPtr(); |
| transactions_[transaction->id()] = std::move(transaction); |
| return transaction_ptr; |
| } |
| |
| void IndexedDBConnection::RemoveTransaction(int64_t id) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| transactions_.erase(id); |
| } |
| |
| } // namespace content |