Kaydet (Commit) 0149e84a authored tarafından Tim Peters's avatar Tim Peters

SF bug #130306: statcache.py full of thread problems.

Fixed the thread races.  Function forget_dir was also utterly Unix-specific.
üst 64d42c5b
...@@ -3,73 +3,72 @@ ...@@ -3,73 +3,72 @@
There are functions to reset the cache or to selectively remove items. There are functions to reset the cache or to selectively remove items.
""" """
import os import os as _os
from stat import * from stat import *
# The cache. # The cache. Keys are pathnames, values are os.stat outcomes.
# Keys are pathnames, values are `os.stat' outcomes. # Remember that multiple threads may be calling this! So, e.g., that
# # cache.has_key(path) returns 1 doesn't mean the cache will still contain
cache = {} # path on the next line. Code defensively.
cache = {}
def stat(path): def stat(path):
"""Stat a file, possibly out of the cache.""" """Stat a file, possibly out of the cache."""
if cache.has_key(path): ret = cache.get(path, None)
return cache[path] if ret is None:
cache[path] = ret = os.stat(path) cache[path] = ret = _os.stat(path)
return ret return ret
def reset(): def reset():
"""Reset the cache completely.""" """Clear the cache."""
global cache cache.clear()
cache = {}
# For thread saftey, always use forget() internally too.
def forget(path): def forget(path):
"""Remove a given item from the cache, if it exists.""" """Remove a given item from the cache, if it exists."""
if cache.has_key(path): try:
del cache[path] del cache[path]
except KeyError:
pass
def forget_prefix(prefix): def forget_prefix(prefix):
"""Remove all pathnames with a given prefix.""" """Remove all pathnames with a given prefix."""
n = len(prefix)
for path in cache.keys(): for path in cache.keys():
if path[:n] == prefix: if path.startswith(prefix):
del cache[path] forget(path)
def forget_dir(prefix): def forget_dir(prefix):
"""Forget about a directory and all entries in it, but not about """Forget a directory and all entries except for entries in subdirs."""
entries in subdirectories."""
if prefix[-1:] == '/' and prefix != '/': # Remove trailing separator, if any. This is tricky to do in a
prefix = prefix[:-1] # x-platform way. For example, Windows accepts both / and \ as
# separators, and if there's nothing *but* a separator we want to
# preserve that this is the root. Only os.path has the platform
# knowledge we need.
from os.path import split, join
prefix = split(join(prefix, "xxx"))[0]
forget(prefix) forget(prefix)
if prefix[-1:] != '/':
prefix = prefix + '/'
n = len(prefix)
for path in cache.keys(): for path in cache.keys():
if path[:n] == prefix: # First check that the path at least starts with the prefix, so
rest = path[n:] # that when it doesn't we can avoid paying for split().
if rest[-1:] == '/': rest = rest[:-1] if path.startswith(prefix) and split(path)[0] == prefix:
if '/' not in rest: forget(path)
del cache[path]
def forget_except_prefix(prefix): def forget_except_prefix(prefix):
"""Remove all pathnames except with a given prefix. """Remove all pathnames except with a given prefix.
Normally used with prefix = '/' after a chdir()."""
n = len(prefix)
for path in cache.keys():
if path[:n] != prefix:
del cache[path]
Normally used with prefix = '/' after a chdir().
"""
for path in cache.keys():
if not path.startswith(prefix):
forget(path)
def isdir(path): def isdir(path):
"""Check for directory.""" """Return 1 if directory, else 0."""
try: try:
st = stat(path) st = stat(path)
except os.error: except _os.error:
return 0 return 0
return S_ISDIR(st[ST_MODE]) return S_ISDIR(st[ST_MODE])
...@@ -197,6 +197,7 @@ Andreas Jung ...@@ -197,6 +197,7 @@ Andreas Jung
Bob Kahn Bob Kahn
Tamito Kajiyama Tamito Kajiyama
Lou Kates Lou Kates
Randall Kern
Magnus Kessler Magnus Kessler
Lawrence Kesteloot Lawrence Kesteloot
Vivek Khera Vivek Khera
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment