]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[1751] addition of a new variables containing statistics data of each pid for multipl...
authorNaoki Kambe <kambe@jprs.co.jp>
Mon, 12 Mar 2012 05:56:04 +0000 (14:56 +0900)
committerNaoki Kambe <kambe@jprs.co.jp>
Tue, 13 Mar 2012 05:28:28 +0000 (14:28 +0900)
src/bin/stats/stats.py.in
src/bin/stats/stats.spec
src/bin/stats/tests/b10-stats_test.py

index 938a06298264bbd2f71d298d56c12b529ca4ad52..5cfb6d8223f7a0f98267f1e9b0303694b04004f4 100755 (executable)
@@ -129,6 +129,8 @@ class Stats:
         self.module_name = self.mccs.get_module_spec().get_module_name()
         self.modules = {}
         self.statistics_data = {}
+        # statistics data by each pid
+        self.statistics_data_bypid = {}
         # get commands spec
         self.commands_spec = self.mccs.get_module_spec().get_commands_spec()
         # add event handler related command_handler of ModuleCCSession
@@ -265,14 +267,17 @@ class Stats:
                          + "owner: " + str(owner) + ", "
                          + "name: " + str(name))
 
-    def update_statistics_data(self, owner=None, **data):
+    def update_statistics_data(self, owner=None, pid=-1, **data):
         """
         change statistics date of specified module into specified
         data. It updates information of each module first, and it
         updates statistics data. If specified data is invalid for
         statistics spec of specified owner, it returns a list of error
         messeges. If there is no error or if neither owner nor data is
-        specified in args, it returns None.
+        specified in args, it returns None. pid is the process id of
+        the sender module in order for stats to identify which
+        instance sends statistics data in the situation that multiple
+        instances are working.
         """
         self.update_modules()
         statistics_data = {}
@@ -290,7 +295,48 @@ class Stats:
             errors = []
             try:
                 if self.modules[owner].validate_statistics(False, data, errors):
-                    self.statistics_data[owner].update(data)
+                    # This is for multiple instances working. It is
+                    # assumed here that they send different statistics
+                    # data with each pid. Stats should save their
+                    # statistics data by pid. The statistics data,
+                    # which is the existing variable, is preserved by
+                    # summarizing from statistics data by pid. This is
+                    # an ad-hoc fix because administrators can not see
+                    # statistics by each instance via bindctl or
+                    # HTTP/XML. These interfaces aren't changed in
+                    # this fix.
+                    if owner in self.statistics_data_bypid:
+                        if pid in self.statistics_data_bypid[owner]:
+                            self.statistics_data_bypid[owner][pid].update(data)
+                        else:
+                            self.statistics_data_bypid[owner][pid] = data
+                    else:
+                        self.statistics_data_bypid[owner] = { pid : data }
+                    def _sum_bymodule(statistics_data_bypid):
+                        # sum recursively each value under each
+                        # element
+                        def _sum(a, b):
+                            if type(a) == dict:
+                                return dict([ (k, _sum(v, b[k])) if k in b else (k, v) \
+                                                  for (k, v) in a.items() ] \
+                                                + [ (k, v) for (k, v) in b.items() \
+                                                        if k not in a ])
+                            elif type(a) == list:
+                                return [ _sum(a[i], b[i]) if len(b) > i else a[i] \
+                                             for i in range(len(a)) ] \
+                                             + [ b[i] for i in range(len(b)) \
+                                                     if len(a) <= i ]
+                            elif type(a) == float or type(a) == int:
+                                return a + b
+                            # If str or other types than above, then
+                            # just replace with the newer value.
+                            return a
+                        ret = {}
+                        for data in statistics_data_bypid.values():
+                            ret.update(_sum(data, ret))
+                        return ret
+                    self.statistics_data[owner].update(
+                        _sum_bymodule(self.statistics_data_bypid[owner]))
                     return
             except KeyError:
                 errors.append("unknown module name: " + str(owner))
@@ -379,11 +425,11 @@ class Stats:
                 1, "specified arguments are incorrect: " \
                     + "owner: " + str(owner) + ", name: " + str(name))
 
-    def command_set(self, owner, data):
+    def command_set(self, owner, pid=-1, data={}):
         """
         handle set command
         """
-        errors = self.update_statistics_data(owner, **data)
+        errors = self.update_statistics_data(owner, pid, **data)
         if errors:
             return isc.config.create_answer(
                 1, "errors while setting statistics data: " \
index d3bdcca54eb0663a96f7c051215001b0fe9ad07a..e25dfade26dc05f81a65d72ee5771c52bb8ee483 100644 (file)
             "item_default": "",
             "item_description": "module name of the owner of the statistics data"
           },
+         {
+           "item_name": "pid",
+            "item_type": "integer",
+            "item_optional": true,
+            "item_default": -1,
+            "item_description": "process id of the owner module"
+          },
          {
            "item_name": "data",
             "item_type": "map",
index d9f8d37a14d6e25f17c0e540a04846f51693b002..636f81cd5f905df95c53f1d93a5cda8cf882352e 100644 (file)
@@ -373,6 +373,40 @@ class TestStats(unittest.TestCase):
         self.assertEqual(self.stats.update_statistics_data(owner='Dummy', foo='bar'),
                          ['unknown module name: Dummy'])
 
+    def test_update_modules_withpid(self):
+        # one pid of Auth
+        self.stats.update_statistics_data(owner='Auth',
+                                          pid=9999,
+                                          **{'queries.tcp':1001})
+        self.assertTrue('Auth' in self.stats.statistics_data)
+        self.assertTrue('queries.tcp' in self.stats.statistics_data['Auth'])
+        self.assertEqual(self.stats.statistics_data['Auth']['queries.tcp'], 1001)
+        self.assertTrue('Auth' in self.stats.statistics_data_bypid)
+        self.assertTrue(9999 in self.stats.statistics_data_bypid['Auth'])
+        self.assertTrue('queries.tcp' in self.stats.statistics_data_bypid['Auth'][9999])
+        self.assertEqual(self.stats.statistics_data_bypid['Auth'][9999]['queries.tcp'], 1001)
+        self.assertEqual(self.stats.statistics_data_bypid,
+                         {'Auth': {9999: {'queries.tcp': 1001}}})
+        # another pid of Auth
+        self.stats.update_statistics_data(owner='Auth',
+                                          pid=9998,
+                                          **{'queries.tcp':1002,
+                                             'queries.udp':1003})
+        self.assertTrue('Auth' in self.stats.statistics_data)
+        self.assertTrue('queries.tcp' in self.stats.statistics_data['Auth'])
+        self.assertTrue('queries.udp' in self.stats.statistics_data['Auth'])
+        self.assertEqual(self.stats.statistics_data['Auth']['queries.tcp'], 2003)
+        self.assertEqual(self.stats.statistics_data['Auth']['queries.udp'], 1003)
+        self.assertTrue('Auth' in self.stats.statistics_data_bypid)
+        self.assertTrue(9999 in self.stats.statistics_data_bypid['Auth'])
+        self.assertTrue(9998 in self.stats.statistics_data_bypid['Auth'])
+        self.assertTrue('queries.tcp' in self.stats.statistics_data_bypid['Auth'][9999])
+        self.assertTrue('queries.udp' in self.stats.statistics_data_bypid['Auth'][9998])
+        self.assertTrue('queries.udp' in self.stats.statistics_data_bypid['Auth'][9998])
+        self.assertEqual(self.stats.statistics_data_bypid['Auth'][9999]['queries.tcp'], 1001)
+        self.assertEqual(self.stats.statistics_data_bypid['Auth'][9998]['queries.tcp'], 1002)
+        self.assertEqual(self.stats.statistics_data_bypid['Auth'][9998]['queries.udp'], 1003)
+
     def test_commands(self):
         # status
         self.assertEqual(self.stats.command_status(),
@@ -710,6 +744,44 @@ class TestStats(unittest.TestCase):
         self.assertRaises(stats.StatsError,
                           self.stats.command_set, owner='Stats', data={ 'dummy' : '_xxxx_yyyy_zzz_' })
 
+    def test_command_set_withpid(self):
+        # one pid of Auth
+        retval = isc.config.ccsession.parse_answer(
+            self.stats.command_set(owner='Auth',
+                                   pid=9997,
+                                   data={ 'queries.tcp' : 1001 }))
+        self.assertEqual(retval, (0,None))
+        self.assertTrue('Auth' in self.stats.statistics_data)
+        self.assertTrue('queries.tcp' in self.stats.statistics_data['Auth'])
+        self.assertEqual(self.stats.statistics_data['Auth']['queries.tcp'], 1001)
+        self.assertTrue('Stats' in self.stats.statistics_data)
+        self.assertTrue('last_update_time' in self.stats.statistics_data['Stats'])
+        self.assertTrue('Auth' in self.stats.statistics_data_bypid)
+        self.assertTrue(9997 in self.stats.statistics_data_bypid['Auth'])
+        self.assertTrue('queries.tcp' in self.stats.statistics_data_bypid['Auth'][9997])
+        self.assertEqual(self.stats.statistics_data_bypid['Auth'][9997]['queries.tcp'], 1001)
+        # another pid of Auth
+        retval = isc.config.ccsession.parse_answer(
+            self.stats.command_set(owner='Auth',
+                                   pid=9996,
+                                   data={ 'queries.tcp' : 1002,
+                                          'queries.udp' : 1003,}))
+        self.assertEqual(retval, (0,None))
+        self.assertTrue('Auth' in self.stats.statistics_data)
+        self.assertTrue('queries.tcp' in self.stats.statistics_data['Auth'])
+        self.assertTrue('queries.udp' in self.stats.statistics_data['Auth'])
+        self.assertEqual(self.stats.statistics_data['Auth']['queries.tcp'], 2003)
+        self.assertEqual(self.stats.statistics_data['Auth']['queries.udp'], 1003)
+        self.assertTrue('Auth' in self.stats.statistics_data_bypid)
+        self.assertTrue(9997 in self.stats.statistics_data_bypid['Auth'])
+        self.assertTrue(9996 in self.stats.statistics_data_bypid['Auth'])
+        self.assertTrue('queries.tcp' in self.stats.statistics_data_bypid['Auth'][9997])
+        self.assertTrue('queries.udp' in self.stats.statistics_data_bypid['Auth'][9996])
+        self.assertTrue('queries.udp' in self.stats.statistics_data_bypid['Auth'][9996])
+        self.assertEqual(self.stats.statistics_data_bypid['Auth'][9997]['queries.tcp'], 1001)
+        self.assertEqual(self.stats.statistics_data_bypid['Auth'][9996]['queries.tcp'], 1002)
+        self.assertEqual(self.stats.statistics_data_bypid['Auth'][9996]['queries.udp'], 1003)
+
 class TestOSEnv(unittest.TestCase):
     def test_osenv(self):
         """