2to3 -f has_key
[sfa.git] / sfa / util / callids.py
1 #!/usr/bin/python
2
3 import threading
4 import time
5
6 from sfa.util.sfalogging import logger
7
8 """
9 Callids: a simple mechanism to remember the call ids served so fas
10 memory-only for now - thread-safe
11 implemented as a (singleton) hash 'callid'->timestamp
12 """
13
14 debug=False
15
16 class _call_ids_impl (dict):
17
18     _instance = None
19     # 5 minutes sounds amply enough
20     purge_timeout=5*60
21     # when trying to get a lock
22     retries=10
23     # in ms
24     wait_ms=100
25
26     def __init__(self): 
27         self._lock=threading.Lock()
28
29     # the only primitive
30     # return True if the callid is unknown, False otherwise
31     def already_handled (self,call_id):
32         # if not provided in the call...
33         if not call_id: return False
34         has_lock=False
35         for attempt in range(_call_ids_impl.retries):
36             if debug: logger.debug("Waiting for lock (%d)"%attempt)
37             if self._lock.acquire(False): 
38                 has_lock=True
39                 if debug: logger.debug("got lock (%d)"%attempt)
40                 break
41             time.sleep(float(_call_ids_impl.wait_ms)/1000)
42         # in the unlikely event where we can't get the lock
43         if not has_lock:
44             logger.warning("_call_ids_impl.should_handle_call_id: could not acquire lock")
45             return False
46         # we're good to go
47         if call_id in self:
48             self._purge()
49             self._lock.release()
50             return True
51         self[call_id]=time.time()
52         self._purge()
53         self._lock.release()
54         if debug: logger.debug("released lock")
55         return False
56         
57     def _purge(self):
58         now=time.time()
59         o_keys=[]
60         for (k,v) in self.iteritems():
61             if (now-v) >= _call_ids_impl.purge_timeout: o_keys.append(k)
62         for k in o_keys: 
63             if debug: logger.debug("Purging call_id %r (%s)"%(k,time.strftime("%H:%M:%S",time.localtime(self[k]))))
64             del self[k]
65         if debug:
66             logger.debug("AFTER PURGE")
67             for (k,v) in self.iteritems(): logger.debug("%s -> %s"%(k,time.strftime("%H:%M:%S",time.localtime(v))))
68         
69 def Callids ():
70     if not _call_ids_impl._instance:
71         _call_ids_impl._instance = _call_ids_impl()
72     return _call_ids_impl._instance