summaryrefslogtreecommitdiffstats
path: root/pym/portage/dbapi/_MergeProcess.py
diff options
context:
space:
mode:
authorDavid James <davidjames@google.com>2011-03-24 19:36:33 -0700
committerZac Medico <zmedico@gentoo.org>2011-03-24 19:36:33 -0700
commit7535cabdf2fab76fc55df83643157613dfd66be9 (patch)
tree535e51878faa5359a7c186ca0aadfbe6ebcc02b2 /pym/portage/dbapi/_MergeProcess.py
parent99ec2a8f810ae7ea2c76d928665ed1d02c2d9cc7 (diff)
downloadportage-7535cabdf2fab76fc55df83643157613dfd66be9.tar.gz
portage-7535cabdf2fab76fc55df83643157613dfd66be9.tar.bz2
portage-7535cabdf2fab76fc55df83643157613dfd66be9.zip
Merge packages asynchronously in Portage.
This allows for the scheduler to continue to run while packages are being merged and installed, allowing for additional parallelism and making better use of the CPUs. Review URL: http://codereview.chromium.org/6713043
Diffstat (limited to 'pym/portage/dbapi/_MergeProcess.py')
-rw-r--r--pym/portage/dbapi/_MergeProcess.py82
1 files changed, 69 insertions, 13 deletions
diff --git a/pym/portage/dbapi/_MergeProcess.py b/pym/portage/dbapi/_MergeProcess.py
index f717d12df..6e63f84fd 100644
--- a/pym/portage/dbapi/_MergeProcess.py
+++ b/pym/portage/dbapi/_MergeProcess.py
@@ -4,30 +4,72 @@
import signal
import traceback
+import errno
+import fcntl
import portage
-from portage import os
+from portage import os, StringIO
+import portage.elog.messages
+from _emerge.PollConstants import PollConstants
from _emerge.SpawnProcess import SpawnProcess
class MergeProcess(SpawnProcess):
"""
- Merge package files in a subprocess, so the Scheduler can run in the
- main thread while files are moved or copied asynchronously.
+ Merge packages in a subprocess, so the Scheduler can run in the main
+ thread while files are moved or copied asynchronously.
"""
- __slots__ = ('cfgfiledict', 'conf_mem_file', \
- 'destroot', 'dblink', 'srcroot',)
+ __slots__ = ('dblink', 'mycat', 'mypkg', 'settings', 'treetype',
+ 'vartree', 'scheduler', 'blockers', 'pkgloc', 'infloc', 'myebuild',
+ 'mydbapi', 'prev_mtimes', '_elog_reader_fd', '_elog_reg_id',
+ '_buf')
- def _spawn(self, args, fd_pipes=None, **kwargs):
+ def _elog_output_handler(self, fd, event):
+ output = None
+ if event & PollConstants.POLLIN:
+ try:
+ output = os.read(fd, self._bufsize)
+ except OSError as e:
+ if e.errno not in (errno.EAGAIN, errno.EINTR):
+ raise
+ if output:
+ lines = output.split('\n')
+ if len(lines) == 1:
+ self._buf += lines[0]
+ else:
+ lines[0] = self._buf + lines[0]
+ self._buf = lines.pop()
+ out = StringIO()
+ for line in lines:
+ funcname, phase, key, msg = line.split(' ', 3)
+ reporter = getattr(portage.elog.messages, funcname)
+ reporter(msg, phase=phase, key=key, out=out)
+
+ def _spawn(self, args, fd_pipes, **kwargs):
"""
Fork a subprocess, apply local settings, and call
- dblink._merge_process().
+ dblink.merge().
"""
+ files = self._files
+ elog_reader_fd, elog_writer_fd = os.pipe()
+ fcntl.fcntl(elog_reader_fd, fcntl.F_SETFL,
+ fcntl.fcntl(elog_reader_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
+ mylink = self.dblink(self.mycat, self.mypkg, settings=self.settings,
+ treetype=self.treetype, vartree=self.vartree,
+ blockers=self.blockers, scheduler=self.scheduler,
+ pipe=elog_writer_fd)
+ fd_pipes[elog_writer_fd] = elog_writer_fd
+ self._elog_reg_id = self.scheduler.register(elog_reader_fd,
+ self._registered_events, self._elog_output_handler)
+
pid = os.fork()
if pid != 0:
+ self._elog_reader_fd = elog_reader_fd
+ self._buf = ""
portage.process.spawned_pids.append(pid)
return [pid]
+ os.close(elog_reader_fd)
portage.process._setup_pipes(fd_pipes)
# Use default signal handlers since the ones inherited
@@ -35,18 +77,19 @@ class MergeProcess(SpawnProcess):
signal.signal(signal.SIGINT, signal.SIG_DFL)
signal.signal(signal.SIGTERM, signal.SIG_DFL)
- portage.output.havecolor = self.dblink.settings.get('NOCOLOR') \
+ portage.output.havecolor = self.settings.get('NOCOLOR') \
not in ('yes', 'true')
- # In this subprocess we want dblink._display_merge() to use
+ # In this subprocess we want mylink._display_merge() to use
# stdout/stderr directly since they are pipes. This behavior
- # is triggered when dblink._scheduler is None.
- self.dblink._scheduler = None
+ # is triggered when mylink._scheduler is None.
+ mylink._scheduler = None
rval = 1
try:
- rval = self.dblink._merge_process(self.srcroot, self.destroot,
- self.cfgfiledict, self.conf_mem_file)
+ rval = mylink.merge(self.pkgloc, self.infloc,
+ myebuild=self.myebuild, mydbapi=self.mydbapi,
+ prev_mtimes=self.prev_mtimes)
except SystemExit:
raise
except:
@@ -55,3 +98,16 @@ class MergeProcess(SpawnProcess):
# Call os._exit() from finally block, in order to suppress any
# finally blocks from earlier in the call stack. See bug #345289.
os._exit(rval)
+
+ def _unregister(self):
+ """
+ Unregister from the scheduler and close open files.
+ """
+ if self._elog_reg_id is not None:
+ self.scheduler.unregister(self._elog_reg_id)
+ self._elog_reg_id = None
+ if self._elog_reader_fd:
+ os.close(self._elog_reader_fd)
+ self._elog_reader_fd = None
+
+ super(MergeProcess, self)._unregister()