source: trunk/src/allmydata/deep_stats.py @ e113cba

Last change on this file since e113cba was 0d47e12, checked in by Brian Warner <warner@…>, at 2016-12-24T03:50:48Z

Add some docstrings.

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