This source file includes following definitions.
- RemoveDatabaseFromMaps
- ReleaseDatabase
- ReleaseBackingStore
- MaybeCloseBackingStore
- CloseBackingStore
- HasLastBackingStoreReference
- ForceClose
- ContextDestroyed
- ReportOutstandingBlobs
- GetDatabaseNames
- DeleteDatabase
- DatabaseDeleted
- HandleBackingStoreFailure
- HandleBackingStoreCorruption
- IsDatabaseOpen
- IsBackingStoreOpen
- IsBackingStorePendingClose
- OpenBackingStore
- Open
- GetOpenDatabasesForOrigin
- GetConnectionCount
#include "content/browser/indexed_db/indexed_db_factory.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "content/browser/indexed_db/indexed_db_backing_store.h"
#include "content/browser/indexed_db/indexed_db_context_impl.h"
#include "content/browser/indexed_db/indexed_db_database_error.h"
#include "content/browser/indexed_db/indexed_db_tracing.h"
#include "content/browser/indexed_db/indexed_db_transaction_coordinator.h"
#include "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
#include "webkit/common/database/database_identifier.h"
using base::ASCIIToUTF16;
namespace content {
const int64 kBackingStoreGracePeriodMs = 2000;
IndexedDBFactory::IndexedDBFactory(IndexedDBContextImpl* context)
: context_(context) {}
IndexedDBFactory::~IndexedDBFactory() {}
void IndexedDBFactory::RemoveDatabaseFromMaps(
const IndexedDBDatabase::Identifier& identifier) {
IndexedDBDatabaseMap::iterator it = database_map_.find(identifier);
DCHECK(it != database_map_.end());
IndexedDBDatabase* database = it->second;
database_map_.erase(it);
std::pair<OriginDBMap::iterator, OriginDBMap::iterator> range =
origin_dbs_.equal_range(database->identifier().first);
DCHECK(range.first != range.second);
for (OriginDBMap::iterator it2 = range.first; it2 != range.second; ++it2) {
if (it2->second == database) {
origin_dbs_.erase(it2);
break;
}
}
}
void IndexedDBFactory::ReleaseDatabase(
const IndexedDBDatabase::Identifier& identifier,
bool forcedClose) {
DCHECK(!database_map_.find(identifier)->second->backing_store());
RemoveDatabaseFromMaps(identifier);
ReleaseBackingStore(identifier.first, forcedClose);
}
void IndexedDBFactory::ReleaseBackingStore(const GURL& origin_url,
bool immediate) {
if (immediate) {
IndexedDBBackingStoreMap::iterator it =
backing_stores_with_active_blobs_.find(origin_url);
if (it != backing_stores_with_active_blobs_.end()) {
it->second->active_blob_registry()->ForceShutdown();
backing_stores_with_active_blobs_.erase(it);
}
}
if (!HasLastBackingStoreReference(origin_url))
return;
if (immediate) {
CloseBackingStore(origin_url);
return;
}
DCHECK(!backing_store_map_[origin_url]->close_timer()->IsRunning());
backing_store_map_[origin_url]->close_timer()->Start(
FROM_HERE,
base::TimeDelta::FromMilliseconds(kBackingStoreGracePeriodMs),
base::Bind(&IndexedDBFactory::MaybeCloseBackingStore, this, origin_url));
}
void IndexedDBFactory::MaybeCloseBackingStore(const GURL& origin_url) {
if (HasLastBackingStoreReference(origin_url))
CloseBackingStore(origin_url);
}
void IndexedDBFactory::CloseBackingStore(const GURL& origin_url) {
IndexedDBBackingStoreMap::iterator it = backing_store_map_.find(origin_url);
DCHECK(it != backing_store_map_.end());
it->second->close_timer()->Stop();
backing_store_map_.erase(it);
}
bool IndexedDBFactory::HasLastBackingStoreReference(const GURL& origin_url)
const {
IndexedDBBackingStore* ptr;
{
IndexedDBBackingStoreMap::const_iterator it =
backing_store_map_.find(origin_url);
DCHECK(it != backing_store_map_.end());
ptr = it->second.get();
}
return ptr->HasOneRef();
}
void IndexedDBFactory::ForceClose(const GURL& origin_url) {
std::pair<OriginDBMapIterator, OriginDBMapIterator> range =
GetOpenDatabasesForOrigin(origin_url);
while (range.first != range.second) {
IndexedDBDatabase* db = range.first->second;
++range.first;
db->ForceClose();
}
if (backing_store_map_.find(origin_url) != backing_store_map_.end())
ReleaseBackingStore(origin_url, true );
}
void IndexedDBFactory::ContextDestroyed() {
for (IndexedDBBackingStoreMap::iterator it = backing_store_map_.begin();
it != backing_store_map_.end();
++it)
it->second->close_timer()->Stop();
backing_store_map_.clear();
backing_stores_with_active_blobs_.clear();
context_ = NULL;
}
void IndexedDBFactory::ReportOutstandingBlobs(const GURL& origin_url,
bool blobs_outstanding) {
if (!context_)
return;
if (blobs_outstanding) {
DCHECK(!backing_stores_with_active_blobs_.count(origin_url));
IndexedDBBackingStoreMap::iterator it = backing_store_map_.find(origin_url);
if (it != backing_store_map_.end())
backing_stores_with_active_blobs_.insert(*it);
else
DCHECK(false);
} else {
IndexedDBBackingStoreMap::iterator it =
backing_stores_with_active_blobs_.find(origin_url);
if (it != backing_stores_with_active_blobs_.end()) {
backing_stores_with_active_blobs_.erase(it);
ReleaseBackingStore(origin_url, false );
}
}
}
void IndexedDBFactory::GetDatabaseNames(
scoped_refptr<IndexedDBCallbacks> callbacks,
const GURL& origin_url,
const base::FilePath& data_directory) {
IDB_TRACE("IndexedDBFactory::GetDatabaseNames");
blink::WebIDBDataLoss data_loss;
std::string data_loss_message;
bool disk_full;
scoped_refptr<IndexedDBBackingStore> backing_store =
OpenBackingStore(origin_url,
data_directory,
&data_loss,
&data_loss_message,
&disk_full);
if (!backing_store) {
callbacks->OnError(
IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
"Internal error opening backing store for "
"indexedDB.webkitGetDatabaseNames."));
return;
}
callbacks->OnSuccess(backing_store->GetDatabaseNames());
backing_store = NULL;
ReleaseBackingStore(origin_url, false );
}
void IndexedDBFactory::DeleteDatabase(
const base::string16& name,
scoped_refptr<IndexedDBCallbacks> callbacks,
const GURL& origin_url,
const base::FilePath& data_directory) {
IDB_TRACE("IndexedDBFactory::DeleteDatabase");
IndexedDBDatabase::Identifier unique_identifier(origin_url, name);
IndexedDBDatabaseMap::iterator it = database_map_.find(unique_identifier);
if (it != database_map_.end()) {
it->second->DeleteDatabase(callbacks);
return;
}
blink::WebIDBDataLoss data_loss;
std::string data_loss_message;
bool disk_full = false;
scoped_refptr<IndexedDBBackingStore> backing_store =
OpenBackingStore(origin_url,
data_directory,
&data_loss,
&data_loss_message,
&disk_full);
if (!backing_store) {
callbacks->OnError(
IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
ASCIIToUTF16(
"Internal error opening backing store "
"for indexedDB.deleteDatabase.")));
return;
}
scoped_refptr<IndexedDBDatabase> database =
IndexedDBDatabase::Create(name, backing_store, this, unique_identifier);
if (!database) {
callbacks->OnError(IndexedDBDatabaseError(
blink::WebIDBDatabaseExceptionUnknownError,
ASCIIToUTF16(
"Internal error creating database backend for "
"indexedDB.deleteDatabase.")));
return;
}
database_map_[unique_identifier] = database;
origin_dbs_.insert(std::make_pair(origin_url, database));
database->DeleteDatabase(callbacks);
RemoveDatabaseFromMaps(unique_identifier);
database = NULL;
backing_store = NULL;
ReleaseBackingStore(origin_url, false );
}
void IndexedDBFactory::DatabaseDeleted(
const IndexedDBDatabase::Identifier& identifier) {
if (!context_)
return;
context_->DatabaseDeleted(identifier.first);
}
void IndexedDBFactory::HandleBackingStoreFailure(const GURL& origin_url) {
if (!context_)
return;
context_->ForceClose(origin_url,
IndexedDBContextImpl::FORCE_CLOSE_BACKING_STORE_FAILURE);
}
void IndexedDBFactory::HandleBackingStoreCorruption(
const GURL& origin_url,
const IndexedDBDatabaseError& error) {
GURL saved_origin_url(origin_url);
DCHECK(context_);
base::FilePath path_base = context_->data_path();
IndexedDBBackingStore::RecordCorruptionInfo(
path_base, saved_origin_url, base::UTF16ToUTF8(error.message()));
HandleBackingStoreFailure(saved_origin_url);
if (!IndexedDBBackingStore::DestroyBackingStore(path_base, saved_origin_url)
.ok())
DLOG(ERROR) << "Unable to delete backing store";
}
bool IndexedDBFactory::IsDatabaseOpen(const GURL& origin_url,
const base::string16& name) const {
return !!database_map_.count(IndexedDBDatabase::Identifier(origin_url, name));
}
bool IndexedDBFactory::IsBackingStoreOpen(const GURL& origin_url) const {
return backing_store_map_.find(origin_url) != backing_store_map_.end();
}
bool IndexedDBFactory::IsBackingStorePendingClose(const GURL& origin_url)
const {
IndexedDBBackingStoreMap::const_iterator it =
backing_store_map_.find(origin_url);
if (it == backing_store_map_.end())
return false;
return it->second->close_timer()->IsRunning();
}
scoped_refptr<IndexedDBBackingStore> IndexedDBFactory::OpenBackingStore(
const GURL& origin_url,
const base::FilePath& data_directory,
blink::WebIDBDataLoss* data_loss,
std::string* data_loss_message,
bool* disk_full) {
const bool open_in_memory = data_directory.empty();
IndexedDBBackingStoreMap::iterator it2 = backing_store_map_.find(origin_url);
if (it2 != backing_store_map_.end()) {
it2->second->close_timer()->Stop();
return it2->second;
}
scoped_refptr<IndexedDBBackingStore> backing_store;
if (open_in_memory) {
backing_store =
IndexedDBBackingStore::OpenInMemory(origin_url, context_->TaskRunner());
} else {
backing_store = IndexedDBBackingStore::Open(this,
origin_url,
data_directory,
data_loss,
data_loss_message,
disk_full,
context_->TaskRunner());
}
if (backing_store.get()) {
backing_store_map_[origin_url] = backing_store;
if (open_in_memory)
session_only_backing_stores_.insert(backing_store);
DCHECK(session_only_backing_stores_.empty() || open_in_memory);
return backing_store;
}
return 0;
}
void IndexedDBFactory::Open(const base::string16& name,
const IndexedDBPendingConnection& connection,
const GURL& origin_url,
const base::FilePath& data_directory) {
IDB_TRACE("IndexedDBFactory::Open");
scoped_refptr<IndexedDBDatabase> database;
IndexedDBDatabase::Identifier unique_identifier(origin_url, name);
IndexedDBDatabaseMap::iterator it = database_map_.find(unique_identifier);
blink::WebIDBDataLoss data_loss =
blink::WebIDBDataLossNone;
std::string data_loss_message;
bool disk_full = false;
bool was_open = (it != database_map_.end());
if (!was_open) {
scoped_refptr<IndexedDBBackingStore> backing_store =
OpenBackingStore(origin_url,
data_directory,
&data_loss,
&data_loss_message,
&disk_full);
if (!backing_store) {
if (disk_full) {
connection.callbacks->OnError(
IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError,
ASCIIToUTF16(
"Encountered full disk while opening "
"backing store for indexedDB.open.")));
return;
}
connection.callbacks->OnError(IndexedDBDatabaseError(
blink::WebIDBDatabaseExceptionUnknownError,
ASCIIToUTF16(
"Internal error opening backing store for indexedDB.open.")));
return;
}
database =
IndexedDBDatabase::Create(name, backing_store, this, unique_identifier);
if (!database) {
connection.callbacks->OnError(IndexedDBDatabaseError(
blink::WebIDBDatabaseExceptionUnknownError,
ASCIIToUTF16(
"Internal error creating database backend for indexedDB.open.")));
return;
}
} else {
database = it->second;
}
if (data_loss != blink::WebIDBDataLossNone)
connection.callbacks->OnDataLoss(data_loss, data_loss_message);
database->OpenConnection(connection);
if (!was_open && database->ConnectionCount() > 0) {
database_map_[unique_identifier] = database;
origin_dbs_.insert(std::make_pair(origin_url, database));
}
}
std::pair<IndexedDBFactory::OriginDBMapIterator,
IndexedDBFactory::OriginDBMapIterator>
IndexedDBFactory::GetOpenDatabasesForOrigin(const GURL& origin_url) const {
return origin_dbs_.equal_range(origin_url);
}
size_t IndexedDBFactory::GetConnectionCount(const GURL& origin_url) const {
size_t count(0);
std::pair<OriginDBMapIterator, OriginDBMapIterator> range =
GetOpenDatabasesForOrigin(origin_url);
for (OriginDBMapIterator it = range.first; it != range.second; ++it)
count += it->second->ConnectionCount();
return count;
}
}