Simplify lock context managers.

This commit is contained in:
Todd Gamblin 2015-09-17 01:05:19 -07:00
parent ccf311c9c6
commit e17ad6a684
10 changed files with 49 additions and 43 deletions

View file

@ -29,13 +29,15 @@
import time import time
import socket import socket
# Default timeout for locks.
DEFAULT_TIMEOUT = 60
class _ReadLockContext(object):
"""Context manager that takes and releases a read lock.
class Read_Lock_Instance(object):
"""
A context manager for getting shared access to the object lock
Arguments are lock and timeout (default 5 minutes) Arguments are lock and timeout (default 5 minutes)
""" """
def __init__(self, lock, timeout=300): def __init__(self, lock, timeout=DEFAULT_TIMEOUT):
self._lock = lock self._lock = lock
self._timeout = timeout self._timeout = timeout
@ -46,12 +48,12 @@ def __exit__(self,type,value,traceback):
self._lock.release_read() self._lock.release_read()
class Write_Lock_Instance(object): class _WriteLockContext(object):
""" """Context manager that takes and releases a write lock.
A context manager for getting exclusive access to the object lock
Arguments are lock and timeout (default 5 minutes) Arguments are lock and timeout (default 5 minutes)
""" """
def __init__(self, lock, timeout=300): def __init__(self, lock, timeout=DEFAULT_TIMEOUT):
self._lock = lock self._lock = lock
self._timeout = timeout self._timeout = timeout
@ -72,7 +74,17 @@ def __init__(self, file_path):
self._writes = 0 self._writes = 0
def acquire_read(self,timeout): def write_lock(self, timeout=DEFAULT_TIMEOUT):
"""Convenience method that returns a write lock context."""
return _WriteLockContext(self, timeout)
def read_lock(self, timeout=DEFAULT_TIMEOUT):
"""Convenience method that returns a read lock context."""
return _ReadLockContext(self, timeout)
def acquire_read(self, timeout):
""" """
Implements recursive lock. If held in both read and write mode, Implements recursive lock. If held in both read and write mode,
the write lock will be maintained until all locks are released the write lock will be maintained until all locks are released

View file

@ -28,7 +28,6 @@
import llnl.util.tty as tty import llnl.util.tty as tty
from llnl.util.lang import attr_setdefault from llnl.util.lang import attr_setdefault
from llnl.util.lock import *
import spack import spack
import spack.spec import spack.spec
@ -125,7 +124,7 @@ def elide_list(line_list, max_num=10):
def disambiguate_spec(spec): def disambiguate_spec(spec):
with Read_Lock_Instance(spack.installed_db.lock,1800): with spack.installed_db.read_lock():
matching_specs = spack.installed_db.get_installed(spec) matching_specs = spack.installed_db.get_installed(spec)
if not matching_specs: if not matching_specs:
tty.die("Spec '%s' matches no installed packages." % spec) tty.die("Spec '%s' matches no installed packages." % spec)

View file

@ -24,7 +24,6 @@
############################################################################## ##############################################################################
from external import argparse from external import argparse
import llnl.util.tty as tty import llnl.util.tty as tty
from llnl.util.lock import *
import spack import spack
import spack.cmd import spack.cmd
@ -55,7 +54,7 @@ def deactivate(parser, args):
if args.all: if args.all:
if pkg.extendable: if pkg.extendable:
tty.msg("Deactivating all extensions of %s" % pkg.spec.short_spec) tty.msg("Deactivating all extensions of %s" % pkg.spec.short_spec)
with Read_Lock_Instance(spack.installed_db.lock,1800): with spack.installed_db.read_lock():
ext_pkgs = spack.installed_db.installed_extensions_for(spec) ext_pkgs = spack.installed_db.installed_extensions_for(spec)
for ext_pkg in ext_pkgs: for ext_pkg in ext_pkgs:

View file

@ -27,7 +27,6 @@
from external import argparse from external import argparse
import llnl.util.tty as tty import llnl.util.tty as tty
from llnl.util.lock import *
import spack import spack
import spack.cmd import spack.cmd
@ -55,7 +54,7 @@ def diy(self, args):
if not args.spec: if not args.spec:
tty.die("spack diy requires a package spec argument.") tty.die("spack diy requires a package spec argument.")
with Write_Lock_Instance(spack.installed_db.lock,1800): with spack.installed_db.write_lock():
specs = spack.cmd.parse_specs(args.spec) specs = spack.cmd.parse_specs(args.spec)
if len(specs) > 1: if len(specs) > 1:
tty.die("spack diy only takes one spec.") tty.die("spack diy only takes one spec.")

View file

@ -27,7 +27,6 @@
import llnl.util.tty as tty import llnl.util.tty as tty
from llnl.util.tty.colify import colify from llnl.util.tty.colify import colify
from llnl.util.lock import *
import spack import spack
import spack.cmd import spack.cmd
@ -81,7 +80,7 @@ def extensions(parser, args):
colify(ext.name for ext in extensions) colify(ext.name for ext in extensions)
# List specs of installed extensions. # List specs of installed extensions.
with Read_Lock_Instance(spack.installed_db.lock,1800): with spack.installed_db.read_lock():
installed = [s.spec for s in spack.installed_db.installed_extensions_for(spec)] installed = [s.spec for s in spack.installed_db.installed_extensions_for(spec)]
print print
if not installed: if not installed:

View file

@ -32,7 +32,6 @@
from llnl.util.tty.colify import * from llnl.util.tty.colify import *
from llnl.util.tty.color import * from llnl.util.tty.color import *
from llnl.util.lang import * from llnl.util.lang import *
from llnl.util.lock import *
import spack import spack
import spack.spec import spack.spec
@ -139,11 +138,11 @@ def find(parser, args):
# Get all the specs the user asked for # Get all the specs the user asked for
if not query_specs: if not query_specs:
with Read_Lock_Instance(spack.installed_db.lock, 1800): with spack.installed_db.read_lock():
specs = set(spack.installed_db.installed_package_specs()) specs = set(spack.installed_db.installed_package_specs())
else: else:
with Read_Lock_Instance(spack.installed_db.lock, 1800): with spack.installed_db.read_lock():
results = [set(spack.installed_db.get_installed(qs)) for qs in query_specs] results = [set(spack.installed_db.get_installed(qs)) for qs in query_specs]
specs = set.union(*results) specs = set.union(*results)

View file

@ -1,5 +1,5 @@
############################################################################## ##############################################################################
# Copyright (c) 2013, Lawrence Livermore National Security, LLC. # Copyright (c) 2013-2015, Lawrence Livermore National Security, LLC.
# Produced at the Lawrence Livermore National Laboratory. # Produced at the Lawrence Livermore National Laboratory.
# #
# This file is part of Spack. # This file is part of Spack.
@ -23,21 +23,10 @@
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
############################################################################## ##############################################################################
from external import argparse from external import argparse
from llnl.util.lock import *
import spack import spack
import os
description = "Correct database irregularities" description = "Correct database irregularities"
#Very basic version of spack fsck # Very basic version of spack fsck
def fsck(parser, args): def fsck(parser, args):
with Write_Lock_Instance(spack.installed_db.lock,1800): spack.installed_db.reindex(spack.install_layout)
#remove database file
if os.path.exists(spack.installed_db._file_path):
os.remove(spack.installed_db._file_path)
#read database
spack.installed_db.read_database()
#write database
spack.installed_db.write()

View file

@ -25,7 +25,6 @@
from external import argparse from external import argparse
import llnl.util.tty as tty import llnl.util.tty as tty
from llnl.util.lock import *
import spack import spack
import spack.cmd import spack.cmd
@ -69,7 +68,7 @@ def install(parser, args):
if args.no_checksum: if args.no_checksum:
spack.do_checksum = False # TODO: remove this global. spack.do_checksum = False # TODO: remove this global.
with Write_Lock_Instance(spack.installed_db.lock,1800): with spack.installed_db.write_lock():
specs = spack.cmd.parse_specs(args.packages, concretize=True) specs = spack.cmd.parse_specs(args.packages, concretize=True)
for spec in specs: for spec in specs:
package = spack.db.get(spec) package = spack.db.get(spec)

View file

@ -27,7 +27,6 @@
import llnl.util.tty as tty import llnl.util.tty as tty
from llnl.util.tty.colify import colify from llnl.util.tty.colify import colify
from llnl.util.lock import *
import spack import spack
import spack.cmd import spack.cmd
@ -54,7 +53,7 @@ def uninstall(parser, args):
if not args.packages: if not args.packages:
tty.die("uninstall requires at least one package argument.") tty.die("uninstall requires at least one package argument.")
with Write_Lock_Instance(spack.installed_db.lock,1800): with spack.installed_db.write_lock():
specs = spack.cmd.parse_specs(args.packages) specs = spack.cmd.parse_specs(args.packages)
# For each spec provided, make sure it refers to only one package. # For each spec provided, make sure it refers to only one package.

View file

@ -24,13 +24,14 @@
############################################################################## ##############################################################################
import os import os
import time import time
import socket
from external import yaml from external import yaml
from external.yaml.error import MarkedYAMLError, YAMLError from external.yaml.error import MarkedYAMLError, YAMLError
import llnl.util.tty as tty import llnl.util.tty as tty
from llnl.util.filesystem import * from llnl.util.filesystem import *
from llnl.util.lock import * from llnl.util.lock import Lock
import spack.spec import spack.spec
from spack.version import Version from spack.version import Version
@ -99,6 +100,16 @@ def __init__(self, root):
self._last_write_time = 0 self._last_write_time = 0
def write_lock(self):
"""Get a write lock context for use in a `with` block."""
return self.lock.write_lock()
def read_lock(self):
"""Get a read lock context for use in a `with` block."""
return self.lock.read_lock()
def _write_to_yaml(self, stream): def _write_to_yaml(self, stream):
"""Write out the databsae to a YAML file.""" """Write out the databsae to a YAML file."""
# map from per-spec hash code to installation record. # map from per-spec hash code to installation record.
@ -198,13 +209,14 @@ def check(cond, msg):
def reindex(self, directory_layout): def reindex(self, directory_layout):
"""Build database index from scratch based from a directory layout.""" """Build database index from scratch based from a directory layout."""
with Write_Lock_Instance(self.lock, 60): with self.write_lock():
data = {} data = {}
for spec in directory_layout.all_specs(): for spec in directory_layout.all_specs():
path = directory_layout.path_for_spec(spec) path = directory_layout.path_for_spec(spec)
hash_key = spec.dag_hash() hash_key = spec.dag_hash()
data[hash_key] = InstallRecord(spec, path) data[hash_key] = InstallRecord(spec, path)
self._data = data self._data = data
self.write() self.write()
@ -264,7 +276,7 @@ def add(self, spec, path):
Write the database back to memory Write the database back to memory
""" """
# Should always already be locked # Should always already be locked
with Write_Lock_Instance(self.lock, 60): with self.write_lock():
self.read() self.read()
self._data[spec.dag_hash()] = InstallRecord(spec, path) self._data[spec.dag_hash()] = InstallRecord(spec, path)
self.write() self.write()
@ -278,7 +290,7 @@ def remove(self, spec):
Writes the database back to memory Writes the database back to memory
""" """
# Should always already be locked # Should always already be locked
with Write_Lock_Instance(self.lock, 60): with self.write_lock():
self.read() self.read()
hash_key = spec.dag_hash() hash_key = spec.dag_hash()
if hash_key in self._data: if hash_key in self._data:
@ -314,7 +326,7 @@ def installed_package_specs(self):
and return their specs and return their specs
""" """
# Should always already be locked # Should always already be locked
with Read_Lock_Instance(self.lock, 60): with self.read_lock():
self.read() self.read()
return sorted(rec.spec for rec in self._data.values()) return sorted(rec.spec for rec in self._data.values())