Home | History | Annotate | Download | only in database
      1 // Copyright (c) 2012 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 "storage/common/database/database_connections.h"
      6 
      7 #include "base/auto_reset.h"
      8 #include "base/bind.h"
      9 #include "base/logging.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/message_loop/message_loop_proxy.h"
     12 
     13 namespace storage {
     14 
     15 DatabaseConnections::DatabaseConnections() {
     16 }
     17 
     18 DatabaseConnections::~DatabaseConnections() {
     19   DCHECK(connections_.empty());
     20 }
     21 
     22 bool DatabaseConnections::IsEmpty() const {
     23   return connections_.empty();
     24 }
     25 
     26 bool DatabaseConnections::IsDatabaseOpened(
     27     const std::string& origin_identifier,
     28     const base::string16& database_name) const {
     29   OriginConnections::const_iterator origin_it =
     30       connections_.find(origin_identifier);
     31   if (origin_it == connections_.end())
     32     return false;
     33   const DBConnections& origin_connections = origin_it->second;
     34   return (origin_connections.find(database_name) != origin_connections.end());
     35 }
     36 
     37 bool DatabaseConnections::IsOriginUsed(
     38     const std::string& origin_identifier) const {
     39   return (connections_.find(origin_identifier) != connections_.end());
     40 }
     41 
     42 bool DatabaseConnections::AddConnection(
     43     const std::string& origin_identifier,
     44     const base::string16& database_name) {
     45   int& count = connections_[origin_identifier][database_name].first;
     46   return ++count == 1;
     47 }
     48 
     49 bool DatabaseConnections::RemoveConnection(
     50     const std::string& origin_identifier,
     51     const base::string16& database_name) {
     52   return RemoveConnectionsHelper(origin_identifier, database_name, 1);
     53 }
     54 
     55 void DatabaseConnections::RemoveAllConnections() {
     56   connections_.clear();
     57 }
     58 
     59 void DatabaseConnections::RemoveConnections(
     60     const DatabaseConnections& connections,
     61     std::vector<std::pair<std::string, base::string16> >* closed_dbs) {
     62   for (OriginConnections::const_iterator origin_it =
     63            connections.connections_.begin();
     64        origin_it != connections.connections_.end();
     65        origin_it++) {
     66     const DBConnections& db_connections = origin_it->second;
     67     for (DBConnections::const_iterator db_it = db_connections.begin();
     68          db_it != db_connections.end(); db_it++) {
     69       if (RemoveConnectionsHelper(origin_it->first, db_it->first,
     70                                   db_it->second.first))
     71         closed_dbs->push_back(std::make_pair(origin_it->first, db_it->first));
     72     }
     73   }
     74 }
     75 
     76 int64 DatabaseConnections::GetOpenDatabaseSize(
     77     const std::string& origin_identifier,
     78     const base::string16& database_name) const {
     79   DCHECK(IsDatabaseOpened(origin_identifier, database_name));
     80   return connections_[origin_identifier][database_name].second;
     81 }
     82 
     83 void DatabaseConnections::SetOpenDatabaseSize(
     84     const std::string& origin_identifier,
     85     const base::string16& database_name,
     86     int64 size) {
     87   DCHECK(IsDatabaseOpened(origin_identifier, database_name));
     88   connections_[origin_identifier][database_name].second = size;
     89 }
     90 
     91 void DatabaseConnections::ListConnections(
     92     std::vector<std::pair<std::string, base::string16> > *list) const {
     93   for (OriginConnections::const_iterator origin_it =
     94            connections_.begin();
     95        origin_it != connections_.end();
     96        origin_it++) {
     97     const DBConnections& db_connections = origin_it->second;
     98     for (DBConnections::const_iterator db_it = db_connections.begin();
     99          db_it != db_connections.end(); db_it++) {
    100       list->push_back(std::make_pair(origin_it->first, db_it->first));
    101     }
    102   }
    103 }
    104 
    105 bool DatabaseConnections::RemoveConnectionsHelper(
    106     const std::string& origin_identifier,
    107     const base::string16& database_name,
    108     int num_connections) {
    109   OriginConnections::iterator origin_iterator =
    110       connections_.find(origin_identifier);
    111   DCHECK(origin_iterator != connections_.end());
    112   DBConnections& db_connections = origin_iterator->second;
    113   int& count = db_connections[database_name].first;
    114   DCHECK(count >= num_connections);
    115   count -= num_connections;
    116   if (count)
    117     return false;
    118   db_connections.erase(database_name);
    119   if (db_connections.empty())
    120     connections_.erase(origin_iterator);
    121   return true;
    122 }
    123 
    124 DatabaseConnectionsWrapper::DatabaseConnectionsWrapper()
    125     : waiting_for_dbs_to_close_(false),
    126       main_thread_(base::MessageLoopProxy::current()) {
    127 }
    128 
    129 DatabaseConnectionsWrapper::~DatabaseConnectionsWrapper() {
    130 }
    131 
    132 void DatabaseConnectionsWrapper::WaitForAllDatabasesToClose() {
    133   // We assume that new databases won't be open while we're waiting.
    134   DCHECK(main_thread_->BelongsToCurrentThread());
    135   if (HasOpenConnections()) {
    136     base::AutoReset<bool> auto_reset(&waiting_for_dbs_to_close_, true);
    137     base::MessageLoop::ScopedNestableTaskAllower allow(
    138         base::MessageLoop::current());
    139     base::MessageLoop::current()->Run();
    140   }
    141 }
    142 
    143 bool DatabaseConnectionsWrapper::HasOpenConnections() {
    144   DCHECK(main_thread_->BelongsToCurrentThread());
    145   base::AutoLock auto_lock(open_connections_lock_);
    146   return !open_connections_.IsEmpty();
    147 }
    148 
    149 void DatabaseConnectionsWrapper::AddOpenConnection(
    150     const std::string& origin_identifier,
    151     const base::string16& database_name) {
    152   // We add to the collection immediately on any thread.
    153   base::AutoLock auto_lock(open_connections_lock_);
    154   open_connections_.AddConnection(origin_identifier, database_name);
    155 }
    156 
    157 void DatabaseConnectionsWrapper::RemoveOpenConnection(
    158     const std::string& origin_identifier,
    159     const base::string16& database_name) {
    160   // But only remove from the collection on the main thread
    161   // so we can handle the waiting_for_dbs_to_close_ case.
    162   if (!main_thread_->BelongsToCurrentThread()) {
    163     main_thread_->PostTask(
    164         FROM_HERE,
    165         base::Bind(&DatabaseConnectionsWrapper::RemoveOpenConnection, this,
    166                    origin_identifier, database_name));
    167     return;
    168   }
    169   base::AutoLock auto_lock(open_connections_lock_);
    170   open_connections_.RemoveConnection(origin_identifier, database_name);
    171   if (waiting_for_dbs_to_close_ && open_connections_.IsEmpty())
    172     base::MessageLoop::current()->Quit();
    173 }
    174 
    175 }  // namespace storage
    176