source: trunk/src/allmydata/deep_stats.py

Last change on this file was 1cfe843d, checked in by Alexandre Detiste <alexandre.detiste@…>, at 2024-02-22T23:40:25Z

more python2 removal

  • Property mode set to 100644
File size: 4.8 KB
Line 
1"""Implementation of the deep stats class.
2
3Ported to Python 3.
4"""
5
6import math
7
8from allmydata.interfaces import IImmutableFileNode
9from allmydata.interfaces import IMutableFileNode
10from allmydata.interfaces import IDirectoryNode
11from allmydata.unknown import UnknownNode
12from allmydata.uri import LiteralFileURI
13from allmydata.uri import from_string
14from allmydata.util import mathutil
15
16class DeepStats(object):
17    """Deep stats object.
18
19    Holds results of the deep-stats operation.
20    Used for json generation in the API."""
21
22    # Json API version.
23    # Rules:
24    # - increment each time a field is removed or changes meaning.
25    # - it's ok to add a new field without incrementing the version.
26    API_VERSION = 1
27
28    def __init__(self, origin):
29        """Initializes DeepStats object. Sets most of the fields to 0."""
30        self.monitor = None
31        self.origin = origin
32        self.stats = {
33            'api-version': self.API_VERSION
34        }
35        for k in ["count-immutable-files",
36                  "count-mutable-files",
37                  "count-literal-files",
38                  "count-files",
39                  "count-directories",
40                  "count-unknown",
41                  "size-immutable-files",
42                  #"size-mutable-files",
43                  "size-literal-files",
44                  "size-directories",
45                  "largest-directory",
46                  "largest-directory-children",
47                  "largest-immutable-file",
48                  #"largest-mutable-file",
49                 ]:
50            self.stats[k] = 0
51        self.histograms = {}
52        for k in ["size-files-histogram"]:
53            self.histograms[k] = {} # maps (min,max) to count
54        self.buckets = [(0, 0), (1, 3)]
55        self.root = math.sqrt(10)
56
57    def set_monitor(self, monitor):
58        """Sets a new monitor."""
59        self.monitor = monitor
60        monitor.origin_si = self.origin.get_storage_index()
61        monitor.set_status(self.get_results())
62
63    def add_node(self, node, childpath):
64        """Adds a node's stats to calculation."""
65        if isinstance(node, UnknownNode):
66            self.add("count-unknown")
67        elif IDirectoryNode.providedBy(node):
68            self.add("count-directories")
69        elif IMutableFileNode.providedBy(node):
70            self.add("count-files")
71            self.add("count-mutable-files")
72            # TODO: update the servermap, compute a size, add it to
73            # size-mutable-files, max it into "largest-mutable-file"
74        elif IImmutableFileNode.providedBy(node): # CHK and LIT
75            self.add("count-files")
76            size = node.get_size()
77            self.histogram("size-files-histogram", size)
78            theuri = from_string(node.get_uri())
79            if isinstance(theuri, LiteralFileURI):
80                self.add("count-literal-files")
81                self.add("size-literal-files", size)
82            else:
83                self.add("count-immutable-files")
84                self.add("size-immutable-files", size)
85                self.max("largest-immutable-file", size)
86
87    def enter_directory(self, parent, children):
88        """Adds directory stats."""
89        dirsize_bytes = parent.get_size()
90        if dirsize_bytes is not None:
91            self.add("size-directories", dirsize_bytes)
92            self.max("largest-directory", dirsize_bytes)
93        dirsize_children = len(children)
94        self.max("largest-directory-children", dirsize_children)
95
96    def add(self, key, value=1):
97        self.stats[key] += value
98
99    def max(self, key, value):
100        self.stats[key] = max(self.stats[key], value)
101
102    def which_bucket(self, size):
103        # return (min,max) such that min <= size <= max
104        # values are from the set (0,0), (1,3), (4,10), (11,31), (32,100),
105        # (101,316), (317, 1000), etc: two per decade
106        assert size >= 0
107        i = 0
108        while True:
109            if i >= len(self.buckets):
110                # extend the list
111                new_lower = self.buckets[i-1][1]+1
112                new_upper = int(mathutil.next_power_of_k(new_lower, self.root))
113                self.buckets.append((new_lower, new_upper))
114            maybe = self.buckets[i]
115            if maybe[0] <= size <= maybe[1]:
116                return maybe
117            i += 1
118
119    def histogram(self, key, size):
120        bucket = self.which_bucket(size)
121        h = self.histograms[key]
122        if bucket not in h:
123            h[bucket] = 0
124        h[bucket] += 1
125
126    def get_results(self):
127        """Returns deep-stats results."""
128        stats = self.stats.copy()
129        for key in self.histograms:
130            h = self.histograms[key]
131            out = [ (bucket[0], bucket[1], h[bucket]) for bucket in h ]
132            out.sort()
133            stats[key] = out
134        return stats
135
136    def finish(self):
137        """Finishes gathering stats."""
138        return self.get_results()
Note: See TracBrowser for help on using the repository browser.