]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[313-return-a-list-of-all-reservations-by-subnet-id] Added getPage[46]
authorFrancis Dupont <fdupont@isc.org>
Sun, 13 Jan 2019 16:11:57 +0000 (17:11 +0100)
committerFrancis Dupont <fdupont@isc.org>
Tue, 29 Jan 2019 09:49:05 +0000 (04:49 -0500)
16 files changed:
src/lib/dhcpsrv/base_host_data_source.h
src/lib/dhcpsrv/cfg_hosts.cc
src/lib/dhcpsrv/cfg_hosts.h
src/lib/dhcpsrv/cql_host_data_source.cc
src/lib/dhcpsrv/cql_host_data_source.h
src/lib/dhcpsrv/host_container.h
src/lib/dhcpsrv/host_mgr.cc
src/lib/dhcpsrv/host_mgr.h
src/lib/dhcpsrv/mysql_host_data_source.cc
src/lib/dhcpsrv/mysql_host_data_source.h
src/lib/dhcpsrv/pgsql_host_data_source.cc
src/lib/dhcpsrv/pgsql_host_data_source.h
src/lib/dhcpsrv/tests/host_cache_unittest.cc
src/lib/dhcpsrv/testutils/memory_host_data_source.cc
src/lib/dhcpsrv/testutils/memory_host_data_source.h
src/lib/dhcpsrv/writable_host_data_source.h

index 815a0d9d07d91d19af76d7f10331c4301ca85b74..9c56abd258addf3599fee288b810e8ca45996c6f 100644 (file)
@@ -40,6 +40,28 @@ public:
         isc::BadValue(file, line, what) { };
 };
 
+/// @brief Wraps value holding size of the page with host reservations.
+class HostPageSize {
+public:
+
+    /// @brief Constructor.
+    ///
+    /// @param page_size page size value.
+    /// @throw OutOfRange if page size is 0 or greater than uint32_t numeric
+    /// limit.
+    explicit HostPageSize(const size_t page_size) : page_size_(page_size) {
+        if (page_size_ == 0) {
+            isc_throw(OutOfRange, "page size of retrieved hosts must not be 0");
+        }
+        if (page_size_ > std::numeric_limits<uint32_t>::max()) {
+            isc_throw(OutOfRange, "page size of retrieved hosts must not be greate than "
+                     << std::numeric_limits<uint32_t>::max());
+        }
+    }
+
+    const size_t page_size_; ///< Holds page size.
+};
+
 /// @brief Base interface for the classes implementing simple data source
 /// for host reservations.
 ///
@@ -114,6 +136,50 @@ public:
     virtual ConstHostCollection
     getAll6(const SubnetID& subnet_id) const = 0;
 
+    /// @brief Returns range of hosts in a DHCPv4 subnet.
+    ///
+    /// This method implements paged browsing of host databases. The
+    /// parameters specify a page size, an index in sources and the
+    /// starting host id of the range. If not zero this host id is
+    /// excluded from the returned range. When a source is exhausted
+    /// the index is updated. There is no guarantee about the order
+    /// of returned host reservations, only the sources are ordered.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param source_index Index of the source.
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    ///
+    /// @return Host collection (may be empty).
+    virtual ConstHostCollection
+    getPage4(const SubnetID& subnet_id,
+             size_t& source_index,
+             uint64_t lower_host_id,
+             const HostPageSize& page_size) const = 0;
+
+    /// @brief Returns range of hosts in a DHCPv6 subnet.
+    ///
+    /// This method implements paged browsing of host databases. The
+    /// parameters specify a page size, an index in sources and the
+    /// starting host id of the range. If not zero this host id is
+    /// excluded from the returned range. When a source is exhausted
+    /// the index is updated. There is no guarantee about the order
+    /// of returned host reservations, only the sources are ordered.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param source_index Index of the source.
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    ///
+    /// @return Host collection (may be empty).
+    virtual ConstHostCollection
+    getPage6(const SubnetID& subnet_id,
+             size_t& source_index,
+             uint64_t lower_host_id,
+             const HostPageSize& page_size) const = 0;
+
     /// @brief Returns a collection of hosts using the specified IPv4 address.
     ///
     /// This method may return multiple @c Host objects if they are connected
index 386bc2888e775405a4c0fbe8b906770746ef7176..81051cb4e6f050d355a0a1d020856de154e61dc6 100644 (file)
@@ -49,7 +49,7 @@ CfgHosts::getAll(const Host::IdentifierType& identifier_type,
 ConstHostCollection
 CfgHosts::getAll4(const SubnetID& subnet_id) const {
     // Do not issue logging message here because it will be logged by
-    // the getAllInternal method.
+    // the getAllInternal4 method.
     ConstHostCollection collection;
     getAllInternal4<ConstHostCollection>(subnet_id, collection);
     return (collection);
@@ -58,7 +58,7 @@ CfgHosts::getAll4(const SubnetID& subnet_id) const {
 HostCollection
 CfgHosts::getAll4(const SubnetID& subnet_id) {
     // Do not issue logging message here because it will be logged by
-    // the getAllInternal method.
+    // the getAllInternal4 method.
     HostCollection collection;
     getAllInternal4<HostCollection>(subnet_id, collection);
     return (collection);
@@ -67,7 +67,7 @@ CfgHosts::getAll4(const SubnetID& subnet_id) {
 ConstHostCollection
 CfgHosts::getAll6(const SubnetID& subnet_id) const {
     // Do not issue logging message here because it will be logged by
-    // the getAllInternal method.
+    // the getAllInternal6 method.
     ConstHostCollection collection;
     getAllInternal6<ConstHostCollection>(subnet_id, collection);
     return (collection);
@@ -76,12 +76,72 @@ CfgHosts::getAll6(const SubnetID& subnet_id) const {
 HostCollection
 CfgHosts::getAll6(const SubnetID& subnet_id) {
     // Do not issue logging message here because it will be logged by
-    // the getAllInternal method.
+    // the getAllInternal6 method.
     HostCollection collection;
     getAllInternal6<HostCollection>(subnet_id, collection);
     return (collection);
 }
 
+ConstHostCollection
+CfgHosts::getPage4(const SubnetID& subnet_id,
+                   size_t& /*source_index*/,
+                   uint64_t lower_host_id,
+                   const HostPageSize& page_size) const {
+    // Do not issue logging message here because it will be logged by
+    // the getPageInternal4 method.
+    ConstHostCollection collection;
+    getPageInternal4<ConstHostCollection>(subnet_id,
+                                          lower_host_id,
+                                          page_size,
+                                          collection);
+    return (collection);
+}
+
+HostCollection
+CfgHosts::getPage4(const SubnetID& subnet_id,
+                   size_t& /*source_index*/,
+                   uint64_t lower_host_id,
+                   const HostPageSize& page_size) {
+    // Do not issue logging message here because it will be logged by
+    // the getPageInternal4 method.
+    HostCollection collection;
+    getPageInternal4<HostCollection>(subnet_id,
+                                     lower_host_id,
+                                     page_size,
+                                     collection);
+    return (collection);
+}
+
+ConstHostCollection
+CfgHosts::getPage6(const SubnetID& subnet_id,
+                   size_t& /*source_index*/,
+                   uint64_t lower_host_id,
+                   const HostPageSize& page_size) const {
+    // Do not issue logging message here because it will be logged by
+    // the getPageInternal6 method.
+    ConstHostCollection collection;
+    getPageInternal6<ConstHostCollection>(subnet_id,
+                                          lower_host_id,
+                                          page_size,
+                                          collection);
+    return (collection);
+}
+
+HostCollection
+CfgHosts::getPage6(const SubnetID& subnet_id,
+                   size_t& /*source_index*/,
+                   uint64_t lower_host_id,
+                   const HostPageSize& page_size) {
+    // Do not issue logging message here because it will be logged by
+    // the getPageInternal6 method.
+    HostCollection collection;
+    getPageInternal6<HostCollection>(subnet_id,
+                                     lower_host_id,
+                                     page_size,
+                                     collection);
+    return (collection);
+}
+
 ConstHostCollection
 CfgHosts::getAll4(const IOAddress& address) const {
     // Do not issue logging message here because it will be logged by
@@ -213,6 +273,88 @@ CfgHosts::getAllInternal6(const SubnetID& subnet_id,
         .arg(storage.size());
 }
 
+template<typename Storage>
+void
+CfgHosts::getPageInternal4(const SubnetID& subnet_id,
+                           uint64_t lower_host_id,
+                           const HostPageSize& page_size,
+                           Storage& storage) const {
+
+    LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE, HOSTS_CFG_GET_ALL_SUBNET_ID4)
+        .arg(subnet_id);
+
+    // Use the host id last index.
+    const HostContainerIndex4& idx = hosts_.get<4>();
+    HostContainerIndex4::const_iterator host = idx.lower_bound(lower_host_id);
+
+    // Exclude the lower bound id when it is not zero.
+    if (lower_host_id &&
+        (host != idx.end()) && ((*host)->getHostId() == lower_host_id)) {
+        ++host;
+    }
+
+    // Return hosts in the subnet within the page size.
+    for (; host != idx.end(); ++host) {
+        if ((*host)->getIPv4SubnetID() != subnet_id) {
+            continue;
+        }
+        LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE_DETAIL_DATA,
+                  HOSTS_CFG_GET_ALL_SUBNET_ID4_HOST)
+            .arg(subnet_id)
+            .arg((*host)->toText());
+        storage.push_back(*host);
+        if (storage.size() >= page_size.page_size_) {
+            break;
+        }
+    }
+
+    // Log how many hosts have been found.
+    LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS, HOSTS_CFG_GET_ALL_SUBNET_ID4_COUNT)
+        .arg(subnet_id)
+        .arg(storage.size());
+}
+
+template<typename Storage>
+void
+CfgHosts::getPageInternal6(const SubnetID& subnet_id,
+                           uint64_t lower_host_id,
+                           const HostPageSize& page_size,
+                           Storage& storage) const {
+
+    LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE, HOSTS_CFG_GET_ALL_SUBNET_ID6)
+        .arg(subnet_id);
+
+    // Use the host id last index.
+    const HostContainerIndex4& idx = hosts_.get<4>();
+    HostContainerIndex4::const_iterator host = idx.lower_bound(lower_host_id);
+
+    // Exclude the lower bound id when it is not zero.
+    if (lower_host_id &&
+        (host != idx.end()) && ((*host)->getHostId() == lower_host_id)) {
+        ++host;
+    }
+
+    // Return hosts in the subnet within the page size.
+    for (; host != idx.end(); ++host) {
+        if ((*host)->getIPv6SubnetID() != subnet_id) {
+            continue;
+        }
+        LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE_DETAIL_DATA,
+                  HOSTS_CFG_GET_ALL_SUBNET_ID6_HOST)
+            .arg(subnet_id)
+            .arg((*host)->toText());
+        storage.push_back(*host);
+        if (storage.size() >= page_size.page_size_) {
+            break;
+        }
+    }
+
+    // Log how many hosts have been found.
+    LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS, HOSTS_CFG_GET_ALL_SUBNET_ID6_COUNT)
+        .arg(subnet_id)
+        .arg(storage.size());
+}
+
 
 template<typename Storage>
 void
@@ -644,6 +786,7 @@ CfgHosts::add4(const HostPtr& host) {
     }
 
     // This is a new instance - add it.
+    host->setHostId(++next_host_id_);
     hosts_.insert(host);
 }
 
index eada8a2a0c6508e8ea853198b72f291a1c6d886b..b2d400aaa86b72df9ddbc457c2d2305b24f912cb 100644 (file)
@@ -119,6 +119,78 @@ public:
     virtual HostCollection
     getAll6(const SubnetID& subnet_id);
 
+    /// @brief Returns range of hosts in a DHCPv4 subnet.
+    ///
+    /// This method returns a page of @c Host objects which represent
+    /// reservations in a specified subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param source_index Index of the source (unused).
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @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;
+
+    /// @brief Returns range of hosts in a DHCPv4 subnet.
+    ///
+    /// This method returns a page of @c Host objects which represent
+    /// reservations in a specified subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param source_index Index of the source (unused).
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    ///
+    /// @return Collection of non-const @c Host objects (may be empty).
+    virtual HostCollection
+    getPage4(const SubnetID& subnet_id,
+             size_t& source_index,
+             uint64_t lower_host_id,
+             const HostPageSize& page_size);
+
+    /// @brief Returns range of hosts in a DHCPv6 subnet.
+    ///
+    /// This method returns a page of @c Host objects which represent
+    /// reservations in a specified subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param source_index Index of the source (unused).
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @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;
+
+    /// @brief Returns range of hosts in a DHCPv6 subnet.
+    ///
+    /// This method returns a page of @c Host objects which represent
+    /// reservations in a specified subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param source_index Index of the source (unused).
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    ///
+    /// @return Collection of non-const @c Host objects (may be empty).
+    virtual HostCollection
+    getPage6(const SubnetID& subnet_id,
+             size_t& source_index,
+             uint64_t lower_host_id,
+             const HostPageSize& page_size);
+
     /// @brief Returns a collection of hosts using the specified IPv4 address.
     ///
     /// This method may return multiple @c Host objects if they are connected
@@ -360,7 +432,7 @@ private:
 
     /// @brief Returns @c Host objects for the specific identifier and type.
     ///
-    /// This private method is called by the @c CfgHosts::getAllInternal
+    /// This private method is called by the @c CfgHosts::getAll
     /// method which finds the @c Host objects using specified identifier.
     /// The retrieved objects are appended to the @c storage container.
     ///
@@ -378,7 +450,7 @@ private:
 
     /// @brief Returns @c Host objects in a DHCPv4 subnet.
     ///
-    /// This private method is called by the @c CfgHosts::getAllInternal
+    /// This private method is called by the @c CfgHosts::getAll4
     /// method which finds the @c Host objects in a specified subnet.
     /// The retrieved objects are appended to the @c storage container.
     ///
@@ -392,7 +464,7 @@ private:
 
     /// @brief Returns @c Host objects in a DHCPv6 subnet.
     ///
-    /// This private method is called by the @c CfgHosts::getAllInternal
+    /// This private method is called by the @c CfgHosts::getAll6
     /// method which finds the @c Host objects in a specified subnet.
     /// The retrieved objects are appended to the @c storage container.
     ///
@@ -404,6 +476,44 @@ private:
     void getAllInternal6(const SubnetID& subnet_id,
                          Storage& storage) const;
 
+    /// @brief Returns a page of @c Host objects in a DHCPv4 subnet.
+    ///
+    /// This private method is called by the @c CfgHosts::getPage4
+    /// method which finds the @c Host objects in a specified subnet.
+    /// The retrieved objects are appended to the @c storage container.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    /// @param [out] storage Container to which the retrieved objects are
+    /// appended.
+    /// @tparam One of the @c ConstHostCollection of @c HostCollection.
+    template<typename Storage>
+    void getPageInternal4(const SubnetID& subnet_id,
+                          uint64_t lower_host_id,
+                          const HostPageSize& page_size,
+                          Storage& storage) const;
+
+    /// @brief Returns a page of @c Host objects in a DHCPv6 subnet.
+    ///
+    /// This private method is called by the @c CfgHosts::getPage6
+    /// method which finds the @c Host objects in a specified subnet.
+    /// The retrieved objects are appended to the @c storage container.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    /// @param [out] storage Container to which the retrieved objects are
+    /// appended.
+    /// @tparam One of the @c ConstHostCollection of @c HostCollection.
+    template<typename Storage>
+    void getPageInternal6(const SubnetID& subnet_id,
+                          uint64_t lower_host_id,
+                          const HostPageSize& page_size,
+                          Storage& storage) const;
+
     /// @brief Returns @c Host objects for the specified IPv4 address.
     ///
     /// This private method is called by the @c CfgHosts::getAll4 methods
@@ -522,12 +632,17 @@ private:
     /// the IPv6 subnet.
     virtual void add6(const HostPtr& host);
 
+    /// @brief Next host id.
+    uint64_t next_host_id_;
+
     /// @brief Multi-index container holding @c Host objects.
     ///
     /// It can be used for finding hosts by the following criteria:
     /// - IPv4 address
     /// - DUID
     /// - HW/MAC address
+    /// - subnet ID
+    /// - host ID
     HostContainer hosts_;
 
     /// @brief Multi-index container holding @c Host objects with v6 reservations.
index ad9dd5d71b26de4c51b9d26c10df282fe4d8217b..0b513c63f11dadb23b55609f8acdf55acd168e59 100644 (file)
@@ -321,6 +321,26 @@ public:
     // associated with a host using subnet identifier.
     static constexpr StatementTag GET_HOST_BY_IPV6_SUBNET_ID =
         "GET_HOST_BY_IPV6_SUBNET_ID";
+
+    // Retrieves host information along with the IPv4 options associated
+    // with it using a subnet identifier. First page.
+    static constexpr StatementTag GET_HOST_BY_IPV4_SUBNET_ID_LIMIT =
+        "GET_HOST_BY_IPV4_SUBNET_ID_LIMIT";
+
+    // Retrieves host information along with the IPv4 options associated
+    // with it using a subnet identifier. Next page.
+    static constexpr StatementTag GET_HOST_BY_IPV4_SUBNET_ID_PAGE =
+        "GET_HOST_BY_IPV4_SUBNET_ID_PAGE";
+
+    // Retrieves host information along with the IPv6 options associated
+    // with it using a subnet identifier. First page.
+    static constexpr StatementTag GET_HOST_BY_IPV6_SUBNET_ID_LIMIT =
+        "GET_HOST_BY_IPV6_SUBNET_ID_LIMIT";
+
+    // Retrieves host information along with the IPv6 options associated
+    // with it using a subnet identifier. Next page.
+    static constexpr StatementTag GET_HOST_BY_IPV6_SUBNET_ID_PAGE =
+        "GET_HOST_BY_IPV6_SUBNET_ID_PAGE";
     /// @}
 
     /// @brief Cassandra statements
@@ -432,6 +452,10 @@ constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS;
 constexpr StatementTag CqlHostExchange::DELETE_HOST;
 constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID;
 constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID;
+constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_LIMIT;
+constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_PAGE;
+constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_LIMIT;
+constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_PAGE;
 
 StatementMap CqlHostExchange::tagged_statements_ = {
     {INSERT_HOST,
@@ -846,6 +870,154 @@ StatementMap CqlHostExchange::tagged_statements_ = {
       "FROM host_reservations "
       "WHERE host_ipv6_subnet_id = ? "
       "ALLOW FILTERING "
+     }},
+
+    {GET_HOST_BY_IPV4_SUBNET_ID_LIMIT,
+     {GET_HOST_BY_IPV4_SUBNET_ID_LIMIT,
+      "SELECT "
+      "id, "
+      "host_identifier, "
+      "host_identifier_type, "
+      "host_ipv4_subnet_id, "
+      "host_ipv6_subnet_id, "
+      "host_ipv4_address, "
+      "host_ipv4_next_server, "
+      "host_ipv4_server_hostname, "
+      "host_ipv4_boot_file_name, "
+      "auth_key, "
+      "hostname, "
+      "user_context, "
+      "host_ipv4_client_classes, "
+      "host_ipv6_client_classes, "
+      "reserved_ipv6_prefix_address, "
+      "reserved_ipv6_prefix_length, "
+      "reserved_ipv6_prefix_address_type, "
+      "iaid, "
+      "option_universe, "
+      "option_code, "
+      "option_value, "
+      "option_formatted_value, "
+      "option_space, "
+      "option_is_persistent, "
+      "option_client_class, "
+      "option_subnet_id, "
+      "option_user_context, "
+      "option_scope_id "
+      "FROM host_reservations "
+      "WHERE host_ipv4_subnet_id = ? "
+      "LIMIT ? "
+      "ALLOW FILTERING "
+     }},
+
+    {GET_HOST_BY_IPV4_SUBNET_ID_PAGE,
+     {GET_HOST_BY_IPV4_SUBNET_ID_PAGE,
+      "SELECT "
+      "id, "
+      "host_identifier, "
+      "host_identifier_type, "
+      "host_ipv4_subnet_id, "
+      "host_ipv6_subnet_id, "
+      "host_ipv4_address, "
+      "host_ipv4_next_server, "
+      "host_ipv4_server_hostname, "
+      "host_ipv4_boot_file_name, "
+      "auth_key, "
+      "hostname, "
+      "user_context, "
+      "host_ipv4_client_classes, "
+      "host_ipv6_client_classes, "
+      "reserved_ipv6_prefix_address, "
+      "reserved_ipv6_prefix_length, "
+      "reserved_ipv6_prefix_address_type, "
+      "iaid, "
+      "option_universe, "
+      "option_code, "
+      "option_value, "
+      "option_formatted_value, "
+      "option_space, "
+      "option_is_persistent, "
+      "option_client_class, "
+      "option_subnet_id, "
+      "option_user_context, "
+      "option_scope_id "
+      "FROM host_reservations "
+      "WHERE host_ipv4_subnet_id = ? AND TOKEN(id) > TOKEN(?) "
+      "LIMIT ? "
+      "ALLOW FILTERING "
+     }},
+
+    {GET_HOST_BY_IPV6_SUBNET_ID_LIMIT,
+     {GET_HOST_BY_IPV6_SUBNET_ID_LIMIT,
+      "SELECT "
+      "id, "
+      "host_identifier, "
+      "host_identifier_type, "
+      "host_ipv4_subnet_id, "
+      "host_ipv6_subnet_id, "
+      "host_ipv4_address, "
+      "host_ipv4_next_server, "
+      "host_ipv4_server_hostname, "
+      "host_ipv4_boot_file_name, "
+      "auth_key, "
+      "hostname, "
+      "user_context, "
+      "host_ipv4_client_classes, "
+      "host_ipv6_client_classes, "
+      "reserved_ipv6_prefix_address, "
+      "reserved_ipv6_prefix_length, "
+      "reserved_ipv6_prefix_address_type, "
+      "iaid, "
+      "option_universe, "
+      "option_code, "
+      "option_value, "
+      "option_formatted_value, "
+      "option_space, "
+      "option_is_persistent, "
+      "option_client_class, "
+      "option_subnet_id, "
+      "option_user_context, "
+      "option_scope_id "
+      "FROM host_reservations "
+      "WHERE host_ipv6_subnet_id = ? "
+      "LIMIT ? "
+      "ALLOW FILTERING "
+     }},
+
+    {GET_HOST_BY_IPV6_SUBNET_ID_PAGE,
+     {GET_HOST_BY_IPV6_SUBNET_ID_PAGE,
+      "SELECT "
+      "id, "
+      "host_identifier, "
+      "host_identifier_type, "
+      "host_ipv4_subnet_id, "
+      "host_ipv6_subnet_id, "
+      "host_ipv4_address, "
+      "host_ipv4_next_server, "
+      "host_ipv4_server_hostname, "
+      "host_ipv4_boot_file_name, "
+      "auth_key, "
+      "hostname, "
+      "user_context, "
+      "host_ipv4_client_classes, "
+      "host_ipv6_client_classes, "
+      "reserved_ipv6_prefix_address, "
+      "reserved_ipv6_prefix_length, "
+      "reserved_ipv6_prefix_address_type, "
+      "iaid, "
+      "option_universe, "
+      "option_code, "
+      "option_value, "
+      "option_formatted_value, "
+      "option_space, "
+      "option_is_persistent, "
+      "option_client_class, "
+      "option_subnet_id, "
+      "option_user_context, "
+      "option_scope_id "
+      "FROM host_reservations "
+      "WHERE host_ipv6_subnet_id = ? AND TOKEN(id) > TOKEN(?) "
+      "LIMIT ? "
+      "ALLOW FILTERING "
      }}
 };
 
@@ -1526,6 +1698,32 @@ public:
     /// @param subnet_id identifier of the subnet to which hosts belong
     virtual ConstHostCollection getAll6(const SubnetID& subnet_id) const;
 
+    /// @brief Implementation of @ref CqlHostDataSource::getPage4()
+    ///
+    /// See @ref CqlHostDataSource::getPage4() for parameter details.
+    ///
+    /// @param subnet_id identifier of the subnet to which hosts belong
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    virtual ConstHostCollection
+    getPage4(const SubnetID& subnet_id,
+             uint64_t lower_host_id,
+             const HostPageSize& page_size) const;
+
+    /// @brief Implementation of @ref CqlHostDataSource::getPage6()
+    ///
+    /// See @ref CqlHostDataSource::getPage6() for parameter details.
+    ///
+    /// @param subnet_id identifier of the subnet to which hosts belong
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    virtual ConstHostCollection
+    getPage6(const SubnetID& subnet_id,
+             uint64_t lower_host_id,
+             const HostPageSize& page_size) const;
+
     /// @brief Implementation of @ref CqlHostDataSource::getAll4()
     ///
     /// See @ref CqlHostDataSource::getAll4() for parameter details.
@@ -1945,6 +2143,67 @@ CqlHostDataSourceImpl::getAll6(const SubnetID& subnet_id) const {
     return (result);
 }
 
+ConstHostCollection
+CqlHostDataSourceImpl::getPage4(const SubnetID& subnet_id,
+                                uint64_t lower_host_id,
+                                const HostPageSize& page_size) const {
+    // Convert to CQL data types.
+    cass_int32_t host_ipv4_subnet_id = static_cast<cass_int32_t>(subnet_id);
+
+    // Bind to array.
+    AnyArray where_values;
+    where_values.add(&host_ipv4_subnet_id);
+
+    cass_int64_t id = static_cast<cass_int64_t>(lower_host_id);
+    if (id) {
+        where_values.add(&id);
+    }
+
+    cass_int32_t page_size_data =
+        static_cast<cass_int32_t>(page_size.page_size_);
+    where_values.add(&page_size_data);
+
+    // Run statement.
+    ConstHostCollection result =
+        getHostCollection(id == 0 ?
+                          CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_LIMIT :
+                          CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_PAGE,
+                          where_values);
+
+    return (result);
+}
+
+ConstHostCollection
+CqlHostDataSourceImpl::getPage6(const SubnetID& subnet_id,
+                                uint64_t lower_host_id,
+                                const HostPageSize& page_size) const {
+    // Convert to CQL data types.
+    cass_int32_t host_ipv6_subnet_id = static_cast<cass_int32_t>(subnet_id);
+
+    // Bind to array.
+    AnyArray where_values;
+    where_values.add(&host_ipv6_subnet_id);
+
+    cass_int64_t id = static_cast<cass_int64_t>(lower_host_id);
+    if (id) {
+        where_values.add(&id);
+    }
+
+    cass_int32_t page_size_data =
+        static_cast<cass_int32_t>(page_size.page_size_);
+    where_values.add(&page_size_data);
+
+    // Run statement.
+    ConstHostCollection result =
+        getHostCollection(id == 0 ?
+                          CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_LIMIT :
+                          CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_PAGE,
+                          where_values);
+
+    return (result);
+}
+
+
 ConstHostCollection
 CqlHostDataSourceImpl::getAll4(const asiolink::IOAddress& address) const {
     // Convert to CQL data types.
@@ -2245,6 +2504,26 @@ CqlHostDataSource::getAll6(const SubnetID& subnet_id) const {
     return (impl_->getAll6(subnet_id));
 }
 
+ConstHostCollection
+CqlHostDataSource::getPage4(const SubnetID& subnet_id,
+                            size_t& /*source_index*/,
+                            uint64_t lower_host_id,
+                            const HostPageSize& page_size) const {
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
+
+    return (impl_->getPage4(subnet_id, lower_host_id, page_size));
+}
+
+ConstHostCollection
+CqlHostDataSource::getPage6(const SubnetID& subnet_id,
+                            size_t& /*source_index*/,
+                            uint64_t lower_host_id,
+                            const HostPageSize& page_size) const {
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
+
+    return (impl_->getPage6(subnet_id, lower_host_id, page_size));
+}
+
 ConstHostCollection
 CqlHostDataSource::getAll4(const asiolink::IOAddress& address) const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
index c657d9c3946cea69462300388428b1ec6ccf984d..d5dc7137366fb675609d25740bb40f9f3986bb02 100644 (file)
@@ -190,6 +190,42 @@ public:
     virtual ConstHostCollection
     getAll6(const SubnetID& subnet_id) const override;
 
+    /// @brief Returns range of hosts in a DHCPv4 subnet.
+    ///
+    /// This method returns a page of @c Host objects which represent
+    /// reservations in a specified subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param source_index Index of the source (unused).
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @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 override;
+
+    /// @brief Returns range of hosts in a DHCPv6 subnet.
+    ///
+    /// This method returns a page of @c Host objects which represent
+    /// reservations in a specified subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param source_index Index of the source (unused).
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @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 override;
+
     /// @brief Returns a collection of hosts using the specified IPv4 address.
     ///
     /// This method may return multiple @ref Host objects if they are connected
index 442a2ea78c2aae51da417fc0bf14740fb8e83ac6..ae21449c4e536963f96c80157eeec96bc2701b4a 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2019 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -81,6 +81,13 @@ typedef boost::multi_index_container<
             // Index using values returned by the @c Host::getIPv6SubnetID
             boost::multi_index::const_mem_fun<Host, SubnetID,
                                               &Host::getIPv6SubnetID>
+        >,
+
+        // Fifth index is used to search by increasing host id
+        boost::multi_index::ordered_unique<
+            // Index using values returned by the @c Host::getHostId
+            boost::multi_index::const_mem_fun<Host, uint64_t,
+                                              &Host::getHostId>
         >
     >
 > HostContainer;
@@ -125,6 +132,15 @@ typedef HostContainer::nth_index<3>::type HostContainerIndex3;
 typedef std::pair<HostContainerIndex3::iterator,
                   HostContainerIndex3::iterator> HostContainerIndex3Range;
 
+/// @brief Fifth index type in the @c HostContainer.
+///
+/// This index allows for searching for @c Host objects using a host id.
+typedef HostContainer::nth_index<4>::type HostContainerIndex4;
+
+/// @brief Results range returned using the @c HostContainerIndex4.
+typedef std::pair<HostContainerIndex4::iterator,
+                  HostContainerIndex4::iterator> HostContainerIndex4Range;
+
 /// @brief Defines one entry for the Host Container for v6 hosts
 ///
 /// It's essentially a pair of (IPv6 reservation, Host pointer).
index 777fceb4d2428eb31d0a83017c7f9e1505825430..9c256577df71a57d753f3b644a059ccf038cbb01 100644 (file)
@@ -131,7 +131,66 @@ HostMgr::getAll6(const SubnetID& subnet_id) const {
     return (hosts);
 }
 
-
+ConstHostCollection
+HostMgr::getPage4(const SubnetID& subnet_id,
+                  size_t& source_index,
+                  uint64_t lower_host_id,
+                  const HostPageSize& page_size) const {
+    for (;;) {
+        if (source_index > alternate_sources_.size()) {
+            return (ConstHostCollection());
+        }
+        ConstHostCollection hosts;
+        if (source_index == 0) {
+            hosts = getCfgHosts()->getPage4(subnet_id,
+                                            source_index,
+                                            lower_host_id,
+                                            page_size);
+        } else {
+            hosts = alternate_sources_[source_index]->getPage4(subnet_id,
+                                                               source_index,
+                                                               lower_host_id,
+                                                               page_size);
+        }
+        if (!hosts.empty()) {
+            return (hosts);
+        } else {
+            ++source_index;
+            continue;
+        }
+    }
+}
+        
+ConstHostCollection
+HostMgr::getPage6(const SubnetID& subnet_id,
+                  size_t& source_index,
+                  uint64_t lower_host_id,
+                  const HostPageSize& page_size) const {
+    for (;;) {
+        if (source_index > alternate_sources_.size()) {
+            return (ConstHostCollection());
+        }
+        ConstHostCollection hosts;
+        if (source_index == 0) {
+            hosts = getCfgHosts()->getPage6(subnet_id,
+                                            source_index,
+                                            lower_host_id,
+                                            page_size);
+        } else {
+            hosts = alternate_sources_[source_index]->getPage6(subnet_id,
+                                                               source_index,
+                                                               lower_host_id,
+                                                               page_size);
+        }
+        if (!hosts.empty()) {
+            return (hosts);
+        } else {
+            ++source_index;
+            continue;
+        }
+    }
+}
+        
 ConstHostCollection
 HostMgr::getAll4(const IOAddress& address) const {
     ConstHostCollection hosts = getCfgHosts()->getAll4(address);
index a5e90a02c4878fbc50526c6b181f225e6ec08cb1..27f73b6ccfbaf30b6a12306fa848c87386d62186 100644 (file)
@@ -160,6 +160,66 @@ public:
     virtual ConstHostCollection
     getAll6(const SubnetID& subnet_id) const;
 
+    /// @brief Returns range of hosts in a DHCPv4 subnet.
+    ///
+    /// This method returns a page of @c Host objects representing
+    /// reservations in a specified subnet as documented in the
+    /// @c BaseHostDataSource::getPage4
+    ///
+    /// The typical usage of this method is as follows:
+    /// - Get the first page of hosts by specifying zero index and id
+    ///   as the beginning of the range.
+    /// - Index and last id of the returned range should be used as
+    ///   starting index and id for the next page in the subsequent call.
+    /// - All returned hosts are from the same source so if the number of
+    ///   hosts returned is lower than the page size, it does not indicate
+    ///   that the last page has been retrieved.
+    /// - If there are no hosts returned it indicates that the previous page
+    ///   was the last page.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param source_index Index of the source.
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    ///
+    /// @return Host collection (may be empty).
+    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.
+    ///
+    /// This method returns a page of @c Host objects representing
+    /// reservations in a specified subnet as documented in the
+    /// @c BaseHostDataSource::getPage6
+    ///
+    /// The typical usage of this method is as follows:
+    /// - Get the first page of hosts by specifying zero index and id
+    ///   as the beginning of the range.
+    /// - Index and last id of the returned range should be used as
+    ///   starting index and id for the next page in the subsequent call.
+    /// - All returned hosts are from the same source so if the number of
+    ///   hosts returned is lower than the page size, it does not indicate
+    ///   that the last page has been retrieved.
+    /// - If there are no hosts returned it indicates that the previous page
+    ///   was the last page.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param source_index Index of the source.
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    ///
+    /// @return Host collection (may be empty).
+    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.
     ///
     /// This method may return multiple @c Host objects if they are connected to
index 448bceca19fa6df6b480f69d93d8e2c3f2a3ba8e..ec1d6508c08ec242bc8229e44d70bf304c88e16d 100644 (file)
@@ -1953,6 +1953,8 @@ public:
         DEL_HOST_SUBID6_ID,     // Delete v6 host (subnet-id, ident.type, identifier)
         GET_HOST_SUBID4,        // Gets host by IPv4 SubnetID
         GET_HOST_SUBID6,        // Gets host by IPv6 SubnetID
+        GET_HOST_SUBID4_PAGE,   // Gets host by IPv4 SubnetID beginning by HID
+        GET_HOST_SUBID6_PAGE,   // Gets host by IPv6 SubnetID beginning by HID
         NUM_STATEMENTS          // Number of statements
     };
 
@@ -2366,8 +2368,43 @@ TaggedStatementArray tagged_statements = { {
             "LEFT JOIN ipv6_reservations AS r "
                 "ON h.host_id = r.host_id "
             "WHERE h.dhcp6_subnet_id = ? "
-            "ORDER BY h.host_id, o.option_id, r.reservation_id"}
+            "ORDER BY h.host_id, o.option_id, r.reservation_id"},
+
+    {MySqlHostDataSourceImpl::GET_HOST_SUBID4_PAGE,
+            "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, "
+                "h.dhcp4_next_server, h.dhcp4_server_hostname, "
+                "h.dhcp4_boot_file_name, h.auth_key, "
+                "o.option_id, o.code, o.value, o.formatted_value, o.space, "
+                "o.persistent, o.user_context "
+            "FROM hosts AS h "
+            "LEFT JOIN dhcp4_options AS o "
+                "ON h.host_id = o.host_id "
+            "WHERE h.dhcp4_subnet_id = ? AND h.host_id > ? "
+            "ORDER BY h.host_id, o.option_id "
+            "LIMIT ?"},
+
+    {MySqlHostDataSourceImpl::GET_HOST_SUBID6_PAGE,
+            "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, "
 
+                "h.dhcp4_next_server, h.dhcp4_server_hostname, "
+                "h.dhcp4_boot_file_name, h.auth_key, "
+                "o.option_id, o.code, o.value, o.formatted_value, o.space, "
+                "o.persistent, o.user_context, "
+                "r.reservation_id, r.address, r.prefix_len, r.type, "
+                "r.dhcp6_iaid "
+            "FROM hosts AS h "
+            "LEFT JOIN dhcp6_options AS o "
+                "ON h.host_id = o.host_id "
+            "LEFT JOIN ipv6_reservations AS r "
+                "ON h.host_id = r.host_id "
+            "WHERE h.dhcp6_subnet_id = ? AND h.host_id > ? "
+            "ORDER BY h.host_id, o.option_id, r.reservation_id"
+            "LIMIT ?"}
     }
 };
 
@@ -2940,6 +2977,74 @@ MySqlHostDataSource::getAll6(const SubnetID& subnet_id) const {
     return (result);
 }
 
+ConstHostCollection
+MySqlHostDataSource::getPage4(const SubnetID& subnet_id,
+                              size_t& /*source_index*/,
+                              uint64_t lower_host_id,
+                              const HostPageSize& page_size) const {
+    // Set up the WHERE clause value
+    MYSQL_BIND inbind[3];
+    memset(inbind, 0, sizeof(inbind));
+
+    // Bind subnet id
+    uint32_t subnet = subnet_id;
+    inbind[0].buffer_type = MYSQL_TYPE_LONG;
+    inbind[0].buffer = reinterpret_cast<char*>(&subnet);
+    inbind[0].is_unsigned = MLM_TRUE;
+
+    // Bind lower host id
+    uint32_t host_id = lower_host_id;
+    inbind[1].buffer_type = MYSQL_TYPE_LONG;
+    inbind[1].buffer = reinterpret_cast<char*>(&host_id);
+    inbind[1].is_unsigned = MLM_TRUE;
+
+    // Bind page size value
+    uint32_t page_size_data = page_size.page_size_;
+    inbind[2].buffer_type = MYSQL_TYPE_LONG;
+    inbind[2].buffer = reinterpret_cast<char*>(&page_size_data);
+    inbind[2].is_unsigned = MLM_TRUE;
+
+    ConstHostCollection result;
+    impl_->getHostCollection(MySqlHostDataSourceImpl::GET_HOST_SUBID4_PAGE,
+                             inbind, impl_->host_exchange_,
+                             result, false);
+    return (result);
+}
+
+ConstHostCollection
+MySqlHostDataSource::getPage6(const SubnetID& subnet_id,
+                              size_t& /*source_index*/,
+                              uint64_t lower_host_id,
+                              const HostPageSize& page_size) const {
+    // Set up the WHERE clause value
+    MYSQL_BIND inbind[3];
+    memset(inbind, 0, sizeof(inbind));
+
+    // Bind subnet id
+    uint32_t subnet = subnet_id;
+    inbind[0].buffer_type = MYSQL_TYPE_LONG;
+    inbind[0].buffer = reinterpret_cast<char*>(&subnet);
+    inbind[0].is_unsigned = MLM_TRUE;
+
+    // Bind lower host id
+    uint32_t host_id = lower_host_id;
+    inbind[1].buffer_type = MYSQL_TYPE_LONG;
+    inbind[1].buffer = reinterpret_cast<char*>(&host_id);
+    inbind[1].is_unsigned = MLM_TRUE;
+
+    // Bind page size value
+    uint32_t page_size_data = page_size.page_size_;
+    inbind[2].buffer_type = MYSQL_TYPE_LONG;
+    inbind[2].buffer = reinterpret_cast<char*>(&page_size_data);
+    inbind[2].is_unsigned = MLM_TRUE;
+
+    ConstHostCollection result;
+    impl_->getHostCollection(MySqlHostDataSourceImpl::GET_HOST_SUBID6_PAGE,
+                             inbind, impl_->host_ipv6_exchange_,
+                             result, false);
+    return (result);
+}
+
 ConstHostCollection
 MySqlHostDataSource::getAll4(const asiolink::IOAddress& address) const {
 
index 2d9509710c78e8bc726f8cf4e6cddb6b84498e73..6f1e3b5c67a720ce42cdfa915f31fd208531ea11 100644 (file)
@@ -153,6 +153,42 @@ public:
     virtual ConstHostCollection
     getAll6(const SubnetID& subnet_id) const;
 
+    /// @brief Returns range of hosts in a DHCPv4 subnet.
+    ///
+    /// This method returns a page of @c Host objects which represent
+    /// reservations in a specified subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param source_index Index of the source (unused).
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @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;
+
+    /// @brief Returns range of hosts in a DHCPv6 subnet.
+    ///
+    /// This method returns a page of @c Host objects which represent
+    /// reservations in a specified subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param source_index Index of the source (unused).
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @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;
+
     /// @brief Returns a collection of hosts using the specified IPv4 address.
     ///
     /// This method may return multiple @c Host objects if they are connected
index 0edb189939974e3d58ff3fb111fe8bcb8063b88e..9145ba4cbca848801c1c952c19501e2797d71b9f 100644 (file)
@@ -1295,6 +1295,8 @@ public:
         DEL_HOST_SUBID6_ID,     // Delete v6 host (subnet-id, ident.type, identifier)
         GET_HOST_SUBID4,        // Gets host by IPv4 SubnetID
         GET_HOST_SUBID6,        // Gets host by IPv6 SubnetID
+        GET_HOST_SUBID4_PAGE,   // Gets host by IPv4 SubnetID beginning by HID
+        GET_HOST_SUBID6_PAGE,   // Gets host by IPv6 SubnetID beginning by HID
         NUM_STATEMENTS          // Number of statements
     };
 
@@ -1760,6 +1762,54 @@ TaggedStatementArray tagged_statements = { {
      "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
      "WHERE h.dhcp6_subnet_id = $1 "
      "ORDER BY h.host_id, o.option_id, r.reservation_id"
+    },
+
+    // PgSqlHostDataSourceImpl::GET_HOST_SUBID4_PAGE
+    // Retrieves host information along with the DHCPv4 options associated with
+    // it. Left joining the dhcp4_options table results in multiple rows being
+    // returned for the same host. The host is retrieved by subnet id.
+    {3,
+     { OID_INT8, OID_INT8, OID_INT8 },
+     "get_host_subid4_page",
+     "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, "
+     "  h.dhcp4_next_server, h.dhcp4_server_hostname, "
+     "  h.dhcp4_boot_file_name, h.auth_key, "
+     "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
+     "  o.persistent, o.user_context "
+     "FROM hosts AS h "
+     "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
+     "WHERE h.dhcp4_subnet_id = $1 AND h.host_id > $2 "
+     "ORDER BY h.host_id, o.option_id "
+     "LIMIT $3"
+    },
+
+    // PgSqlHostDataSourceImpl::GET_HOST_SUBID6_PAGE
+    // Retrieves host information, IPv6 reservations and DHCPv6 options
+    // associated with a host using IPv6 subnet id. This query returns
+    // host information for a single host. However, multiple rows are
+    // returned due to left joining IPv6 reservations and DHCPv6 options.
+    // The number of rows returned is multiplication of number of existing
+    // IPv6 reservations and DHCPv6 options.
+    {3,
+     { OID_INT8, OID_INT8, OID_INT8 },
+     "get_host_subid6_page",
+     "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, "
+     "  h.dhcp4_next_server, h.dhcp4_server_hostname, "
+     "  h.dhcp4_boot_file_name, h.auth_key, "
+     "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
+     "  o.persistent, o.user_context, "
+     "  r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid "
+     "FROM hosts AS h "
+     "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
+     "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
+     "WHERE h.dhcp6_subnet_id = $1 AND h.host_id > $2 "
+     "ORDER BY h.host_id, o.option_id, r.reservation_id "
+     "LIMIT $3"
     }
 }
 };
@@ -2175,6 +2225,60 @@ PgSqlHostDataSource::getAll6(const SubnetID& subnet_id) const {
     return (result);
 }
 
+ConstHostCollection
+PgSqlHostDataSource::getPage4(const SubnetID& subnet_id,
+                              size_t& /*source_index*/,
+                              uint64_t lower_host_id,
+                              const HostPageSize& page_size) const {
+    // Set up the WHERE clause value
+    PsqlBindArrayPtr bind_array(new PsqlBindArray());
+
+    // Add the subnet id.
+    bind_array->add(subnet_id);
+
+    // Add the lower bound host id.
+    bind_array->add(lower_host_id);
+
+    // Add the page size value.
+    string page_size_data =
+        boost::lexical_cast<std::string>(page_size.page_size_);
+    bind_array->add(page_size_data);
+
+    ConstHostCollection result;
+    impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_SUBID4_PAGE,
+                             bind_array, impl_->host_exchange_,
+                             result, false);
+
+    return (result);
+}
+
+ConstHostCollection
+PgSqlHostDataSource::getPage6(const SubnetID& subnet_id,
+                              size_t& /*source_index*/,
+                              uint64_t lower_host_id,
+                              const HostPageSize& page_size) const {
+    // Set up the WHERE clause value
+    PsqlBindArrayPtr bind_array(new PsqlBindArray());
+
+    // Add the subnet id.
+    bind_array->add(subnet_id);
+
+    // Add the lower bound host id.
+    bind_array->add(lower_host_id);
+
+    // Add the page size value.
+    string page_size_data =
+        boost::lexical_cast<std::string>(page_size.page_size_);
+    bind_array->add(page_size_data);
+
+    ConstHostCollection result;
+    impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_SUBID6_PAGE,
+                             bind_array, impl_->host_exchange_,
+                             result, false);
+
+    return (result);
+}
+
 ConstHostCollection
 PgSqlHostDataSource::getAll4(const asiolink::IOAddress& address) const {
 
index e93f4f9e1fdf4ea2ff397b731ff91b18486703ac..e5094e1011be4ab17566ffe1688a532370e7ae13 100644 (file)
@@ -180,6 +180,42 @@ public:
     virtual ConstHostCollection
     getAll6(const SubnetID& subnet_id) const;
 
+    /// @brief Returns range of hosts in a DHCPv4 subnet.
+    ///
+    /// This method returns a page of @c Host objects which represent
+    /// reservations in a specified subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param source_index Index of the source (unused).
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @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;
+
+    /// @brief Returns range of hosts in a DHCPv6 subnet.
+    ///
+    /// This method returns a page of @c Host objects which represent
+    /// reservations in a specified subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param source_index Index of the source (unused).
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @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;
+
     /// @brief Returns a collection of hosts using the specified IPv4 address.
     ///
     /// This method may return multiple @c Host objects if they are connected
index 91eca0996010148b5a7edfb89706cbae4e9121bb..d24f249d06c3bd9659f2994737c30ed13b54f0f5 100644 (file)
@@ -611,6 +611,16 @@ public:
         return (getCollection());
     }
 
+    ConstHostCollection getPage4(const SubnetID&, size_t&, uint64_t,
+                                 const HostPageSize&) const {
+        return (getCollection());
+    }
+
+    ConstHostCollection getPage6(const SubnetID&, size_t&, uint64_t,
+                                 const HostPageSize&) const {
+        return (getCollection());
+    }
+
     ConstHostCollection getAll4(const IOAddress&) const {
         return (getCollection());
     }
index fd07827c65808ecd4e9188539ec21402f14aea85..7a465b5c597b11723582c3543b1a00d4d2a45526 100644 (file)
@@ -46,6 +46,22 @@ MemHostDataSource::getAll6(const SubnetID& subnet_id) const {
     return (hosts);
 }
 
+ConstHostCollection
+MemHostDataSource::getPage4(const SubnetID& /*subnet_id*/,
+                            size_t& /*source_index*/,
+                            uint64_t /*lower_host_id*/,
+                            const HostPageSize& /*page_size*/) const {
+    return (ConstHostCollection());
+}
+
+ConstHostCollection
+MemHostDataSource::getPage6(const SubnetID& /*subnet_id*/,
+                            size_t& /*source_index*/,
+                            uint64_t /*lower_host_id*/,
+                            const HostPageSize& /*page_size*/) const {
+    return (ConstHostCollection());
+}
+
 ConstHostCollection
 MemHostDataSource::getAll4(const asiolink::IOAddress& /*address*/) const {
     return (ConstHostCollection());
index 370e5fe6eb7d6a7aa54398f175917acd5d6fee46..43fc74fe0ccdbb2ddc3b950aa7ab7f87d9841b46 100644 (file)
@@ -58,6 +58,36 @@ public:
     virtual ConstHostCollection
     getAll6(const SubnetID& subnet_id) const;
 
+    /// @brief Return range of hosts in a DHCPv4 subnet.
+    ///
+    /// Currently not implemented.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param source_index Index of the source (unused).
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    virtual ConstHostCollection
+    getPage4(const SubnetID& subnet_id,
+             size_t& source_index,
+             uint64_t lower_host_id,
+             const HostPageSize& page_size) const;
+
+    /// @brief Return range of hosts in a DHCPv6 subnet.
+    ///
+    /// Currently not implemented.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param source_index Index of the source (unused).
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    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.
     ///
     /// Currently not implemented.
index d3965c9e2fd5bef4742da4cbce576f28671057f2..1a398064f3afd4fb661b7690c8473f31423cb041 100644 (file)
@@ -57,6 +57,36 @@ public:
     virtual HostCollection
     getAll6(const SubnetID& subnet_id) = 0;
 
+    /// @brief Returns range of hosts in a DHCPv4 subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param source_index Index of the source.
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    ///
+    /// @return Collection of non-const @c Host objects.
+    virtual HostCollection
+    getPage4(const SubnetID& subnet_id,
+             size_t& source_index,
+             uint64_t lower_host_id,
+             const HostPageSize& page_size) = 0;
+
+    /// @brief Returns range of hosts in a DHCPv6 subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param source_index Index of the source.
+    /// @param lower_host_id Host identifier used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    ///
+    /// @return Collection of non-const @c Host objects.
+    virtual HostCollection
+    getPage6(const SubnetID& subnet_id,
+             size_t& source_index,
+             uint64_t lower_host_id,
+             const HostPageSize& page_size) = 0;
+
     /// @brief Returns a collection of hosts using the specified IPv4 address.
     ///
     /// This method may return multiple @c Host objects if they are connected