From: Razvan Becheriu Date: Fri, 10 Jan 2020 18:57:42 +0000 (+0200) Subject: [#1074] implemented connection pool for pgsql host mgr X-Git-Tag: Kea-1.7.5~86 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=def2e03f87cb91afb1fa2fac0c7a191eb7e3b763;p=thirdparty%2Fkea.git [#1074] implemented connection pool for pgsql host mgr --- diff --git a/src/lib/dhcpsrv/pgsql_host_data_source.cc b/src/lib/dhcpsrv/pgsql_host_data_source.cc index 692d71ce3d..8e6e0208fa 100644 --- a/src/lib/dhcpsrv/pgsql_host_data_source.cc +++ b/src/lib/dhcpsrv/pgsql_host_data_source.cc @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -24,6 +25,8 @@ #include #include + +#include #include using namespace isc; @@ -188,8 +191,7 @@ public: /// bound values extracted from host /// /// @throw DbOperationError if bind_array cannot be populated. - PsqlBindArrayPtr - createBindForSend(const HostPtr& host) { + PsqlBindArrayPtr createBindForSend(const HostPtr& host) { if (!host) { isc_throw(BadValue, "createBindForSend:: host object is NULL"); } @@ -311,6 +313,7 @@ public: /// a second time. /// /// @return HostPtr to the newly created Host object + /// /// @throw DbOperationError if the host cannot be created. HostPtr retrieveHost(const PgSqlResult& r, int row, const HostID& peeked_host_id = 0) { @@ -1173,10 +1176,9 @@ public: /// /// @return pointer to newly constructed bind_array containing the /// bound values extracted from host - PsqlBindArrayPtr - createBindForSend(const OptionDescriptor& opt_desc, - const std::string& opt_space, - const HostID& host_id) { + PsqlBindArrayPtr createBindForSend(const OptionDescriptor& opt_desc, + const std::string& opt_space, + const HostID& host_id) { // Hold pointer to the option to make sure it remains valid until // we complete a query. option_ = opt_desc.option_; @@ -1263,11 +1265,72 @@ private: OptionPtr option_; }; -} // end of anonymous namespace +} // namespace namespace isc { namespace dhcp { +/// @brief PostgreSQL Host Context +/// +/// This class stores the thread context for the manager pool. +class PgSqlHostContext { +public: + + /// @brief Constructor + /// + /// @param parameters See PgSqlHostMgr constructor. + PgSqlHostContext(const DatabaseConnection::ParameterMap& parameters); + + /// The exchange objects are used for transfer of data to/from the database. + /// They are pointed-to objects as the contents may change in "const" calls, + /// while the rest of this object does not. (At alternative would be to + /// declare them as "mutable".) + + /// @brief Pointer to the object representing an exchange which + /// can be used to retrieve hosts and DHCPv4 options. + boost::shared_ptr host_exchange_; + + /// @brief Pointer to an object representing an exchange which can + /// be used to retrieve hosts, DHCPv6 options and IPv6 reservations. + boost::shared_ptr host_ipv6_exchange_; + + /// @brief Pointer to an object representing an exchange which can + /// be used to retrieve hosts, DHCPv4 and DHCPv6 options, and + /// IPv6 reservations using a single query. + boost::shared_ptr host_ipv46_exchange_; + + /// @brief Pointer to an object representing an exchange which can + /// be used to insert new IPv6 reservation. + boost::shared_ptr host_ipv6_reservation_exchange_; + + /// @brief Pointer to an object representing an exchange which can + /// be used to insert DHCPv4 or DHCPv6 option into dhcp4_options + /// or dhcp6_options table. + boost::shared_ptr host_option_exchange_; + + /// @brief PostgreSQL connection + PgSqlConnection conn_; + + /// @brief Indicates if the database is opened in read only mode. + bool is_readonly_; +}; + +/// @brief PostgreSQL Host Context Pool +/// +/// This class provides a pool of contexts. +class PgSqlHostContextPool { +public: + + /// @brief The vector of available contexts. + std::vector pool_; + + /// @brief The mutex to protect pool access. + std::mutex mutex_; +}; + +/// @brief Type of pointers to context pools. +typedef boost::shared_ptr PgSqlHostContextPoolPtr; + /// @brief Implementation of the @ref PgSqlHostDataSource. class PgSqlHostDataSourceImpl { public: @@ -1321,8 +1384,20 @@ public: /// @brief Destructor. ~PgSqlHostDataSourceImpl(); + /// @brief Create a new context. + /// + /// The database is opened with all the SQL commands pre-compiled. + /// + /// @return A new (never null) context. + /// + /// @throw isc::dhcp::NoDatabaseName Mandatory database name not given. + /// @throw isc::db::DbOperationError An operation on the open database has + /// failed. + PgSqlHostContextPtr createContext() const; + /// @brief Executes statements which insert a row into one of the tables. /// + /// @param ctx Context /// @param stindex Index of a statement being executed. /// @param bind Vector of PgsqlBindArray objects to be used for the query /// @param return_last_id flag indicating whether or not the insert @@ -1336,33 +1411,42 @@ public: /// the value in the result set in the first col of the first row. /// /// @throw isc::db::DuplicateEntry Database throws duplicate entry error - uint64_t addStatement(PgSqlHostDataSourceImpl::StatementIndex stindex, + uint64_t addStatement(PgSqlHostContextPtr& ctx, + PgSqlHostDataSourceImpl::StatementIndex stindex, PsqlBindArrayPtr& bind, const bool return_last_id = false); /// @brief Executes statements that delete records. /// + /// @param ctx Context /// @param stindex Index of a statement being executed. /// @param bind pointer to PsqlBindArray objects to be used for the query + /// /// @return true if any records were deleted, false otherwise - bool delStatement(PgSqlHostDataSourceImpl::StatementIndex stindex, + bool delStatement(PgSqlHostContextPtr& ctx, + PgSqlHostDataSourceImpl::StatementIndex stindex, PsqlBindArrayPtr& bind); /// @brief Inserts IPv6 Reservation into ipv6_reservation table. /// + /// @param ctx Context /// @param resv IPv6 Reservation to be added /// @param id ID of a host owning this reservation - void addResv(const IPv6Resrv& resv, const HostID& id); + void addResv(PgSqlHostContextPtr& ctx, + const IPv6Resrv& resv, + const HostID& id); /// @brief Inserts a single DHCP option into the database. /// + /// @param ctx Context /// @param stindex Index of a statement being executed. /// @param opt_desc Option descriptor holding information about an option /// to be inserted into the database. /// @param opt_space Option space name. /// @param subnet_id Subnet identifier. /// @param host_id Host identifier. - void addOption(const PgSqlHostDataSourceImpl::StatementIndex& stindex, + void addOption(PgSqlHostContextPtr& ctx, + const PgSqlHostDataSourceImpl::StatementIndex& stindex, const OptionDescriptor& opt_desc, const std::string& opt_space, const Optional& subnet_id, @@ -1370,12 +1454,14 @@ public: /// @brief Inserts multiple options into the database. /// + /// @param ctx Context /// @param stindex Index of a statement being executed. /// @param options_cfg An object holding a collection of options to be /// inserted into the database. /// @param host_id Host identifier retrieved using getColumnValue /// in addStatement method - void addOptions(const StatementIndex& stindex, + void addOptions(PgSqlHostContextPtr& ctx, + const StatementIndex& stindex, const ConstCfgOptionPtr& options_cfg, const uint64_t host_id); @@ -1389,6 +1475,7 @@ public: /// Whether IPv6 reservations and/or options are assigned to the /// @ref Host objects depends on the type of the exchange object. /// + /// @param ctx Context /// @param stindex Statement index. /// @param bind Pointer to an array of PgSQL bindings. /// @param exchange Pointer to the exchange object used for the @@ -1396,7 +1483,8 @@ public: /// @param [out] result Reference to the collection of hosts returned. /// @param single A boolean value indicating if a single host is /// expected to be returned, or multiple hosts. - void getHostCollection(StatementIndex stindex, PsqlBindArrayPtr bind, + void getHostCollection(PgSqlHostContextPtr& ctx, + StatementIndex stindex, PsqlBindArrayPtr bind, boost::shared_ptr exchange, ConstHostCollection& result, bool single) const; @@ -1405,6 +1493,7 @@ public: /// This method is used by both PgSqlHostDataSource::get4 and /// PgSqlHostDataSource::get6 methods. /// + /// @param ctx Context /// @param subnet_id Subnet identifier. /// @param identifier_type Identifier type. /// @param identifier_begin Pointer to a beginning of a buffer containing @@ -1416,7 +1505,8 @@ public: /// /// @return Pointer to const instance of Host or null pointer if /// no host found. - ConstHostPtr getHost(const SubnetID& subnet_id, + ConstHostPtr getHost(PgSqlHostContextPtr& ctx, + const SubnetID& subnet_id, const Host::IdentifierType& identifier_type, const uint8_t* identifier_begin, const size_t identifier_len, @@ -1429,8 +1519,10 @@ public: /// database. If the backend is operating in read-only mode this /// method will throw exception. /// + /// @param ctx Context + /// /// @throw DbReadOnly if backend is operating in read only mode. - void checkReadOnly() const; + void checkReadOnly(PgSqlHostContextPtr& ctx) const; /// @brief Returns PostgreSQL schema version of the open database /// @@ -1442,36 +1534,11 @@ public: /// has failed. std::pair getVersion() const; - /// @brief Pointer to the object representing an exchange which - /// can be used to retrieve hosts and DHCPv4 options. - boost::shared_ptr host_exchange_; - - /// @brief Pointer to an object representing an exchange which can - /// be used to retrieve hosts, DHCPv6 options and IPv6 reservations. - boost::shared_ptr host_ipv6_exchange_; - - /// @brief Pointer to an object representing an exchange which can - /// be used to retrieve hosts, DHCPv4 and DHCPv6 options, and - /// IPv6 reservations using a single query. - boost::shared_ptr host_ipv46_exchange_; - - /// @brief Pointer to an object representing an exchange which can - /// be used to insert new IPv6 reservation. - boost::shared_ptr host_ipv6_reservation_exchange_; - - /// @brief Pointer to an object representing an exchange which can - /// be used to insert DHCPv4 or DHCPv6 option into dhcp4_options - /// or dhcp6_options table. - boost::shared_ptr host_option_exchange_; - /// @brief The parameters PgSqlConnection::ParameterMap parameters_; - /// @brief PgSQL connection - PgSqlConnection conn_; - - /// @brief Indicates if the database is opened in read only mode. - bool is_readonly_; + /// @brief The pool of contexts + PgSqlHostContextPoolPtr pool_; }; namespace { @@ -1658,7 +1725,8 @@ TaggedStatementArray tagged_statements = { { // results in multiple rows being returned for the same host. The hosts are // retrieved by subnet id. {1, - { OID_INT8 }, "get_host_subid4", + { OID_INT8 }, + "get_host_subid4", "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, " " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " @@ -1683,7 +1751,8 @@ TaggedStatementArray tagged_statements = { { // are usually many hosts in a subnet. The amount of returned data may // be huge. {1, - { OID_INT8 }, "get_host_subid6", + { OID_INT8 }, + "get_host_subid6", "SELECT h.host_id, h.dhcp_identifier, " " h.dhcp_identifier_type, h.dhcp4_subnet_id, " " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " @@ -1857,7 +1926,7 @@ TaggedStatementArray tagged_statements = { { // Using fixed scope_id = 3, which associates an option with host. {7, { OID_INT2, OID_BYTEA, OID_TEXT, - OID_VARCHAR, OID_BOOL, OID_TEXT, OID_INT8}, + OID_VARCHAR, OID_BOOL, OID_TEXT, OID_INT8 }, "insert_v4_host_option", "INSERT INTO dhcp4_options(code, value, formatted_value, space, " " persistent, user_context, host_id, scope_id) " @@ -1869,7 +1938,7 @@ TaggedStatementArray tagged_statements = { { // Using fixed scope_id = 3, which associates an option with host. {7, { OID_INT2, OID_BYTEA, OID_TEXT, - OID_VARCHAR, OID_BOOL, OID_TEXT, OID_INT8}, + OID_VARCHAR, OID_BOOL, OID_TEXT, OID_INT8 }, "insert_v6_host_option", "INSERT INTO dhcp6_options(code, value, formatted_value, space, " " persistent, user_context, host_id, scope_id) " @@ -1906,19 +1975,47 @@ TaggedStatementArray tagged_statements = { { } }; -}; // end anonymous namespace +} // namespace + +// PgSqlHostContext Constructor -PgSqlHostDataSourceImpl:: -PgSqlHostDataSourceImpl(const PgSqlConnection::ParameterMap& parameters) - : host_exchange_(new PgSqlHostWithOptionsExchange(PgSqlHostWithOptionsExchange::DHCP4_ONLY)), - host_ipv6_exchange_(new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange::DHCP6_ONLY)), - host_ipv46_exchange_(new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange:: - DHCP4_AND_DHCP6)), - host_ipv6_reservation_exchange_(new PgSqlIPv6ReservationExchange()), - host_option_exchange_(new PgSqlOptionExchange()), - parameters_(parameters), - conn_(parameters), - is_readonly_(false) { +PgSqlHostContext::PgSqlHostContext(const DatabaseConnection::ParameterMap& parameters) + : conn_(parameters), is_readonly_(true) { +} + +// PgSqlHostContextAlloc Constructor and Destructor + +PgSqlHostDataSource::PgSqlHostContextAlloc::PgSqlHostContextAlloc( + const PgSqlHostDataSourceImpl& mgr) : ctx_(), mgr_(mgr) { + + if (MultiThreadingMgr::instance().getMode()) { + { + lock_guard lock(mgr_.pool_->mutex_); + if (!mgr_.pool_->pool_.empty()) { + ctx_ = mgr_.pool_->pool_.back(); + mgr_.pool_->pool_.pop_back(); + } + } + if (!ctx_) { + ctx_ = mgr_.createContext(); + } + } else { + if (mgr_.pool_->pool_.empty()) { + isc_throw(Unexpected, "No available PostgreSQL lease context?!"); + } + ctx_ = mgr_.pool_->pool_.back(); + } +} + +PgSqlHostDataSource::PgSqlHostContextAlloc::~PgSqlHostContextAlloc() { + if (MultiThreadingMgr::instance().getMode()) { + lock_guard lock(mgr_.pool_->mutex_); + mgr_.pool_->pool_.push_back(ctx_); + } +} + +PgSqlHostDataSourceImpl::PgSqlHostDataSourceImpl(const PgSqlConnection::ParameterMap& parameters) + : parameters_(parameters) { // Validate the schema version first. std::pair code_version(PG_SCHEMA_VERSION_MAJOR, @@ -1928,41 +2025,61 @@ PgSqlHostDataSourceImpl(const PgSqlConnection::ParameterMap& parameters) isc_throw(DbOpenError, "PostgreSQL schema version mismatch: need version: " << code_version.first << "." << code_version.second - << " found version: " << db_version.first << "." + << " found version: " << db_version.first << "." << db_version.second); } + // Create an initial context. + pool_.reset(new PgSqlHostContextPool()); + pool_->pool_.push_back(createContext()); +} + +// Create context. + +PgSqlHostContextPtr +PgSqlHostDataSourceImpl::createContext() const { + PgSqlHostContextPtr ctx(new PgSqlHostContext(parameters_)); + // Open the database. - conn_.openDatabase(); + ctx->conn_.openDatabase(); // Now prepare the SQL statements. - conn_.prepareStatements(tagged_statements.begin(), - tagged_statements.begin() + WRITE_STMTS_BEGIN); + ctx->conn_.prepareStatements(tagged_statements.begin(), + tagged_statements.begin() + WRITE_STMTS_BEGIN); // Check if the backend is explicitly configured to operate with // read only access to the database. - is_readonly_ = conn_.configuredReadOnly(); + ctx->is_readonly_ = ctx->conn_.configuredReadOnly(); // If we are using read-write mode for the database we also prepare // statements for INSERTS etc. - if (!is_readonly_) { - conn_.prepareStatements(tagged_statements.begin() + WRITE_STMTS_BEGIN, - tagged_statements.end()); + if (!ctx->is_readonly_) { + ctx->conn_.prepareStatements(tagged_statements.begin() + WRITE_STMTS_BEGIN, + tagged_statements.end()); } else { LOG_INFO(dhcpsrv_logger, DHCPSRV_PGSQL_HOST_DB_READONLY); } + + ctx->host_exchange_.reset(new PgSqlHostWithOptionsExchange(PgSqlHostWithOptionsExchange::DHCP4_ONLY)); + ctx->host_ipv6_exchange_.reset(new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange::DHCP6_ONLY)); + ctx->host_ipv46_exchange_.reset(new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange::DHCP4_AND_DHCP6)); + ctx->host_ipv6_reservation_exchange_.reset(new PgSqlIPv6ReservationExchange()); + ctx->host_option_exchange_.reset(new PgSqlOptionExchange()); + + return (ctx); } PgSqlHostDataSourceImpl::~PgSqlHostDataSourceImpl() { } uint64_t -PgSqlHostDataSourceImpl::addStatement(StatementIndex stindex, +PgSqlHostDataSourceImpl::addStatement(PgSqlHostContextPtr& ctx, + StatementIndex stindex, PsqlBindArrayPtr& bind_array, const bool return_last_id) { uint64_t last_id = 0; - PgSqlResult r(PQexecPrepared(conn_, tagged_statements[stindex].name, + PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name, tagged_statements[stindex].nbparams, &bind_array->values_[0], &bind_array->lengths_[0], @@ -1972,13 +2089,13 @@ PgSqlHostDataSourceImpl::addStatement(StatementIndex stindex, if (s != PGRES_COMMAND_OK) { // Failure: check for the special case of duplicate entry. - if (conn_.compareError(r, PgSqlConnection::DUPLICATE_KEY)) { + if (ctx->conn_.compareError(r, PgSqlConnection::DUPLICATE_KEY)) { isc_throw(DuplicateEntry, "Database duplicate entry error"); } // Connection determines if the error is fatal or not, and // throws the appropriate exception - conn_.checkStatementError(r, tagged_statements[stindex]); + ctx->conn_.checkStatementError(r, tagged_statements[stindex]); } if (return_last_id) { @@ -1989,9 +2106,10 @@ PgSqlHostDataSourceImpl::addStatement(StatementIndex stindex, } bool -PgSqlHostDataSourceImpl::delStatement(StatementIndex stindex, +PgSqlHostDataSourceImpl::delStatement(PgSqlHostContextPtr& ctx, + StatementIndex stindex, PsqlBindArrayPtr& bind_array) { - PgSqlResult r(PQexecPrepared(conn_, tagged_statements[stindex].name, + PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name, tagged_statements[stindex].nbparams, &bind_array->values_[0], &bind_array->lengths_[0], @@ -2002,7 +2120,7 @@ PgSqlHostDataSourceImpl::delStatement(StatementIndex stindex, if (s != PGRES_COMMAND_OK) { // Connection determines if the error is fatal or not, and // throws the appropriate exception - conn_.checkStatementError(r, tagged_statements[stindex]); + ctx->conn_.checkStatementError(r, tagged_statements[stindex]); } // Now check how many rows (hosts) were deleted. This should be either @@ -2016,27 +2134,29 @@ PgSqlHostDataSourceImpl::delStatement(StatementIndex stindex, } void -PgSqlHostDataSourceImpl::addResv(const IPv6Resrv& resv, +PgSqlHostDataSourceImpl::addResv(PgSqlHostContextPtr& ctx, + const IPv6Resrv& resv, const HostID& id) { - PsqlBindArrayPtr bind_array; - bind_array = host_ipv6_reservation_exchange_->createBindForSend(resv, id); - addStatement(INSERT_V6_RESRV, bind_array); + PsqlBindArrayPtr bind_array = ctx->host_ipv6_reservation_exchange_->createBindForSend(resv, id); + + addStatement(ctx, INSERT_V6_RESRV, bind_array); } void -PgSqlHostDataSourceImpl::addOption(const StatementIndex& stindex, +PgSqlHostDataSourceImpl::addOption(PgSqlHostContextPtr& ctx, + const StatementIndex& stindex, const OptionDescriptor& opt_desc, const std::string& opt_space, const Optional&, const HostID& id) { - PsqlBindArrayPtr bind_array; - bind_array = host_option_exchange_->createBindForSend(opt_desc, opt_space, - id); - addStatement(stindex, bind_array); + PsqlBindArrayPtr bind_array = ctx->host_option_exchange_->createBindForSend(opt_desc, opt_space, id); + + addStatement(ctx, stindex, bind_array); } void -PgSqlHostDataSourceImpl::addOptions(const StatementIndex& stindex, +PgSqlHostDataSourceImpl::addOptions(PgSqlHostContextPtr& ctx, + const StatementIndex& stindex, const ConstCfgOptionPtr& options_cfg, const uint64_t host_id) { // Get option space names and vendor space names and combine them within a @@ -2048,36 +2168,35 @@ PgSqlHostDataSourceImpl::addOptions(const StatementIndex& stindex, // For each option space retrieve all options and insert them into the // database. - for (std::list::const_iterator space = option_spaces.begin(); - space != option_spaces.end(); ++space) { + for (auto space = option_spaces.begin(); space != option_spaces.end(); ++space) { OptionContainerPtr options = options_cfg->getAll(*space); if (options && !options->empty()) { - for (OptionContainer::const_iterator opt = options->begin(); - opt != options->end(); ++opt) { - addOption(stindex, *opt, *space, Optional(), - host_id); + for (auto opt = options->begin(); opt != options->end(); ++opt) { + addOption(ctx, stindex, *opt, *space, Optional(), host_id); } } } } void -PgSqlHostDataSourceImpl:: -getHostCollection(StatementIndex stindex, PsqlBindArrayPtr bind_array, - boost::shared_ptr exchange, - ConstHostCollection& result, bool single) const { +PgSqlHostDataSourceImpl::getHostCollection(PgSqlHostContextPtr& ctx, + StatementIndex stindex, + PsqlBindArrayPtr bind_array, + boost::shared_ptr exchange, + ConstHostCollection& result, + bool single) const { exchange->clear(); - PgSqlResult r(PQexecPrepared(conn_, tagged_statements[stindex].name, + PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name, tagged_statements[stindex].nbparams, &bind_array->values_[0], &bind_array->lengths_[0], &bind_array->formats_[0], 0)); - conn_.checkStatementError(r, tagged_statements[stindex]); + ctx->conn_.checkStatementError(r, tagged_statements[stindex]); int rows = r.getRows(); - for(int row = 0; row < rows; ++row) { + for (int row = 0; row < rows; ++row) { exchange->processRowData(result, r, row); if (single && result.size() > 1) { @@ -2089,13 +2208,13 @@ getHostCollection(StatementIndex stindex, PsqlBindArrayPtr bind_array, } ConstHostPtr -PgSqlHostDataSourceImpl:: -getHost(const SubnetID& subnet_id, - const Host::IdentifierType& identifier_type, - const uint8_t* identifier_begin, - const size_t identifier_len, - StatementIndex stindex, - boost::shared_ptr exchange) const { +PgSqlHostDataSourceImpl::getHost(PgSqlHostContextPtr& ctx, + const SubnetID& subnet_id, + const Host::IdentifierType& identifier_type, + const uint8_t* identifier_begin, + const size_t identifier_len, + StatementIndex stindex, + boost::shared_ptr exchange) const { // Set up the WHERE clause value PsqlBindArrayPtr bind_array(new PsqlBindArray()); @@ -2110,25 +2229,27 @@ getHost(const SubnetID& subnet_id, bind_array->add(identifier_begin, identifier_len); ConstHostCollection collection; - getHostCollection(stindex, bind_array, exchange, collection, true); + getHostCollection(ctx, stindex, bind_array, exchange, collection, true); // Return single record if present, else clear the host. ConstHostPtr result; - if (!collection.empty()) + if (!collection.empty()) { result = *collection.begin(); + } return (result); } -std::pair PgSqlHostDataSourceImpl::getVersion() const { +std::pair +PgSqlHostDataSourceImpl::getVersion() const { LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_PGSQL_HOST_DB_GET_VERSION); return (PgSqlConnection::getVersion(parameters_)); } void -PgSqlHostDataSourceImpl::checkReadOnly() const { - if (is_readonly_) { +PgSqlHostDataSourceImpl::checkReadOnly(PgSqlHostContextPtr& ctx) const { + if (ctx->is_readonly_) { isc_throw(ReadOnlyDb, "PostgreSQL host database backend is configured" " to operate in read only mode"); } @@ -2136,44 +2257,46 @@ PgSqlHostDataSourceImpl::checkReadOnly() const { /*********** PgSqlHostDataSource *********************/ -PgSqlHostDataSource:: -PgSqlHostDataSource(const PgSqlConnection::ParameterMap& parameters) +PgSqlHostDataSource::PgSqlHostDataSource(const PgSqlConnection::ParameterMap& parameters) : impl_(new PgSqlHostDataSourceImpl(parameters)) { } PgSqlHostDataSource::~PgSqlHostDataSource() { - delete impl_; } void PgSqlHostDataSource::add(const HostPtr& host) { + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; + // If operating in read-only mode, throw exception. - impl_->checkReadOnly(); + impl_->checkReadOnly(ctx); // Initiate PostgreSQL transaction as we will have to make multiple queries // to insert host information into multiple tables. If that fails on // any stage, the transaction will be rolled back by the destructor of // the PgSqlTransaction class. - PgSqlTransaction transaction(impl_->conn_); + PgSqlTransaction transaction(ctx->conn_); // Create the PgSQL Bind array for the host - PsqlBindArrayPtr bind_array = impl_->host_exchange_->createBindForSend(host); + PsqlBindArrayPtr bind_array = ctx->host_exchange_->createBindForSend(host); // ... and insert the host. - uint32_t host_id = impl_->addStatement(PgSqlHostDataSourceImpl::INSERT_HOST, + uint32_t host_id = impl_->addStatement(ctx, PgSqlHostDataSourceImpl::INSERT_HOST, bind_array, true); // Insert DHCPv4 options. ConstCfgOptionPtr cfg_option4 = host->getCfgOption4(); if (cfg_option4) { - impl_->addOptions(PgSqlHostDataSourceImpl::INSERT_V4_HOST_OPTION, + impl_->addOptions(ctx, PgSqlHostDataSourceImpl::INSERT_V4_HOST_OPTION, cfg_option4, host_id); } // Insert DHCPv6 options. ConstCfgOptionPtr cfg_option6 = host->getCfgOption6(); if (cfg_option6) { - impl_->addOptions(PgSqlHostDataSourceImpl::INSERT_V6_HOST_OPTION, + impl_->addOptions(ctx, PgSqlHostDataSourceImpl::INSERT_V6_HOST_OPTION, cfg_option6, host_id); } @@ -2182,7 +2305,7 @@ PgSqlHostDataSource::add(const HostPtr& host) { if (std::distance(v6resv.first, v6resv.second) > 0) { for (IPv6ResrvIterator resv = v6resv.first; resv != v6resv.second; ++resv) { - impl_->addResv(resv->second, host_id); + impl_->addResv(ctx, resv->second, host_id); } } @@ -2192,14 +2315,18 @@ PgSqlHostDataSource::add(const HostPtr& host) { bool PgSqlHostDataSource::del(const SubnetID& subnet_id, const asiolink::IOAddress& addr) { + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; + // If operating in read-only mode, throw exception. - impl_->checkReadOnly(); + impl_->checkReadOnly(ctx); if (addr.isV4()) { PsqlBindArrayPtr bind_array(new PsqlBindArray()); bind_array->add(subnet_id); bind_array->add(addr); - return (impl_->delStatement(PgSqlHostDataSourceImpl::DEL_HOST_ADDR4, + return (impl_->delStatement(ctx, PgSqlHostDataSourceImpl::DEL_HOST_ADDR4, bind_array)); } @@ -2217,6 +2344,12 @@ PgSqlHostDataSource::del4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type, const uint8_t* identifier_begin, const size_t identifier_len) { + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; + + // If operating in read-only mode, throw exception. + impl_->checkReadOnly(ctx); PsqlBindArrayPtr bind_array(new PsqlBindArray()); @@ -2229,7 +2362,7 @@ PgSqlHostDataSource::del4(const SubnetID& subnet_id, // identifier bind_array->add(identifier_begin, identifier_len); - return (impl_->delStatement(PgSqlHostDataSourceImpl::DEL_HOST_SUBID4_ID, + return (impl_->delStatement(ctx, PgSqlHostDataSourceImpl::DEL_HOST_SUBID4_ID, bind_array)); } @@ -2238,6 +2371,13 @@ PgSqlHostDataSource::del6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type, const uint8_t* identifier_begin, const size_t identifier_len) { + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; + + // If operating in read-only mode, throw exception. + impl_->checkReadOnly(ctx); + PsqlBindArrayPtr bind_array(new PsqlBindArray()); // Subnet-id @@ -2249,7 +2389,7 @@ PgSqlHostDataSource::del6(const SubnetID& subnet_id, // identifier bind_array->add(identifier_begin, identifier_len); - return (impl_->delStatement(PgSqlHostDataSourceImpl::DEL_HOST_SUBID6_ID, + return (impl_->delStatement(ctx, PgSqlHostDataSourceImpl::DEL_HOST_SUBID6_ID, bind_array)); } @@ -2257,6 +2397,10 @@ ConstHostCollection PgSqlHostDataSource::getAll(const Host::IdentifierType& identifier_type, const uint8_t* identifier_begin, const size_t identifier_len) const { + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; + // Set up the WHERE clause value PsqlBindArrayPtr bind_array(new PsqlBindArray()); @@ -2267,14 +2411,18 @@ PgSqlHostDataSource::getAll(const Host::IdentifierType& identifier_type, bind_array->add(static_cast(identifier_type)); ConstHostCollection result; - impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_DHCPID, - bind_array, impl_->host_ipv46_exchange_, - result, false); + impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_DHCPID, + bind_array, ctx->host_ipv46_exchange_, result, false); + return (result); } ConstHostCollection PgSqlHostDataSource::getAll4(const SubnetID& subnet_id) const { + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; + // Set up the WHERE clause value PsqlBindArrayPtr bind_array(new PsqlBindArray()); @@ -2282,15 +2430,18 @@ PgSqlHostDataSource::getAll4(const SubnetID& subnet_id) const { bind_array->add(subnet_id); ConstHostCollection result; - impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_SUBID4, - bind_array, impl_->host_exchange_, - result, false); + impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID4, + bind_array, ctx->host_exchange_, result, false); return (result); } ConstHostCollection PgSqlHostDataSource::getAll6(const SubnetID& subnet_id) const { + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; + // Set up the WHERE clause value PsqlBindArrayPtr bind_array(new PsqlBindArray()); @@ -2298,15 +2449,18 @@ PgSqlHostDataSource::getAll6(const SubnetID& subnet_id) const { bind_array->add(subnet_id); ConstHostCollection result; - impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_SUBID6, - bind_array, impl_->host_ipv6_exchange_, - result, false); + impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID6, + bind_array, ctx->host_ipv6_exchange_, result, false); return (result); } ConstHostCollection PgSqlHostDataSource::getAllbyHostname(const std::string& hostname) const { + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; + // Set up the WHERE clause value PsqlBindArrayPtr bind_array(new PsqlBindArray()); @@ -2314,15 +2468,19 @@ PgSqlHostDataSource::getAllbyHostname(const std::string& hostname) const { bind_array->add(hostname); ConstHostCollection result; - impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME, - bind_array, impl_->host_ipv46_exchange_, - result, false); + impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME, + bind_array, ctx->host_ipv46_exchange_, result, false); + return (result); } ConstHostCollection PgSqlHostDataSource::getAllbyHostname4(const std::string& hostname, const SubnetID& subnet_id) const { + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; + // Set up the WHERE clause value PsqlBindArrayPtr bind_array(new PsqlBindArray()); @@ -2333,9 +2491,8 @@ PgSqlHostDataSource::getAllbyHostname4(const std::string& hostname, bind_array->add(subnet_id); ConstHostCollection result; - impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME_SUBID4, - bind_array, impl_->host_exchange_, - result, false); + impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME_SUBID4, + bind_array, ctx->host_exchange_, result, false); return (result); } @@ -2343,6 +2500,10 @@ PgSqlHostDataSource::getAllbyHostname4(const std::string& hostname, ConstHostCollection PgSqlHostDataSource::getAllbyHostname6(const std::string& hostname, const SubnetID& subnet_id) const { + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; + // Set up the WHERE clause value PsqlBindArrayPtr bind_array(new PsqlBindArray()); @@ -2353,9 +2514,8 @@ PgSqlHostDataSource::getAllbyHostname6(const std::string& hostname, bind_array->add(subnet_id); ConstHostCollection result; - impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME_SUBID6, - bind_array, impl_->host_ipv6_exchange_, - result, false); + impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME_SUBID6, + bind_array, ctx->host_ipv6_exchange_, result, false); return (result); } @@ -2365,6 +2525,10 @@ PgSqlHostDataSource::getPage4(const SubnetID& subnet_id, size_t& /*source_index*/, uint64_t lower_host_id, const HostPageSize& page_size) const { + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; + // Set up the WHERE clause value PsqlBindArrayPtr bind_array(new PsqlBindArray()); @@ -2380,9 +2544,8 @@ PgSqlHostDataSource::getPage4(const SubnetID& subnet_id, bind_array->add(page_size_data); ConstHostCollection result; - impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_SUBID4_PAGE, - bind_array, impl_->host_exchange_, - result, false); + impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID4_PAGE, + bind_array, ctx->host_exchange_, result, false); return (result); } @@ -2392,6 +2555,10 @@ PgSqlHostDataSource::getPage6(const SubnetID& subnet_id, size_t& /*source_index*/, uint64_t lower_host_id, const HostPageSize& page_size) const { + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; + // Set up the WHERE clause value PsqlBindArrayPtr bind_array(new PsqlBindArray()); @@ -2407,15 +2574,17 @@ PgSqlHostDataSource::getPage6(const SubnetID& subnet_id, bind_array->add(page_size_data); ConstHostCollection result; - impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_SUBID6_PAGE, - bind_array, impl_->host_ipv6_exchange_, - result, false); + impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID6_PAGE, + bind_array, ctx->host_ipv6_exchange_, result, false); return (result); } ConstHostCollection PgSqlHostDataSource::getAll4(const asiolink::IOAddress& address) const { + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; // Set up the WHERE clause value PsqlBindArrayPtr bind_array(new PsqlBindArray()); @@ -2424,8 +2593,8 @@ PgSqlHostDataSource::getAll4(const asiolink::IOAddress& address) const { bind_array->add(address); ConstHostCollection result; - impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_ADDR, bind_array, - impl_->host_exchange_, result, false); + impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_ADDR, + bind_array, ctx->host_exchange_, result, false); return (result); } @@ -2435,16 +2604,22 @@ PgSqlHostDataSource::get4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type, const uint8_t* identifier_begin, const size_t identifier_len) const { + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; - return (impl_->getHost(subnet_id, identifier_type, identifier_begin, - identifier_len, + return (impl_->getHost(ctx, subnet_id, identifier_type, identifier_begin, identifier_len, PgSqlHostDataSourceImpl::GET_HOST_SUBID4_DHCPID, - impl_->host_exchange_)); + ctx->host_exchange_)); } ConstHostPtr PgSqlHostDataSource::get4(const SubnetID& subnet_id, const asiolink::IOAddress& address) const { + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; + if (!address.isV4()) { isc_throw(BadValue, "PgSqlHostDataSource::get4(id, address) - " " wrong address type, address supplied is an IPv6 address"); @@ -2460,14 +2635,14 @@ PgSqlHostDataSource::get4(const SubnetID& subnet_id, bind_array->add(address); ConstHostCollection collection; - impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_SUBID_ADDR, - bind_array, impl_->host_exchange_, collection, - true); + impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID_ADDR, + bind_array, ctx->host_exchange_, collection, true); // Return single record if present, else clear the host. ConstHostPtr result; - if (!collection.empty()) + if (!collection.empty()) { result = *collection.begin(); + } return (result); } @@ -2477,16 +2652,26 @@ PgSqlHostDataSource::get6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type, const uint8_t* identifier_begin, const size_t identifier_len) const { + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; - return (impl_->getHost(subnet_id, identifier_type, identifier_begin, - identifier_len, PgSqlHostDataSourceImpl::GET_HOST_SUBID6_DHCPID, - impl_->host_ipv6_exchange_)); + return (impl_->getHost(ctx, subnet_id, identifier_type, identifier_begin, identifier_len, + PgSqlHostDataSourceImpl::GET_HOST_SUBID6_DHCPID, + ctx->host_ipv6_exchange_)); } ConstHostPtr PgSqlHostDataSource::get6(const asiolink::IOAddress& prefix, const uint8_t prefix_len) const { - /// @todo: Check that prefix is v6 address, not v4. + if (!prefix.isV6()) { + isc_throw(BadValue, "PgSqlHostDataSource::get6(prefix, prefix_len): " + "wrong address type, address supplied is an IPv4 address"); + } + + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; // Set up the WHERE clause value PsqlBindArrayPtr bind_array(new PsqlBindArray()); @@ -2498,9 +2683,8 @@ PgSqlHostDataSource::get6(const asiolink::IOAddress& prefix, bind_array->add(prefix_len); ConstHostCollection collection; - impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_PREFIX, - bind_array, impl_->host_ipv6_exchange_, - collection, true); + impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_PREFIX, + bind_array, ctx->host_ipv6_exchange_, collection, true); // Return single record if present, else clear the host. ConstHostPtr result; @@ -2514,7 +2698,14 @@ PgSqlHostDataSource::get6(const asiolink::IOAddress& prefix, ConstHostPtr PgSqlHostDataSource::get6(const SubnetID& subnet_id, const asiolink::IOAddress& address) const { - /// @todo: Check that prefix is v6 address, not v4. + if (!address.isV6()) { + isc_throw(BadValue, "PgSqlHostDataSource::get6(id, address): " + "wrong address type, address supplied is an IPv4 address"); + } + + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; // Set up the WHERE clause value PsqlBindArrayPtr bind_array(new PsqlBindArray()); @@ -2526,9 +2717,8 @@ PgSqlHostDataSource::get6(const SubnetID& subnet_id, bind_array->add(address); ConstHostCollection collection; - impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_SUBID6_ADDR, - bind_array, impl_->host_ipv6_exchange_, - collection, true); + impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID6_ADDR, + bind_array, ctx->host_ipv6_exchange_, collection, true); // Return single record if present, else clear the host. ConstHostPtr result; @@ -2541,38 +2731,53 @@ PgSqlHostDataSource::get6(const SubnetID& subnet_id, // Miscellaneous database methods. -std::string PgSqlHostDataSource::getName() const { +std::string +PgSqlHostDataSource::getName() const { std::string name = ""; + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; + try { - name = impl_->conn_.getParameter("name"); + name = ctx->conn_.getParameter("name"); } catch (...) { // Return an empty name } return (name); } -std::string PgSqlHostDataSource::getDescription() const { +std::string +PgSqlHostDataSource::getDescription() const { return (std::string("Host data source that stores host information" "in PostgreSQL database")); } -std::pair PgSqlHostDataSource::getVersion() const { +std::pair +PgSqlHostDataSource::getVersion() const { return(impl_->getVersion()); } void PgSqlHostDataSource::commit() { + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; + // If operating in read-only mode, throw exception. - impl_->checkReadOnly(); - impl_->conn_.commit(); + impl_->checkReadOnly(ctx); + ctx->conn_.commit(); } void PgSqlHostDataSource::rollback() { + // Get a context + PgSqlHostContextAlloc get_context(*impl_); + PgSqlHostContextPtr ctx = get_context.ctx_; + // If operating in read-only mode, throw exception. - impl_->checkReadOnly(); - impl_->conn_.rollback(); + impl_->checkReadOnly(ctx); + ctx->conn_.rollback(); } -}; // end of isc::dhcp namespace -}; // end of isc namespace +} // namespace dhcp +} // namespace isc diff --git a/src/lib/dhcpsrv/pgsql_host_data_source.h b/src/lib/dhcpsrv/pgsql_host_data_source.h index 4b4a662784..42c211789a 100644 --- a/src/lib/dhcpsrv/pgsql_host_data_source.h +++ b/src/lib/dhcpsrv/pgsql_host_data_source.h @@ -17,6 +17,15 @@ namespace dhcp { /// Forward declaration to the implementation of the @ref PgSqlHostDataSource. class PgSqlHostDataSourceImpl; +/// @brief Type of pointers to PgSqlHostDataSourceImpl. +typedef boost::shared_ptr PgSqlHostDataSourceImplPtr; + +/// Forward declaration for the thread context for the manager pool. +class PgSqlHostContext; + +/// @brief Type of pointers to contexts. +typedef boost::shared_ptr PgSqlHostContextPtr; + /// @brief PostgreSQL Host Data Source /// /// This class implements the @ref isc::dhcp::BaseHostDataSource interface to @@ -32,7 +41,7 @@ class PgSqlHostDataSourceImpl; /// - IDENT_CIRCUIT_ID /// - IDENT_CLIENT_ID /// -class PgSqlHostDataSource: public BaseHostDataSource { +class PgSqlHostDataSource : public BaseHostDataSource { public: /// @brief Constructor @@ -107,7 +116,8 @@ public: /// @param addr specified address. /// @return true if deletion was successful, false if the host was not there. /// @throw various exceptions in case of errors - virtual bool del(const SubnetID& subnet_id, const asiolink::IOAddress& addr); + virtual bool del(const SubnetID& subnet_id, + const asiolink::IOAddress& addr); /// @brief Attempts to delete a host by (subnet4-id, identifier type, identifier) /// @@ -123,7 +133,8 @@ public: /// @throw various exceptions in case of errors virtual bool del4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type, - const uint8_t* identifier_begin, const size_t identifier_len); + const uint8_t* identifier_begin, + const size_t identifier_len); /// @brief Attempts to delete a host by (subnet6-id, identifier type, identifier) /// @@ -139,7 +150,8 @@ public: /// @throw various exceptions in case of errors virtual bool del6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type, - const uint8_t* identifier_begin, const size_t identifier_len); + const uint8_t* identifier_begin, + const size_t identifier_len); /// @brief Return all hosts connected to any subnet for which reservations /// have been made using a specified identifier. @@ -154,9 +166,9 @@ public: /// @param identifier_len Identifier length. /// /// @return Collection of const @c Host objects. - virtual ConstHostCollection - getAll(const Host::IdentifierType& identifier_type, - const uint8_t* identifier_begin, const size_t identifier_len) const; + virtual ConstHostCollection getAll(const Host::IdentifierType& identifier_type, + const uint8_t* identifier_begin, + const size_t identifier_len) const; /// @brief Return all hosts in a DHCPv4 subnet. /// @@ -167,8 +179,7 @@ public: /// @param subnet_id subnet identifier to filter by /// /// @return Collection of const @ref Host objects. - virtual ConstHostCollection - getAll4(const SubnetID& subnet_id) const; + virtual ConstHostCollection getAll4(const SubnetID& subnet_id) const; /// @brief Return all hosts in a DHCPv6 subnet. /// @@ -179,8 +190,7 @@ public: /// @param subnet_id subnet identifier to filter by /// /// @return Collection of const @ref Host objects. - virtual ConstHostCollection - getAll6(const SubnetID& subnet_id) const; + virtual ConstHostCollection getAll6(const SubnetID& subnet_id) const; /// @brief Return all hosts with a hostname. /// @@ -192,8 +202,7 @@ public: /// @param hostname The lower case hostname. /// /// @return Collection of const @c Host objects. - virtual ConstHostCollection - getAllbyHostname(const std::string& hostname) const; + virtual ConstHostCollection getAllbyHostname(const std::string& hostname) const; /// @brief Return all hosts with a hostname in a DHCPv4 subnet. /// @@ -204,8 +213,8 @@ public: /// @param subnet_id Subnet identifier. /// /// @return Collection of const @c Host objects. - virtual ConstHostCollection - getAllbyHostname4(const std::string& hostname, const SubnetID& subnet_id) const; + virtual ConstHostCollection getAllbyHostname4(const std::string& hostname, + const SubnetID& subnet_id) const; /// @brief Return all hosts with a hostname in a DHCPv6 subnet. /// @@ -216,8 +225,8 @@ public: /// @param subnet_id Subnet identifier. /// /// @return Collection of const @c Host objects. - virtual ConstHostCollection - getAllbyHostname6(const std::string& hostname, const SubnetID& subnet_id) const; + virtual ConstHostCollection getAllbyHostname6(const std::string& hostname, + const SubnetID& subnet_id) const; /// @brief Returns range of hosts in a DHCPv4 subnet. /// @@ -236,11 +245,10 @@ public: /// @param page_size maximum size of the page returned. /// /// @return Collection of const @c Host objects (may be empty). - virtual ConstHostCollection - getPage4(const SubnetID& subnet_id, - size_t& source_index, - uint64_t lower_host_id, - const HostPageSize& page_size) const; + virtual ConstHostCollection getPage4(const SubnetID& subnet_id, + size_t& source_index, + uint64_t lower_host_id, + const HostPageSize& page_size) const; /// @brief Returns range of hosts in a DHCPv6 subnet. /// @@ -259,11 +267,10 @@ public: /// @param page_size maximum size of the page returned. /// /// @return Collection of const @c Host objects (may be empty). - virtual ConstHostCollection - getPage6(const SubnetID& subnet_id, - size_t& source_index, - uint64_t lower_host_id, - const HostPageSize& page_size) const; + virtual ConstHostCollection getPage6(const SubnetID& subnet_id, + size_t& source_index, + uint64_t lower_host_id, + const HostPageSize& page_size) const; /// @brief Returns a collection of hosts using the specified IPv4 address. /// @@ -273,8 +280,7 @@ public: /// @param address IPv4 address for which the @c Host object is searched. /// /// @return Collection of const @c Host objects. - virtual ConstHostCollection - getAll4(const asiolink::IOAddress& address) const; + virtual ConstHostCollection getAll4(const asiolink::IOAddress& address) const; /// @brief Returns a host connected to the IPv4 subnet. /// @@ -286,9 +292,10 @@ public: /// /// @return Const @c Host object for which reservation has been made using /// the specified identifier. - virtual ConstHostPtr - get4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type, - const uint8_t* identifier_begin, const size_t identifier_len) const; + virtual ConstHostPtr get4(const SubnetID& subnet_id, + const Host::IdentifierType& identifier_type, + const uint8_t* identifier_begin, + const size_t identifier_len) const; /// @brief Returns a host connected to the IPv4 subnet and having /// a reservation for a specified IPv4 address. @@ -304,8 +311,8 @@ public: /// /// @return Const @c Host object using a specified IPv4 address. /// @throw BadValue is given an IPv6 address - virtual ConstHostPtr - get4(const SubnetID& subnet_id, const asiolink::IOAddress& address) const; + virtual ConstHostPtr get4(const SubnetID& subnet_id, + const asiolink::IOAddress& address) const; /// @brief Returns a host connected to the IPv6 subnet. /// @@ -317,9 +324,10 @@ public: /// /// @return Const @c Host object for which reservation has been made using /// the specified identifier. - virtual ConstHostPtr - get6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type, - const uint8_t* identifier_begin, const size_t identifier_len) const; + virtual ConstHostPtr get6(const SubnetID& subnet_id, + const Host::IdentifierType& identifier_type, + const uint8_t* identifier_begin, + const size_t identifier_len) const; /// @brief Returns a host using the specified IPv6 prefix. /// @@ -327,8 +335,8 @@ public: /// @param prefix_len IPv6 prefix length. /// /// @return Const @c Host object using a specified IPv6 prefix. - virtual ConstHostPtr - get6(const asiolink::IOAddress& prefix, const uint8_t prefix_len) const; + virtual ConstHostPtr get6(const asiolink::IOAddress& prefix, + const uint8_t prefix_len) const; /// @brief Returns a host connected to the IPv6 subnet and having /// a reservation for a specified IPv6 address or prefix. @@ -337,8 +345,8 @@ public: /// @param address reserved IPv6 address/prefix. /// /// @return Const @c Host object using a specified IPv6 address/prefix. - virtual ConstHostPtr - get6(const SubnetID& subnet_id, const asiolink::IOAddress& address) const; + virtual ConstHostPtr get6(const SubnetID& subnet_id, + const asiolink::IOAddress& address) const; /// @brief Return backend type /// @@ -387,9 +395,34 @@ public: /// Rolls back all pending database operations. virtual void rollback(); + /// @brief Context RAII Allocator. + class PgSqlHostContextAlloc { + public: + + /// @brief Constructor + /// + /// This constructor takes a context of the pool if one is available + /// or creates a new one. + /// + /// @param mgr A parent instance + PgSqlHostContextAlloc(const PgSqlHostDataSourceImpl& mgr); + + /// @brief Destructor + /// + /// This destructor puts back the context in the pool. + ~PgSqlHostContextAlloc(); + + /// @brief The context + PgSqlHostContextPtr ctx_; + + private: + /// @brief The manager + const PgSqlHostDataSourceImpl& mgr_; + }; + private: /// @brief Pointer to the implementation of the @ref PgSqlHostDataSource. - PgSqlHostDataSourceImpl* impl_; + PgSqlHostDataSourceImplPtr impl_; }; } diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.cc b/src/lib/dhcpsrv/pgsql_lease_mgr.cc index 7ef9ab42f0..b0af21717c 100644 --- a/src/lib/dhcpsrv/pgsql_lease_mgr.cc +++ b/src/lib/dhcpsrv/pgsql_lease_mgr.cc @@ -841,7 +841,7 @@ public: /// prevent cryptic errors during conversions from NULL /// to actual values. - isc::asiolink::IOAddress addr(getIPv6Value(r, row, ADDRESS_COL)); + IOAddress addr(getIPv6Value(r, row, ADDRESS_COL)); convertFromBytea(r, row, DUID_COL, duid_buffer_, sizeof(duid_buffer_), duid_length_); DuidPtr duid_ptr(new DUID(duid_buffer_, duid_length_)); @@ -1147,8 +1147,8 @@ protected: // PgSqlLeaseContext Constructor -PgSqlLeaseContext::PgSqlLeaseContext( - const DatabaseConnection::ParameterMap& parameters) : conn_(parameters) { +PgSqlLeaseContext::PgSqlLeaseContext(const DatabaseConnection::ParameterMap& parameters) + : conn_(parameters) { } // PgSqlLeaseContextAlloc Constructor and Destructor @@ -1216,7 +1216,6 @@ PgSqlLeaseMgr::~PgSqlLeaseMgr() { PgSqlLeaseContextPtr PgSqlLeaseMgr::createContext() const { - PgSqlLeaseContextPtr ctx(new PgSqlLeaseContext(parameters_)); // Open the database. @@ -1252,7 +1251,7 @@ PgSqlLeaseMgr::getDBVersion() { } bool -PgSqlLeaseMgr::addLeaseCommon(PgSqlLeaseContextPtr ctx, +PgSqlLeaseMgr::addLeaseCommon(PgSqlLeaseContextPtr& ctx, StatementIndex stindex, PsqlBindArray& bind_array) { PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name, @@ -1318,7 +1317,7 @@ PgSqlLeaseMgr::addLease(const Lease6Ptr& lease) { template void -PgSqlLeaseMgr::getLeaseCollection(PgSqlLeaseContextPtr ctx, +PgSqlLeaseMgr::getLeaseCollection(PgSqlLeaseContextPtr& ctx, StatementIndex stindex, PsqlBindArray& bind_array, Exchange& exchange, @@ -1346,7 +1345,7 @@ PgSqlLeaseMgr::getLeaseCollection(PgSqlLeaseContextPtr ctx, } void -PgSqlLeaseMgr::getLease(PgSqlLeaseContextPtr ctx, +PgSqlLeaseMgr::getLease(PgSqlLeaseContextPtr& ctx, StatementIndex stindex, PsqlBindArray& bind_array, Lease4Ptr& result) const { // Create appropriate collection object and get all leases matching @@ -1367,7 +1366,7 @@ PgSqlLeaseMgr::getLease(PgSqlLeaseContextPtr ctx, } void -PgSqlLeaseMgr::getLease(PgSqlLeaseContextPtr ctx, +PgSqlLeaseMgr::getLease(PgSqlLeaseContextPtr& ctx, StatementIndex stindex, PsqlBindArray& bind_array, Lease6Ptr& result) const { // Create appropriate collection object and get all leases matching @@ -1388,7 +1387,7 @@ PgSqlLeaseMgr::getLease(PgSqlLeaseContextPtr ctx, } Lease4Ptr -PgSqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const { +PgSqlLeaseMgr::getLease4(const IOAddress& addr) const { LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_PGSQL_GET_ADDR4) .arg(addr.toText()); @@ -1597,7 +1596,7 @@ PgSqlLeaseMgr::getLeases4() const { } Lease4Collection -PgSqlLeaseMgr::getLeases4(const asiolink::IOAddress& lower_bound_address, +PgSqlLeaseMgr::getLeases4(const IOAddress& lower_bound_address, const LeasePageSize& page_size) const { // Expecting IPv4 address. if (!lower_bound_address.isV4()) { @@ -1635,7 +1634,7 @@ PgSqlLeaseMgr::getLeases4(const asiolink::IOAddress& lower_bound_address, Lease6Ptr PgSqlLeaseMgr::getLease6(Lease::Type lease_type, - const isc::asiolink::IOAddress& addr) const { + const IOAddress& addr) const { LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_PGSQL_GET_ADDR6) .arg(addr.toText()) .arg(lease_type); @@ -1824,7 +1823,7 @@ PgSqlLeaseMgr::getLeases6() const { } Lease6Collection -PgSqlLeaseMgr::getLeases6(const asiolink::IOAddress& lower_bound_address, +PgSqlLeaseMgr::getLeases6(const IOAddress& lower_bound_address, const LeasePageSize& page_size) const { // Expecting IPv6 address. if (!lower_bound_address.isV6()) { @@ -1915,7 +1914,7 @@ PgSqlLeaseMgr::getExpiredLeasesCommon(LeaseCollection& expired_leases, template void -PgSqlLeaseMgr::updateLeaseCommon(PgSqlLeaseContextPtr ctx, +PgSqlLeaseMgr::updateLeaseCommon(PgSqlLeaseContextPtr& ctx, StatementIndex stindex, PsqlBindArray& bind_array, const LeasePtr& lease) { @@ -2028,7 +2027,7 @@ PgSqlLeaseMgr::deleteLeaseCommon(StatementIndex stindex, bool PgSqlLeaseMgr::deleteLease(const Lease4Ptr& lease) { - const isc::asiolink::IOAddress& addr = lease->addr_; + const IOAddress& addr = lease->addr_; LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_PGSQL_DELETE_ADDR) .arg(addr.toText()); @@ -2062,7 +2061,7 @@ PgSqlLeaseMgr::deleteLease(const Lease4Ptr& lease) { bool PgSqlLeaseMgr::deleteLease(const Lease6Ptr& lease) { - const isc::asiolink::IOAddress& addr = lease->addr_; + const IOAddress& addr = lease->addr_; LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_PGSQL_DELETE_ADDR) .arg(addr.toText()); diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.h b/src/lib/dhcpsrv/pgsql_lease_mgr.h index 5a955efa58..6339592b09 100644 --- a/src/lib/dhcpsrv/pgsql_lease_mgr.h +++ b/src/lib/dhcpsrv/pgsql_lease_mgr.h @@ -668,8 +668,9 @@ private: /// /// @throw isc::db::DbOperationError An operation on the open database has /// failed. - bool addLeaseCommon(PgSqlLeaseContextPtr ctx, - StatementIndex stindex, db::PsqlBindArray& bind_array); + bool addLeaseCommon(PgSqlLeaseContextPtr& ctx, + StatementIndex stindex, + db::PsqlBindArray& bind_array); /// @brief Get Lease Collection Common Code /// @@ -693,7 +694,7 @@ private: /// @throw isc::db::MultipleRecords Multiple records were retrieved /// from the database where only one was expected. template - void getLeaseCollection(PgSqlLeaseContextPtr ctx, + void getLeaseCollection(PgSqlLeaseContextPtr& ctx, StatementIndex stindex, db::PsqlBindArray& bind_array, Exchange& exchange, LeaseCollection& result, @@ -716,7 +717,7 @@ private: /// failed. /// @throw isc::db::MultipleRecords Multiple records were retrieved /// from the database where only one was expected. - void getLeaseCollection(PgSqlLeaseContextPtr ctx, + void getLeaseCollection(PgSqlLeaseContextPtr& ctx, StatementIndex stindex, db::PsqlBindArray& bind_array, Lease4Collection& result) const { @@ -739,7 +740,7 @@ private: /// failed. /// @throw isc::db::MultipleRecords Multiple records were retrieved /// from the database where only one was expected. - void getLeaseCollection(PgSqlLeaseContextPtr ctx, + void getLeaseCollection(PgSqlLeaseContextPtr& ctx, StatementIndex stindex, db::PsqlBindArray& bind_array, Lease6Collection& result) const { @@ -756,7 +757,7 @@ private: /// @param stindex Index of statement being executed /// @param bind_array array for input parameters /// @param result Lease4 object returned - void getLease(PgSqlLeaseContextPtr ctx, + void getLease(PgSqlLeaseContextPtr& ctx, StatementIndex stindex, db::PsqlBindArray& bind_array, Lease4Ptr& result) const; @@ -771,7 +772,7 @@ private: /// @param stindex Index of statement being executed /// @param bind_array array for input parameters /// @param result Lease6 object returned - void getLease(PgSqlLeaseContextPtr ctx, + void getLease(PgSqlLeaseContextPtr& ctx, StatementIndex stindex, db::PsqlBindArray& bind_array, Lease6Ptr& result) const; @@ -812,7 +813,7 @@ private: /// @throw isc::db::DbOperationError An operation on the open database has /// failed. template - void updateLeaseCommon(PgSqlLeaseContextPtr ctx, + void updateLeaseCommon(PgSqlLeaseContextPtr& ctx, StatementIndex stindex, db::PsqlBindArray& bind_array, const LeasePtr& lease);