Ticket #13826: trac_13826_star_imports_race.patch

File trac_13826_star_imports_race.patch, 3.7 KB (added by vbraun, 9 years ago)

Updated patch

  • sage/all.py

    # HG changeset patch
    # User Volker Braun <vbraun.name@gmail.com>
    # Date 1355406608 0
    # Node ID 78217505d51142f6085fe59f55279a9f8685cd5f
    # Parent  00b3012077ca50e517bc175c0a568ad1c8b4ae4f
    Fix race condition when moving the star import cache
    
    diff --git a/sage/all.py b/sage/all.py
    a b  
    6363
    6464from time                import sleep
    6565
     66import sage.misc.lazy_import
    6667from sage.misc.all       import *         # takes a while
    6768
    6869from sage.misc.sh import sh
     
    138139from sage.ext.fast_callable  import fast_callable
    139140from sage.ext.fast_eval      import fast_float
    140141
    141 from sage.sandpiles.all import *
     142sage.misc.lazy_import.lazy_import('sage.sandpiles.all', '*', globals())
    142143
    143144from sage.tensor.all     import *
    144145
     
    291292#sage.structure.sage_object.register_unpickle_override('sage.categories.category_types', '', )
    292293
    293294# Cache the contents of star imports.
    294 import sage.misc.lazy_import
    295295sage.misc.lazy_import.save_cache_file()
    296296
    297297
  • sage/misc/lazy_import.pyx

    diff --git a/sage/misc/lazy_import.pyx b/sage/misc/lazy_import.pyx
    a b  
    3939cdef extern from *:
    4040    cdef int Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE
    4141
    42 import os, shutil, tempfile, cPickle as pickle, operator
     42import os, tempfile, cPickle as pickle, operator
    4343import inspect
    4444import sageinspect
    4545
     
    869869    global star_imports
    870870    if star_imports is None:
    871871        star_imports = {}
    872     _, tmp_file = tempfile.mkstemp()
    873     pickle.dump(star_imports, open(tmp_file, "w"))
    874     cache_dir = os.path.dirname(get_cache_file())
     872    cache_file = get_cache_file()
     873    cache_dir = os.path.dirname(cache_file)
    875874    try:
    876875        os.makedirs(cache_dir)
    877876    except OSError:
    878         # Probably failed because directory already exists, but we make sure.
    879         if not os.path.isdir(cache_dir):
     877        if not os.path.isdir(cache_dir):
    880878            raise
    881     shutil.move(tmp_file, get_cache_file())
     879    try:
     880        os.unlink(cache_file)
     881    except OSError:
     882        pass   # cache_file does not exist, fine
     883    # important: create temp dir in cache_dir (trac #13826) to move atomically
     884    _, tmp_file = tempfile.mkstemp(dir=cache_dir)
     885    with open(tmp_file, "w") as tmp:
     886        pickle.dump(star_imports, tmp)
     887    try:
     888        os.rename(tmp_file, cache_file)
     889    except OSError:
     890        pass   # Windows can end up here, ignore
    882891
    883892def get_star_imports(module_name):
    884893    """
     
    892901        True
    893902        sage: 'EllipticCurve' in get_star_imports('sage.schemes.all')
    894903        True
     904
     905    TESTS::
     906
     907        sage: import os, tempfile
     908        sage: fd, cache_file = tempfile.mkstemp()
     909        sage: os.write(fd, 'invalid')
     910        7
     911        sage: os.close(fd)
     912        sage: import sage.misc.lazy_import as lazy
     913        sage: lazy.get_cache_file = (lambda: cache_file)
     914        sage: lazy.star_imports = None
     915        sage: lazy.get_star_imports('sage.schemes.all')
     916        doctest:...: UserWarning: star_imports cache is corrupted
     917        [...]
     918        sage: os.remove(cache_file)
    895919    """
    896920    global star_imports
    897921    if star_imports is None:
    898         cache_file = get_cache_file()
    899         if os.path.exists(cache_file):
    900             star_imports = pickle.load(open(cache_file))
    901         else:
    902             star_imports = {}
     922        try:
     923            with open(get_cache_file()) as cache_file:
     924                star_imports = pickle.load(cache_file)
     925        except IOError:        # file does not exist
     926            pass
     927        except Exception:  # unpickling failed
     928            import warnings
     929            warnings.warn('star_imports cache is corrupted')
     930        star_imports = {}
    903931    try:
    904932        return star_imports[module_name]
    905933    except KeyError: