[or-cvs] r17051: {weather} Add safeRelease() as a method to ensure that we always relea (weather/trunk)

ioerror at seul.org ioerror at seul.org
Thu Oct 9 03:56:30 UTC 2008


Author: ioerror
Date: 2008-10-08 23:56:29 -0400 (Wed, 08 Oct 2008)
New Revision: 17051

Modified:
   weather/trunk/poll.py
   weather/trunk/weather.py
Log:
Add safeRelease() as a method to ensure that we always release the lock on the database, even if we may have tried to release it before. Also, I think this fixes a bug in GET where we would attempt to acquire a lock and possibly return without a proper release(). Lots of refactoring to ensure that we try: ... finally: gdbm_lock.release() whenever we have a locking issue with the database. I do not believe that we need this for the antispam locking code... yet...


Modified: weather/trunk/poll.py
===================================================================
--- weather/trunk/poll.py	2008-10-08 10:47:23 UTC (rev 17050)
+++ weather/trunk/poll.py	2008-10-09 03:56:29 UTC (rev 17051)
@@ -14,6 +14,7 @@
 from config import authenticator, URLbase, weather_email, failure_threshold
 from config import poll_period, ping_targets, weather_storage
 from weather import parse_subscriptions
+from weather import safeRelease
 
 # Lets debug this
 import traceback
@@ -152,18 +153,22 @@
     if not self.tp.test():
       return False
     print 'Timestamp', datetime.now().isoformat('-')
-    self.gdbm_lock.acquire()
-    node = self.subscriptions.firstkey()
-    while node != None:
-      # nodes stay in the subscription db even if nobody is subscribed to them
-      # anymore
-      if self.subscriptions[node] != "":
-        self.gdbm_lock.release()
-        self.ping(node)       # this is time consuming ; don't hold the lock
+
+    try:
         self.gdbm_lock.acquire()
+        node = self.subscriptions.firstkey()
+        while node != None:
+          # nodes stay in the subscription db even if nobody is subscribed to them
+          # anymore
+          if self.subscriptions[node] != "":
+            self.gdbm_lock.release()
+            self.ping(node)       # this is time consuming ; don't hold the lock
+            self.gdbm_lock.acquire()
+          node = self.subscriptions.nextkey(node)
 
-      node = self.subscriptions.nextkey(node)
-    self.gdbm_lock.release()
+    finally:
+        safeRelease(self.gdbm_lock)
+
     #del self.tp   # this minimises the chance of confusion a local tor control
                   # port crash with a remote node being down
     if debug: print "Ping_all finished"
@@ -230,9 +235,11 @@
     # envelope header.
     s = smtplib.SMTP()
     s.connect()
-    self.gdbm_lock.acquire()
-    list = parse_subscriptions(node,self.subscriptions)
-    self.gdbm_lock.release()
+    try:
+        self.gdbm_lock.acquire()
+        list = parse_subscriptions(node,self.subscriptions)
+    finally:
+        safeRelease(self.gdbm_lock)
     for address, unsub_token in list:
  
       unsub_url = URLbase+"/unsubscribe/" + unsub_token

Modified: weather/trunk/weather.py
===================================================================
--- weather/trunk/weather.py	2008-10-08 10:47:23 UTC (rev 17050)
+++ weather/trunk/weather.py	2008-10-09 03:56:29 UTC (rev 17051)
@@ -25,6 +25,13 @@
 '/unsubscribe/(.*)', 'unsubscribe'
 )
 
+
+def safeRelease(gdbm_lock):
+    try:
+        gdbm_lock.release()
+    except AssertionError:
+        pass
+
 if apache_fcgi:
   web.wsgi.runwsgi = lambda func, addr=None: web.wsgi.runfcgi(func, addr)
 
@@ -173,27 +180,32 @@
       return True
 
   def already_subscribed(self, address, node):
-    gdbm_lock.acquire()
-
     try:
-      words = subscriptions[node].split()
-      if address in words:
-        already = True
-      else:
-        already = False
-    except KeyError:
-      already = False
+        gdbm_lock.acquire()
 
-    gdbm_lock.release()
-    return already
+        try:
+          words = subscriptions[node].split()
+          if address in words:
+            already = True
+          else:
+            already = False
+        except KeyError:
+          already = False
+
+    finally:
+        gdbm_lock.release()
+        return already
     
   def send_confirmation_email(self, address, node):
     authstring = randstring()
 
-    gdbm_lock.acquire()
-    requests[authstring] = address + " " + node
-    gdbm_lock.release()
+    try:
+        gdbm_lock.acquire()
+        requests[authstring] = address + " " + node
 
+    finally:
+        gdbm_lock.release()
+
     if dummy_testing:
       print "gotcha"
       return True
@@ -283,36 +295,41 @@
     web.header('content-type', 'text/html')
     print "<html>"
     if debug: print "checking confirmation..."
-    gdbm_lock.acquire()
 
-    if not requests.has_key(authstring):
-      print "Error in subscription request!"
-      gdbm_lock.release()
-      return 0
+    try:
+        gdbm_lock.acquire()
 
-    email, node = requests[authstring].split()
+        if not requests.has_key(authstring):
+          print "Error in subscription request!"
+          gdbm_lock.release()
+          return 0
 
-    # We want a single link in every outgoing email that will unsubscribe that
-    # user.  But we don't want to generate a new database entry every time
-    # an email gets sent.  So do it now, and remember the token.
-    unsub_authstring = randstring()
-    subscription = email + " " + node + " " + unsub_authstring
-    unsubscriptions[unsub_authstring] = subscription
-    subscription2 = email + " " + unsub_authstring
-    if subscriptions.has_key(node):
-      subscriptions[node] += " " +subscription2
-    else:
-      subscriptions[node] = subscription2
-    url = web.ctx.homedomain + "/unsubscribe/" + unsub_authstring
-    print "Succesfully subscribed <tt>", email, 
-    print "</tt> to weather reports about Tor node", node
-    print "<p>You can unsubscribe at any time by clicking on the following link:"
-    print '<p><a href="' + url + '">' + url + '</a>'
-    print '<p>(you will be reminded of it in each weather report we send)'
-    
-    del(requests[authstring])
-    subscriptions.sync()
-    gdbm_lock.release()
+        email, node = requests[authstring].split()
+
+        # We want a single link in every outgoing email that will unsubscribe that
+        # user.  But we don't want to generate a new database entry every time
+        # an email gets sent.  So do it now, and remember the token.
+        unsub_authstring = randstring()
+        subscription = email + " " + node + " " + unsub_authstring
+        unsubscriptions[unsub_authstring] = subscription
+        subscription2 = email + " " + unsub_authstring
+        if subscriptions.has_key(node):
+          subscriptions[node] += " " +subscription2
+        else:
+          subscriptions[node] = subscription2
+        url = web.ctx.homedomain + "/unsubscribe/" + unsub_authstring
+        print "Succesfully subscribed <tt>", email, 
+        print "</tt> to weather reports about Tor node", node
+        print "<p>You can unsubscribe at any time by clicking on the following link:"
+        print '<p><a href="' + url + '">' + url + '</a>'
+        print '<p>(you will be reminded of it in each weather report we send)'
+        
+        del(requests[authstring])
+        subscriptions.sync()
+
+    finally:
+        safeRelease(gdbm_lock)
+
     # okay now slacken antispam watch
     antispam_lock.acquire()
     if antispam.has_key(web.ctx.ip):
@@ -320,27 +337,30 @@
       if antispam[web.ctx.ip] >= antispam_max:
         del antispam[web.ctx.ip]
     antispam_lock.release()
-
     
 class unsubscribe:
   def GET(self,authstring):
 
     web.header('content-type', 'text/html')
-    gdbm_lock.acquire()
-    if not unsubscriptions.has_key(authstring):
-      print "Invalid unsubscription request!"
-      print unsubscriptions
-      return 0
+    try:
+        gdbm_lock.acquire()
+        if not unsubscriptions.has_key(authstring):
+          print "Invalid unsubscription request!"
+          print unsubscriptions
+          gdbm_lock.release()
+          return 0
 
-    email, node, _ = unsubscriptions[authstring].split()
+        email, node, _ = unsubscriptions[authstring].split()
 
-    delete_sub ((email, authstring), subscriptions, node)
-    #subscriptions[node].remove((email,authstring))
-    print "<html>Succesfully unsubscribed <tt>", email, 
-    print "</tt> from weather reports about Tor node", node, "</html>"
-    del (unsubscriptions[authstring])
-    gdbm_lock.release()
+        delete_sub ((email, authstring), subscriptions, node)
+        #subscriptions[node].remove((email,authstring))
+        print "<html>Succesfully unsubscribed <tt>", email, 
+        print "</tt> from weather reports about Tor node", node, "</html>"
+        del (unsubscriptions[authstring])
 
+    finally:
+        safeRelease(gdbm_lock)
+
 class AntispamRelaxer(threading.Thread):
   "Prevent long term accretion of antispam counts."
   timescale = 24 * 3600          # sleep for up to a day



More information about the tor-commits mailing list