summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--giscanner/cachestore.py26
2 files changed, 27 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index b5d6ba3c..ba52604a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2008-12-08 Johan Dahlin <johan@async.com.br>
+
+ * giscanner/cachestore.py (CacheStore.store): Dump the cache
+ file to a temporary file and rename it the expected filename
+ only when it's completely written.
+ This should make the cache more roboust when run in parallel,
+ and hopefully avoid triggering bugs in Python.
+
2008-12-03 Christophe Fergeau <teuf@gnome.org>
Bug 562971 – g-ir-scanner failure on libgpod headers
diff --git a/giscanner/cachestore.py b/giscanner/cachestore.py
index 4629e622..d9163464 100644
--- a/giscanner/cachestore.py
+++ b/giscanner/cachestore.py
@@ -18,11 +18,11 @@
# Boston, MA 02111-1307, USA.
#
+import errno
import cPickle
import hashlib
import os
-import errno
-
+import tempfile
def _get_cachedir():
cachedir = os.path.join(os.environ['HOME'], '.cache')
@@ -61,7 +61,7 @@ class CacheStore(object):
return (os.stat(store_filename).st_mtime >=
os.stat(filename).st_mtime)
- def _purge_cache(self, filename):
+ def _remove_filename(filename):
try:
os.unlink(filename)
except IOError, e:
@@ -81,19 +81,31 @@ class CacheStore(object):
store_filename = self._get_filename(filename)
if store_filename is None:
return
+
if (os.path.exists(store_filename) and
self._cache_is_valid(store_filename, filename)):
return None
- fd = open(store_filename, 'w')
+
+ tmp_fd, tmp_filename = tempfile.mkstemp(prefix='g-ir-scanner-cache-')
try:
- cPickle.dump(data, fd)
+ cPickle.dump(data, os.fdopen(tmp_fd, 'w'))
except IOError, e:
# No space left on device
- if e.errno == e.ENOSPC:
+ if e.errno == errno.ENOSPC:
+ self._remove_filename(tmp_filename)
return
else:
raise
+ try:
+ os.rename(tmp_filename, store_filename)
+ except OSError, e:
+ # Permission denied
+ if e.errno == errno.EACCES:
+ self._remove_filename(tmp_filename)
+ else:
+ raise
+
def load(self, filename):
store_filename = self._get_filename(filename)
if store_filename is None:
@@ -111,6 +123,6 @@ class CacheStore(object):
data = cPickle.load(fd)
except (EOFError, ValueError, cPickle.BadPickleGet):
# Broken cache entry, remove it
- self._purge_cache(store_filename)
+ self._remove_filename(store_filename)
data = None
return data