Added conservative locking to the spack commands that access the database at _index

This commit is contained in:
Gregory Becker 2015-09-03 09:21:19 -07:00
parent c3246ee8ba
commit 9c8e46dc22
8 changed files with 105 additions and 87 deletions

View File

@ -28,6 +28,7 @@
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
@ -124,15 +125,16 @@ def elide_list(line_list, max_num=10):
def disambiguate_spec(spec): def disambiguate_spec(spec):
matching_specs = spack.installed_db.get_installed(spec) with Read_Lock_Instance(spack.installed_db.lock,1800):
if not matching_specs: matching_specs = spack.installed_db.get_installed(spec)
tty.die("Spec '%s' matches no installed packages." % spec) if not matching_specs:
tty.die("Spec '%s' matches no installed packages." % spec)
elif len(matching_specs) > 1: elif len(matching_specs) > 1:
args = ["%s matches multiple packages." % spec, args = ["%s matches multiple packages." % spec,
"Matching packages:"] "Matching packages:"]
args += [" " + str(s) for s in matching_specs] args += [" " + str(s) for s in matching_specs]
args += ["Use a more specific spec."] args += ["Use a more specific spec."]
tty.die(*args) tty.die(*args)
return matching_specs[0] return matching_specs[0]

View File

@ -24,6 +24,7 @@
############################################################################## ##############################################################################
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
@ -54,12 +55,13 @@ 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)
ext_pkgs = spack.installed_db.installed_extensions_for(spec) with Read_Lock_Instance(spack.installed_db.lock,1800):
ext_pkgs = spack.installed_db.installed_extensions_for(spec)
for ext_pkg in ext_pkgs: for ext_pkg in ext_pkgs:
ext_pkg.spec.normalize() ext_pkg.spec.normalize()
if ext_pkg.activated: if ext_pkg.activated:
ext_pkg.do_deactivate(force=True) ext_pkg.do_deactivate(force=True)
elif pkg.is_extension: elif pkg.is_extension:
if not args.force and not spec.package.activated: if not args.force and not spec.package.activated:

View File

@ -27,6 +27,7 @@
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
@ -54,40 +55,41 @@ 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.")
specs = spack.cmd.parse_specs(args.spec) with Write_Lock_Instance(spack.installed_db.lock,1800):
if len(specs) > 1: specs = spack.cmd.parse_specs(args.spec)
tty.die("spack diy only takes one spec.") if len(specs) > 1:
tty.die("spack diy only takes one spec.")
spec = specs[0] spec = specs[0]
if not spack.db.exists(spec.name): if not spack.db.exists(spec.name):
tty.warn("No such package: %s" % spec.name) tty.warn("No such package: %s" % spec.name)
create = tty.get_yes_or_no("Create this package?", default=False) create = tty.get_yes_or_no("Create this package?", default=False)
if not create: if not create:
tty.msg("Exiting without creating.") tty.msg("Exiting without creating.")
sys.exit(1)
else:
tty.msg("Running 'spack edit -f %s'" % spec.name)
edit_package(spec.name, True)
return
if not spec.version.concrete:
tty.die("spack diy spec must have a single, concrete version.")
spec.concretize()
package = spack.db.get(spec)
if package.installed:
tty.error("Already installed in %s" % package.prefix)
tty.msg("Uninstall or try adding a version suffix for this DIY build.")
sys.exit(1) sys.exit(1)
else:
tty.msg("Running 'spack edit -f %s'" % spec.name)
edit_package(spec.name, True)
return
if not spec.version.concrete: # Forces the build to run out of the current directory.
tty.die("spack diy spec must have a single, concrete version.") package.stage = DIYStage(os.getcwd())
spec.concretize()
package = spack.db.get(spec)
if package.installed:
tty.error("Already installed in %s" % package.prefix)
tty.msg("Uninstall or try adding a version suffix for this DIY build.")
sys.exit(1)
# Forces the build to run out of the current directory.
package.stage = DIYStage(os.getcwd())
# TODO: make this an argument, not a global. # TODO: make this an argument, not a global.
spack.do_checksum = False spack.do_checksum = False
package.do_install( package.do_install(
keep_prefix=args.keep_prefix, keep_prefix=args.keep_prefix,
ignore_deps=args.ignore_deps, ignore_deps=args.ignore_deps,
keep_stage=True) # don't remove source dir for DIY. keep_stage=True) # don't remove source dir for DIY.

View File

@ -27,6 +27,7 @@
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
@ -80,7 +81,8 @@ 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.
installed = [s.spec for s in spack.installed_db.installed_extensions_for(spec)] with Read_Lock_Instance(spack.installed_db.lock,1800):
installed = [s.spec for s in spack.installed_db.installed_extensions_for(spec)]
print print
if not installed: if not installed:
tty.msg("None installed.") tty.msg("None installed.")

View File

@ -32,6 +32,7 @@
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
@ -138,9 +139,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:
specs = set(spack.installed_db.installed_package_specs()) with Read_Lock_Instance(spack.installed_db.lock,1800):
specs = set(spack.installed_db.installed_package_specs())
else: else:
results = [set(spack.installed_db.get_installed(qs)) for qs in query_specs] with Read_Lock_Instance(spack.installed_db.lock,1800):
results = [set(spack.installed_db.get_installed(qs)) for qs in query_specs]
specs = set.union(*results) specs = set.union(*results)
if not args.mode: if not args.mode:

View File

@ -25,6 +25,7 @@
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
@ -68,13 +69,14 @@ 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.
specs = spack.cmd.parse_specs(args.packages, concretize=True) with Write_Lock_Instance(spack.installed_db.lock,1800):
for spec in specs: specs = spack.cmd.parse_specs(args.packages, concretize=True)
package = spack.db.get(spec) for spec in specs:
package.do_install( package = spack.db.get(spec)
keep_prefix=args.keep_prefix, package.do_install(
keep_stage=args.keep_stage, keep_prefix=args.keep_prefix,
ignore_deps=args.ignore_deps, keep_stage=args.keep_stage,
make_jobs=args.jobs, ignore_deps=args.ignore_deps,
verbose=args.verbose, make_jobs=args.jobs,
fake=args.fake) verbose=args.verbose,
fake=args.fake)

View File

@ -27,6 +27,7 @@
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
@ -53,35 +54,36 @@ 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.")
specs = spack.cmd.parse_specs(args.packages) with Write_Lock_Instance(spack.installed_db.lock,1800):
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.
# Fail and ask user to be unambiguous if it doesn't # Fail and ask user to be unambiguous if it doesn't
pkgs = [] pkgs = []
for spec in specs: for spec in specs:
matching_specs = spack.installed_db.get_installed(spec) matching_specs = spack.installed_db.get_installed(spec)
if not args.all and len(matching_specs) > 1: if not args.all and len(matching_specs) > 1:
tty.error("%s matches multiple packages:" % spec) tty.error("%s matches multiple packages:" % spec)
print print
display_specs(matching_specs, long=True) display_specs(matching_specs, long=True)
print print
print "You can either:" print "You can either:"
print " a) Use a more specific spec, or" print " a) Use a more specific spec, or"
print " b) use spack uninstall -a to uninstall ALL matching specs." print " b) use spack uninstall -a to uninstall ALL matching specs."
sys.exit(1) sys.exit(1)
if len(matching_specs) == 0: if len(matching_specs) == 0:
if args.force: continue if args.force: continue
tty.die("%s does not match any installed packages." % spec) tty.die("%s does not match any installed packages." % spec)
for s in matching_specs: for s in matching_specs:
try: try:
# should work if package is known to spack # should work if package is known to spack
pkgs.append(s.package) pkgs.append(s.package)
except spack.packages.UnknownPackageError, e: except spack.packages.UnknownPackageError, e:
# The package.py file has gone away -- but still want to uninstall. # The package.py file has gone away -- but still want to uninstall.
spack.Package(s).do_uninstall(force=True) spack.Package(s).do_uninstall(force=True)
# Sort packages to be uninstalled by the number of installed dependents # Sort packages to be uninstalled by the number of installed dependents
# This ensures we do things in the right order # This ensures we do things in the right order

View File

@ -158,12 +158,12 @@ def write(self):
within the same lock, so there is no need to refresh within the same lock, so there is no need to refresh
the database within write() the database within write()
""" """
temp_name = os.getpid() + socket.getfqdn() + ".temp" temp_name = str(os.getpid()) + socket.getfqdn() + ".temp"
temp_file = path.join(self._root,temp_name) temp_file = join_path(self._root,temp_name)
with open(self.temp_path,'w') as f: with open(temp_file,'w') as f:
self._last_write_time = int(time.time()) self._last_write_time = int(time.time())
self._write_database_to_yaml(f) self._write_database_to_yaml(f)
os.rename(temp_name,self._file_path) os.rename(temp_file,self._file_path)
def is_dirty(self): def is_dirty(self):
""" """
@ -184,6 +184,7 @@ def add(self, spec, path):
sph['path']=path sph['path']=path
sph['hash']=spec.dag_hash() sph['hash']=spec.dag_hash()
#Should always already be locked
with Write_Lock_Instance(self.lock,60): with Write_Lock_Instance(self.lock,60):
self.read_database() self.read_database()
self._data.append(sph) self._data.append(sph)
@ -197,6 +198,7 @@ def remove(self, spec):
Searches for and removes the specified spec Searches for and removes the specified spec
Writes the database back to memory Writes the database back to memory
""" """
#Should always already be locked
with Write_Lock_Instance(self.lock,60): with Write_Lock_Instance(self.lock,60):
self.read_database() self.read_database()
@ -237,6 +239,7 @@ def installed_package_specs(self):
Read installed package names from the database Read installed package names from the database
and return their specs and return their specs
""" """
#Should always already be locked
with Read_Lock_Instance(self.lock,60): with Read_Lock_Instance(self.lock,60):
self.read_database() self.read_database()