[tor-commits] [stem/master] Lazily parsing ExitPolicy

atagar at torproject.org atagar at torproject.org
Mon Dec 31 05:37:27 UTC 2012


commit da65f282699d3e8e763e1f3ba3c7612cc970178a
Author: Damian Johnson <atagar at torproject.org>
Date:   Sun Dec 30 21:00:50 2012 -0800

    Lazily parsing ExitPolicy
    
    Why parse exit policies that we never use?
    
    ExitPolicy instances exist numerous places, note notably in the descriptors.
    Users may never use or care about the exit policy, so there's no point in
    putting effort into parsing them until they're needed.
    
    The advantages is that this means faster untime and less memory usage if they
    go unused. Down side is that we won't pick up on malformed content until
    they're used (handy for tests, but not somethign that users care about).
    
    This dropped the runtime for the server descriptor integ tests on my system
    from 10.1 to 7.7 seconds.
---
 stem/exit_policy.py |   40 ++++++++++++++++++++++++++--------------
 1 files changed, 26 insertions(+), 14 deletions(-)

diff --git a/stem/exit_policy.py b/stem/exit_policy.py
index e1f68b7..462a0b5 100644
--- a/stem/exit_policy.py
+++ b/stem/exit_policy.py
@@ -86,16 +86,13 @@ class ExitPolicy(object):
   """
   
   def __init__(self, *rules):
-    self._rules = []
-    
+    # sanity check the types
     for rule in rules:
-      if isinstance(rule, str):
-        self._rules.append(ExitPolicyRule(rule.strip()))
-      elif isinstance(rule, ExitPolicyRule):
-        self._rules.append(rule)
-      else:
+      if not (isinstance(rule, str) or isinstance(rule, ExitPolicyRule)):
         raise TypeError("Exit policy rules can only contain strings or ExitPolicyRules, got a %s (%s)" % (type(rule), rules))
     
+    self._rules = None          # lazily loaded series of ExitPolicyRule
+    self._input_rules = rules   # input rules, only kept until self._rules is set
     self._is_allowed_default = True
     self._summary_representation = None
   
@@ -111,7 +108,7 @@ class ExitPolicy(object):
     :returns: **True** if exiting to this destination is allowed, **False** otherwise
     """
     
-    for rule in self._rules:
+    for rule in self._get_rules():
       if rule.is_match(address, port):
         return rule.is_accept
     
@@ -124,7 +121,7 @@ class ExitPolicy(object):
     """
     
     rejected_ports = set()
-    for rule in self._rules:
+    for rule in self._get_rules():
       if rule.is_accept:
         for port in xrange(rule.min_port, rule.max_port + 1):
           if not port in rejected_ports:
@@ -161,7 +158,7 @@ class ExitPolicy(object):
       # determines if we're a white-list or blacklist
       is_whitelist = not self._is_allowed_default
       
-      for rule in self._rules:
+      for rule in self._get_rules():
         if rule.is_address_wildcard() and rule.is_port_wildcard():
           is_whitelist = not rule.is_accept
           break
@@ -173,7 +170,7 @@ class ExitPolicy(object):
       
       display_ports, skip_ports = [], set()
       
-      for rule in self._rules:
+      for rule in self._get_rules():
         if not rule.is_address_wildcard(): continue
         elif rule.is_port_wildcard(): break
         
@@ -231,16 +228,31 @@ class ExitPolicy(object):
     
     self._is_allowed_default = is_allowed_default
   
+  def _get_rules(self):
+    if self._rules is None:
+      rules = []
+      
+      for rule in self._input_rules:
+        if isinstance(rule, str):
+          rules.append(ExitPolicyRule(rule.strip()))
+        elif isinstance(rule, ExitPolicyRule):
+          rules.append(rule)
+      
+      self._rules = rules
+      self._input_rules = None
+    
+    return self._rules
+  
   def __iter__(self):
-    for rule in self._rules:
+    for rule in self._get_rules():
       yield rule
   
   def __str__(self):
-    return ', '.join([str(rule) for rule in self._rules])
+    return ', '.join([str(rule) for rule in self._get_rules()])
   
   def __eq__(self, other):
     if isinstance(other, ExitPolicy):
-      return self._rules == list(other)
+      return self._get_rules() == list(other)
     else:
       return False
 





More information about the tor-commits mailing list