From 365263addd08cf302dee0477c019a6193a617d00 Mon Sep 17 00:00:00 2001 From: Jay Hutchinson Date: Wed, 25 Aug 2010 03:31:21 -0500 Subject: Finished adding optional cache write-back semantics. --- lru.py | 44 ++++++++++++++++++++++++-------------------- test.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/lru.py b/lru.py index f14ebf7..09225d2 100644 --- a/lru.py +++ b/lru.py @@ -67,12 +67,8 @@ class lrucache(object): def __len__(self): return len(self.table) + # Does not call callback to write any changes! def clear(self): - if self.callback: - for key in self.table: - node = self.table[key] - self.callback(node.key, node.obj) - self.table.clear() node = self.head @@ -80,11 +76,16 @@ class lrucache(object): node.key = None node.obj = None node = node.next + def __contains__(self, key): return key in self.table # XXX Should this move the object to front of list? XXX + def peek(self, key): + # Look up the node + node = self.table[key] + return node.obj def __getitem__(self, key): @@ -258,30 +259,32 @@ class lrucache(object): -# Wrapper using write-through semantics class lruwrap(object): def __init__(self, store, size, writethrough=True): + self.store = store self.writethrough = writethrough if self.writethrough: self.cache = lrucache(size) else: - self.cache = lrucache(size, self.ejectCallBack) self.dirty = set() - - self.store = store - - + def callback(key, value): + if key in self.dirty: + self.store[key] = value + self.dirty.remove(key) + self.cache = lrucache(size, callback) def __len__(self): - # XXX We could cache the size return len(self.store) + def size(self, size=None): + self.cache.size(size) + def clear(self): self.cache.clear() - if self.writethrough: # XXX Remove this test XXX - assert len(self.dirty) == 0 self.store.clear() + if not self.writethrough: + self.dirty.clear() def __contains__(self, key): # XXX Should this bring the key/value into the cache? @@ -317,15 +320,16 @@ class lruwrap(object): pass del self.store[key] - def ejectCallback(self, key, value): - if key in self.dirty: - self.store[key] = value - self.dirty.remove(key) + + def sync(self): + if not self.writethrough: + for key in self.dirty: + value = self.cache.peek(key) # Doesn't change the cache's order + self.store[key] = value + self.dirty.clear() def __del__(self): - # Flush the dirty objects self.sync() - class lrudecorator(object): diff --git a/test.py b/test.py index 1c0a94d..6b9b1b2 100644 --- a/test.py +++ b/test.py @@ -123,6 +123,35 @@ def wraptest(): assert tmp1 == tmp2 +def wraptest2(): + import random + + q = dict() + x = lruwrap(q, 32, False) + for i in range(256): + a = random.randint(0, 256) + b = random.randint(0, 256) + + x[a] = b + + x.sync() + for i in range(512): + a = random.randint(0, 256) + tmp1 = None + tmp2 = None + try: + tmp1 = x[a] + except KeyError: + tmp1 = None + + try: + tmp2 = q[a] + except KeyError: + tmp2 = None + + assert tmp1 == tmp2 + + @lrudecorator(14) def cube(x): return x*x*x @@ -131,6 +160,7 @@ if __name__ == '__main__': import random wraptest() + wraptest2() for i in range(300): x = random.randint(0, 25) -- cgit v1.2.1