text: // Copyright (c) 2012 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 "storage/common/database/database_connections.h"
  
  #include <ostream>
  
  #include "base/check.h"
  
  namespace storage {
  
  DatabaseConnections::DatabaseConnections() = default;
  
  DatabaseConnections::~DatabaseConnections() {
    DCHECK(connections_.empty());
  }
  
  bool DatabaseConnections::IsEmpty() const {
    return connections_.empty();
  }
  
  bool DatabaseConnections::IsDatabaseOpened(
      const std::string& origin_identifier,
      const base::string16& database_name) const {
    auto origin_it = connections_.find(origin_identifier);
    if (origin_it == connections_.end())
      return false;
    const DBConnections& origin_connections = origin_it->second;
    return (origin_connections.find(database_name) != origin_connections.end());
  }
  
  bool DatabaseConnections::IsOriginUsed(
      const std::string& origin_identifier) const {
    return (connections_.find(origin_identifier) != connections_.end());
  }
  
  bool DatabaseConnections::AddConnection(
      const std::string& origin_identifier,
      const base::string16& database_name) {
    int& count = connections_[origin_identifier][database_name].first;
    return ++count == 1;
  }
  
  bool DatabaseConnections::RemoveConnection(
      const std::string& origin_identifier,
      const base::string16& database_name) {
    return RemoveConnectionsHelper(origin_identifier, database_name, 1);
  }
  
  void DatabaseConnections::RemoveAllConnections() {
    connections_.clear();
  }
  
  std::vector<std::pair<std::string, base::string16>>
  DatabaseConnections::RemoveConnections(const DatabaseConnections& connections) {
    std::vector<std::pair<std::string, base::string16>> closed_dbs;
    for (const auto& origin_connections_pair : connections.connections_) {
      const DBConnections& db_connections = origin_connections_pair.second;
      for (const auto& count_size_pair : db_connections) {
        if (RemoveConnectionsHelper(origin_connections_pair.first,
                                    count_size_pair.first,
                                    count_size_pair.second.first)) {
          closed_dbs.emplace_back(origin_connections_pair.first,
                                  count_size_pair.first);
        }
      }
    }
    return closed_dbs;
  }
  
  int64_t DatabaseConnections::GetOpenDatabaseSize(
      const std::string& origin_identifier,
      const base::string16& database_name) const {
    auto origin_it = connections_.find(origin_identifier);
    DCHECK(origin_it != connections_.end()) << "Database not opened";
    auto it = origin_it->second.find(database_name);
    DCHECK(it != origin_it->second.end()) << "Database not opened";
    return it->second.second;
  }
  
  void DatabaseConnections::SetOpenDatabaseSize(
      const std::string& origin_identifier,
      const base::string16& database_name,
      int64_t size) {
    DCHECK(IsDatabaseOpened(origin_identifier, database_name));
    connections_[origin_identifier][database_name].second = size;
  }
  
  std::vector<std::pair<std::string, base::string16>>
  DatabaseConnections::ListConnections() const {
    std::vector<std::pair<std::string, base::string16>> list;
    for (const auto& origin_connections_pair : connections_) {
      const DBConnections& db_connections = origin_connections_pair.second;
      for (const auto& count_size_pair : db_connections)
        list.emplace_back(origin_connections_pair.first, count_size_pair.first);
    }
    return list;
  }
  
  bool DatabaseConnections::RemoveConnectionsHelper(
      const std::string& origin_identifier,
      const base::string16& database_name,
      int num_connections) {
    auto origin_iterator = connections_.find(origin_identifier);
    DCHECK(origin_iterator != connections_.end());
    DBConnections& db_connections = origin_iterator->second;
    int& count = db_connections[database_name].first;
    DCHECK(count >= num_connections);
    count -= num_connections;
    if (count)
      return false;
    db_connections.erase(database_name);
    if (db_connections.empty())
      connections_.erase(origin_iterator);
    return true;
  }
  
  }  // namespace storage
  