blob: 7f65d75f40b89ac2f0957f39931e5c994c195c90 [file] [log] [blame]
// Copyright (c) 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.
#ifndef CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_DATABASE_H_
#define CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_DATABASE_H_
#include <stddef.h>
#include <stdint.h>
#include <list>
#include <map>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "base/callback.h"
#include "base/containers/queue.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "content/browser/indexed_db/indexed_db.h"
#include "content/browser/indexed_db/indexed_db_backing_store.h"
#include "content/browser/indexed_db/indexed_db_callbacks.h"
#include "content/browser/indexed_db/indexed_db_connection_coordinator.h"
#include "content/browser/indexed_db/indexed_db_observer.h"
#include "content/browser/indexed_db/indexed_db_origin_state_handle.h"
#include "content/browser/indexed_db/indexed_db_pending_connection.h"
#include "content/browser/indexed_db/indexed_db_task_helper.h"
#include "content/browser/indexed_db/indexed_db_value.h"
#include "content/browser/indexed_db/list_set.h"
#include "content/browser/indexed_db/scopes/scopes_lock_manager.h"
#include "content/common/content_export.h"
#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
namespace blink {
class IndexedDBKeyPath;
class IndexedDBKeyRange;
struct IndexedDBDatabaseMetadata;
struct IndexedDBIndexMetadata;
struct IndexedDBObjectStoreMetadata;
} // namespace blink
namespace url {
class Origin;
}
namespace content {
class IndexedDBClassFactory;
class IndexedDBConnection;
class IndexedDBDatabaseCallbacks;
class IndexedDBFactory;
class IndexedDBMetadataCoding;
class IndexedDBOriginStateHandle;
class IndexedDBTransaction;
struct IndexedDBValue;
class CONTENT_EXPORT IndexedDBDatabase {
public:
// Identifier is pair of (origin, database name).
using Identifier = std::pair<url::Origin, base::string16>;
// Used to report irrecoverable backend errors. The second argument can be
// null.
using ErrorCallback =
base::RepeatingCallback<void(leveldb::Status, const char*)>;
static const int64_t kInvalidId = 0;
static const int64_t kMinimumIndexId = 30;
virtual ~IndexedDBDatabase();
const Identifier& identifier() const { return identifier_; }
IndexedDBBackingStore* backing_store() { return backing_store_; }
int64_t id() const { return metadata_.id; }
const base::string16& name() const { return metadata_.name; }
const url::Origin& origin() const { return identifier_.first; }
const blink::IndexedDBDatabaseMetadata& metadata() const { return metadata_; }
ScopesLockManager* transaction_lock_manager() { return lock_manager_; }
const ScopesLockManager* transaction_lock_manager() const {
return lock_manager_;
}
const list_set<IndexedDBConnection*>& connections() const {
return connections_;
}
TasksAvailableCallback tasks_available_callback() {
return tasks_available_callback_;
}
// TODO(dmurph): Remove this method and have transactions be directly
// scheduled using the lock manager.
enum class RunTasksResult { kDone, kError, kCanBeDestroyed };
std::tuple<RunTasksResult, leveldb::Status> RunTasks();
void RegisterAndScheduleTransaction(IndexedDBTransaction* transaction);
// The database object (this object) must be kept alive for the duration of
// this call. This means the caller should own an IndexedDBOriginStateHandle
// while caling this methods.
leveldb::Status ForceCloseAndRunTasks();
void Commit(IndexedDBTransaction* transaction);
void TransactionCreated();
void TransactionFinished(blink::mojom::IDBTransactionMode mode,
bool committed);
void AbortAllTransactionsForConnections();
void AddPendingObserver(IndexedDBTransaction* transaction,
int32_t observer_id,
const IndexedDBObserver::Options& options);
// |value| can be null for delete and clear operations.
void FilterObservation(IndexedDBTransaction*,
int64_t object_store_id,
blink::mojom::IDBOperationType type,
const blink::IndexedDBKeyRange& key_range,
const IndexedDBValue* value);
void SendObservations(
std::map<int32_t, blink::mojom::IDBObserverChangesPtr> change_map);
void ScheduleOpenConnection(
IndexedDBOriginStateHandle origin_state_handle,
std::unique_ptr<IndexedDBPendingConnection> connection);
void ScheduleDeleteDatabase(IndexedDBOriginStateHandle origin_state_handle,
scoped_refptr<IndexedDBCallbacks> callbacks,
base::OnceClosure on_deletion_complete);
void AddObjectStoreToMetadata(blink::IndexedDBObjectStoreMetadata metadata,
int64_t new_max_object_store_id);
blink::IndexedDBObjectStoreMetadata RemoveObjectStoreFromMetadata(
int64_t object_store_id);
void AddIndexToMetadata(int64_t object_store_id,
blink::IndexedDBIndexMetadata metadata,
int64_t new_max_index_id);
blink::IndexedDBIndexMetadata RemoveIndexFromMetadata(int64_t object_store_id,
int64_t index_id);
// The following methods all schedule a task on the transaction & modify the
// database:
// Number of connections that have progressed passed initial open call.
size_t ConnectionCount() const { return connections_.size(); }
// Number of active open/delete calls (running or blocked on other
// connections).
size_t ActiveOpenDeleteCount() const {
return connection_coordinator_.ActiveOpenDeleteCount();
}
// Number of open/delete calls that are waiting their turn.
size_t PendingOpenDeleteCount() const {
return connection_coordinator_.PendingOpenDeleteCount();
}
// The following methods are all of the ones actually scheduled asynchronously
// within transctions:
leveldb::Status CreateObjectStoreOperation(
int64_t object_store_id,
const base::string16& name,
const blink::IndexedDBKeyPath& key_path,
bool auto_increment,
IndexedDBTransaction* transaction);
void CreateObjectStoreAbortOperation(int64_t object_store_id);
leveldb::Status DeleteObjectStoreOperation(int64_t object_store_id,
IndexedDBTransaction* transaction);
void DeleteObjectStoreAbortOperation(
blink::IndexedDBObjectStoreMetadata object_store_metadata);
leveldb::Status RenameObjectStoreOperation(int64_t object_store_id,
const base::string16& new_name,
IndexedDBTransaction* transaction);
void RenameObjectStoreAbortOperation(int64_t object_store_id,
base::string16 old_name);
leveldb::Status VersionChangeOperation(
int64_t version,
scoped_refptr<IndexedDBCallbacks> callbacks,
IndexedDBTransaction* transaction);
void VersionChangeAbortOperation(int64_t previous_version);
leveldb::Status CreateIndexOperation(int64_t object_store_id,
int64_t index_id,
const base::string16& name,
const blink::IndexedDBKeyPath& key_path,
bool unique,
bool multi_entry,
IndexedDBTransaction* transaction);
void CreateIndexAbortOperation(int64_t object_store_id, int64_t index_id);
leveldb::Status DeleteIndexOperation(int64_t object_store_id,
int64_t index_id,
IndexedDBTransaction* transaction);
void DeleteIndexAbortOperation(int64_t object_store_id,
blink::IndexedDBIndexMetadata index_metadata);
leveldb::Status RenameIndexOperation(int64_t object_store_id,
int64_t index_id,
const base::string16& new_name,
IndexedDBTransaction* transaction);
void RenameIndexAbortOperation(int64_t object_store_id,
int64_t index_id,
base::string16 old_name);
leveldb::Status GetOperation(
base::WeakPtr<IndexedDBDispatcherHost> dispatcher_host,
int64_t object_store_id,
int64_t index_id,
std::unique_ptr<blink::IndexedDBKeyRange> key_range,
indexed_db::CursorType cursor_type,
blink::mojom::IDBDatabase::GetCallback callback,
IndexedDBTransaction* transaction);
leveldb::Status GetAllOperation(
base::WeakPtr<IndexedDBDispatcherHost> dispatcher_host,
int64_t object_store_id,
int64_t index_id,
std::unique_ptr<blink::IndexedDBKeyRange> key_range,
indexed_db::CursorType cursor_type,
int64_t max_count,
blink::mojom::IDBDatabase::GetAllCallback callback,
IndexedDBTransaction* transaction);
struct CONTENT_EXPORT PutOperationParams {
PutOperationParams();
~PutOperationParams();
int64_t object_store_id;
IndexedDBValue value;
std::unique_ptr<blink::IndexedDBKey> key;
blink::mojom::IDBPutMode put_mode;
blink::mojom::IDBTransaction::PutCallback callback;
std::vector<blink::IndexedDBIndexKeys> index_keys;
private:
DISALLOW_COPY_AND_ASSIGN(PutOperationParams);
};
leveldb::Status PutOperation(std::unique_ptr<PutOperationParams> params,
IndexedDBTransaction* transaction);
leveldb::Status SetIndexKeysOperation(
int64_t object_store_id,
std::unique_ptr<blink::IndexedDBKey> primary_key,
const std::vector<blink::IndexedDBIndexKeys>& index_keys,
IndexedDBTransaction* transaction);
leveldb::Status SetIndexesReadyOperation(size_t index_count,
IndexedDBTransaction* transaction);
struct OpenCursorOperationParams {
OpenCursorOperationParams();
~OpenCursorOperationParams();
int64_t object_store_id;
int64_t index_id;
std::unique_ptr<blink::IndexedDBKeyRange> key_range;
blink::mojom::IDBCursorDirection direction;
indexed_db::CursorType cursor_type;
blink::mojom::IDBTaskType task_type;
blink::mojom::IDBDatabase::OpenCursorCallback callback;
private:
DISALLOW_COPY_AND_ASSIGN(OpenCursorOperationParams);
};
leveldb::Status OpenCursorOperation(
std::unique_ptr<OpenCursorOperationParams> params,
const url::Origin& origin,
base::WeakPtr<IndexedDBDispatcherHost> dispatcher_host,
IndexedDBTransaction* transaction);
leveldb::Status CountOperation(
int64_t object_store_id,
int64_t index_id,
std::unique_ptr<blink::IndexedDBKeyRange> key_range,
scoped_refptr<IndexedDBCallbacks> callbacks,
IndexedDBTransaction* transaction);
leveldb::Status DeleteRangeOperation(
int64_t object_store_id,
std::unique_ptr<blink::IndexedDBKeyRange> key_range,
scoped_refptr<IndexedDBCallbacks> callbacks,
IndexedDBTransaction* transaction);
leveldb::Status GetKeyGeneratorCurrentNumberOperation(
int64_t object_store_id,
scoped_refptr<IndexedDBCallbacks> callbacks,
IndexedDBTransaction* transaction);
leveldb::Status ClearOperation(int64_t object_store_id,
scoped_refptr<IndexedDBCallbacks> callbacks,
IndexedDBTransaction* transaction);
bool IsObjectStoreIdInMetadata(int64_t object_store_id) const;
bool IsObjectStoreIdAndIndexIdInMetadata(int64_t object_store_id,
int64_t index_id) const;
bool IsObjectStoreIdAndMaybeIndexIdInMetadata(int64_t object_store_id,
int64_t index_id) const;
bool IsObjectStoreIdInMetadataAndIndexNotInMetadata(int64_t object_store_id,
int64_t index_id) const;
base::WeakPtr<IndexedDBDatabase> AsWeakPtr() {
return weak_factory_.GetWeakPtr();
}
void AddConnectionForTesting(IndexedDBConnection* connection) {
connections_.insert(connection);
}
protected:
friend class IndexedDBTransaction;
friend class IndexedDBConnectionCoordinator;
friend class IndexedDBConnectionCoordinator::ConnectionRequest;
friend class IndexedDBConnectionCoordinator::OpenRequest;
friend class IndexedDBConnectionCoordinator::DeleteRequest;
IndexedDBDatabase(const base::string16& name,
IndexedDBBackingStore* backing_store,
IndexedDBFactory* factory,
IndexedDBClassFactory* class_factory,
TasksAvailableCallback tasks_available_callback,
std::unique_ptr<IndexedDBMetadataCoding> metadata_coding,
const Identifier& unique_identifier,
ScopesLockManager* transaction_lock_manager);
// May be overridden in tests.
virtual size_t GetUsableMessageSizeInBytes() const;
private:
friend class MockBrowserTestIndexedDBClassFactory;
friend class IndexedDBClassFactory;
FRIEND_TEST_ALL_PREFIXES(IndexedDBDatabaseTest, OpenDeleteClear);
void CallUpgradeTransactionStartedForTesting(int64_t old_version);
class ConnectionRequest;
class OpenRequest;
class DeleteRequest;
leveldb::Status OpenInternal();
// If there is no active request, grab a new one from the pending queue and
// start it. Afterwards, possibly release the database by calling
// MaybeReleaseDatabase().
void ProcessRequestQueueAndMaybeRelease();
// If there are no connections, pending requests, or an active request, then
// this function will call |destroy_me_|, which can destruct this object.
void MaybeReleaseDatabase();
std::unique_ptr<IndexedDBConnection> CreateConnection(
IndexedDBOriginStateHandle origin_state_handle,
scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks,
int child_process_id);
// Ack that one of the connections notified with a "versionchange" event did
// not promptly close. Therefore a "blocked" event should be fired at the
// pending connection.
void VersionChangeIgnored();
bool HasNoConnections() const;
void SendVersionChangeToAllConnections(int64_t old_version,
int64_t new_version);
// This can only be called when the given connection is closed and no longer
// has any transaction objects.
void ConnectionClosed(IndexedDBConnection* connection);
bool CanBeDestroyed();
// Safe because the IndexedDBBackingStore is owned by the same object which
// owns us, the IndexedDBPerOriginFactory.
IndexedDBBackingStore* backing_store_;
blink::IndexedDBDatabaseMetadata metadata_;
const Identifier identifier_;
// TODO(dmurph): Remove the need for this to be here (and then remove it).
IndexedDBFactory* factory_;
IndexedDBClassFactory* const class_factory_;
std::unique_ptr<IndexedDBMetadataCoding> metadata_coding_;
ScopesLockManager* lock_manager_;
int64_t transaction_count_ = 0;
list_set<IndexedDBConnection*> connections_;
TasksAvailableCallback tasks_available_callback_;
bool force_closing_ = false;
IndexedDBConnectionCoordinator connection_coordinator_;
// |weak_factory_| is used for all callback uses.
base::WeakPtrFactory<IndexedDBDatabase> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(IndexedDBDatabase);
};
} // namespace content
#endif // CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_DATABASE_H_