[Zope-CVS] CVS: Products/AdaptableStorage/gateway_fs - ShortLivedCache.py:1.1 FSConnection.py:1.12
Shane Hathaway
shane@zope.com
Wed, 5 Feb 2003 10:08:04 -0500
Update of /cvs-repository/Products/AdaptableStorage/gateway_fs
In directory cvs.zope.org:/tmp/cvs-serv13924/gateway_fs
Modified Files:
FSConnection.py
Added Files:
ShortLivedCache.py
Log Message:
Added short-lived caching (1 second) to FSConnection to offset the cost of
property files and automatic filename extensions.
=== Added File Products/AdaptableStorage/gateway_fs/ShortLivedCache.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Simple short-lived object cache.
$Id: ShortLivedCache.py,v 1.1 2003/02/05 15:08:01 shane Exp $
"""
from time import time
class ShortLivedCache:
def __init__(self, lifetime=1):
# The default lifetime is 1 second.
self.lifetime = lifetime
self.data = {}
self.expiration = time() + lifetime
def get(self, key, default=None):
now = time()
if now >= self.expiration:
self.data.clear()
return default
res = self.data.get(key, default)
return res
def set(self, key, value):
now = time()
if now >= self.expiration:
self.data.clear()
self.expiration = now + self.lifetime
self.data[key] = value
def invalidate(self, key):
try:
del self.data[key]
except KeyError:
pass
def clear(self):
self.data.clear()
=== Products/AdaptableStorage/gateway_fs/FSConnection.py 1.11 => 1.12 ===
--- Products/AdaptableStorage/gateway_fs/FSConnection.py:1.11 Tue Feb 4 23:59:16 2003
+++ Products/AdaptableStorage/gateway_fs/FSConnection.py Wed Feb 5 10:08:01 2003
@@ -24,6 +24,7 @@
from interfaces.public import IFSConnection
from exceptions import FSWriteError
from mapper_public import ITPCConnection, NoStateFoundError
+from ShortLivedCache import ShortLivedCache
# Try to decipher this regular expression ;-)
@@ -59,6 +60,8 @@
# _pending holds the data to be written.
# _pending: { subpath string -> { section_name -> data } }
self._pending = {}
+ self._props_cache = ShortLivedCache()
+ self._dir_cache = ShortLivedCache()
def computeDirectoryContents(self, path, ignore_error=0):
@@ -66,6 +69,10 @@
Returns (filenames, object_names, translations).
"""
+ res = self._dir_cache.get(path)
+ if res is not None:
+ return res
+
filenames = []
obj_names = []
trans = {} # { base name -> filename with extension or None }
@@ -73,7 +80,7 @@
fns = os.listdir(path)
except OSError:
if ignore_error:
- return filenames, obj_names, trans
+ return (filenames, obj_names, trans)
hidden_filename_prefix = self.hidden_filename_prefix
for fn in fns:
if fn.startswith(hidden_filename_prefix):
@@ -100,7 +107,10 @@
if '.' in obj_name:
base, ext = obj_name.split('.', 1)
trans[base] = None
- return filenames, obj_names, trans
+
+ res = (filenames, obj_names, trans)
+ self._dir_cache.set(path, res)
+ return res
def listDirectoryAsMapping(self, path, ignore_error=0):
@@ -136,7 +146,6 @@
dir_path, obj_name = os.path.split(path)
if '.' not in obj_name:
# This object might have an automatic filename extension.
- # XXX This is expensive.
filenames, obj_names, trans = self.computeDirectoryContents(
dir_path, 1)
fn = trans.get(obj_name)
@@ -222,13 +231,19 @@
def getPropertiesFromFile(self, path):
"""Reads a properties file next to path."""
+ res = self._props_cache.get(path)
+ if res is not None:
+ return res
+
props_fn = self.getPropertiesPath(path)
try:
f = open(props_fn, 'rb')
except IOError:
# The file is presumably nonexistent
- return {}
+ res = {}
+ self._props_cache.set(path, res)
+ return res
try:
data = f.read()
finally:
@@ -252,6 +267,7 @@
prev_section_name = match.group(1)
pos = match.end()
+ self._props_cache.set(path, res)
return res
@@ -291,6 +307,7 @@
writeSection(props_f, OBJECT_NAMES_SECTION,
'\n'.join(data))
self.disableConflictingExtensions(subpath, data)
+ self._dir_cache.invalidate(path)
else:
# Change the file contents.
f = open(path, 'wb')
@@ -305,6 +322,9 @@
writeSection(props_f, name, data)
finally:
props_f.close()
+ self._props_cache.invalidate(path)
+ # The file might be new, so invalidate the directory.
+ self._dir_cache.invalidate(os.path.dirname(path))
def removeUnlinkedItems(self, path, names):
@@ -344,8 +364,7 @@
subpath = subpath[:-1]
for obj_name in obj_names:
if reserved.has_key(obj_name):
- # obj_name has no extension and must not have an
- # automatic extension.
+ # Prevent obj_name from using an automatic extension.
child_subpath = '%s/%s' % (subpath, obj_name)
self.queue(child_subpath, SUGGESTED_EXTENSION_SECTION,
'', force=1)
@@ -429,7 +448,8 @@
os.makedirs(self.basepath)
def begin(self):
- pass
+ self._props_cache.clear()
+ self._dir_cache.clear()
def vote(self):
"""Do some early verification
@@ -444,6 +464,8 @@
def reset(self):
self._final = 0
self._pending.clear()
+ self._props_cache.clear()
+ self._dir_cache.clear()
def abort(self):
self.reset()