Skip to content

Commit 3e68156

Browse files
author
Richard Jones
committed
simple LRU cache for SQL databases
1 parent bd24652 commit 3e68156

File tree

1 file changed

+56
-2
lines changed

1 file changed

+56
-2
lines changed

roundup/backends/rdbms_common.py

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $Id: rdbms_common.py,v 1.5 2002-09-19 03:56:20 richard Exp $
1+
# $Id: rdbms_common.py,v 1.6 2002-09-19 05:30:25 richard Exp $
22

33
# standard python modules
44
import sys, os, time, re, errno, weakref, copy
@@ -13,7 +13,16 @@
1313
from roundup.indexer import Indexer
1414
from sessions import Sessions
1515

16+
# number of rows to keep in memory
17+
ROW_CACHE_SIZE = 100
18+
1619
class Database(FileStorage, hyperdb.Database, roundupdb.Database):
20+
''' Wrapper around an SQL database that presents a hyperdb interface.
21+
22+
- some functionality is specific to the actual SQL database, hence
23+
the sql_* methods that are NotImplemented
24+
- we keep a cache of the latest ROW_CACHE_SIZE row fetches.
25+
'''
1726
# flag to set on retired entries
1827
RETIRED_FLAG = '__hyperdb_retired'
1928

@@ -30,6 +39,11 @@ def __init__(self, config, journaltag=None):
3039
# additional transaction support for external files and the like
3140
self.transactions = []
3241

42+
# keep a cache of the N most recently retrieved rows of any kind
43+
# (classname, nodeid) = row
44+
self.cache = {}
45+
self.cache_lru = []
46+
3347
# open a connection to the database, creating the "conn" attribute
3448
self.open_connection()
3549

@@ -453,6 +467,13 @@ def addnode(self, classname, nodeid, node):
453467
if not node.has_key(col):
454468
node[col] = None
455469

470+
# clear this node out of the cache if it's in there
471+
key = (classname, nodeid)
472+
if self.cache.has_key(key):
473+
del self.cache[key]
474+
self.cache_lru.remove(key)
475+
476+
# make the node data safe for the DB
456477
node = self.serialise(classname, node)
457478

458479
# make sure the ordering is correct for column name -> column value
@@ -483,6 +504,13 @@ def setnode(self, classname, nodeid, node, multilink_changes):
483504
'''
484505
if __debug__:
485506
print >>hyperdb.DEBUG, 'setnode', (self, classname, nodeid, node)
507+
508+
# clear this node out of the cache if it's in there
509+
key = (classname, nodeid)
510+
if self.cache.has_key(key):
511+
del self.cache[key]
512+
self.cache_lru.remove(key)
513+
486514
node = self.serialise(classname, node)
487515

488516
cl = self.classes[classname]
@@ -531,6 +559,16 @@ def getnode(self, classname, nodeid):
531559
'''
532560
if __debug__:
533561
print >>hyperdb.DEBUG, 'getnode', (self, classname, nodeid)
562+
563+
# see if we have this node cached
564+
key = (classname, nodeid)
565+
if self.cache.has_key(key):
566+
# push us back to the top of the LRU
567+
self.cache_lru.remove(key)
568+
self.cache_lry.insert(0, key)
569+
# return the cached information
570+
return self.cache[key]
571+
534572
# figure the columns we're fetching
535573
cl = self.classes[classname]
536574
cols, mls = self.determine_columns(cl.properties.items())
@@ -559,7 +597,17 @@ def getnode(self, classname, nodeid):
559597
# extract the first column from the result
560598
node[col] = [x[0] for x in cursor.fetchall()]
561599

562-
return self.unserialise(classname, node)
600+
# un-dbificate the node data
601+
node = self.unserialise(classname, node)
602+
603+
# save off in the cache
604+
key = (classname, nodeid)
605+
self.cache[key] = node
606+
# update the LRU
607+
self.cache_lru.insert(0, key)
608+
del self.cache[self.cache_lru.pop()]
609+
610+
return node
563611

564612
def destroynode(self, classname, nodeid):
565613
'''Remove a node from the database. Called exclusively by the
@@ -572,6 +620,10 @@ def destroynode(self, classname, nodeid):
572620
if not self.hasnode(classname, nodeid):
573621
raise IndexError, '%s has no node %s'%(classname, nodeid)
574622

623+
# see if we have this node cached
624+
if self.cache.has_key((classname, nodeid)):
625+
del self.cache[(classname, nodeid)]
626+
575627
# see if there's any obvious commit actions that we should get rid of
576628
for entry in self.transactions[:]:
577629
if entry[1][:2] == (classname, nodeid):
@@ -1636,6 +1688,8 @@ def filter(self, search_matches, filterspec, sort, group):
16361688
if '-1' in v:
16371689
v.remove('-1')
16381690
xtra = ' or _%s is NULL'%k
1691+
else:
1692+
xtra = ''
16391693
s = ','.join([a for x in v])
16401694
where.append('(_%s in (%s)%s)'%(k, s, xtra))
16411695
args = args + v

0 commit comments

Comments
 (0)