|
@@ -279,55 +279,66 @@ class Stats:
|
|
instance sends statistics data in the situation that multiple
|
|
instance sends statistics data in the situation that multiple
|
|
instances are working.
|
|
instances are working.
|
|
"""
|
|
"""
|
|
- self.update_modules()
|
|
|
|
- statistics_data = {}
|
|
|
|
- for (name, module) in self.modules.items():
|
|
|
|
- value = get_spec_defaults(module.get_statistics_spec())
|
|
|
|
- if module.validate_statistics(True, value):
|
|
|
|
- statistics_data[name] = value
|
|
|
|
- for (name, value) in self.statistics_data.items():
|
|
|
|
- if name in statistics_data:
|
|
|
|
- statistics_data[name].update(value)
|
|
|
|
- else:
|
|
|
|
- statistics_data[name] = value
|
|
|
|
- self.statistics_data = statistics_data
|
|
|
|
- def _sum_bymodule(statistics_data_bypid):
|
|
|
|
- # sum recursively each value under each
|
|
|
|
- # element
|
|
|
|
- def _sum(a, b):
|
|
|
|
|
|
+ # Note:
|
|
|
|
+ # The fix of #1751 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 accumlating 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.
|
|
|
|
+
|
|
|
|
+ def _accum_bymodule(statistics_data_bypid):
|
|
|
|
+ # This is an internal function for the superordinate
|
|
|
|
+ # function. It accumulates statistics data of each PID by
|
|
|
|
+ # module. It returns the accumulation result.
|
|
|
|
+ def _accum(a, b):
|
|
|
|
+ # If the first arg is dict or list type, two values
|
|
|
|
+ # would be merged and accumlated.
|
|
if type(a) is dict:
|
|
if type(a) is dict:
|
|
- return dict([ (k, _sum(v, b[k])) if k in b else (k, v) \
|
|
|
|
|
|
+ return dict([ (k, _accum(v, b[k])) \
|
|
|
|
+ if k in b else (k, v) \
|
|
for (k, v) in a.items() ] \
|
|
for (k, v) in a.items() ] \
|
|
- + [ (k, v) for (k, v) in b.items() \
|
|
|
|
|
|
+ + [ (k, v) \
|
|
|
|
+ for (k, v) in b.items() \
|
|
if k not in a ])
|
|
if k not in a ])
|
|
elif type(a) is list:
|
|
elif type(a) is list:
|
|
- return [ _sum(a[i], b[i]) if len(b) > i else a[i] \
|
|
|
|
|
|
+ return [ _accum(a[i], b[i]) \
|
|
|
|
+ if len(b) > i else a[i] \
|
|
for i in range(len(a)) ] \
|
|
for i in range(len(a)) ] \
|
|
- + [ b[i] for i in range(len(b)) \
|
|
|
|
|
|
+ + [ b[i] \
|
|
|
|
+ for i in range(len(b)) \
|
|
if len(a) <= i ]
|
|
if len(a) <= i ]
|
|
- elif type(a) is float or type(a) is int:
|
|
|
|
|
|
+ # If the first arg is integer or float type, two
|
|
|
|
+ # values are just added.
|
|
|
|
+ elif type(a) is int or type(a) is float:
|
|
return a + b
|
|
return a + b
|
|
- # If str or other types than above, then
|
|
|
|
- # just replace with the newer value.
|
|
|
|
|
|
+ # If the first arg is str or other types than above,
|
|
|
|
+ # then it just returns the first arg which is assumed
|
|
|
|
+ # to be the newer value.
|
|
return a
|
|
return a
|
|
ret = {}
|
|
ret = {}
|
|
for data in statistics_data_bypid.values():
|
|
for data in statistics_data_bypid.values():
|
|
- ret.update(_sum(data, ret))
|
|
|
|
|
|
+ ret.update(_accum(data, ret))
|
|
return ret
|
|
return ret
|
|
|
|
+
|
|
|
|
+ # Firstly, it gets default statistics data in each spec file.
|
|
|
|
+ self.update_modules()
|
|
|
|
+ statistics_data = {}
|
|
|
|
+ for (name, module) in self.modules.items():
|
|
|
|
+ value = get_spec_defaults(module.get_statistics_spec())
|
|
|
|
+ if module.validate_statistics(True, value):
|
|
|
|
+ statistics_data[name] = value
|
|
|
|
+ self.statistics_data = statistics_data
|
|
|
|
+
|
|
|
|
+ # If the "owner" and "data" arguments in this function are
|
|
|
|
+ # specified, then the variable of statistics data of each pid
|
|
|
|
+ # would be updated.
|
|
|
|
+ errors = []
|
|
if owner and data:
|
|
if owner and data:
|
|
- errors = []
|
|
|
|
try:
|
|
try:
|
|
if self.modules[owner].validate_statistics(False, data, errors):
|
|
if self.modules[owner].validate_statistics(False, data, errors):
|
|
- # 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 owner in self.statistics_data_bypid:
|
|
if pid in self.statistics_data_bypid[owner]:
|
|
if pid in self.statistics_data_bypid[owner]:
|
|
self.statistics_data_bypid[owner][pid].update(data)
|
|
self.statistics_data_bypid[owner][pid].update(data)
|
|
@@ -335,13 +346,16 @@ class Stats:
|
|
self.statistics_data_bypid[owner][pid] = data
|
|
self.statistics_data_bypid[owner][pid] = data
|
|
else:
|
|
else:
|
|
self.statistics_data_bypid[owner] = { pid : data }
|
|
self.statistics_data_bypid[owner] = { pid : data }
|
|
- self.statistics_data[owner].update(
|
|
|
|
- _sum_bymodule(self.statistics_data_bypid[owner]))
|
|
|
|
except KeyError:
|
|
except KeyError:
|
|
errors.append("unknown module name: " + str(owner))
|
|
errors.append("unknown module name: " + str(owner))
|
|
- if errors: return errors
|
|
|
|
- # Find dead instances by invoking "show_processes" to Boss,
|
|
|
|
- # then remove their statistics data if there are ones
|
|
|
|
|
|
+
|
|
|
|
+ # If there are inactive instances, which was actually running
|
|
|
|
+ # on the system before, their statistics data would be
|
|
|
|
+ # removed. To find inactive instances, it invokes the
|
|
|
|
+ # "show_processes" command to Boss via the cc session. Then it
|
|
|
|
+ # gets active instance list and compares its PIDs with PIDs in
|
|
|
|
+ # statistics data which it already has. If inactive instances
|
|
|
|
+ # are found, it would remove their statistics data.
|
|
seq = self.cc_session.group_sendmsg(
|
|
seq = self.cc_session.group_sendmsg(
|
|
isc.config.ccsession.create_command("show_processes", None),
|
|
isc.config.ccsession.create_command("show_processes", None),
|
|
"Boss")
|
|
"Boss")
|
|
@@ -349,27 +363,33 @@ class Stats:
|
|
if answer:
|
|
if answer:
|
|
(rcode, value) = isc.config.ccsession.parse_answer(answer)
|
|
(rcode, value) = isc.config.ccsession.parse_answer(answer)
|
|
if rcode == 0:
|
|
if rcode == 0:
|
|
- if type(value) is not list:
|
|
|
|
- return
|
|
|
|
- for v in value:
|
|
|
|
- if type(v) is not list or len(v) < 2:
|
|
|
|
- return
|
|
|
|
- mlist = [ k for k in self.statistics_data_bypid.keys() ]
|
|
|
|
- for m in mlist:
|
|
|
|
- plist1 = [ p for p in self.statistics_data_bypid[m].keys() ]
|
|
|
|
- plist2 = [ v[0] for v in value \
|
|
|
|
- if v[1].lower().find(m.lower()) >= 0 ] \
|
|
|
|
- + [-1] # add the default pid
|
|
|
|
- # set object difference: nplist = plist1 - plist2
|
|
|
|
- nplist = set(plist1).difference(set(plist2))
|
|
|
|
- for p in nplist:
|
|
|
|
- self.statistics_data_bypid[m].pop(p)
|
|
|
|
- if self.statistics_data_bypid[m]:
|
|
|
|
- if m in self.statistics_data:
|
|
|
|
- self.statistics_data[m].update(
|
|
|
|
- _sum_bymodule(self.statistics_data_bypid[m]))
|
|
|
|
- else:
|
|
|
|
- self.statistics_data_bypid.pop(m)
|
|
|
|
|
|
+ if type(value) is list and len(value) > 0 \
|
|
|
|
+ and type(value[0]) is list and len(value[0]) > 1:
|
|
|
|
+ mlist = [ k for k in self.statistics_data_bypid.keys() ]
|
|
|
|
+ for m in mlist:
|
|
|
|
+ # PID list which it has before except for -1
|
|
|
|
+ plist1 = [ p for p in self.statistics_data_bypid[m]\
|
|
|
|
+ .keys() if p != -1]
|
|
|
|
+ # PID list of active instances which is
|
|
|
|
+ # received from Boss
|
|
|
|
+ plist2 = [ v[0] for v in value \
|
|
|
|
+ if v[1].lower().find(m.lower()) \
|
|
|
|
+ >= 0 ]
|
|
|
|
+ # get inactive instance list by the difference
|
|
|
|
+ # between plist1 and plist2
|
|
|
|
+ nplist = set(plist1).difference(set(plist2))
|
|
|
|
+ for p in nplist:
|
|
|
|
+ self.statistics_data_bypid[m].pop(p)
|
|
|
|
+ if self.statistics_data_bypid[m]:
|
|
|
|
+ if m in self.statistics_data:
|
|
|
|
+ self.statistics_data[m].update(
|
|
|
|
+ _accum_bymodule(
|
|
|
|
+ self.statistics_data_bypid[m]))
|
|
|
|
+ # remove statistics data of the module with no
|
|
|
|
+ # PID
|
|
|
|
+ else:
|
|
|
|
+ self.statistics_data_bypid.pop(m)
|
|
|
|
+ if errors: return errors
|
|
|
|
|
|
def command_status(self):
|
|
def command_status(self):
|
|
"""
|
|
"""
|