Changeset 793


Ignore:
Timestamp:
Jul 30, 2008, 9:50:42 PM (16 years ago)
Author:
y_z
Message:

added shared/exclusive locking; added shared locking of initial JSON cache read

Location:
trunk/packages/sipb-xen-base/files/usr/share/python-support/sipb-xen-base/invirt
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/packages/sipb-xen-base/files/usr/share/python-support/sipb-xen-base/invirt/common.py

    r790 r793  
    4040    return wrapper
    4141
    42 def with_lock_file(path):
     42def with_lock_file(path, exclusive = True):
    4343    """
    4444    Context manager for lock files.  Example:
     
    5454        @with_closing(file(path, 'w'))
    5555        def g(f):
    56             flock(f, LOCK_EX)
     56            if exclusive: locktype = LOCK_EX
     57            else:         locktype = LOCK_SH
     58            flock(f, locktype)
    5759            try: return func()
    5860            finally: flock(f, LOCK_UN)
  • trunk/packages/sipb-xen-base/files/usr/share/python-support/sipb-xen-base/invirt/config.py

    r792 r793  
    55default_src_path   = '/etc/invirt/master.yaml'
    66default_cache_path = '/var/lib/invirt/cache.json'
     7lock_file          = '/var/lib/invirt/cache.lock'
    78
    89def load(src_path = default_src_path,
     
    1516    I assume I have the permissions to write to the cache directory.
    1617    """
     18    # Namespace container for various state variables, so that they can be
     19    # updated by closures.
     20    ns = struct()
     21
    1722    if force_refresh:
    18         do_refresh = True
     23        ns.do_refresh = True
    1924    else:
    2025        src_mtime = getmtime(src_path)
    21         try:            cache_mtime = getmtime(cache_path)
    22         except OSError: do_refresh = True
    23         else:           do_refresh = src_mtime > cache_mtime
     26        try:            cache_mtime   = getmtime(cache_path)
     27        except OSError: ns.do_refresh = True
     28        else:           ns.do_refresh = src_mtime > cache_mtime
    2429
    25     if not do_refresh:
    26         # try reading from the cache first
    27         try: cfg = with_closing(file(cache_path))(lambda f: json.read(f.read()))
    28         except: do_refresh = True
     30    if not ns.do_refresh:
     31        # Try reading from the cache first.  This must be transactionally
     32        # isolated from concurrent writes to prevent reading an incomplete
     33        # (changing) version of the data (but the transaction can share the
     34        # lock with other concurrent reads).
     35        @with_lock_file(lock_file, False)
     36        def read_cache():
     37            try: ns.cfg = with_closing(file(cache_path))(lambda f: json.read(f.read()))
     38            except: ns.do_refresh = True
    2939
    30     if do_refresh:
     40    if ns.do_refresh:
    3141        # Atomically reload the source and regenerate the cache.  The read and
    3242        # write must be a single transaction, or a stale version may be
    3343        # written.
    34         @with_lock_file('/var/lib/invirt/cache.lock')
    35         def cfg():
     44        @with_lock_file(lock_file)
     45        def refresh_cache():
    3646            import yaml
    3747            try:    default_loader = yaml.CSafeLoader
    3848            except: default_loader = yaml.SafeLoader
    39             cfg = with_closing(file(src_path))(lambda f: yaml.load(f, default_loader))
    40             try: with_closing(file(cache_path, 'w'))(lambda f: f.write(json.write(cfg)))
     49            ns.cfg = with_closing(file(src_path))(lambda f: yaml.load(f, default_loader))
     50            try: with_closing(file(cache_path, 'w'))(lambda f: f.write(json.write(ns.cfg)))
    4151            except: pass # silent failure
    42             return cfg
    43     return cfg
     52    return ns.cfg
    4453
    4554dicts = load()
Note: See TracChangeset for help on using the changeset viewer.