cache-like structure

K

konstantin

Hi,

I've write a class that actually is data structure with items that
automatically removed from collection when timeout expires. Interface
is pretty simple. First public method is to make a record. And second
(__contains__) is to define if record is actually in table. I prefer
async way to clean out expired records. Thus I have to create timeout
thread every cycle to wait for the next clean-up.

So my questions are:
- is the implementation thread-safe (or I've missed something)
- is there way to avoid creating new timer every cycle
- are there better ways to do this (or any ready recipes)

---
import threading
import time
import collections

class CacheTable(object):
def __init__(self, ttl):
self.records = collections.deque()
self.ttl = ttl
self.timer = None
self.mutex = threading.Lock()

def record(self, item):
self.mutex.acquire()
try:
self.records.append((time.time(), item))
if not self.timer:
self.__settimer(self.ttl)
finally:
self.mutex.release()

def __cleanup(self):
self.mutex.acquire()
try:
current = time.time()
self.timer = None
while self.records:
timestamp, item = self.records.popleft()
if timestamp + self.ttl > current:
self.records.appendleft((timestamp, item))
time_to_wait = timestamp + self.ttl - current
self.__settimer(time_to_wait)
break
finally:
self.mutex.release()

def __settimer(self, timeout):
self.timer = threading.Timer(timeout, self.__cleanup)
self.timer.start()

def __contains__(self, value):
self.mutex.acquire()
try:
items = [item for ts, item in self.records]
return items.__contains__(value)
finally:
self.mutex.release()
 
M

maxime

konstantin said:
Hi, Hi
...
- are there better ways to do this (or any ready recipes)


Did you consider using the shed module (not threaded)?

Cheers,

Maxime
 
M

maxime

Did you consider using the shed module (not threaded)?

Cheers,

Maxime

If you need threading, what i would do is implementing a _remove
method like:
def _remove(self, rec): #try not to use __form, almost always an error
self.records.remove(rec)

the Timer would become
Timer(ttl, self._remove, [(t, item)]) # t is the time that you got
before

And if you change the deque for a Queue.Queue, you don't even need a
Lock...

Cheers,

Maxime
 
K

konstantin

And if you change the deque for a Queue.Queue, you don't even need a
Lock...

Cheers,

Maxime

Maxime,

thanks, sched module could be a nice solution. I've never used it
before
but it seems to be the right way.
You guessed right. I want to used it in Queue. But this implementation
does
not guarantee that __cleanup__ won't be invoked while __contains__
processing.
def _remove(self, rec): #try not to use __form, almost always an error
self.records.remove(rec)

the Timer would become
Timer(ttl, self._remove, [(t, item)]) # t is the time that you got
before

This solution has one shortcoming. When record() called many times
during
short period (almost simultaneously) the _remove(item) calls do not
manage to
remove records on time. So I choosed batch cleanup.

But thanks for suggestion! I'll try sched.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,273
Latest member
DamonShoem

Latest Threads

Top