]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#2658] add big integer support to statistics
authorAndrei Pavel <andrei@isc.org>
Wed, 26 Apr 2023 12:45:29 +0000 (15:45 +0300)
committerAndrei Pavel <andrei@isc.org>
Wed, 17 May 2023 16:09:38 +0000 (19:09 +0300)
Pool capacities have been promoted in code from uint64_t to uint128_t.

Bigint is modelled as an int128_t in statistics, following the precedent of
signed integer of int64_t from statistics.

- "total-nas" is extended to 128 bits as requested in the issue.
- "total-pds" has the same risk of overflowing so it has been extended
  as well.
- "total-addresses" always fits in 64 bits, but certain code forces a
  128 bit value on it. See Pool::getCapacity(), Subnet::getPoolCapacity(),
  Subnet::sumPoolCapacity(). It could have been truncated to a 64 bit value,
  but that seems like an unnecessary complication.

Because of the disparity in signedness there is some truncation that can
happen when pool capacity values are passed on to statistics. That only happens
for the last half of the value range, so for prefix ranges larger than /1.

35 files changed:
src/bin/dhcp4/tests/fqdn_unittest.cc
src/hooks/dhcp/stat_cmds/stat_cmds.cc
src/lib/asiolink/addr_utilities.cc
src/lib/asiolink/addr_utilities.h
src/lib/asiolink/tests/addr_utilities_unittest.cc
src/lib/dhcpsrv/alloc_engine.cc
src/lib/dhcpsrv/alloc_engine.h
src/lib/dhcpsrv/base_host_data_source.h
src/lib/dhcpsrv/cfg_subnets4.cc
src/lib/dhcpsrv/cfg_subnets6.cc
src/lib/dhcpsrv/host_data_source_factory.cc
src/lib/dhcpsrv/host_data_source_factory.h
src/lib/dhcpsrv/lease_mgr.cc
src/lib/dhcpsrv/parsers/dhcp_parsers.cc
src/lib/dhcpsrv/parsers/duid_config_parser.cc
src/lib/dhcpsrv/parsers/multi_threading_config_parser.cc
src/lib/dhcpsrv/pool.h
src/lib/dhcpsrv/subnet.cc
src/lib/dhcpsrv/subnet.h
src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc
src/lib/dhcpsrv/tests/cfgmgr_unittest.cc
src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc
src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc
src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.h
src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc
src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc
src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc
src/lib/dhcpsrv/tests/pool_unittest.cc
src/lib/dhcpsrv/tests/subnet_unittest.cc
src/lib/stats/observation.cc
src/lib/stats/observation.h
src/lib/stats/stats_mgr.cc
src/lib/stats/stats_mgr.h
src/lib/stats/tests/observation_unittest.cc
src/lib/stats/testutils/stats_test_utils.h

index 2f1cda9b5f86992aafc5a1b6d146c5ca9b47bab6..2b87a360a161a67f634e67b689d5e488b8f8d04b 100644 (file)
@@ -894,11 +894,12 @@ public:
     }
 
 
-    /// @brief Checks the value of statistic for a given subnet.
+    /// @brief Checks the value of an integer statistic for a given subnet.
     ///
-    /// @param subnet_id Identifier of a subnet for which statistics should be
-    /// @param name statistic name (e.g. "assigned-addresses", "total-addresses" ...)
+    /// @param subnet_id identifier of a subnet for which the statistic should be checked
+    /// @param name statistic name (e.g. "assigned-addresses", "total-addresses", ...)
     /// @param exp_value expected value of the statistic
+    ///
     /// @return Number of assigned addresses for a subnet.
     void checkSubnetStat(const SubnetID& subnet_id, const std::string& name, int64_t exp_value) const {
         // Retrieve statistics name, e.g. subnet[1234].assigned-addresses.
@@ -907,6 +908,21 @@ public:
         ASSERT_TRUE(obs) << "cannot find: " << stats_name;
         EXPECT_EQ(exp_value, obs->getInteger().first);
     }
+
+    /// @brief Checks the value of a big integer statistic for a given subnet.
+    ///
+    /// @param subnet_id identifier of a subnet for which the statistic should be checked
+    /// @param name statistic name (e.g. "total-nas", "total-pds", ...)
+    /// @param exp_value expected value of the statistic
+    ///
+    /// @return Number of assigned addresses for a subnet.
+    void checkBigSubnetStat(const SubnetID& subnet_id, const std::string& name, int64_t exp_value) const {
+        // Retrieve statistics name, e.g. subnet[1234].assigned-addresses.
+        const std::string stats_name = StatsMgr::generateName("subnet", subnet_id, name);
+        ObservationPtr obs =  StatsMgr::instance().getObservation(stats_name);
+        ASSERT_TRUE(obs) << "cannot find: " << stats_name;
+        EXPECT_EQ(exp_value, obs->getBigInteger().first);
+    }
 };
 
 // Tests the following scenario:
index 026da5c9e35ffea080a16dfd476fb3a7915b9e32..eb43ae771be2a8a7ccaded0f2074a03ca6019927 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2018-2022 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2018-2023 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
@@ -205,13 +205,21 @@ public:
     void addValueRow6(ElementPtr value_rows, const SubnetID &subnet_id,
                       int64_t assigned, int64_t declined, int64_t assigned_pds);
 
-    /// @brief Fetches a single statistic for a subnet from StatsMgr
+    /// @brief Fetches a single integer statistic for a subnet from StatsMgr.
     ///
     /// Uses the given id and name to query the StatsMgr for the desired value.
     ///
-    /// @param subnet_id id of the desired subnet
-    /// @param name name of the desired statistic
+    /// @param subnet_id the subnet ID for the desired statistic
+    /// @param name the name of the desired statistic
     int64_t getSubnetStat(const SubnetID& subnet_id, const std::string& name);
+
+    /// @brief Fetches a single bigint statistic for a subnet from StatsMgr.
+    ///
+    /// Uses the given id and name to query the StatsMgr for the desired value.
+    ///
+    /// @param subnet_id the subnet ID for the desired statistic
+    /// @param name the name of the desired statistic
+    int128_t getBigSubnetStat(const SubnetID& subnet_id, const std::string& name);
 };
 
 int
@@ -676,7 +684,7 @@ LeaseStatCmdsImpl::createResultSet(const ElementPtr &result_wrapper,
 
 void
 LeaseStatCmdsImpl::addValueRow4(ElementPtr value_rows, const SubnetID &subnet_id,
-                          int64_t assigned, int64_t declined) {
+                                int64_t assigned, int64_t declined) {
     ElementPtr row = Element::createList();
     row->add(Element::create(static_cast<int64_t>(subnet_id)));
     row->add(Element::create(getSubnetStat(subnet_id, "total-addresses")));
@@ -688,14 +696,14 @@ LeaseStatCmdsImpl::addValueRow4(ElementPtr value_rows, const SubnetID &subnet_id
 
 void
 LeaseStatCmdsImpl::addValueRow6(ElementPtr value_rows, const SubnetID &subnet_id,
-                           int64_t assigned, int64_t declined, int64_t assigned_pds) {
+                                int64_t assigned, int64_t declined, int64_t assigned_pds) {
     ElementPtr row = Element::createList();
     row->add(Element::create(static_cast<int64_t>(subnet_id)));
-    row->add(Element::create(getSubnetStat(subnet_id, "total-nas")));
+    row->add(Element::create(getBigSubnetStat(subnet_id, "total-nas")));
     row->add(Element::create(getSubnetStat(subnet_id, "cumulative-assigned-nas")));
     row->add(Element::create(assigned));
     row->add(Element::create(declined));
-    row->add(Element::create(getSubnetStat(subnet_id, "total-pds")));
+    row->add(Element::create(getBigSubnetStat(subnet_id, "total-pds")));
     row->add(Element::create(getSubnetStat(subnet_id, "cumulative-assigned-pds")));
     row->add(Element::create(assigned_pds));
     value_rows->add(row);
@@ -712,6 +720,17 @@ LeaseStatCmdsImpl::getSubnetStat(const SubnetID& subnet_id, const std::string& n
     return (0);
 }
 
+int128_t
+LeaseStatCmdsImpl::getBigSubnetStat(const SubnetID& subnet_id, const std::string& name) {
+    ObservationPtr stat = StatsMgr::instance().
+                          getObservation(StatsMgr::generateName("subnet", subnet_id, name));
+    if (stat) {
+        return (stat->getBigInteger().first);
+    }
+
+    return (0);
+}
+
 // Using a critical section to avoid any changes in parallel.
 
 int
index 04b44dc5170f1ab51c9cfe4b7b2f8e7c415e09b4..d99c66b49a01dd427408f968b958b097493b3a2f 100644 (file)
@@ -15,6 +15,7 @@
 
 using namespace isc;
 using namespace isc::asiolink;
+using namespace isc::util;
 
 namespace {
 
@@ -199,7 +200,7 @@ IOAddress getNetmask4(uint8_t len) {
     return (IOAddress(x));
 }
 
-uint64_t
+uint128_t
 addrsInRange(const IOAddress& min, const IOAddress& max) {
     if (min.getFamily() != max.getFamily()) {
         isc_throw(BadValue, "Both addresses have to be the same family");
@@ -349,28 +350,19 @@ prefixLengthFromRange(const IOAddress& min, const IOAddress& max) {
     }
 }
 
-uint64_t prefixesInRange(const uint8_t pool_len, const uint8_t delegated_len) {
+uint128_t prefixesInRange(const uint8_t pool_len, const uint8_t delegated_len) {
     if (delegated_len < pool_len) {
         return (0);
     }
 
-    uint64_t count = delegated_len - pool_len;
-
-    if (count == 0) {
-        // If we want to delegate /64 out of /64 pool, we have only
-        // one prefix.
-        return (1);
-    } else if (count >= 64) {
-        // If the difference is greater than or equal 64, e.g. we want to
-        // delegate /96 out of /16 pool, the number is bigger than we can
-        // express, so we'll stick with maximum value of uint64_t.
-        return (std::numeric_limits<uint64_t>::max());
-    } else {
-        // Now count specifies the exponent (e.g. if the difference between the
-        // delegated and pool length is 4, we have 16 prefixes), so we need
-        // to calculate 2^(count - 1)
-        return ((static_cast<uint64_t>(2)) << (count - 1));
+    uint8_t const count(delegated_len - pool_len);
+
+    if (count == 128) {
+        // One off is the best we can do, unless we promote to uint256_t.
+        return uint128_t(-1);
     }
+
+    return (uint128_t(1) << count);
 }
 
 IOAddress offsetAddress(const IOAddress& addr, uint64_t offset) {
index bd78deec4ca4a64e362ef7e90834a1ad0a0c2bf3..9aa9af2d10b11a473993bfd745ab1ece128aef1b 100644 (file)
@@ -8,6 +8,7 @@
 #define ADDR_UTILITIES_H
 
 #include <asiolink/io_address.h>
+#include <util/bigints.h>
 
 namespace isc {
 namespace asiolink {
@@ -54,7 +55,7 @@ IOAddress getNetmask4(uint8_t len);
 /// @param min the first address in range
 /// @param max the last address in range
 /// @return number of addresses in range
-uint64_t addrsInRange(const IOAddress& min, const IOAddress& max);
+isc::util::uint128_t addrsInRange(const IOAddress& min, const IOAddress& max);
 
 /// @brief Returns prefix length from the specified range (min - max).
 ///
@@ -78,7 +79,7 @@ int prefixLengthFromRange(const IOAddress& min, const IOAddress& max);
 /// @param pool_len length of the pool in bits
 /// @param delegated_len length of the prefixes to be delegated from the pool
 /// @return number of prefixes in range
-uint64_t prefixesInRange(const uint8_t pool_len, const uint8_t delegated_len);
+isc::util::uint128_t prefixesInRange(const uint8_t pool_len, const uint8_t delegated_len);
 
 /// @brief Finds the address increased by offset.
 ///
@@ -92,7 +93,7 @@ uint64_t prefixesInRange(const uint8_t pool_len, const uint8_t delegated_len);
 /// @return address being offset greater than the input address
 IOAddress offsetAddress(const IOAddress& addr, uint64_t offset);
 
-};
-};
+}  // namespace asiolink
+}  // namespace isc
 
 #endif // ADDR_UTILITIES_H
index a8564379a6fda021a164c89d04406aee2f717305..df7a6aca185e16226ac08b9463a3467eea0ce401 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <asiolink/addr_utilities.h>
 #include <exceptions/exceptions.h>
+#include <util/bigints.h>
 
 #include <gtest/gtest.h>
 
@@ -18,6 +19,7 @@
 
 using namespace std;
 using namespace isc::asiolink;
+using namespace isc::util;
 
 namespace {
 
@@ -358,13 +360,13 @@ TEST(AddrUtilitiesTest, prefixesInRange) {
     EXPECT_EQ(uint64_t(9223372036854775808ull), prefixesInRange(64, 127));
 
     // How many /128 prefixes are in /64 pool?
-    EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
-              prefixesInRange(64, 128));
+    EXPECT_EQ(uint128_t(1) << 64, prefixesInRange(64, 128));
 
     // Let's go overboard again. How many IPv6 addresses are there?
-    EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
-              prefixesInRange(0, 128));
+    EXPECT_EQ(uint128_t(1) << 127, prefixesInRange(1, 128));
 
+    // Let's go overboard again. How many IPv6 addresses are there?
+    EXPECT_EQ(uint128_t(-1), prefixesInRange(0, 128));
 }
 
 // Checks the function which finds an IPv4 address from input address and offset.
index 374aa0695f5dfda27682c366c7d886a612afd001..733404a17c76dc4a8954532dce64d1e1d857f00e 100644 (file)
@@ -35,7 +35,6 @@
 #include <boost/make_shared.hpp>
 
 #include <algorithm>
-#include <limits>
 #include <sstream>
 #include <stdint.h>
 #include <string.h>
@@ -90,7 +89,7 @@ AllocEngineHooks Hooks;
 namespace isc {
 namespace dhcp {
 
-AllocEngine::AllocEngine(uint64_t attempts)
+AllocEngine::AllocEngine(uint128_t const& attempts)
     : attempts_(attempts), incomplete_v4_reclamations_(0),
       incomplete_v6_reclamations_(0) {
 
@@ -969,17 +968,21 @@ AllocEngine::allocateBestMatch(ClientContext6& ctx,
         // - we find a free address
         // - we find an address for which the lease has expired
         // - we exhaust number of tries
-        uint64_t possible_attempts = subnet->getPoolCapacity(ctx.currentIA().type_,
-                                                             classes,
-                                                             prefix_length_match,
-                                                             hint_prefix_length);
+        uint128_t const possible_attempts =
+            subnet->getPoolCapacity(ctx.currentIA().type_,
+                                    classes,
+                                    prefix_length_match,
+                                    hint_prefix_length);
 
         // If the number of tries specified in the allocation engine constructor
         // is set to 0 (unlimited) or the pools capacity is lower than that number,
         // let's use the pools capacity as the maximum number of tries. Trying
         // more than the actual pools capacity is a waste of time. If the specified
         // number of tries is lower than the pools capacity, use that number.
-        uint64_t max_attempts = ((attempts_ == 0) || (possible_attempts < attempts_)) ? possible_attempts : attempts_;
+        uint128_t const max_attempts =
+            (attempts_ == 0 || possible_attempts < attempts_) ?
+                possible_attempts :
+                attempts_;
 
         if (max_attempts > 0) {
             // If max_attempts is greater than 0, there are some pools in this subnet
@@ -4360,7 +4363,7 @@ AllocEngine::allocateUnreservedLease4(ClientContext4& ctx) {
 
     Subnet4Ptr original_subnet = subnet;
 
-    uint64_t total_attempts = 0;
+    uint128_t total_attempts = 0;
 
     // The following counter tracks the number of subnets with matching client
     // classes from which the allocation engine attempted to assign leases.
@@ -4377,7 +4380,7 @@ AllocEngine::allocateUnreservedLease4(ClientContext4& ctx) {
             client_id = ctx.clientid_;
         }
 
-        uint64_t possible_attempts =
+        uint128_t const possible_attempts =
             subnet->getPoolCapacity(Lease::TYPE_V4, classes);
 
         // If the number of tries specified in the allocation engine constructor
@@ -4385,7 +4388,10 @@ AllocEngine::allocateUnreservedLease4(ClientContext4& ctx) {
         // let's use the pools capacity as the maximum number of tries. Trying
         // more than the actual pools capacity is a waste of time. If the specified
         // number of tries is lower than the pools capacity, use that number.
-        uint64_t max_attempts = ((attempts_ == 0 || possible_attempts < attempts_) ? possible_attempts : attempts_);
+        uint128_t const max_attempts =
+            (attempts_ == 0 || possible_attempts < attempts_) ?
+                possible_attempts :
+                attempts_;
 
         if (max_attempts > 0) {
             // If max_attempts is greater than 0, there are some pools in this subnet
@@ -4402,7 +4408,7 @@ AllocEngine::allocateUnreservedLease4(ClientContext4& ctx) {
 
         CalloutHandle::CalloutNextStep callout_status = CalloutHandle::NEXT_STEP_CONTINUE;
 
-        for (uint64_t i = 0; i < max_attempts; ++i) {
+        for (uint128_t i = 0; i < max_attempts; ++i) {
 
             ++total_attempts;
 
index f844fa7710ba3f69882bb79e0630f4645d49bff6..88bb9044db7db1844d334367966981894e13e8b0 100644 (file)
@@ -56,7 +56,7 @@ public:
     ///
     /// @param attempts number of attempts for each lease allocation before
     ///        we give up (0 means unlimited)
-    AllocEngine(uint64_t attempts);
+    AllocEngine(isc::util::uint128_t const& attempts);
 
     /// @brief Destructor.
     virtual ~AllocEngine() { }
@@ -64,7 +64,7 @@ public:
 private:
 
     /// @brief number of attempts before we give up lease allocation (0=unlimited)
-    uint64_t attempts_;
+    isc::util::uint128_t attempts_;
 
     /// @brief Hook name indexes (used in hooks callouts)
     int hook_index_lease4_select_; ///< index for lease4_select hook
index fa512ec3d70c6f72b44054c0be42ce08c39b5391..f3013a659123ce147d9a43996972d206dfa25855 100644 (file)
@@ -13,6 +13,7 @@
 #include <exceptions/exceptions.h>
 #include <boost/shared_ptr.hpp>
 
+#include <limits>
 #include <vector>
 
 namespace isc {
index 381b4d44042cd6d7ee072398293cfe588bea7aa3..aaebbd693a7a682650c82f741f566994cc420c2a 100644 (file)
@@ -553,8 +553,7 @@ CfgSubnets4::updateStatistics() {
 
         stats_mgr.setValue(StatsMgr::
                            generateName("subnet", subnet_id, "total-addresses"),
-                                        static_cast<int64_t>
-                                        (subnet4->getPoolCapacity(Lease::TYPE_V4)));
+                                        int64_t(subnet4->getPoolCapacity(Lease::TYPE_V4)));
         std::string name =
             StatsMgr::generateName("subnet", subnet_id, "cumulative-assigned-addresses");
         if (!stats_mgr.getObservation(name)) {
index 45b42fd99f94bcc8ed81e478cfdcbf314ad7779f..819d77adedc1615a8fdc64132f6870d73461849f 100644 (file)
@@ -450,13 +450,11 @@ CfgSubnets6::updateStatistics() {
 
         stats_mgr.setValue(StatsMgr::generateName("subnet", subnet_id,
                                                   "total-nas"),
-                           static_cast<int64_t>
-                           (subnet6->getPoolCapacity(Lease::TYPE_NA)));
+                           subnet6->getPoolCapacity(Lease::TYPE_NA));
 
         stats_mgr.setValue(StatsMgr::generateName("subnet", subnet_id,
                                                   "total-pds"),
-                            static_cast<int64_t>
-                            (subnet6->getPoolCapacity(Lease::TYPE_PD)));
+                           subnet6->getPoolCapacity(Lease::TYPE_PD));
 
         const std::string& name_nas =
             StatsMgr::generateName("subnet", subnet_id, "cumulative-assigned-nas");
index 6f6141d78728358e4ca60a0cd1e254660a3e672c..fa27d08f8fa99256310246065e10c37dc2b7c122 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2015-2022 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2023 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
@@ -21,7 +21,6 @@
 
 #include <boost/algorithm/string.hpp>
 #include <boost/foreach.hpp>
-#include <boost/scoped_ptr.hpp>
 
 #include <algorithm>
 #include <iostream>
index 76b2a9db72546a99bef74a78a95c47a2b1ba8299..f2ae0dbb72f81db7b01e06ced01396fa84f9468b 100644 (file)
@@ -10,7 +10,6 @@
 #include <database/database_connection.h>
 #include <dhcpsrv/base_host_data_source.h>
 #include <exceptions/exceptions.h>
-#include <boost/scoped_ptr.hpp>
 
 #include <functional>
 #include <string>
index 9511a67df41f832748e035221bc23334619f5a16..ded2577f7ff77a2ec034dadf1b29f4083d42f8da 100644 (file)
@@ -21,6 +21,7 @@
 #include <algorithm>
 #include <iostream>
 #include <iterator>
+#include <limits>
 #include <map>
 #include <sstream>
 #include <string>
index 2aa74afc8be1f3d4c992ffd54256a734e10d3340..eed5493f5864b46513f294f7f46d42cc4b515b25 100644 (file)
@@ -27,6 +27,7 @@
 #include <boost/make_shared.hpp>
 #include <boost/scoped_ptr.hpp>
 
+#include <limits>
 #include <map>
 #include <string>
 #include <vector>
index 5817bafe7e8ad49be752e8186e90745d99a0f5cf..f2922816eb2f70d5ae235e74b7f0babd92cf3f32 100644 (file)
@@ -15,7 +15,7 @@
 #include <exceptions/exceptions.h>
 #include <boost/foreach.hpp>
 #include <boost/lexical_cast.hpp>
-#include <limits>
+
 #include <string>
 
 using namespace isc::data;
index 8793ba67b99b196e20943bde8d94a0beb50e3828..68f6c41991157fcd4d7ded04c626bdff0f314860 100644 (file)
@@ -11,6 +11,8 @@
 #include <dhcpsrv/parsers/multi_threading_config_parser.h>
 #include <util/multi_threading_mgr.h>
 
+#include <limits>
+
 using namespace isc::data;
 using namespace isc::util;
 
index 8917e81167b102cedfa743a5979b4587b2e97cd2..368cc6e0b6772f38d067bd4ad39e4ea2c513a372 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2022 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2023 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
@@ -16,6 +16,7 @@
 #include <dhcpsrv/cfg_option.h>
 #include <dhcpsrv/lease.h>
 #include <dhcpsrv/ip_range_permutation.h>
+#include <util/bigints.h>
 
 #include <boost/shared_ptr.hpp>
 
@@ -84,7 +85,7 @@ public:
     /// Note that this is the upper bound, assuming that no leases are used
     /// and there are no host reservations. This is just a theoretical calculation.
     /// @return number of possible leases in this pool
-    uint64_t getCapacity() const {
+    isc::util::uint128_t getCapacity() const {
         return (capacity_);
     }
 
@@ -208,7 +209,7 @@ protected:
     /// involved, so it is more efficient to calculate it once and just store
     /// the result. Note that for very large pools, the number is capped at
     /// max value of uint64_t.
-    uint64_t capacity_;
+    isc::util::uint128_t capacity_;
 
     /// @brief Pointer to the option data configuration for this pool.
     CfgOptionPtr cfg_option_;
index ef37ca52fbfb7f3e8610a6a460e2f76a1d579ee8..fca60a582909c4172346056973971c8594379136 100644 (file)
@@ -23,6 +23,7 @@
 #include <boost/make_shared.hpp>
 
 #include <algorithm>
+#include <limits>
 #include <sstream>
 
 using namespace isc::asiolink;
@@ -30,6 +31,8 @@ using namespace isc::data;
 using namespace isc::dhcp;
 using namespace isc::util;
 
+using namespace std;
+
 namespace {
 
 /// @brief Function used in calls to std::upper_bound to check
@@ -89,7 +92,7 @@ Subnet::toText() const {
     return (tmp.str());
 }
 
-uint64_t
+uint128_t
 Subnet::getPoolCapacity(Lease::Type type) const {
     switch (type) {
     case Lease::TYPE_V4:
@@ -105,7 +108,7 @@ Subnet::getPoolCapacity(Lease::Type type) const {
     }
 }
 
-uint64_t
+uint128_t
 Subnet::getPoolCapacity(Lease::Type type,
                         const ClientClasses& client_classes) const {
     switch (type) {
@@ -122,7 +125,7 @@ Subnet::getPoolCapacity(Lease::Type type,
     }
 }
 
-uint64_t
+uint128_t
 Subnet::getPoolCapacity(Lease::Type type,
                         const ClientClasses& client_classes,
                         Allocator::PrefixLenMatchType prefix_length_match,
@@ -142,52 +145,53 @@ Subnet::getPoolCapacity(Lease::Type type,
     }
 }
 
-uint64_t
+uint128_t
 Subnet::sumPoolCapacity(const PoolCollection& pools) const {
-    uint64_t sum = 0;
+    uint128_t sum(0);
     for (auto const& p : pools) {
-        uint64_t x = p->getCapacity();
+        uint128_t const c(p->getCapacity());
 
-        // Check if we can add it. If sum + x > uint64::max, then we would have
+        // Check if we can add it. If sum + c > UINT128_MAX, then we would have
         // overflown if we tried to add it.
-        if (x > std::numeric_limits<uint64_t>::max() - sum) {
-            return (std::numeric_limits<uint64_t>::max());
+        if (c > numeric_limits<uint128_t>::max() - sum) {
+            return (numeric_limits<uint128_t>::max());
         }
 
-        sum += x;
+        sum += c;
     }
 
     return (sum);
 }
 
-uint64_t
+uint128_t
 Subnet::sumPoolCapacity(const PoolCollection& pools,
                         const ClientClasses& client_classes) const {
-    uint64_t sum = 0;
+    uint128_t sum(0);
     for (auto const& p : pools) {
         if (!p->clientSupported(client_classes)) {
             continue;
         }
-        uint64_t x = p->getCapacity();
 
-        // Check if we can add it. If sum + x > uint64::max, then we would have
+        uint128_t const c(p->getCapacity());
+
+        // Check if we can add it. If sum + c > UINT128_MAX, then we would have
         // overflown if we tried to add it.
-        if (x > std::numeric_limits<uint64_t>::max() - sum) {
-            return (std::numeric_limits<uint64_t>::max());
+        if (c > numeric_limits<uint128_t>::max() - sum) {
+            return (numeric_limits<uint128_t>::max());
         }
 
-        sum += x;
+        sum += c;
     }
 
     return (sum);
 }
 
-uint64_t
+uint128_t
 Subnet::sumPoolCapacity(const PoolCollection& pools,
                         const ClientClasses& client_classes,
                         Allocator::PrefixLenMatchType prefix_length_match,
                         uint8_t hint_prefix_length) const {
-    uint64_t sum = 0;
+    uint128_t sum(0);
     for (auto const& p : pools) {
         if (!p->clientSupported(client_classes)) {
             continue;
@@ -198,15 +202,15 @@ Subnet::sumPoolCapacity(const PoolCollection& pools,
             continue;
         }
 
-        uint64_t x = p->getCapacity();
+        uint128_t const c(p->getCapacity());
 
-        // Check if we can add it. If sum + x > uint64::max, then we would have
+        // Check if we can add it. If sum + c > UINT128_MAX, then we would have
         // overflown if we tried to add it.
-        if (x > std::numeric_limits<uint64_t>::max() - sum) {
-            return (std::numeric_limits<uint64_t>::max());
+        if (c > numeric_limits<uint128_t>::max() - sum) {
+            return (numeric_limits<uint128_t>::max());
         }
 
-        sum += x;
+        sum += c;
     }
 
     return (sum);
index 891d20d42437cabd57f114c31f97c6c803c2859b..a875bbeac8886fc11098e2c0f5abffe1ecab0a29 100644 (file)
@@ -17,6 +17,7 @@
 #include <dhcpsrv/network.h>
 #include <dhcpsrv/pool.h>
 #include <dhcpsrv/subnet_id.h>
+#include <util/bigints.h>
 #include <util/dhcp_space.h>
 #include <util/triplet.h>
 
@@ -28,7 +29,6 @@
 #include <boost/multi_index_container.hpp>
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <boost/pointer_cast.hpp>
-#include <boost/scoped_ptr.hpp>
 #include <boost/shared_ptr.hpp>
 
 #include <cstdint>
@@ -176,7 +176,7 @@ public:
     /// @brief Returns the number of possible leases for specified lease type.
     ///
     /// @param type type of the lease
-    uint64_t getPoolCapacity(Lease::Type type) const;
+    isc::util::uint128_t getPoolCapacity(Lease::Type type) const;
 
     /// @brief Returns the number of possible leases for specified lease type
     /// allowed for a client which belongs to classes.
@@ -184,8 +184,8 @@ public:
     /// @param type type of the lease
     /// @param client_classes list of classes the client belongs to
     /// @return number of leases matching lease type and classes
-    uint64_t getPoolCapacity(Lease::Type type,
-                             const ClientClasses& client_classes) const;
+    isc::util::uint128_t getPoolCapacity(Lease::Type type,
+                                         const ClientClasses& client_classes) const;
 
     /// @brief Returns the number of possible leases for specified lease type
     /// allowed for a client which belongs to classes and matching selection
@@ -198,10 +198,10 @@ public:
     /// @param hint_prefix_length the hint prefix length that the client
     /// provided
     /// @return number of leases matching lease type and classes
-    uint64_t getPoolCapacity(Lease::Type type,
-                             const ClientClasses& client_classes,
-                             Allocator::PrefixLenMatchType prefix_length_match,
-                             uint8_t hint_prefix_length) const;
+    isc::util::uint128_t getPoolCapacity(Lease::Type type,
+                                         const ClientClasses& client_classes,
+                                         Allocator::PrefixLenMatchType prefix_length_match,
+                                         uint8_t hint_prefix_length) const;
 
     /// @brief Returns textual representation of the subnet (e.g.
     /// "2001:db8::/64").
@@ -393,15 +393,15 @@ protected:
     ///
     /// @param pools list of pools
     /// @return sum of possible leases
-    uint64_t sumPoolCapacity(const PoolCollection& pools) const;
+    isc::util::uint128_t sumPoolCapacity(const PoolCollection& pools) const;
 
     /// @brief Returns a sum of possible leases in all pools allowing classes.
     ///
     /// @param pools list of pools
     /// @param client_classes list of classes
     /// @return sum of possible/allowed leases
-    uint64_t sumPoolCapacity(const PoolCollection& pools,
-                             const ClientClasses& client_classes) const;
+    isc::util::uint128_t sumPoolCapacity(const PoolCollection& pools,
+                                         const ClientClasses& client_classes) const;
 
     /// @brief Returns a sum of possible leases in all pools allowing classes
     /// and matching selection criteria relative to provided hint prefix length.
@@ -415,10 +415,10 @@ protected:
     /// @param hint_prefix_length the hint prefix length that the client
     /// provided
     /// @return sum of possible/allowed leases
-    uint64_t sumPoolCapacity(const PoolCollection& pools,
-                             const ClientClasses& client_classes,
-                             Allocator::PrefixLenMatchType prefix_length_match,
-                             uint8_t hint_prefix_length) const;
+    isc::util::uint128_t sumPoolCapacity(const PoolCollection& pools,
+                                         const ClientClasses& client_classes,
+                                         Allocator::PrefixLenMatchType prefix_length_match,
+                                         uint8_t hint_prefix_length) const;
 
     /// @brief Checks if the specified pool overlaps with an existing pool.
     ///
index 71ad585300d53d7530caac917bc00b87b5aeccbf..e5a5f511a0fe62ea313d36ea066627dc7f3093c8 100644 (file)
@@ -1717,13 +1717,13 @@ TEST(CfgSubnets6Test, updateStatistics) {
         StatsMgr::generateName("subnet", subnet_id,
                                "total-nas"));
     ASSERT_TRUE(observation);
-    ASSERT_EQ(0, observation->getInteger().first);
+    ASSERT_EQ(0, observation->getBigInteger().first);
 
     observation = StatsMgr::instance().getObservation(
         StatsMgr::generateName("subnet", subnet_id,
                                "total-pds"));
     ASSERT_TRUE(observation);
-    ASSERT_EQ(0, observation->getInteger().first);
+    ASSERT_EQ(0, observation->getBigInteger().first);
 
     observation = StatsMgr::instance().getObservation(
         StatsMgr::generateName("subnet", subnet_id,
@@ -1786,24 +1786,24 @@ TEST(CfgSubnets6Test, removeStatistics) {
     StatsMgr::instance().setValue(
         StatsMgr::generateName("subnet", subnet_id,
                                "total-nas"),
-        int64_t(0));
+        int128_t(0));
 
     observation = StatsMgr::instance().getObservation(
         StatsMgr::generateName("subnet", subnet_id,
                                "total-nas"));
     ASSERT_TRUE(observation);
-    ASSERT_EQ(0, observation->getInteger().first);
+    ASSERT_EQ(0, observation->getBigInteger().first);
 
     StatsMgr::instance().setValue(
         StatsMgr::generateName("subnet", subnet_id,
                                "total-pds"),
-        int64_t(0));
+        int128_t(0));
 
     observation = StatsMgr::instance().getObservation(
         StatsMgr::generateName("subnet", subnet_id,
                                "total-pds"));
     ASSERT_TRUE(observation);
-    ASSERT_EQ(0, observation->getInteger().first);
+    ASSERT_EQ(0, observation->getBigInteger().first);
 
     StatsMgr::instance().setValue(
         StatsMgr::generateName("subnet", subnet_id,
index d1b5413aad62d3094864f4668302a9a4bef21304..e84fab7b6fd3f556b8487d09691039c7e1e15491 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2022 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2023 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
@@ -17,8 +17,6 @@
 #include <stats/stats_mgr.h>
 #include <util/chrono_time_utils.h>
 
-#include <boost/scoped_ptr.hpp>
-
 #include <gtest/gtest.h>
 
 #include <iostream>
@@ -36,10 +34,6 @@ using namespace isc::stats;
 using namespace isc::process;
 using namespace isc;
 
-// don't import the entire boost namespace.  It will unexpectedly hide uint8_t
-// for some systems.
-using boost::scoped_ptr;
-
 namespace {
 
 template <typename Storage>
@@ -593,7 +587,7 @@ TEST_F(CfgMgrTest, commitStats4) {
     CfgSubnets4Ptr subnets = cfg_mgr.getStagingCfg()->getCfgSubnets4();
     subnets->add(subnet1);
     cfg_mgr.commit();
-    stats_mgr.addValue("subnet[123].total-addresses", static_cast<int64_t>(256));
+    stats_mgr.addValue("subnet[123].total-addresses", int64_t(256));
     stats_mgr.setValue("subnet[123].assigned-addresses", static_cast<int64_t>(150));
 
     // Now, let's change the configuration to something new.
@@ -646,7 +640,7 @@ TEST_F(CfgMgrTest, mergeIntoCurrentStats4) {
     CfgSubnets4Ptr subnets = cfg_mgr.getStagingCfg()->getCfgSubnets4();
     subnets->add(subnet1);
     cfg_mgr.commit();
-    stats_mgr.addValue("subnet[123].total-addresses", static_cast<int64_t>(256));
+    stats_mgr.addValue("subnet[123].total-addresses", int64_t(256));
     stats_mgr.setValue("subnet[123].assigned-addresses", static_cast<int64_t>(150));
 
     // There should be no stats for subnet 42 at this point.
@@ -705,7 +699,7 @@ TEST_F(CfgMgrTest, clearStats4) {
     CfgSubnets4Ptr subnets = cfg_mgr.getStagingCfg()->getCfgSubnets4();
     subnets->add(subnet1);
     cfg_mgr.commit();
-    stats_mgr.addValue("subnet[123].total-addresses", static_cast<int64_t>(256));
+    stats_mgr.addValue("subnet[123].total-addresses", int64_t(256));
     stats_mgr.setValue("subnet[123].assigned-addresses", static_cast<int64_t>(150));
 
     // The stats should be there.
@@ -733,10 +727,10 @@ TEST_F(CfgMgrTest, commitStats6) {
     CfgSubnets6Ptr subnets = cfg_mgr.getStagingCfg()->getCfgSubnets6();
     subnets->add(subnet1);
     cfg_mgr.commit();
-    stats_mgr.addValue("subnet[123].total-nas", static_cast<int64_t>(256));
+    stats_mgr.addValue("subnet[123].total-nas", int128_t(256));
     stats_mgr.setValue("subnet[123].assigned-nas", static_cast<int64_t>(150));
 
-    stats_mgr.addValue("subnet[123].total-pds", static_cast<int64_t>(256));
+    stats_mgr.addValue("subnet[123].total-pds", int128_t(256));
     stats_mgr.setValue("subnet[123].assigned-pds", static_cast<int64_t>(150));
 
     // Now, let's change the configuration to something new.
@@ -774,7 +768,7 @@ TEST_F(CfgMgrTest, commitStats6) {
     ObservationPtr total_addrs;
     EXPECT_NO_THROW(total_addrs = stats_mgr.getObservation("subnet[42].total-nas"));
     ASSERT_TRUE(total_addrs);
-    EXPECT_EQ(128, total_addrs->getInteger().first);
+    EXPECT_EQ(128, total_addrs->getBigInteger().first);
     EXPECT_TRUE(total_addrs->getMaxSampleCount().first);
     EXPECT_EQ(14, total_addrs->getMaxSampleCount().second);
     EXPECT_FALSE(total_addrs->getMaxSampleAge().first);
@@ -783,7 +777,7 @@ TEST_F(CfgMgrTest, commitStats6) {
     ObservationPtr total_prfx;
     EXPECT_NO_THROW(total_prfx = stats_mgr.getObservation("subnet[42].total-pds"));
     ASSERT_TRUE(total_prfx);
-    EXPECT_EQ(65536, total_prfx->getInteger().first);
+    EXPECT_EQ(65536, total_prfx->getBigInteger().first);
     EXPECT_TRUE(total_prfx->getMaxSampleCount().first);
     EXPECT_EQ(14, total_prfx->getMaxSampleCount().second);
     EXPECT_FALSE(total_prfx->getMaxSampleAge().first);
@@ -856,11 +850,11 @@ TEST_F(CfgMgrTest, DISABLED_mergeIntoCurrentStats6) {
     ObservationPtr total_addrs;
     EXPECT_NO_THROW(total_addrs = stats_mgr.getObservation("subnet[42].total-nas"));
     ASSERT_TRUE(total_addrs);
-    EXPECT_EQ(128, total_addrs->getInteger().first);
+    EXPECT_EQ(128, total_addrs->getBigInteger().first);
 
     EXPECT_NO_THROW(total_addrs = stats_mgr.getObservation("subnet[42].total-pds"));
     ASSERT_TRUE(total_addrs);
-    EXPECT_EQ(65536, total_addrs->getInteger().first);
+    EXPECT_EQ(65536, total_addrs->getBigInteger().first);
 }
 
 // This test verifies that once the configuration is cleared, the v6 statistics
index 489f7cca0c38b10626654a4ec59fcb4ce90cd6f5..de9f6a2e5d63c1d3acbb13426e5b0407f576c3ca 100644 (file)
@@ -38,7 +38,6 @@
 #include <gtest/gtest.h>
 #include <boost/foreach.hpp>
 #include <boost/pointer_cast.hpp>
-#include <boost/scoped_ptr.hpp>
 
 #include <map>
 #include <string>
index d6c46cc52059aa6189c9b6e382eafd88fdb00ba6..93e132dbe5568460b9fa6945c1d08885e4c7b90a 100644 (file)
@@ -16,7 +16,9 @@
 #include <dhcpsrv/testutils/test_utils.h>
 #include <exceptions/exceptions.h>
 #include <stats/stats_mgr.h>
+#include <stats/testutils/stats_test_utils.h>
 #include <testutils/gtest_utils.h>
+#include <util/bigints.h>
 
 #include <boost/foreach.hpp>
 #include <boost/scoped_ptr.hpp>
@@ -31,6 +33,11 @@ using namespace std;
 using namespace isc::asiolink;
 using namespace isc::data;
 using namespace isc::db;
+using namespace isc::stats;
+using namespace isc::util;
+
+using isc::stats::test::checkStat;
+
 namespace ph = std::placeholders;
 
 namespace isc {
@@ -75,6 +82,17 @@ GenericLeaseMgrTest::GenericLeaseMgrTest()
         /// a template
         leasetype6_.push_back(LEASETYPE6[i]);
     }
+
+    // Clear all subnets defined in previous tests.
+    for (Subnet4Ptr const& subnet : *CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->getAll()) {
+        CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->del(subnet);
+    }
+    for (Subnet6Ptr const& subnet : *CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->getAll()) {
+        CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->del(subnet);
+    }
+
+    // Clear all stats.
+    StatsMgr::instance().removeAll();
 }
 
 GenericLeaseMgrTest::~GenericLeaseMgrTest() {
@@ -2854,17 +2872,6 @@ GenericLeaseMgrTest::testGetDeclinedLeases6() {
     }
 }
 
-void
-GenericLeaseMgrTest::checkStat(const std::string& name,
-                               const int64_t expected_value) {
-    stats::ObservationPtr obs =
-        stats::StatsMgr::instance().getObservation(name);
-
-    ASSERT_TRUE(obs) << " stat: " << name << " not found ";
-    ASSERT_EQ(expected_value, obs->getInteger().first)
-                << " stat: " << name << " value wrong";
-}
-
 void
 GenericLeaseMgrTest::checkLeaseStats(const StatValMapList& expectedStats) {
     // Global accumulators
@@ -3063,7 +3070,6 @@ GenericLeaseMgrTest::testRecountLeaseStats4() {
     ASSERT_NO_FATAL_FAILURE(checkLeaseStats(expectedStats));
 }
 
-
 void
 GenericLeaseMgrTest::testRecountLeaseStats6() {
     using namespace stats;
@@ -4577,6 +4583,44 @@ GenericLeaseMgrTest::testRecreateWithoutCallbacks(const std::string& access) {
     EXPECT_TRUE(logs_.empty());
 }
 
+void
+GenericLeaseMgrTest::testBigStats() {
+    StatValMapList expected_stats(1);
+
+    // Create the largest possible subnet with the largest possible IPv4 pool.
+    Subnet4Ptr subnet4(new Subnet4(IOAddress("0.0.0.0"), 1, 1, 2, 3, 1));
+    subnet4->addPool(Pool4Ptr(new Pool4(IOAddress("0.0.0.0"), 1)));
+    expected_stats[0]["total-addresses"] = 2147483648;
+
+    // Create the largest possible subnet with the largest possible IA_NA pool.
+    Subnet6Ptr subnet6(new Subnet6(IOAddress("::"), 1, 1, 2, 3, 4, 1));
+    subnet6->addPool(Pool6Ptr(new Pool6(Lease::TYPE_NA, IOAddress("::"), 1)));
+
+    // Add the largest possible IA_PD pool.
+    subnet6->addPool(Pool6Ptr(new Pool6(Lease::TYPE_PD, IOAddress("8000::"), 1)));
+
+    // Commit the subnets to the configurations.
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->add(subnet4);
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet6);
+    ASSERT_NO_THROW(CfgMgr::instance().commit());
+
+    // Create the expected stats list. At this point, the only stats
+    // that should be non-zero are total-addresses, total-nas, total-pds.
+    expected_stats[0]["assigned-nas"] = 0;
+    expected_stats[0]["declined-addresses"] = 0;
+    expected_stats[0]["reclaimed-declined-addresses"] = 0;
+    expected_stats[0]["assigned-pds"] = 0;
+    expected_stats[0]["reclaimed-leases"] = 0;
+
+    // Make sure stats are as expected.
+    ASSERT_NO_THROW(checkLeaseStats(expected_stats));
+
+    // Check the big integers separately.
+    int128_t const two_to_the_power_of_127(int128_t(1) << 127);
+    checkStat(StatsMgr::generateName("subnet", 1, "total-nas"), two_to_the_power_of_127);
+    checkStat(StatsMgr::generateName("subnet", 1, "total-pds"), two_to_the_power_of_127);
+}
+
 }  // namespace test
 }  // namespace dhcp
 }  // namespace isc
index 3f47baf2ff8c7f14b727242ce735bea7fcb2e30d..b0d64eb56a597c40a91bb4ce4631fa9c67606ff2 100644 (file)
@@ -115,16 +115,6 @@ public:
     /// @return vector<Lease6Ptr> Vector of pointers to leases
     std::vector<Lease6Ptr> createLeases6();
 
-    /// @brief Compares a StatsMgr statistic to an expected value
-    ///
-    /// Attempt to fetch the named statistic from the StatsMgr and if
-    /// found, compare its observed value to the given value.
-    /// Fails if the stat is not found or if the values do not match.
-    ///
-    /// @param name StatsMgr name for the statistic to check
-    /// @param expected_value expected value of the statistic
-    void checkStat(const std::string& name, const int64_t expected_value);
-
     /// @brief Compares StatsMgr statistics against an expected list of values
     ///
     /// Iterates over a list of statistic names and expected values, attempting
@@ -669,6 +659,9 @@ public:
     /// lease manager.
     void testRecreateWithoutCallbacks(const std::string& access);
 
+    /// @brief Checks that statistic with big integer values are handled correctly.
+    void testBigStats();
+
     /// @brief String forms of IPv4 addresses
     std::vector<std::string> straddress4_;
 
index 443e7f4df59fcecc55a03059b3c0ecafb76515a9..8a8daadf8d177c13aa4298db3a9c4cbb192429e2 100644 (file)
@@ -4404,4 +4404,9 @@ TEST_F(MemfileLeaseMgrTest, recreateWithoutCallbacks) {
     testRecreateWithoutCallbacks(getConfigString(V4));
 }
 
+TEST_F(MemfileLeaseMgrTest, bigStats) {
+    startBackend(V4);
+    testBigStats();
+}
+
 }  // namespace
index 87b6b82500a863731b7592fb8cc2cf5ae03271d8..eebe5a9b793bafd8d41e98a61a81c579fb2c8a84 100644 (file)
@@ -1339,4 +1339,8 @@ TEST_F(MySqlLeaseMgrTest, recreateWithoutCallbacks) {
     testRecreateWithoutCallbacks(validMySQLConnectionString());
 }
 
+TEST_F(MySqlLeaseMgrTest, bigStats) {
+    testBigStats();
+}
+
 }  // namespace
index b0be50cc7011f03c308c9677a2b35c093d54b1cc..0045cefd74a2005176e9aa33ac8b9b0fe64e89fd 100644 (file)
@@ -1328,5 +1328,8 @@ TEST_F(PgSqlLeaseMgrTest, recreateWithoutCallbacks) {
     testRecreateWithoutCallbacks(validPgSQLConnectionString());
 }
 
+TEST_F(PgSqlLeaseMgrTest, bigStats) {
+    testBigStats();
+}
 
 }  // namespace
index 3b532674c46d743509ba0b4b70e01c935789f135..8ee26e75aa1dff71caa0b09cd5e1364757ed33f4 100644 (file)
 #include <dhcpsrv/pool.h>
 #include <testutils/test_to_element.h>
 
-#include <boost/scoped_ptr.hpp>
-
 #include <gtest/gtest.h>
 
 #include <iostream>
 #include <vector>
 #include <sstream>
 
-using boost::scoped_ptr;
 using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::data;
index b4151b52777b89d5a642dee9a5ff8b4bedd68ba9..dfab6fceb0713a53db9512dea8924e0acfd4515f 100644 (file)
 #include <exceptions/exceptions.h>
 
 #include <boost/pointer_cast.hpp>
-#include <boost/scoped_ptr.hpp>
-#include <gtest/gtest.h>
-#include <limits>
 
-// don't import the entire boost namespace.  It will unexpectedly hide uint8_t
-// for some systems.
-using boost::scoped_ptr;
+#include <gtest/gtest.h>
 
 using namespace isc;
 using namespace isc::dhcp;
@@ -1103,12 +1098,12 @@ TEST(Subnet6Test, Pool6PdgetPoolCapacity) {
     // This is 2^64.
     PoolPtr pool4(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:4::"), 48, 112));
     subnet->addPool(pool4);
-    EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
+    EXPECT_EQ(65536 + 4294967296ull + 4294967296ull + (int128_t(1) << 64),
               subnet->getPoolCapacity(Lease::TYPE_PD));
 
     PoolPtr pool5(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:5::"), 48, 112));
     subnet->addPool(pool5);
-    EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
+    EXPECT_EQ(65536 + 4294967296ull + 4294967296ull + (int128_t(1) << 64) + (int128_t(1) << 64),
               subnet->getPoolCapacity(Lease::TYPE_PD));
 }
 
index c8e7b0f5fda8dc541383aef80ceb0a8fba0e9578..034f2b974568669fa4bb8e19859512425d96a241 100644 (file)
@@ -9,12 +9,14 @@
 #include <stats/observation.h>
 #include <util/chrono_time_utils.h>
 #include <cc/data.h>
+
 #include <chrono>
 #include <utility>
 
 using namespace std;
 using namespace std::chrono;
 using namespace isc::data;
+using namespace isc::util;
 
 namespace isc {
 namespace stats {
@@ -33,6 +35,13 @@ Observation::Observation(const std::string& name, const int64_t value) :
     setValue(value);
 }
 
+Observation::Observation(const std::string& name, const int128_t& value) :
+    name_(name), type_(STAT_BIG_INTEGER),
+    max_sample_count_(default_max_sample_count_),
+    max_sample_age_(default_max_sample_age_) {
+    setValue(value);
+}
+
 Observation::Observation(const std::string& name, const double value) :
     name_(name), type_(STAT_FLOAT),
     max_sample_count_(default_max_sample_count_),
@@ -60,6 +69,10 @@ void Observation::setMaxSampleAge(const StatsDuration& duration) {
         setMaxSampleAgeInternal(integer_samples_, duration, STAT_INTEGER);
         return;
     }
+    case STAT_BIG_INTEGER: {
+        setMaxSampleAgeInternal(big_integer_samples_, duration, STAT_BIG_INTEGER);
+        return;
+    }
     case STAT_FLOAT: {
         setMaxSampleAgeInternal(float_samples_, duration, STAT_FLOAT);
         return;
@@ -84,6 +97,10 @@ void Observation::setMaxSampleCount(uint32_t max_samples) {
         setMaxSampleCountInternal(integer_samples_, max_samples, STAT_INTEGER);
         return;
     }
+    case STAT_BIG_INTEGER: {
+        setMaxSampleCountInternal(big_integer_samples_, max_samples, STAT_BIG_INTEGER);
+        return;
+    }
     case STAT_FLOAT: {
         setMaxSampleCountInternal(float_samples_, max_samples, STAT_FLOAT);
         return;
@@ -107,6 +124,11 @@ void Observation::addValue(const int64_t value) {
     setValue(current.first + value);
 }
 
+void Observation::addValue(const int128_t& value) {
+    BigIntegerSample current = getBigInteger();
+    setValue(current.first + value);
+}
+
 void Observation::addValue(const double value) {
     FloatSample current = getFloat();
     setValue(current.first + value);
@@ -126,6 +148,10 @@ void Observation::setValue(const int64_t value) {
     setValueInternal(value, integer_samples_, STAT_INTEGER);
 }
 
+void Observation::setValue(const int128_t& value) {
+    setValueInternal(value, big_integer_samples_, STAT_BIG_INTEGER);
+}
+
 void Observation::setValue(const double value) {
     setValueInternal(value, float_samples_, STAT_FLOAT);
 }
@@ -145,6 +171,10 @@ size_t Observation::getSize() const {
         size = getSizeInternal(integer_samples_, STAT_INTEGER);
         return (size);
     }
+    case STAT_BIG_INTEGER: {
+        size = getSizeInternal(big_integer_samples_, STAT_BIG_INTEGER);
+        return (size);
+    }
     case STAT_FLOAT: {
         size = getSizeInternal(float_samples_, STAT_FLOAT);
         return (size);
@@ -223,6 +253,10 @@ IntegerSample Observation::getInteger() const {
     return (getValueInternal<IntegerSample>(integer_samples_, STAT_INTEGER));
 }
 
+BigIntegerSample Observation::getBigInteger() const {
+    return (getValueInternal<BigIntegerSample>(big_integer_samples_, STAT_BIG_INTEGER));
+}
+
 FloatSample Observation::getFloat() const {
     return (getValueInternal<FloatSample>(float_samples_, STAT_FLOAT));
 }
@@ -256,6 +290,10 @@ std::list<IntegerSample> Observation::getIntegers() const {
     return (getValuesInternal<IntegerSample>(integer_samples_, STAT_INTEGER));
 }
 
+std::list<BigIntegerSample> Observation::getBigIntegers() const {
+    return (getValuesInternal<BigIntegerSample>(big_integer_samples_, STAT_BIG_INTEGER));
+}
+
 std::list<FloatSample> Observation::getFloats() const {
     return (getValuesInternal<FloatSample>(float_samples_, STAT_FLOAT));
 }
@@ -370,6 +408,9 @@ std::string Observation::typeToText(Type type) {
     case STAT_INTEGER:
         tmp << "integer";
         break;
+    case STAT_BIG_INTEGER:
+        tmp << "big integer";
+        break;
     case STAT_FLOAT:
         tmp << "float";
         break;
@@ -414,6 +455,23 @@ Observation::getJSON() const {
         }
         break;
     }
+    case STAT_BIG_INTEGER: {
+        std::list<BigIntegerSample> const& samples(getBigIntegers());
+
+        // Iterate over all elements in the list and alternately add
+        // value and timestamp to the entry.
+        for (BigIntegerSample const& i : samples) {
+            entry = isc::data::Element::createList();
+            value = isc::data::Element::create(i.first);
+            timestamp = isc::data::Element::create(isc::util::clockToText(i.second));
+
+            entry->add(value);
+            entry->add(timestamp);
+
+            list->add(entry);
+        }
+        break;
+    }
     case STAT_FLOAT: {
         std::list<FloatSample> s = getFloats();
 
@@ -480,6 +538,11 @@ void Observation::reset() {
         setValue(static_cast<int64_t>(0));
         return;
     }
+    case STAT_BIG_INTEGER: {
+        big_integer_samples_.clear();
+        setValue(int128_t(0));
+        return;
+    }
     case STAT_FLOAT: {
         float_samples_.clear();
         setValue(0.0);
index f1e0117ef424d40fb7df59c30d365649f26bd54d..883d7e7d1ddfb84768c3d1c48d4ddde04c337d7c 100644 (file)
@@ -9,9 +9,13 @@
 
 #include <cc/data.h>
 #include <exceptions/exceptions.h>
+#include <util/bigints.h>
+
 #include <boost/shared_ptr.hpp>
+
 #include <chrono>
 #include <list>
+
 #include <stdint.h>
 
 namespace isc {
@@ -55,6 +59,9 @@ inline long toSeconds(const StatsDuration& dur) {
 /// @brief Integer (implemented as signed 64-bit integer)
 typedef std::pair<int64_t, SampleClock::time_point> IntegerSample;
 
+/// @brief BigInteger (implemented as signed 128-bit integer)
+typedef std::pair<isc::util::int128_t, SampleClock::time_point> BigIntegerSample;
+
 /// @brief Float (implemented as double precision)
 typedef std::pair<double, SampleClock::time_point> FloatSample;
 
@@ -93,10 +100,11 @@ public:
     /// int64_t and double. If convincing use cases appear to change them
     /// to something else, we may change the underlying type.
     enum Type {
-        STAT_INTEGER, ///< this statistic is unsigned 64-bit integer value
-        STAT_FLOAT,   ///< this statistic is a floating point value
-        STAT_DURATION,///< this statistic represents time duration
-        STAT_STRING   ///< this statistic represents a string
+        STAT_INTEGER,       ///< this statistic is signed 64-bit integer value
+        STAT_BIG_INTEGER,   ///< this statistic is signed 128-bit integer value
+        STAT_FLOAT,         ///< this statistic is a floating point value
+        STAT_DURATION,      ///< this statistic represents time duration
+        STAT_STRING         ///< this statistic represents a string
     };
 
     /// @brief Constructor for integer observations
@@ -105,6 +113,12 @@ public:
     /// @param value integer value observed.
     Observation(const std::string& name, const int64_t value);
 
+    /// @brief Constructor for big integer observations
+    ///
+    /// @param name observation name
+    /// @param value integer value observed.
+    Observation(const std::string& name, const isc::util::int128_t& value);
+
     /// @brief Constructor for floating point observations
     ///
     /// @param name observation name
@@ -184,6 +198,12 @@ public:
     /// @throw InvalidStatType if statistic is not integer
     void setValue(const int64_t value);
 
+    /// @brief Records big integer observation
+    ///
+    /// @param value integer value observed
+    /// @throw InvalidStatType if statistic is not integer
+    void setValue(const isc::util::int128_t& value);
+
     /// @brief Records absolute floating point observation
     ///
     /// @param value floating point value observed
@@ -208,6 +228,12 @@ public:
     /// @throw InvalidStatType if statistic is not integer
     void addValue(const int64_t value);
 
+    /// @brief Records incremental integer observation
+    ///
+    /// @param value integer value observed
+    /// @throw InvalidStatType if statistic is not integer
+    void addValue(const isc::util::int128_t& value);
+
     /// @brief Records incremental floating point observation
     ///
     /// @param value floating point value observed
@@ -258,6 +284,11 @@ public:
     /// @throw InvalidStatType if statistic is not integer
     IntegerSample getInteger() const;
 
+    /// @brief Returns observed integer sample
+    /// @return observed sample (value + timestamp)
+    /// @throw InvalidStatType if statistic is not integer
+    BigIntegerSample getBigInteger() const;
+
     /// @brief Returns observed float sample
     /// @return observed sample (value + timestamp)
     /// @throw InvalidStatType if statistic is not fp
@@ -278,6 +309,11 @@ public:
     /// @throw InvalidStatType if statistic is not integer
     std::list<IntegerSample> getIntegers() const;
 
+    /// @brief Returns observed big-integer samples
+    /// @return list of observed samples (value + timestamp)
+    /// @throw InvalidStatType if statistic is not integer
+    std::list<BigIntegerSample> getBigIntegers() const;
+
     /// @brief Returns observed float samples
     /// @return list of observed samples (value + timestamp)
     /// @throw InvalidStatType if statistic is not fp
@@ -425,6 +461,9 @@ private:
     /// @brief Storage for integer samples
     std::list<IntegerSample> integer_samples_;
 
+    /// @brief Storage for big integer samples
+    std::list<BigIntegerSample> big_integer_samples_;
+
     /// @brief Storage for floating point samples
     std::list<FloatSample> float_samples_;
 
index 58b36abeed0ee6b24b5952142d3ba703196957fe..37536d31d017af3d95befb2fdd2513055e649824 100644 (file)
 #include <cc/data.h>
 #include <cc/command_interpreter.h>
 #include <util/multi_threading_mgr.h>
+#include <util/bigints.h>
+
 #include <boost/make_shared.hpp>
+
 #include <chrono>
 
 using namespace std;
@@ -35,92 +38,68 @@ StatsMgr::StatsMgr() :
 
 void
 StatsMgr::setValue(const string& name, const int64_t value) {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        setValueInternal(name, value);
-    } else {
-        setValueInternal(name, value);
-    }
+    MultiThreadingLock lock(*mutex_);
+    setValueInternal(name, value);
+}
+
+void
+StatsMgr::setValue(const string& name, const int128_t& value) {
+    MultiThreadingLock lock(*mutex_);
+    setValueInternal(name, value);
 }
 
 void
 StatsMgr::setValue(const string& name, const double value) {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        setValueInternal(name, value);
-    } else {
-        setValueInternal(name, value);
-    }
+    MultiThreadingLock lock(*mutex_);
+    setValueInternal(name, value);
 }
 
 void
 StatsMgr::setValue(const string& name, const StatsDuration& value) {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        setValueInternal(name, value);
-    } else {
-        setValueInternal(name, value);
-    }
+    MultiThreadingLock lock(*mutex_);
+    setValueInternal(name, value);
 }
 
 void
 StatsMgr::setValue(const string& name, const string& value) {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        setValueInternal(name, value);
-    } else {
-        setValueInternal(name, value);
-    }
+    MultiThreadingLock lock(*mutex_);
+    setValueInternal(name, value);
 }
 
 void
 StatsMgr::addValue(const string& name, const int64_t value) {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        addValueInternal(name, value);
-    } else {
-        addValueInternal(name, value);
-    }
+    MultiThreadingLock lock(*mutex_);
+    addValueInternal(name, value);
+}
+
+void
+StatsMgr::addValue(const string& name, const int128_t& value) {
+    MultiThreadingLock lock(*mutex_);
+    addValueInternal(name, value);
 }
 
 void
 StatsMgr::addValue(const string& name, const double value) {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        addValueInternal(name, value);
-    } else {
-        addValueInternal(name, value);
-    }
+    MultiThreadingLock lock(*mutex_);
+    addValueInternal(name, value);
 }
 
 void
 StatsMgr::addValue(const string& name, const StatsDuration& value) {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        addValueInternal(name, value);
-    } else {
-        addValueInternal(name, value);
-    }
+    MultiThreadingLock lock(*mutex_);
+    addValueInternal(name, value);
 }
 
 void
 StatsMgr::addValue(const string& name, const string& value) {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        addValueInternal(name, value);
-    } else {
-        addValueInternal(name, value);
-    }
+    MultiThreadingLock lock(*mutex_);
+    addValueInternal(name, value);
 }
 
 ObservationPtr
 StatsMgr::getObservation(const string& name) const {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        return (getObservationInternal(name));
-    } else {
-        return (getObservationInternal(name));
-    }
+    MultiThreadingLock lock(*mutex_);
+    return (getObservationInternal(name));
 }
 
 ObservationPtr
@@ -132,12 +111,8 @@ StatsMgr::getObservationInternal(const string& name) const {
 
 void
 StatsMgr::addObservation(const ObservationPtr& stat) {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        addObservationInternal(stat);
-    } else {
-        addObservationInternal(stat);
-    }
+    MultiThreadingLock lock(*mutex_);
+    addObservationInternal(stat);
 }
 
 void
@@ -149,12 +124,8 @@ StatsMgr::addObservationInternal(const ObservationPtr& stat) {
 
 bool
 StatsMgr::deleteObservation(const string& name) {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        return (deleteObservationInternal(name));
-    } else {
-        return (deleteObservationInternal(name));
-    }
+    MultiThreadingLock lock(*mutex_);
+    return (deleteObservationInternal(name));
 }
 
 bool
@@ -166,12 +137,8 @@ StatsMgr::deleteObservationInternal(const string& name) {
 
 bool
 StatsMgr::setMaxSampleAge(const string& name, const StatsDuration& duration) {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        return (setMaxSampleAgeInternal(name, duration));
-    } else {
-        return (setMaxSampleAgeInternal(name, duration));
-    }
+    MultiThreadingLock lock(*mutex_);
+    return (setMaxSampleAgeInternal(name, duration));
 }
 
 bool
@@ -187,12 +154,8 @@ StatsMgr::setMaxSampleAgeInternal(const string& name,
 
 bool
 StatsMgr::setMaxSampleCount(const string& name, uint32_t max_samples) {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        return (setMaxSampleCountInternal(name, max_samples));
-    } else {
-        return (setMaxSampleCountInternal(name, max_samples));
-    }
+    MultiThreadingLock lock(*mutex_);
+    return (setMaxSampleCountInternal(name, max_samples));
 }
 
 bool
@@ -208,12 +171,8 @@ StatsMgr::setMaxSampleCountInternal(const string& name,
 
 void
 StatsMgr::setMaxSampleAgeAll(const StatsDuration& duration) {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        setMaxSampleAgeAllInternal(duration);
-    } else {
-        setMaxSampleAgeAllInternal(duration);
-    }
+    MultiThreadingLock lock(*mutex_);
+    setMaxSampleAgeAllInternal(duration);
 }
 
 void
@@ -223,12 +182,8 @@ StatsMgr::setMaxSampleAgeAllInternal(const StatsDuration& duration) {
 
 void
 StatsMgr::setMaxSampleCountAll(uint32_t max_samples) {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        setMaxSampleCountAllInternal(max_samples);
-    } else {
-        setMaxSampleCountAllInternal(max_samples);
-    }
+    MultiThreadingLock lock(*mutex_);
+    setMaxSampleCountAllInternal(max_samples);
 }
 
 void
@@ -238,12 +193,8 @@ StatsMgr::setMaxSampleCountAllInternal(uint32_t max_samples) {
 
 void
 StatsMgr::setMaxSampleAgeDefault(const StatsDuration& duration) {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        setMaxSampleAgeDefaultInternal(duration);
-    } else {
-        setMaxSampleAgeDefaultInternal(duration);
-    }
+    MultiThreadingLock lock(*mutex_);
+    setMaxSampleAgeDefaultInternal(duration);
 }
 
 void
@@ -253,12 +204,8 @@ StatsMgr::setMaxSampleAgeDefaultInternal(const StatsDuration& duration) {
 
 void
 StatsMgr::setMaxSampleCountDefault(uint32_t max_samples) {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        setMaxSampleCountDefaultInternal(max_samples);
-    } else {
-        setMaxSampleCountDefaultInternal(max_samples);
-    }
+    MultiThreadingLock lock(*mutex_);
+    setMaxSampleCountDefaultInternal(max_samples);
 }
 
 void
@@ -268,12 +215,8 @@ StatsMgr::setMaxSampleCountDefaultInternal(uint32_t max_samples) {
 
 const StatsDuration&
 StatsMgr::getMaxSampleAgeDefault() const {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        return (getMaxSampleAgeDefaultInternal());
-    } else {
-        return (getMaxSampleAgeDefaultInternal());
-    }
+    MultiThreadingLock lock(*mutex_);
+    return (getMaxSampleAgeDefaultInternal());
 }
 
 const StatsDuration&
@@ -283,12 +226,8 @@ StatsMgr::getMaxSampleAgeDefaultInternal() const {
 
 uint32_t
 StatsMgr::getMaxSampleCountDefault() const {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        return (getMaxSampleCountDefaultInternal());
-    } else {
-        return (getMaxSampleCountDefaultInternal());
-    }
+    MultiThreadingLock lock(*mutex_);
+    return (getMaxSampleCountDefaultInternal());
 }
 
 uint32_t
@@ -298,12 +237,8 @@ StatsMgr::getMaxSampleCountDefaultInternal() const {
 
 bool
 StatsMgr::reset(const string& name) {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        return (resetInternal(name));
-    } else {
-        return (resetInternal(name));
-    }
+    MultiThreadingLock lock(*mutex_);
+    return (resetInternal(name));
 }
 
 bool
@@ -318,12 +253,8 @@ StatsMgr::resetInternal(const string& name) {
 
 bool
 StatsMgr::del(const string& name) {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        return (delInternal(name));
-    } else {
-        return (delInternal(name));
-    }
+    MultiThreadingLock lock(*mutex_);
+    return (delInternal(name));
 }
 
 bool
@@ -333,12 +264,8 @@ StatsMgr::delInternal(const string& name) {
 
 void
 StatsMgr::removeAll() {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        removeAllInternal();
-    } else {
-        removeAllInternal();
-    }
+    MultiThreadingLock lock(*mutex_);
+    removeAllInternal();
 }
 
 void
@@ -348,12 +275,8 @@ StatsMgr::removeAllInternal() {
 
 ConstElementPtr
 StatsMgr::get(const string& name) const {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        return (getInternal(name));
-    } else {
-        return (getInternal(name));
-    }
+    MultiThreadingLock lock(*mutex_);
+    return (getInternal(name));
 }
 
 ConstElementPtr
@@ -368,12 +291,8 @@ StatsMgr::getInternal(const string& name) const {
 
 ConstElementPtr
 StatsMgr::getAll() const {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        return (getAllInternal());
-    } else {
-        return (getAllInternal());
-    }
+    MultiThreadingLock lock(*mutex_);
+    return (getAllInternal());
 }
 
 ConstElementPtr
@@ -383,12 +302,8 @@ StatsMgr::getAllInternal() const {
 
 void
 StatsMgr::resetAll() {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        resetAllInternal();
-    } else {
-        resetAllInternal();
-    }
+    MultiThreadingLock lock(*mutex_);
+    resetAllInternal();
 }
 
 void
@@ -398,12 +313,8 @@ StatsMgr::resetAllInternal() {
 
 size_t
 StatsMgr::getSize(const string& name) const {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        return (getSizeInternal(name));
-    } else {
-        return (getSizeInternal(name));
-    }
+    MultiThreadingLock lock(*mutex_);
+    return (getSizeInternal(name));
 }
 
 size_t
@@ -417,12 +328,8 @@ StatsMgr::getSizeInternal(const string& name) const {
 
 size_t
 StatsMgr::count() const {
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        return (countInternal());
-    } else {
-        return (countInternal());
-    }
+    MultiThreadingLock lock(*mutex_);
+    return (countInternal());
 }
 
 size_t
@@ -545,16 +452,10 @@ StatsMgr::statisticSetMaxSampleAgeAllHandler(const ConstElementPtr& params) {
     if (!StatsMgr::getStatDuration(params, duration, error)) {
         return (createAnswer(CONTROL_RESULT_ERROR, error));
     }
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        StatsMgr::instance().setMaxSampleCountDefaultInternal(0);
-        StatsMgr::instance().setMaxSampleAgeDefaultInternal(duration);
-        StatsMgr::instance().setMaxSampleAgeAllInternal(duration);
-    } else {
-        StatsMgr::instance().setMaxSampleCountDefaultInternal(0);
-        StatsMgr::instance().setMaxSampleAgeDefaultInternal(duration);
-        StatsMgr::instance().setMaxSampleAgeAllInternal(duration);
-    }
+    MultiThreadingLock lock(*mutex_);
+    StatsMgr::instance().setMaxSampleCountDefaultInternal(0);
+    StatsMgr::instance().setMaxSampleAgeDefaultInternal(duration);
+    StatsMgr::instance().setMaxSampleAgeAllInternal(duration);
     return (createAnswer(CONTROL_RESULT_SUCCESS,
                          "All statistics duration limit are set."));
 }
@@ -570,14 +471,9 @@ StatsMgr::statisticSetMaxSampleCountAllHandler(const ConstElementPtr& params) {
         error = "'max-samples' parameter must not be zero";
         return (createAnswer(CONTROL_RESULT_ERROR, error));
     }
-    if (MultiThreadingMgr::instance().getMode()) {
-        lock_guard<mutex> lock(*mutex_);
-        StatsMgr::instance().setMaxSampleCountDefaultInternal(max_samples);
-        StatsMgr::instance().setMaxSampleCountAllInternal(max_samples);
-    } else {
-        StatsMgr::instance().setMaxSampleCountDefaultInternal(max_samples);
-        StatsMgr::instance().setMaxSampleCountAllInternal(max_samples);
-    }
+    MultiThreadingLock lock(*mutex_);
+    StatsMgr::instance().setMaxSampleCountDefaultInternal(max_samples);
+    StatsMgr::instance().setMaxSampleCountAllInternal(max_samples);
     return (createAnswer(CONTROL_RESULT_SUCCESS,
                          "All statistics count limit are set."));
 }
index 564df439768de9f0b35a01c2ca1596bec5f700ae..c1e688d290f685e9bd0e3202e32169c85d8d788f 100644 (file)
@@ -9,6 +9,8 @@
 
 #include <stats/observation.h>
 #include <stats/context.h>
+#include <util/bigints.h>
+
 #include <boost/noncopyable.hpp>
 #include <boost/scoped_ptr.hpp>
 
@@ -79,6 +81,13 @@ public:
     /// @throw InvalidStatType if statistic is not integer
     void setValue(const std::string& name, const int64_t value);
 
+    /// @brief Records an absolute big integer observation.
+    ///
+    /// @param name name of the observation
+    /// @param value integer value observed
+    /// @throw InvalidStatType if statistic is not integer
+    void setValue(const std::string& name, const isc::util::int128_t& value);
+
     /// @brief Records absolute floating point observation.
     ///
     /// @param name name of the observation
@@ -107,6 +116,13 @@ public:
     /// @throw InvalidStatType if statistic is not integer
     void addValue(const std::string& name, const int64_t value);
 
+    /// @brief Records an incremental big integer observation.
+    ///
+    /// @param name name of the observation
+    /// @param value integer value observed
+    /// @throw InvalidStatType if statistic is not integer
+    void addValue(const std::string& name, const isc::util::int128_t& value);
+
     /// @brief Records incremental floating point observation.
     ///
     /// @param name name of the observation
index ad1036809c2f9aa605bc638ef0e245c44a418b30..dc0a4d98267961e3b2d76da4e2f8a12e6f675e53 100644 (file)
@@ -6,10 +6,13 @@
 
 #include <config.h>
 
-#include <stats/observation.h>
 #include <exceptions/exceptions.h>
+#include <stats/observation.h>
 #include <util/chrono_time_utils.h>
+#include <util/bigints.h>
+
 #include <boost/shared_ptr.hpp>
+
 #include <gtest/gtest.h>
 
 #include <iostream>
@@ -19,6 +22,7 @@
 
 using namespace isc;
 using namespace isc::stats;
+using namespace isc::util;
 using namespace std::chrono;
 
 namespace {
@@ -51,13 +55,15 @@ public:
         a("alpha", static_cast<int64_t>(1234)), // integer
         b("beta", 12.34), // float
         c("gamma", dur1234), // duration
-        d("delta", "1234") { // string
+        d("delta", "1234"), // string
+        e("epsilon", int128_t(12e34)) { // big integer
     }
 
     Observation a;
     Observation b;
     Observation c;
     Observation d;
+    Observation e;
 };
 
 // Basic tests for the Observation constructors. This test checks whether
@@ -67,29 +73,40 @@ TEST_F(ObservationTest, constructor) {
     EXPECT_EQ(Observation::STAT_FLOAT, b.getType());
     EXPECT_EQ(Observation::STAT_DURATION, c.getType());
     EXPECT_EQ(Observation::STAT_STRING, d.getType());
+    EXPECT_EQ(Observation::STAT_BIG_INTEGER, e.getType());
 
     EXPECT_EQ(1234, a.getInteger().first);
     EXPECT_EQ(12.34, b.getFloat().first);
     EXPECT_EQ(dur1234, c.getDuration().first);
     EXPECT_EQ("1234", d.getString().first);
+    EXPECT_EQ(int128_t(12e34), e.getBigInteger().first);
 
     // Let's check that attempting to get a different type
     // than used will cause an exception.
     EXPECT_THROW(a.getFloat(), InvalidStatType);
     EXPECT_THROW(a.getDuration(), InvalidStatType);
     EXPECT_THROW(a.getString(), InvalidStatType);
+    EXPECT_THROW(a.getBigInteger(), InvalidStatType);
 
     EXPECT_THROW(b.getInteger(), InvalidStatType);
     EXPECT_THROW(b.getDuration(), InvalidStatType);
     EXPECT_THROW(b.getString(), InvalidStatType);
+    EXPECT_THROW(b.getBigInteger(), InvalidStatType);
 
     EXPECT_THROW(c.getInteger(), InvalidStatType);
     EXPECT_THROW(c.getFloat(), InvalidStatType);
     EXPECT_THROW(c.getString(), InvalidStatType);
+    EXPECT_THROW(c.getBigInteger(), InvalidStatType);
 
     EXPECT_THROW(d.getInteger(), InvalidStatType);
     EXPECT_THROW(d.getFloat(), InvalidStatType);
     EXPECT_THROW(d.getDuration(), InvalidStatType);
+    EXPECT_THROW(d.getBigInteger(), InvalidStatType);
+
+    EXPECT_THROW(e.getInteger(), InvalidStatType);
+    EXPECT_THROW(e.getFloat(), InvalidStatType);
+    EXPECT_THROW(e.getDuration(), InvalidStatType);
+    EXPECT_THROW(e.getString(), InvalidStatType);
 }
 
 // This test checks whether it is possible to set to an absolute value for all
@@ -99,30 +116,40 @@ TEST_F(ObservationTest, setValue) {
     EXPECT_NO_THROW(b.setValue(56e+78));
     EXPECT_NO_THROW(c.setValue(dur5678));
     EXPECT_NO_THROW(d.setValue("fiveSixSevenEight"));
-
+    EXPECT_NO_THROW(e.setValue(int128_t(43e21)));
 
     EXPECT_EQ(5678, a.getInteger().first);
     EXPECT_EQ(56e+78, b.getFloat().first);
     EXPECT_EQ(dur5678, c.getDuration().first);
     EXPECT_EQ("fiveSixSevenEight", d.getString().first);
+    EXPECT_EQ(int128_t(43e21), e.getBigInteger().first);
 
     // Now check whether setting value to a different type does
     // throw an exception
     EXPECT_THROW(a.setValue(56e+78), InvalidStatType);
     EXPECT_THROW(a.setValue(dur5678), InvalidStatType);
     EXPECT_THROW(a.setValue("fiveSixSevenEight"), InvalidStatType);
+    EXPECT_THROW(a.setValue(int128_t(43e21)), InvalidStatType);
 
     EXPECT_THROW(b.setValue(static_cast<int64_t>(5678)), InvalidStatType);
     EXPECT_THROW(b.setValue(dur5678), InvalidStatType);
     EXPECT_THROW(b.setValue("fiveSixSevenEight"), InvalidStatType);
+    EXPECT_THROW(b.setValue(int128_t(43e21)), InvalidStatType);
 
     EXPECT_THROW(c.setValue(static_cast<int64_t>(5678)), InvalidStatType);
     EXPECT_THROW(c.setValue(56e+78), InvalidStatType);
     EXPECT_THROW(c.setValue("fiveSixSevenEight"), InvalidStatType);
+    EXPECT_THROW(c.setValue(int128_t(43e21)), InvalidStatType);
 
     EXPECT_THROW(d.setValue(static_cast<int64_t>(5678)), InvalidStatType);
     EXPECT_THROW(d.setValue(56e+78), InvalidStatType);
     EXPECT_THROW(d.setValue(dur5678), InvalidStatType);
+    EXPECT_THROW(d.setValue(int128_t(43e21)), InvalidStatType);
+
+    EXPECT_THROW(e.setValue(int64_t(5678)), InvalidStatType);
+    EXPECT_THROW(e.setValue(56e+78), InvalidStatType);
+    EXPECT_THROW(e.setValue(dur5678), InvalidStatType);
+    EXPECT_THROW(e.setValue("fiveSixSevenEight"), InvalidStatType);
 }
 
 // This test checks whether it is possible to add value to existing
@@ -135,16 +162,19 @@ TEST_F(ObservationTest, addValue) {
     EXPECT_NO_THROW(b.addValue(56.78));
     EXPECT_NO_THROW(c.addValue(dur5678));
     EXPECT_NO_THROW(d.addValue("fiveSixSevenEight"));
+    EXPECT_NO_THROW(e.addValue(int128_t(43e21)));
 
     EXPECT_EQ(6912, a.getInteger().first);
     EXPECT_EQ(69.12, b.getFloat().first);
     EXPECT_EQ(dur681012, c.getDuration().first);
     EXPECT_EQ("1234fiveSixSevenEight", d.getString().first);
+    EXPECT_EQ(int128_t(12e34) + int128_t(43e21), e.getBigInteger().first);
 
     ASSERT_EQ(a.getSize(), 2);
     ASSERT_EQ(b.getSize(), 2);
     ASSERT_EQ(c.getSize(), 2);
     ASSERT_EQ(d.getSize(), 2);
+    ASSERT_EQ(e.getSize(), 2);
 }
 
 // This test checks if collecting more than one sample
@@ -153,37 +183,42 @@ TEST_F(ObservationTest, moreThanOne) {
     // Arrays of 4 types of samples
     int64_t int_samples[3] = {1234, 6912, 5678};
     double float_samples[3] = {12.34, 69.12, 56e+78};
-    StatsDuration duration_samples[3] = {dur1234,
-        dur681012, dur5678};
+    StatsDuration duration_samples[3] = {dur1234, dur681012, dur5678};
     std::string string_samples[3] = {"1234", "1234fiveSixSevenEight", "fiveSixSevenEight"};
+    int128_t bigint_samples[3] = {int128_t(12e34), int128_t(12e34) + int128_t(43e21),
+                                  int128_t(43e21)};
 
     EXPECT_NO_THROW(a.addValue(static_cast<int64_t>(5678)));
     EXPECT_NO_THROW(b.addValue(56.78));
     EXPECT_NO_THROW(c.addValue(dur5678));
     EXPECT_NO_THROW(d.addValue("fiveSixSevenEight"));
+    EXPECT_NO_THROW(e.addValue(int128_t(43e21)));
 
     EXPECT_NO_THROW(a.setValue(static_cast<int64_t>(5678)));
     EXPECT_NO_THROW(b.setValue(56e+78));
     EXPECT_NO_THROW(c.setValue(dur5678));
     EXPECT_NO_THROW(d.setValue("fiveSixSevenEight"));
+    EXPECT_NO_THROW(e.setValue(int128_t(43e21)));
 
     ASSERT_EQ(a.getSize(), 3);
     ASSERT_EQ(b.getSize(), 3);
     ASSERT_EQ(c.getSize(), 3);
     ASSERT_EQ(d.getSize(), 3);
+    ASSERT_EQ(e.getSize(), 3);
 
     ASSERT_NO_THROW(a.getIntegers());
     ASSERT_NO_THROW(b.getFloats());
     ASSERT_NO_THROW(c.getDurations());
     ASSERT_NO_THROW(d.getStrings());
+    ASSERT_NO_THROW(e.getBigIntegers());
 
     std::list<IntegerSample> samples_int = a.getIntegers(); // List of all integer samples
     std::list<FloatSample> samples_float = b.getFloats(); // List of all float samples
     std::list<DurationSample> samples_dur = c.getDurations(); // List of all duration samples
     std::list<StringSample> samples_str = d.getStrings(); // List of all string samples
+    std::list<BigIntegerSample> samples_bigint = e.getBigIntegers(); // List of all big integer samples
 
     uint32_t i = 2; // Index pointed to the end of array of samples
-
     for (std::list<IntegerSample>::iterator it = samples_int.begin(); it != samples_int.end(); ++it) {
         EXPECT_EQ(int_samples[i], static_cast<int64_t>((*it).first));
         --i;
@@ -203,6 +238,11 @@ TEST_F(ObservationTest, moreThanOne) {
         EXPECT_EQ(string_samples[i], (*it).first);
         --i;
     }
+    i = 2;
+    for (BigIntegerSample const& sample : samples_bigint) {
+        EXPECT_EQ(bigint_samples[i], sample.first);
+        --i;
+    }
 }
 
 // This test checks whether the size of storage
@@ -213,27 +253,32 @@ TEST_F(ObservationTest, getSize) {
     ASSERT_EQ(b.getSize(), 1);
     ASSERT_EQ(c.getSize(), 1);
     ASSERT_EQ(d.getSize(), 1);
+    ASSERT_EQ(e.getSize(), 1);
 
     a.addValue(static_cast<int64_t>(5678));
     b.addValue(56.78);
     c.addValue(dur5678);
     d.addValue("fiveSixSevenEight");
+    e.addValue(int128_t(43e21));
 
     EXPECT_NO_THROW(a.getSize());
     EXPECT_NO_THROW(b.getSize());
     EXPECT_NO_THROW(c.getSize());
     EXPECT_NO_THROW(d.getSize());
+    EXPECT_NO_THROW(e.getSize());
 
     // Check if size of storages is equal to 2
     ASSERT_EQ(a.getSize(), 2);
     ASSERT_EQ(b.getSize(), 2);
     ASSERT_EQ(c.getSize(), 2);
     ASSERT_EQ(d.getSize(), 2);
+    ASSERT_EQ(e.getSize(), 2);
 
     a.setValue(static_cast<int64_t>(5678));
     b.setValue(56e+78);
     c.setValue(dur5678);
     d.setValue("fiveSixSevenEight");
+    e.setValue(int128_t(43e21));
 
     EXPECT_NO_THROW(a.getSize());
     EXPECT_NO_THROW(b.getSize());
@@ -245,6 +290,7 @@ TEST_F(ObservationTest, getSize) {
     ASSERT_EQ(b.getSize(), 3);
     ASSERT_EQ(c.getSize(), 3);
     ASSERT_EQ(d.getSize(), 3);
+    ASSERT_EQ(e.getSize(), 3);
 }
 
 // Checks whether setting amount limits works properly
@@ -279,18 +325,23 @@ TEST_F(ObservationTest, setCountLimit) {
     for (uint32_t i = 0; i < 21; ++i) {
         d.setValue(string_samples[i]);
     }
+    for (uint32_t i = 0; i < 21; ++i) {
+        e.setValue(int128_t(int_samples[i]));
+    }
 
     // Getting all 4 types of samples after inserting 21 values
     std::list<IntegerSample> samples_int = a.getIntegers();
     std::list<FloatSample> samples_float = b.getFloats();
     std::list<DurationSample> samples_duration = c.getDurations();
     std::list<StringSample> samples_string = d.getStrings();
+    std::list<BigIntegerSample> samples_bigint = e.getBigIntegers();
 
     // Check if size of storages is equal to 20
     ASSERT_EQ(a.getSize(), 20);
     ASSERT_EQ(b.getSize(), 20);
     ASSERT_EQ(c.getSize(), 20);
     ASSERT_EQ(d.getSize(), 20);
+    ASSERT_EQ(e.getSize(), 20);
 
     // And whether stored values are correct
     uint32_t i = 20; // index of the last element in array of test's samples
@@ -313,23 +364,31 @@ TEST_F(ObservationTest, setCountLimit) {
         EXPECT_EQ((*it).first, string_samples[i]);
         --i;
     }
+    i = 20; // index of last element in array of test's samples
+    for (BigIntegerSample const& sample : samples_bigint) {
+        EXPECT_EQ(sample.first, int_samples[i]);
+        --i;
+    }
 
     // Change size of storage to smaller one
     ASSERT_NO_THROW(a.setMaxSampleCount(10));
     ASSERT_NO_THROW(b.setMaxSampleCount(10));
     ASSERT_NO_THROW(c.setMaxSampleCount(10));
     ASSERT_NO_THROW(d.setMaxSampleCount(10));
+    ASSERT_NO_THROW(e.setMaxSampleCount(10));
 
     samples_int = a.getIntegers();
     samples_float = b.getFloats();
     samples_duration = c.getDurations();
     samples_string = d.getStrings();
+    samples_bigint = e.getBigIntegers();
 
     // Check if size of storages is equal to 10
     ASSERT_EQ(a.getSize(), 10);
     ASSERT_EQ(b.getSize(), 10);
     ASSERT_EQ(c.getSize(), 10);
     ASSERT_EQ(d.getSize(), 10);
+    ASSERT_EQ(e.getSize(), 10);
 
     // And whether storages contain only the 10 newest values
     i = 20; // index of last element in array of test's samples
@@ -352,34 +411,44 @@ TEST_F(ObservationTest, setCountLimit) {
         EXPECT_EQ((*it).first, string_samples[i]);
         --i;
     }
+    i = 20; // index of last element in array of test's samples
+    for (BigIntegerSample const& sample : samples_bigint) {
+        EXPECT_EQ(sample.first, int_samples[i]);
+        --i;
+    }
 
     // Resize max_sample_count to greater
     ASSERT_NO_THROW(a.setMaxSampleCount(50));
     ASSERT_NO_THROW(b.setMaxSampleCount(50));
     ASSERT_NO_THROW(c.setMaxSampleCount(50));
     ASSERT_NO_THROW(d.setMaxSampleCount(50));
+    ASSERT_NO_THROW(e.setMaxSampleCount(50));
 
     // Check if size of storages did not change without adding new value
     ASSERT_EQ(a.getSize(), 10);
     ASSERT_EQ(b.getSize(), 10);
     ASSERT_EQ(c.getSize(), 10);
     ASSERT_EQ(d.getSize(), 10);
+    ASSERT_EQ(e.getSize(), 10);
 
     // Add new values to each type of Observation
     a.setValue(static_cast<int64_t>(21));
     b.setValue(21.0);
     c.setValue(milliseconds(21));
     d.setValue("v");
+    e.setValue(int128_t(21));
 
     samples_int = a.getIntegers();
     samples_float = b.getFloats();
     samples_duration = c.getDurations();
     samples_string = d.getStrings();
+    samples_bigint = e.getBigIntegers();
 
     ASSERT_EQ(a.getSize(), 11);
     ASSERT_EQ(b.getSize(), 11);
     ASSERT_EQ(c.getSize(), 11);
     ASSERT_EQ(d.getSize(), 11);
+    ASSERT_EQ(e.getSize(), 11);
 
     i = 21; // index of last element in array of test's samples
     for (std::list<IntegerSample>::iterator it = samples_int.begin(); it != samples_int.end(); ++it) {
@@ -401,7 +470,11 @@ TEST_F(ObservationTest, setCountLimit) {
         EXPECT_EQ((*it).first, string_samples[i]);
         --i;
     }
-
+    i = 21; // index of last element in array of test's samples
+    for (BigIntegerSample const& sample : samples_bigint) {
+        EXPECT_EQ(sample.first, int_samples[i]);
+        --i;
+    }
 }
 
 // Checks whether setting age limits works properly
@@ -451,42 +524,50 @@ TEST_F(ObservationTest, getLimits) {
     EXPECT_EQ(b.getMaxSampleAge().first, false);
     EXPECT_EQ(c.getMaxSampleAge().first, false);
     EXPECT_EQ(d.getMaxSampleAge().first, false);
+    EXPECT_EQ(e.getMaxSampleAge().first, false);
 
     EXPECT_EQ(a.getMaxSampleCount().first, true);
     EXPECT_EQ(b.getMaxSampleCount().first, true);
     EXPECT_EQ(c.getMaxSampleCount().first, true);
     EXPECT_EQ(d.getMaxSampleCount().first, true);
+    EXPECT_EQ(e.getMaxSampleCount().first, true);
 
     EXPECT_EQ(a.getMaxSampleCount().second, 20);
     EXPECT_EQ(b.getMaxSampleCount().second, 20);
     EXPECT_EQ(c.getMaxSampleCount().second, 20);
     EXPECT_EQ(d.getMaxSampleCount().second, 20);
+    EXPECT_EQ(e.getMaxSampleCount().second, 20);
 
     // change limit to time duration
     ASSERT_NO_THROW(a.setMaxSampleAge(dur453));
     ASSERT_NO_THROW(b.setMaxSampleAge(dur453));
     ASSERT_NO_THROW(c.setMaxSampleAge(dur453));
     ASSERT_NO_THROW(d.setMaxSampleAge(dur453));
+    ASSERT_NO_THROW(e.setMaxSampleAge(dur453));
 
     EXPECT_EQ(a.getMaxSampleAge().first, true);
     EXPECT_EQ(b.getMaxSampleAge().first, true);
     EXPECT_EQ(c.getMaxSampleAge().first, true);
     EXPECT_EQ(d.getMaxSampleAge().first, true);
+    EXPECT_EQ(e.getMaxSampleAge().first, true);
 
     EXPECT_EQ(a.getMaxSampleAge().second, dur453);
     EXPECT_EQ(b.getMaxSampleAge().second, dur453);
     EXPECT_EQ(c.getMaxSampleAge().second, dur453);
     EXPECT_EQ(d.getMaxSampleAge().second, dur453);
+    EXPECT_EQ(e.getMaxSampleAge().second, dur453);
 
     EXPECT_EQ(a.getMaxSampleCount().first, false);
     EXPECT_EQ(b.getMaxSampleCount().first, false);
     EXPECT_EQ(c.getMaxSampleCount().first, false);
     EXPECT_EQ(d.getMaxSampleCount().first, false);
+    EXPECT_EQ(e.getMaxSampleCount().first, false);
 
     EXPECT_EQ(a.getMaxSampleCount().second, 20);
     EXPECT_EQ(b.getMaxSampleCount().second, 20);
     EXPECT_EQ(c.getMaxSampleCount().second, 20);
     EXPECT_EQ(d.getMaxSampleCount().second, 20);
+    EXPECT_EQ(e.getMaxSampleCount().second, 20);
 }
 
 // limit defaults are tested with StatsMgr.
@@ -525,7 +606,6 @@ TEST_F(ObservationTest, integerToJSON) {
     std::string exp = "[ [ 1234, \"" +
         isc::util::clockToText(a.getInteger().second) + "\" ]" + first_sample;
 
-    std::cout << a.getJSON()->str() << std::endl;
     EXPECT_EQ(exp, a.getJSON()->str());
 }
 
@@ -546,7 +626,6 @@ TEST_F(ObservationTest, floatToJSON) {
     std::string exp = "[ [ 1234.5, \"" +
         isc::util::clockToText(b.getFloat().second) + "\" ]" + first_sample;
 
-    std::cout << b.getJSON()->str() << std::endl;
     EXPECT_EQ(exp, b.getJSON()->str());
 }
 
@@ -564,7 +643,6 @@ TEST_F(ObservationTest, durationToJSON) {
     std::string exp = "[ [ \"01:02:03.004000\", \"" +
         isc::util::clockToText(c.getDuration().second) + "\" ]" + first_sample;
 
-    std::cout << c.getJSON()->str() << std::endl;
     EXPECT_EQ(exp, c.getJSON()->str());
 }
 
@@ -581,31 +659,50 @@ TEST_F(ObservationTest, stringToJSON) {
     std::string exp = "[ [ \"Lorem ipsum dolor sit amet\", \"" +
         isc::util::clockToText(d.getString().second) + "\" ]" + first_sample;
 
-    std::cout << d.getJSON()->str() << std::endl;
     EXPECT_EQ(exp, d.getJSON()->str());
 }
 
+// Checks whether a big integer statistic can generate proper JSON structures.
+// See https://gitlab.isc.org/isc-projects/kea/wikis/designs/Stats-design
+// for details.
+TEST_F(ObservationTest, bigIntegerToJSON) {
+    // String which contains first added sample
+    std::string first_sample = ", [ 120000000000000007304085773727301632, \"" +
+        isc::util::clockToText(e.getBigInteger().second) + "\" ] ]";
+
+    e.setValue(int128_t(43e21));
+
+    std::string exp = "[ [ 43000000000000002097152, \"" +
+        isc::util::clockToText(e.getBigInteger().second) + "\" ]" + first_sample;
+
+    EXPECT_EQ(exp, e.getJSON()->str());
+}
+
 // Checks whether reset() resets the statistics properly.
 TEST_F(ObservationTest, reset) {
     EXPECT_NO_THROW(a.addValue(static_cast<int64_t>(5678)));
     EXPECT_NO_THROW(b.addValue(56.78));
     EXPECT_NO_THROW(c.addValue(dur5678));
     EXPECT_NO_THROW(d.addValue("fiveSixSevenEight"));
+    EXPECT_NO_THROW(e.addValue(int128_t(43e21)));
 
     a.reset(); // integer
     b.reset(); // float
     c.reset(); // duration
     d.reset(); // string
+    e.reset(); // big integer
 
     EXPECT_EQ(0, a.getInteger().first);
     EXPECT_EQ(0.0, b.getFloat().first);
     EXPECT_EQ(StatsDuration::zero(), c.getDuration().first);
     EXPECT_EQ("", d.getString().first);
+    EXPECT_EQ(0, e.getBigInteger().first);
 
     ASSERT_EQ(a.getSize(), 1);
     ASSERT_EQ(b.getSize(), 1);
     ASSERT_EQ(c.getSize(), 1);
     ASSERT_EQ(d.getSize(), 1);
+    ASSERT_EQ(e.getSize(), 1);
 }
 
 // Checks whether an observation can keep its name.
@@ -614,6 +711,7 @@ TEST_F(ObservationTest, names) {
     EXPECT_EQ("beta", b.getName());
     EXPECT_EQ("gamma", c.getName());
     EXPECT_EQ("delta", d.getName());
+    EXPECT_EQ("epsilon", e.getName());
 }
 
-}
+}  // namespace
index 808dced39ae43d3a2aff4379baf06ab386594096..cad71a35d17b4b14ab6efeac99e74df2b00dae06 100644 (file)
@@ -27,12 +27,21 @@ typedef std::map<std::string, int64_t> StatMap;
 ///
 /// @param name StatsMgr name for the statistic to check.
 /// @param expected_value expected value of the statistic.
-inline void checkStat(const std::string& name, const int64_t expected_value) {
-    using namespace isc::stats;
-    ObservationPtr obs = StatsMgr::instance().getObservation(name);
-    ASSERT_TRUE(obs) << " stat: " << name << " not found ";
-    ASSERT_EQ(expected_value, obs->getInteger().first)
-        << " stat: " << name << " value wrong";
+inline void checkStat(const std::string& name,
+                      const isc::util::int128_t expected_value) {
+    ObservationPtr const obs(isc::stats::StatsMgr::instance().getObservation(name));
+
+    ASSERT_TRUE(obs) << "stat " << name << " not found ";
+    if (obs->getType() == Observation::STAT_INTEGER) {
+        EXPECT_EQ(expected_value, obs->getInteger().first)
+            << " wrong value for stat " << name;
+    } else if (obs->getType() == Observation::STAT_BIG_INTEGER) {
+        EXPECT_EQ(expected_value, obs->getBigInteger().first)
+            << " wrong value for stat " << name;
+    } else {
+        GTEST_FAIL() << "unexpected statistic type: "
+                     << Observation::typeToText(obs->getType());
+    }
 }
 
 /// @brief Check if a statistic does not exists.