%PoolWorker Worker object for parallel pool jobs

% Copyright 2012-2020 The MathWorks, Inc.
classdef PoolWorker < parallel.internal.pool.AbstractWorker
    properties ( Access = private )
        NewWorldComms
    end

    methods
        function obj = PoolWorker()
        % Important note: there is a convenient fiction here - we pretend that our
        % labindex is "labindex-1", and that numlabs is "numlabs-1" so that the
        % parallel pool can still work with client and labs 1:N, rather than having to
        % deal with the fact that the client also happens to have a labindex.
            obj@parallel.internal.pool.AbstractWorker( labindex - 1, ...
                                                       numlabs  - 1 );
        end

        function start(obj, leadingTaskNum)
        %start This will start a parallel pool job on the non-leading labs
        %   The labs connect to the specified host and port and create their
        %   session object.
            try
                workerBuild = labBroadcast(leadingTaskNum);

                % Set up for SPMD execution - make a new MPI communicator that involves only
                % labs 2:numlabs.
                obj.NewWorldComms = mpiCommManip( 'split', 1, labindex );
                gcat( {obj.NewWorldComms} );

                % Deadlock detection on for now while we don't have a good way of
                % interrupting non-dd communications
                mpiSettings( 'DeadlockDetection', 'on' );

                broadcastFcn = @(varargin) assert(false, 'This function should not be used.');
                obj.connectToClient(workerBuild, broadcastFcn);
                mpiCommManip( 'select', obj.NewWorldComms );
            catch err
                dctSchedulerMessage(1, 'Error message from PoolWorker/start: %s', ...
                                    err.message);
                rethrow(err);
            end
        end

        function stopLabAndDisconnect(obj)
        %stopLabAndDisconnect Stop pmode, destroy Java objects and close sockets.

        % This is not quite a 1:1 copy of @interactivelab/stopLabAndDisconnect.m -
        % as we need to free the "NewWorldComms"

        % Destroy the Java objects for this pmode session, including the sockets.
            try
                mpiCommManip( 'select', 'world' );
                dctSchedulerMessage(3, 'Destroying the current lab session object.');
                
                %Finished with Session - forget about it
                % This is safe, as during client Session destruction in Java,
                % worker Session destruction is started which in turn
                % indirectly calls this method. Therefore the Session will
                % have gone away already.
                obj.Session = [];

                mpiCommManip( 'free',   obj.NewWorldComms );
                % Clean up memory associated with Composites
                spmdlang.ValueStore.clear();                
                
            catch err
                dctSchedulerMessage(1, ['Failed to destroy session object ', ...
                                    'with message:\n''%s'''], err.message);
                rethrow(err);
            end
        end
    end
end
