summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJay Hutchinson <jlhutch@gmail.com>2010-08-25 03:31:21 -0500
committerJay Hutchinson <jlhutch@gmail.com>2010-08-25 03:31:21 -0500
commit365263addd08cf302dee0477c019a6193a617d00 (patch)
treee5aabb7b22877ace028c95528b9ae60703aa8d82
parent921882ca647f8c046ccf735deabbf19ae7020b39 (diff)
downloadpylru-365263addd08cf302dee0477c019a6193a617d00.tar.gz
Finished adding optional cache write-back semantics.
-rw-r--r--lru.py44
-rw-r--r--test.py30
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)