Rev 17: Simplify stat classes definitions by __init__'ing from format. in file:///v/home/vila/.bazaar/plugins/transportstats/

Vincent Ladeuil v.ladeuil+lp at free.fr
Mon Oct 8 13:16:20 BST 2007


At file:///v/home/vila/.bazaar/plugins/transportstats/

------------------------------------------------------------
revno: 17
revision-id: v.ladeuil+lp at free.fr-20071008121619-hmmlpdvlh3v8qy7w
parent: v.ladeuil+lp at free.fr-20071008103516-c9gs7qecktcnjhyx
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: transportstats
timestamp: Mon 2007-10-08 14:16:19 +0200
message:
  Simplify stat classes definitions by __init__'ing from format.
  
  * statsfile.py:
  (StatsFile.read_stat_name, StatsFile.read_stat_body): Cleaner
  methods replacing read_stat.
  
  * stats.py:
  Delete useles classes now that StatsPart cleanly tes all
  attributes from format.
  (StatsPart.__init__): Build from format now.
  (StatsRegistry.register): Also register the class to be used when
  reading a stat from file.
  (StatsRegistry.get_class, StatsRegistry.get_format): New methods.
  (Stats.__iter__): Get the class from the registry instead of
  building its name heuristically.
  
  * serialize.py:
  Stop using file as a paramter name, it's a builtin.
  
  * decorator.py:
  Get proper names now that classes are explicit in stats.py.
  (StatsCollector.__latency): Enforce latency values between 0 and
  65535.
modified:
  decorator.py                   decorator.py-20070926152401-52kuiex1mu755ajk-1
  serialize.py                   serialize.py-20071005112454-5v72oa7pqcdhjytc-1
  stats.py                       stats.py-20070928061304-7i3r2h4gg6rbi03e-1
  statsfile.py                   structuredfile.py-20070927123433-krruwbx4mkalu3xs-1
-------------- next part --------------
=== modified file 'decorator.py'
--- a/decorator.py	2007-10-08 10:35:16 +0000
+++ b/decorator.py	2007-10-08 12:16:19 +0000
@@ -61,7 +61,7 @@
 
     def __latency(self):
         latency = int((time.time() - self.__start_time) * 1000)
-        return min(65535, latency)
+        return max(0, min(65535, latency))
 
     @classmethod
     def _get_url_prefix(self):
@@ -72,20 +72,20 @@
         """See Transport.has()."""
         self.__start()
         ret = self._decorated.has(relpath)
-        self.__collect('Transport_has', relpath, self.__latency())
+        self.__collect('Transport.has', relpath, self.__latency())
         return ret
 
     def get(self, relpath):
         """See Transport.get()."""
         self.__start()
-        file = self._decorated.get(relpath)
+        f = self._decorated.get(relpath)
         latency = self.__latency()
         temp_file = tempfile.TemporaryFile()
-        nb_bytes = self._pump(file, temp_file)
+        nb_bytes = self._pump(f, temp_file)
         temp_file.seek(0)
-        file.close()
+        f.close()
 
-        self.__collect('Transport_get', relpath, nb_bytes, latency)
+        self.__collect('Transport.get', relpath, nb_bytes, latency)
         return temp_file
 
     def get_bytes(self, relpath):
@@ -93,7 +93,7 @@
         self.__start()
         bytes = self._decorated.get_bytes(relpath)
 
-        self.__collect('Transport_get_bytes', relpath, len(bytes),
+        self.__collect('Transport.get_bytes', relpath, len(bytes),
                        self.__latency())
         return bytes
 
@@ -110,16 +110,16 @@
         # level which provides a rough estimate (1 transaction, n bytes read).
         for (pos, data) in self._decorated.readv(relpath, offsets):
             if first:
-                self.__collect('Transport_readv', relpath, self.__latency())
+                self.__collect('Transport.readv', relpath, self.__latency())
                 first = False
-            self.__collect('Transport_readv__offset', relpath, pos, len(data))
+            self.__collect('Transport.readv/offset', relpath, pos, len(data))
             yield pos, data
 
     def stat(self, relpath):
         """See Transport.stat()."""
         self.__start()
         ret = self._decorated.stat(relpath)
-        self.__collect('Transport_stat', relpath, self.__latency())
+        self.__collect('Transport.stat', relpath, self.__latency())
         return ret
 
 

=== modified file 'serialize.py'
--- a/serialize.py	2007-10-08 09:46:16 +0000
+++ b/serialize.py	2007-10-08 12:16:19 +0000
@@ -30,44 +30,44 @@
 
 class UnsignedByte(FormatSpecifier):
 
-    def pack(self, file, value):
-        file.write(struct.pack('>B', value))
+    def pack(self, f, value):
+        f.write(struct.pack('>B', value))
 
-    def unpack(self, file):
-        (lg,) = struct.unpack('>B', file.read(1))
+    def unpack(self, f):
+        (lg,) = struct.unpack('>B', f.read(1))
         return lg
 
 
 class UnsignedShort(FormatSpecifier):
 
-    def pack(self, file, value):
-        file.write(struct.pack('>H', value))
+    def pack(self, f, value):
+        f.write(struct.pack('>H', value))
 
-    def unpack(self, file):
-        (lg,) = struct.unpack('>H', file.read(2))
+    def unpack(self, f):
+        (lg,) = struct.unpack('>H', f.read(2))
         return lg
 
 
 class UnsignedLong(FormatSpecifier):
 
-    def pack(self, file, value):
-        file.write(struct.pack('>L', value))
+    def pack(self, f, value):
+        f.write(struct.pack('>L', value))
 
-    def unpack(self, file):
-        (lg,) = struct.unpack('>L', file.read(4))
+    def unpack(self, f):
+        (lg,) = struct.unpack('>L', f.read(4))
         return lg
 
 
 class ByteLongString(FormatSpecifier):
 
-    def pack(self, file, str):
+    def pack(self, f, str):
         lg = len(str)
         fmt = '>B%ds' % lg
-        file.write(struct.pack(fmt, lg, str))
+        f.write(struct.pack(fmt, lg, str))
 
-    def unpack(self, file):
-        (lg,) = struct.unpack('>B', file.read(1))
-        (str,) = struct.unpack('>%ds' % lg, file.read(lg))
+    def unpack(self, f):
+        (lg,) = struct.unpack('>B', f.read(1))
+        (str,) = struct.unpack('>%ds' % lg, f.read(lg))
         return str
 
 
@@ -121,19 +121,19 @@
 
     def packer_method(self):
 
-        def pack(file, *args):
+        def pack(f, *args):
             if len(args) != len(self.parts):
                 raise TypeError(
                     'Waiting for %r, got %r' % ([p.name for p in self.parts],
                                                 args))
             for part, arg in map(None, self.parts, args):
-                part.pack(file, arg)
+                part.pack(f, arg)
 
         return pack
 
     def unpacker_method(self):
 
-        def unpack(file):
-            return [ part.unpack(file) for part in self.parts]
+        def unpack(f):
+            return [ part.unpack(f) for part in self.parts]
 
         return unpack

=== modified file 'stats.py'
--- a/stats.py	2007-10-08 10:35:16 +0000
+++ b/stats.py	2007-10-08 12:16:19 +0000
@@ -40,70 +40,28 @@
 
 
 class StatsPart(object):
-    pass
-
-
-class TransportStatsPart(StatsPart):
-
-    def __init__(self, base):
-        StatsPart.__init__(self)
-        self.base = base
+
+    def __init__(self, format, *args):
+        for fmt_spec, value in map(None, format.parts, args):
+            object.__setattr__(self, fmt_spec.name, value)
+
+
+class TransportStat(StatsPart):
+
+    def __init__(self, *args):
+        StatsPart.__init__(self, *args)
+        # Default values for most of the stats
         self.requests = 1
 
-# FIXME: __init__ methods should really be generated from format
-class _Transport_has_stat(TransportStatsPart):
-
-    def __init__(self, base, relpath, latency):
-        super(self.__class__, self).__init__(base)
-        self.relpath = relpath
-        self.relpath = latency
-
-
-class _Transport_get_stat(TransportStatsPart):
-
-    def __init__(self, base, relpath, bytes_read, latency):
-        super(self.__class__, self).__init__(base)
-        self.relpath = relpath
-        self.bytes_read = bytes_read
-        self.relpath = latency
-
-
-class _Transport_get_bytes_stat(TransportStatsPart):
-
-    def __init__(self, base, relpath, bytes_read, latency):
-        super(self.__class__, self).__init__(base)
-        self.relpath = relpath
-        self.bytes_read = bytes_read
-        self.relpath = latency
-
-
-class _Transport_readv_stat(TransportStatsPart):
-
-    def __init__(self, base, relpath, latency):
-        super(self.__class__, self).__init__(base)
-        self.relpath = relpath
-        self.latency = latency
-
-
-class _Transport_readv__offset_stat(TransportStatsPart):
-
-    def __init__(self, base, relpath, offset, bytes_read):
-        super(self.__class__, self).__init__(base)
-        self.relpath = relpath
-        self.offset = offset
-        self.bytes_read = bytes_read
+
+class TransportReadvOffset(TransportStat):
+
+    def __init__(self, *args):
+        super(self.__class__, self).__init__(*args)
         # Special case, this stat is part of a request, not a request itself
         self.requests = 0
 
 
-class _Transport_stat_stat(TransportStatsPart):
-
-    def __init__(self, base, relpath, latency):
-        super(self.__class__, self).__init__(base)
-        self.relpath = relpath
-        self.relpath = latency
-
-
 class StatsRegistry(registry.Registry):
     """Statitics registry."""
 
@@ -114,13 +72,17 @@
             serialize.format_specifier_registry.get('us')('stat_name',
                                                           self._stat_names)
 
-    def register(self, key, description,
-                 help=None, info=None, override_existing=False):
+    def register(self, key, klass, description):
         format = statsfile.StatsFormat(description)
-        super(StatsRegistry, self).register(key, format, help, info,
-                                            override_existing)
+        super(StatsRegistry, self).register(key, (klass, format))
         self._stat_names.add(key, write_only=False)
 
+    def get_class(self, key):
+        return self.get(key)[0]
+
+    def get_format(self, key):
+        return self.get(key)[1]
+
     @property
     def stat_names(self):
         return self._stat_names
@@ -135,17 +97,17 @@
 
 # Shortcut
 register_stat = stats_registry.register
-register_stat('Transport_has',
-              '%(base)us%(relpath)us%(latency)H')
-register_stat('Transport_get',
-              '%(base)us%(relpath)us%(bytes_read)L%(latency)H')
-register_stat('Transport_get_bytes',
-              '%(base)us%(relpath)us%(bytes_read)L%(latency)H')
-register_stat('Transport_readv',
-              '%(base)us%(relpath)us%(latency)H')
-register_stat('Transport_readv__offset',
+register_stat('Transport.has', TransportStat,
+              '%(base)us%(relpath)us%(latency)H')
+register_stat('Transport.get', TransportStat,
+              '%(base)us%(relpath)us%(bytes_read)L%(latency)H')
+register_stat('Transport.get_bytes', TransportStat,
+              '%(base)us%(relpath)us%(bytes_read)L%(latency)H')
+register_stat('Transport.readv', TransportStat,
+              '%(base)us%(relpath)us%(latency)H')
+register_stat('Transport.readv/offset', TransportReadvOffset,
               '%(base)us%(relpath)us%(offset)L%(bytes_read)L')
-register_stat('Transport_stat',
+register_stat('Transport.stat', TransportStat,
               '%(base)us%(relpath)us%(latency)H')
 
 
@@ -227,23 +189,27 @@
         osutils.delete_any(Stats._default_name)
 
     def write_stat(self, name, *args):
+        # FIXME: layer violation between Stats/StatsFile There are two
+        # conflictings aims here: keep the stat registry here and hides the
+        # stat encoding in statsfile. That can be solved by passing the stat
+        # registry to statsfile but that means keeping the declaration here is
+        # a bit arbitrary.
         self._sfile.write_stat(self._name_serializer, name,
-                               stats_registry.get(name), *args)
+                               stats_registry.get_format(name), *args)
 
     def __iter__(self):
         self._ensure_mode('exploiting')
         for stat in self._sfile:
-            name, file, stat_format = self._sfile.read_stat(
-                stat, self._name_serializer, stats_registry)
-
-            class_name = '_' + name + '_stat'
-            stat_class = globals().get(class_name, None)
-            if stat_class is None:
-                trace.warning(
-                    'Unknown method in stats file: %s' % class_name )
+            # FIXME: layer violation between Stats/StatsFile
+            name, body_file = self._sfile.read_stat_name(
+                stat, self._name_serializer)
+            try:
+                (stat_class, stat_format) = stats_registry.get(name)
+            except:
+                trace.warning('Unknown method in stats file: %s' % name)
             else:
-                args = stat_format.unpack(file)
-                yield stat_class(*args)
+                body = self._sfile.read_stat_body(body_file, stat_format)
+                yield stat_class(stat_format, *body)
 
     def collect(self):
         requests = 0

=== modified file 'statsfile.py'
--- a/statsfile.py	2007-10-07 19:52:40 +0000
+++ b/statsfile.py	2007-10-08 12:16:19 +0000
@@ -328,19 +328,6 @@
             stat_fmt.pack(f, *args)
         self.stats.append(f.getvalue())
 
-    def read_stat(self, raw_stat, name_fmt, stat_fmt_of):
-        """Read a statistic name and provides body data.
-
-        :returns: name, file, stat_format. name is the statistic name, file a
-          file-like object containing the stat body data and stat_format the
-          format able to decode the body.
-        """
-        file = StringIO(raw_stat)
-        name = name_fmt.unpack(file)
-        stat_format = stat_fmt_of.get(name)
-        stat_format.set_unique_strings_container(self.unique_strings)
-        return name, file, stat_format
-
     def read_stats_section(self):
         # We may have to read a ustrings section
         header = self._header_of['stats']
@@ -360,6 +347,15 @@
         self.stats.read(self._file)
         self.read_header('marker')
 
+    def read_stat_name(self, raw_stat, name_fmt):
+        file = StringIO(raw_stat)
+        name = name_fmt.unpack(file)
+        return name, file
+
+    def read_stat_body(self, f, body_fmt):
+        body_fmt.set_unique_strings_container(self.unique_strings)
+        return body_fmt.unpack(f)
+
     def flush(self):
         if len(self.unique_strings):
             self.write_header('ustrings')



More information about the bazaar-commits mailing list