mirror of https://github.com/python/cpython.git
SF bug #130306: statcache.py full of thread problems.
Fixed the thread races. Function forget_dir was also utterly Unix-specific.
This commit is contained in:
parent
64d42c5bb1
commit
0149e84af2
|
@ -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 != '/':
|
|
||||||
prefix = prefix[:-1]
|
|
||||||
forget(prefix)
|
|
||||||
if prefix[-1:] != '/':
|
|
||||||
prefix = prefix + '/'
|
|
||||||
n = len(prefix)
|
|
||||||
for path in cache.keys():
|
|
||||||
if path[:n] == prefix:
|
|
||||||
rest = path[n:]
|
|
||||||
if rest[-1:] == '/': rest = rest[:-1]
|
|
||||||
if '/' not in rest:
|
|
||||||
del cache[path]
|
|
||||||
|
|
||||||
|
# Remove trailing separator, if any. This is tricky to do in a
|
||||||
|
# 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)
|
||||||
|
for path in cache.keys():
|
||||||
|
# First check that the path at least starts with the prefix, so
|
||||||
|
# that when it doesn't we can avoid paying for split().
|
||||||
|
if path.startswith(prefix) and split(path)[0] == prefix:
|
||||||
|
forget(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])
|
||||||
|
|
Loading…
Reference in New Issue