Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-09 09:28:46

0001 //------------------------------------------------------------------------------
0002 // Copyright (c) 2011-2017 by European Organization for Nuclear Research (CERN)
0003 // Author: Krzysztof Jamrog <krzysztof.piotr.jamrog@cern.ch>,
0004 //         Michal Simon <michal.simon@cern.ch>
0005 //------------------------------------------------------------------------------
0006 // This file is part of the XRootD software suite.
0007 //
0008 // XRootD is free software: you can redistribute it and/or modify
0009 // it under the terms of the GNU Lesser General Public License as published by
0010 // the Free Software Foundation, either version 3 of the License, or
0011 // (at your option) any later version.
0012 //
0013 // XRootD is distributed in the hope that it will be useful,
0014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
0015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0016 // GNU General Public License for more details.
0017 //
0018 // You should have received a copy of the GNU Lesser General Public License
0019 // along with XRootD.  If not, see <http://www.gnu.org/licenses/>.
0020 //
0021 // In applying this licence, CERN does not waive the privileges and immunities
0022 // granted to it by virtue of its status as an Intergovernmental Organization
0023 // or submit itself to any jurisdiction.
0024 //------------------------------------------------------------------------------
0025 
0026 #ifndef __XRD_CL_OPERATIONS_HH__
0027 #define __XRD_CL_OPERATIONS_HH__
0028 
0029 #include <memory>
0030 #include <stdexcept>
0031 #include <sstream>
0032 #include <tuple>
0033 #include <future>
0034 #include "XrdCl/XrdClXRootDResponses.hh"
0035 #include "XrdCl/XrdClOperationHandlers.hh"
0036 #include "XrdCl/XrdClArg.hh"
0037 #include "XrdCl/XrdClOperationTimeout.hh"
0038 #include "XrdCl/XrdClFinalOperation.hh"
0039 #include "XrdSys/XrdSysPthread.hh"
0040 
0041 #include "XrdCl/XrdClResponseJob.hh"
0042 #include "XrdCl/XrdClJobManager.hh"
0043 #include "XrdCl/XrdClPostMaster.hh"
0044 #include "XrdCl/XrdClDefaultEnv.hh"
0045 
0046 namespace XrdCl
0047 {
0048 
0049   class Pipeline;
0050   class PipelineHandler;
0051 
0052   //----------------------------------------------------------------------------
0053   //! Operation template. An Operation is a once-use-only object - once executed
0054   //! by a Workflow engine it is invalidated. Also if used as an argument for
0055   //! >> or | the original object gets invalidated.
0056   //!
0057   //! @arg HasHndl : true if operation has a handler, false otherwise
0058   //----------------------------------------------------------------------------
0059   template<bool HasHndl>
0060   class Operation
0061   {
0062       // Declare friendship between templates
0063       template<bool>
0064       friend class Operation;
0065 
0066       friend std::future<XRootDStatus> Async( Pipeline, uint16_t );
0067 
0068       friend class Pipeline;
0069       friend class PipelineHandler;
0070 
0071     public:
0072 
0073       //------------------------------------------------------------------------
0074       //! Constructor
0075       //------------------------------------------------------------------------
0076       Operation() : valid( true )
0077       {
0078       }
0079 
0080       //------------------------------------------------------------------------
0081       //! Move constructor between template instances.
0082       //------------------------------------------------------------------------
0083       template<bool from>
0084       Operation( Operation<from> && op ) :
0085           handler( std::move( op.handler ) ), valid( true )
0086       {
0087         if( !op.valid ) throw std::invalid_argument( "Cannot construct "
0088             "Operation from an invalid Operation!" );
0089         op.valid = false;
0090       }
0091 
0092       //------------------------------------------------------------------------
0093       //! Destructor
0094       //------------------------------------------------------------------------
0095       virtual ~Operation()
0096       {
0097       }
0098 
0099       //------------------------------------------------------------------------
0100       //! Name of the operation.
0101       //------------------------------------------------------------------------
0102       virtual std::string ToString() = 0;
0103 
0104       //------------------------------------------------------------------------
0105       //! Move current object into newly allocated instance
0106       //!
0107       //! @return : the new instance
0108       //------------------------------------------------------------------------
0109       virtual Operation<HasHndl>* Move() = 0;
0110 
0111       //------------------------------------------------------------------------
0112       //! Move current object into newly allocated instance, and convert
0113       //! it into 'handled' operation.
0114       //!
0115       //! @return : the new instance
0116       //------------------------------------------------------------------------
0117       virtual Operation<true>* ToHandled() = 0;
0118 
0119     protected:
0120 
0121       //------------------------------------------------------------------------
0122       //! Run operation
0123       //!
0124       //! @param prms   : the promise that we will have a result
0125       //! @param final  : the object to call at the end of pipeline
0126       //------------------------------------------------------------------------
0127       void Run( Timeout                                   timeout,
0128                 std::promise<XRootDStatus>                prms,
0129                 std::function<void(const XRootDStatus&)>  final );
0130 
0131       //------------------------------------------------------------------------
0132       //! Run the actual operation
0133       //!
0134       //! @param params :  container with parameters forwarded from
0135       //!                  previous operation
0136       //! @return       :  status of the operation
0137       //------------------------------------------------------------------------
0138       virtual XRootDStatus RunImpl( PipelineHandler *handler, uint16_t timeout ) = 0;
0139 
0140       //------------------------------------------------------------------------
0141       //! Add next operation in the pipeline
0142       //!
0143       //! @param op : operation to add
0144       //------------------------------------------------------------------------
0145       void AddOperation( Operation<true> *op );
0146 
0147       //------------------------------------------------------------------------
0148       //! Operation handler
0149       //------------------------------------------------------------------------
0150       std::unique_ptr<PipelineHandler> handler;
0151 
0152       //------------------------------------------------------------------------
0153       //! Flag indicating if it is a valid object
0154       //------------------------------------------------------------------------
0155       bool valid;
0156   };
0157 
0158   //----------------------------------------------------------------------------
0159   //! Type of the recovery function to be provided by the user
0160   //----------------------------------------------------------------------------
0161   typedef std::function<Operation<true>*(const XRootDStatus&)>  rcvry_func;
0162 
0163   //----------------------------------------------------------------------------
0164   //! Wrapper for ResponseHandler, used only internally to run next operation
0165   //! after previous one is finished
0166   //----------------------------------------------------------------------------
0167   class PipelineHandler: public ResponseHandler
0168   {
0169       template<bool> friend class Operation;
0170 
0171     public:
0172 
0173       //------------------------------------------------------------------------
0174       //! Constructor.
0175       //!
0176       //! @param handler  : the handler of our operation
0177       //------------------------------------------------------------------------
0178       PipelineHandler( ResponseHandler   *handler );
0179 
0180       //------------------------------------------------------------------------
0181       //! Default Constructor.
0182       //------------------------------------------------------------------------
0183       PipelineHandler()
0184       {
0185       }
0186 
0187       //------------------------------------------------------------------------
0188       //! Callback function.
0189       //------------------------------------------------------------------------
0190       void HandleResponseWithHosts( XRootDStatus *status, AnyObject *response,
0191           HostList *hostList );
0192 
0193       //------------------------------------------------------------------------
0194       //! Callback function.
0195       //------------------------------------------------------------------------
0196       void HandleResponse( XRootDStatus *status, AnyObject *response );
0197 
0198       //------------------------------------------------------------------------
0199       //! Destructor.
0200       //------------------------------------------------------------------------
0201       ~PipelineHandler()
0202       {
0203       }
0204 
0205       //------------------------------------------------------------------------
0206       //! Add new operation to the pipeline
0207       //!
0208       //! @param operation  :  operation to add
0209       //------------------------------------------------------------------------
0210       void AddOperation( Operation<true> *operation );
0211 
0212       //------------------------------------------------------------------------
0213       //! Set workflow to this and all next handlers. In the last handler
0214       //! it is used to finish workflow execution
0215       //!
0216       //! @param  prms         :  a promis that the pipeline will have a result
0217       //! @param  final        :  a callable that should be called at the end of
0218       //!                         pipeline
0219       //------------------------------------------------------------------------
0220       void Assign( const Timeout                            &timeout,
0221                    std::promise<XRootDStatus>                prms,
0222                    std::function<void(const XRootDStatus&)>  final,
0223                    Operation<true>                          *opr );
0224 
0225       //------------------------------------------------------------------------
0226       //! Assign the finalization routine
0227       //------------------------------------------------------------------------
0228       void Assign( std::function<void(const XRootDStatus&)>  final );
0229 
0230       //------------------------------------------------------------------------
0231       //! Called by a pipeline on the handler of its first operation before Run
0232       //------------------------------------------------------------------------
0233       void PreparePipelineStart();
0234 
0235     private:
0236 
0237       //------------------------------------------------------------------------
0238       //! Callback function implementation;
0239       //------------------------------------------------------------------------
0240       void HandleResponseImpl( XRootDStatus *status, AnyObject *response, HostList *hostList );
0241 
0242       inline void dealloc( XRootDStatus *status, AnyObject *response,
0243           HostList *hostList )
0244       {
0245         delete status;
0246         delete response;
0247         delete hostList;
0248       }
0249 
0250       //------------------------------------------------------------------------
0251       //! The handler of our operation
0252       //------------------------------------------------------------------------
0253       std::unique_ptr<ResponseHandler> responseHandler;
0254 
0255       //------------------------------------------------------------------------
0256       //! The operation the handler is assigned to
0257       //------------------------------------------------------------------------
0258       std::unique_ptr<Operation<true>> currentOperation;
0259 
0260       //------------------------------------------------------------------------
0261       //! Next operation in the pipeline
0262       //------------------------------------------------------------------------
0263       std::unique_ptr<Operation<true>> nextOperation;
0264 
0265       //------------------------------------------------------------------------
0266       //! Pipeline timeout
0267       //------------------------------------------------------------------------
0268       Timeout timeout;
0269 
0270       //------------------------------------------------------------------------
0271       //! The promise that there will be a result (traveling along the pipeline)
0272       //------------------------------------------------------------------------
0273       std::promise<XRootDStatus> prms;
0274 
0275       //------------------------------------------------------------------------
0276       //! The lambda/function/functor that should be called at the end of the
0277       //! pipeline (traveling along the pipeline)
0278       //------------------------------------------------------------------------
0279       std::function<void(const XRootDStatus&)> final;
0280   };
0281 
0282   //----------------------------------------------------------------------------
0283   //! A wrapper around operation pipeline. A Pipeline is a once-use-only
0284   //! object - once executed by a Workflow engine it is invalidated.
0285   //!
0286   //! Takes ownership of given operation pipeline (which is in most would
0287   //! be a temporary object)
0288   //----------------------------------------------------------------------------
0289   class Pipeline
0290   {
0291       template<bool> friend class ParallelOperation;
0292       friend std::future<XRootDStatus> Async( Pipeline, uint16_t );
0293       friend class PipelineHandler;
0294 
0295     public:
0296 
0297       //------------------------------------------------------------------------
0298       //! Default constructor
0299       //------------------------------------------------------------------------
0300       Pipeline()
0301       {
0302       }
0303 
0304       //------------------------------------------------------------------------
0305       //! Constructor
0306       //------------------------------------------------------------------------
0307       Pipeline( Operation<true> *op ) :
0308           operation( op->Move() )
0309       {
0310       }
0311 
0312       //------------------------------------------------------------------------
0313       //! Constructor
0314       //------------------------------------------------------------------------
0315       Pipeline( Operation<true> &op ) :
0316           operation( op.Move() )
0317       {
0318       }
0319 
0320       //------------------------------------------------------------------------
0321       //! Constructor
0322       //------------------------------------------------------------------------
0323       Pipeline( Operation<true> &&op ) :
0324           operation( op.Move() )
0325       {
0326       }
0327 
0328       Pipeline( Operation<false> *op ) :
0329           operation( op->ToHandled() )
0330       {
0331       }
0332 
0333       //------------------------------------------------------------------------
0334       //! Constructor
0335       //------------------------------------------------------------------------
0336       Pipeline( Operation<false> &op ) :
0337           operation( op.ToHandled() )
0338       {
0339       }
0340 
0341       //------------------------------------------------------------------------
0342       //! Constructor
0343       //------------------------------------------------------------------------
0344       Pipeline( Operation<false> &&op ) :
0345           operation( op.ToHandled() )
0346       {
0347       }
0348 
0349       Pipeline( Pipeline &&pipe ) :
0350           operation( std::move( pipe.operation ) )
0351       {
0352       }
0353 
0354       //------------------------------------------------------------------------
0355       //! Constructor
0356       //------------------------------------------------------------------------
0357       Pipeline& operator=( Pipeline &&pipe )
0358       {
0359         operation = std::move( pipe.operation );
0360         return *this;
0361       }
0362 
0363       //------------------------------------------------------------------------
0364       //! Extend pipeline
0365       //------------------------------------------------------------------------
0366       Pipeline& operator|=( Operation<true>&& op )
0367       {
0368         operation->AddOperation( op.Move() );
0369         return *this;
0370       }
0371 
0372       //------------------------------------------------------------------------
0373       //! Extend pipeline
0374       //------------------------------------------------------------------------
0375       Pipeline& operator|=( Operation<false>&& op )
0376       {
0377         operation->AddOperation( op.ToHandled() );
0378         return *this;
0379       }
0380 
0381       //------------------------------------------------------------------------
0382       //! Conversion to Operation<true>
0383       //!
0384       //! @throws : std::logic_error if pipeline is invalid
0385       //------------------------------------------------------------------------
0386       operator Operation<true>&()
0387       {
0388         if( !bool( operation ) ) throw std::logic_error( "Invalid pipeline." );
0389         return *operation.get();
0390       }
0391 
0392       //------------------------------------------------------------------------
0393       //! Conversion to boolean
0394       //!
0395       //! @return : true if it's a valid pipeline, false otherwise
0396       //------------------------------------------------------------------------
0397       operator bool()
0398       {
0399         return bool( operation );
0400       }
0401 
0402       //------------------------------------------------------------------------
0403       //! Stop the current pipeline
0404       //!
0405       //! @param status : the final status for the pipeline
0406       //------------------------------------------------------------------------
0407       static void Stop( const XRootDStatus &status = XrdCl::XRootDStatus() );
0408 
0409       //------------------------------------------------------------------------
0410       //! Repeat current operation
0411       //------------------------------------------------------------------------
0412       static void Repeat();
0413 
0414       //------------------------------------------------------------------------
0415       //! Replace current operation
0416       //------------------------------------------------------------------------
0417       static void Replace( Operation<false> &&opr );
0418 
0419       //------------------------------------------------------------------------
0420       //! Replace with pipeline
0421       //------------------------------------------------------------------------
0422       static void Replace( Pipeline p );
0423 
0424       //------------------------------------------------------------------------
0425       //! Ignore error and proceed with the pipeline
0426       //------------------------------------------------------------------------
0427       static void Ignore();
0428 
0429     private:
0430 
0431       //------------------------------------------------------------------------
0432       //! Member access declaration, provides access to the underlying
0433       //! operation.
0434       //!
0435       //! @return : pointer to the underlying
0436       //------------------------------------------------------------------------
0437       Operation<true>* operator->()
0438       {
0439         return operation.get();
0440       }
0441 
0442       //------------------------------------------------------------------------
0443       //! Schedules the underlying pipeline for execution.
0444       //!
0445       //! @param timeout : pipeline timeout value
0446       //! @param final   : to be called at the end of the pipeline
0447       //------------------------------------------------------------------------
0448       void Run( Timeout timeout, std::function<void(const XRootDStatus&)> final = nullptr )
0449       {
0450         if( ftr.valid() )
0451           throw std::logic_error( "Pipeline is already running!" );
0452 
0453         // a promise that the pipe will have a result
0454         std::promise<XRootDStatus> prms;
0455         ftr = prms.get_future();
0456 
0457         if( !operation ) std::logic_error( "Empty pipeline!" );
0458 
0459         Operation<true> *opr = operation.release();
0460         PipelineHandler *h = opr->handler.get();
0461         if( h )
0462           h->PreparePipelineStart();
0463 
0464         opr->Run( timeout, std::move( prms ), std::move( final ) );
0465       }
0466 
0467       //------------------------------------------------------------------------
0468       //! First operation in the pipeline
0469       //------------------------------------------------------------------------
0470       std::unique_ptr<Operation<true>> operation;
0471 
0472       //------------------------------------------------------------------------
0473       //! The future result of the pipeline
0474       //------------------------------------------------------------------------
0475       std::future<XRootDStatus> ftr;
0476 
0477   };
0478 
0479   //----------------------------------------------------------------------------
0480   //! Helper function, schedules execution of given pipeline
0481   //!
0482   //! @param pipeline : the pipeline to be executed
0483   //! @param timeout  : the pipeline timeout
0484   //!
0485   //! @return         : future status of the operation
0486   //----------------------------------------------------------------------------
0487   inline std::future<XRootDStatus> Async( Pipeline pipeline, uint16_t timeout = 0 )
0488   {
0489     pipeline.Run( timeout );
0490     return std::move( pipeline.ftr );
0491   }
0492 
0493   //----------------------------------------------------------------------------
0494   //! Helper function, schedules execution of given pipeline and waits for
0495   //! the status
0496   //!
0497   //! @param pipeline : the pipeline to be executed
0498   //! @param timeout  : the pipeline timeout
0499   //!
0500   //! @return         : status of the operation
0501   //----------------------------------------------------------------------------
0502   inline XRootDStatus WaitFor( Pipeline pipeline, uint16_t timeout = 0 )
0503   {
0504     return Async( std::move( pipeline ), timeout ).get();
0505   }
0506 
0507   //----------------------------------------------------------------------------
0508   //! Concrete Operation template
0509   //! Defines | and >> operator as well as operation arguments.
0510   //!
0511   //! @arg Derived : the class that derives from this template (CRTP)
0512   //! @arg HasHndl : true if operation has a handler, false otherwise
0513   //! @arg Args    : operation arguments
0514   //----------------------------------------------------------------------------
0515   template<template<bool> class Derived, bool HasHndl, typename HdlrFactory, typename ... Args>
0516   class ConcreteOperation: public Operation<HasHndl>
0517   {
0518       template<template<bool> class, bool, typename, typename ...>
0519       friend class ConcreteOperation;
0520 
0521     public:
0522 
0523       //------------------------------------------------------------------------
0524       //! Constructor
0525       //!
0526       //! @param args : operation arguments
0527       //------------------------------------------------------------------------
0528       ConcreteOperation( Args&&... args ) : args( std::tuple<Args...>( std::move( args )... ) ),
0529                                             timeout( 0 )
0530       {
0531         static_assert( !HasHndl, "It is only possible to construct operation without handler" );
0532       }
0533 
0534       //------------------------------------------------------------------------
0535       //! Move constructor from other states
0536       //!
0537       //! @arg from : state from which the object is being converted
0538       //!
0539       //! @param op : the object that is being converted
0540       //------------------------------------------------------------------------
0541       template<bool from>
0542       ConcreteOperation( ConcreteOperation<Derived, from, HdlrFactory, Args...> && op ) :
0543         Operation<HasHndl>( std::move( op ) ), args( std::move( op.args ) ), timeout( 0 )
0544       {
0545       }
0546 
0547       //------------------------------------------------------------------------
0548       //! Adds ResponseHandler/function/functor/lambda/future handler for
0549       //! the operation.
0550       //!
0551       //! Note: due to reference collapsing this covers both l-value and
0552       //!       r-value references.
0553       //!
0554       //! @param hdlr : function/functor/lambda
0555       //------------------------------------------------------------------------
0556       template<typename Hdlr>
0557       Derived<true> operator>>( Hdlr &&hdlr )
0558       {
0559         return this->StreamImpl( HdlrFactory::Create( hdlr ) );
0560       }
0561 
0562       //------------------------------------------------------------------------
0563       //! Creates a pipeline of 2 or more operations
0564       //!
0565       //! @param op  : operation to add
0566       //!
0567       //! @return    : handled operation
0568       //------------------------------------------------------------------------
0569       Derived<true> operator|( Operation<true> &op )
0570       {
0571         return PipeImpl( *this, op );
0572       }
0573 
0574       //------------------------------------------------------------------------
0575       //! Creates a pipeline of 2 or more operations
0576       //!
0577       //! @param op :  operation to add
0578       //!
0579       //! @return   :  handled operation
0580       //------------------------------------------------------------------------
0581       Derived<true> operator|( Operation<true> &&op )
0582       {
0583         return PipeImpl( *this, op );
0584       }
0585 
0586       //------------------------------------------------------------------------
0587       //! Creates a pipeline of 2 or more operations
0588       //!
0589       //! @param op   operation to add
0590       //!
0591       //! @return     handled operation
0592       //------------------------------------------------------------------------
0593       Derived<true> operator|( Operation<false> &op )
0594       {
0595         return PipeImpl( *this, op );
0596       }
0597 
0598       //------------------------------------------------------------------------
0599       //! Creates a pipeline of 2 or more operations
0600       //!
0601       //! @param op  : operation to add
0602       //!
0603       //! @return    : handled operation
0604       //------------------------------------------------------------------------
0605       Derived<true> operator|( Operation<false> &&op )
0606       {
0607         return PipeImpl( *this, op );
0608       }
0609 
0610       //------------------------------------------------------------------------
0611       //! Adds a final operation to the pipeline
0612       //------------------------------------------------------------------------
0613       Derived<true> operator|( FinalOperation &&fo )
0614       {
0615         AllocHandler( *this );
0616         this->handler->Assign( fo.final );
0617         return this->template Transform<true>();
0618       }
0619 
0620       //------------------------------------------------------------------------
0621       //! Move current object into newly allocated instance
0622       //!
0623       //! @return : the new instance
0624       //------------------------------------------------------------------------
0625       inline Operation<HasHndl>* Move()
0626       {
0627         Derived<HasHndl> *me = static_cast<Derived<HasHndl>*>( this );
0628         return new Derived<HasHndl>( std::move( *me ) );
0629       }
0630 
0631       //------------------------------------------------------------------------
0632       //! Transform operation to handled
0633       //!
0634       //! @return Operation<true>&
0635       //------------------------------------------------------------------------
0636       inline Operation<true>* ToHandled()
0637       {
0638         this->handler.reset( new PipelineHandler() );
0639         Derived<HasHndl> *me = static_cast<Derived<HasHndl>*>( this );
0640         return new Derived<true>( std::move( *me ) );
0641       }
0642 
0643       //------------------------------------------------------------------------
0644       //! Set operation timeout
0645       //------------------------------------------------------------------------
0646       Derived<HasHndl> Timeout( uint16_t timeout )
0647       {
0648         this->timeout = timeout;
0649         Derived<HasHndl> *me = static_cast<Derived<HasHndl>*>( this );
0650         return std::move( *me );
0651       }
0652 
0653     protected:
0654 
0655       //------------------------------------------------------------------------
0656       //! Transform into a new instance with desired state
0657       //!
0658       //! @return : new instance in the desired state
0659       //------------------------------------------------------------------------
0660       template<bool to>
0661       inline Derived<to> Transform()
0662       {
0663         Derived<HasHndl> *me = static_cast<Derived<HasHndl>*>( this );
0664         return Derived<to>( std::move( *me ) );
0665       }
0666 
0667       //------------------------------------------------------------------------
0668       //! Implements operator>> functionality
0669       //!
0670       //! @param handler :  handler to be added
0671       //!
0672       //! @return   :  return an instance of Derived<true>
0673       //------------------------------------------------------------------------
0674       inline Derived<true> StreamImpl( ResponseHandler *handler )
0675       {
0676         static_assert( !HasHndl, "Operator >> is available only for operation without handler" );
0677         this->handler.reset( new PipelineHandler( handler ) );
0678         return Transform<true>();
0679       }
0680 
0681       //------------------------------------------------------------------------
0682       // Allocate handler if necessary
0683       //------------------------------------------------------------------------
0684       inline static
0685       void AllocHandler( ConcreteOperation<Derived, true, HdlrFactory, Args...> &me )
0686       {
0687         // nothing to do
0688       }
0689 
0690       //------------------------------------------------------------------------
0691       // Allocate handler if necessary
0692       //------------------------------------------------------------------------
0693       inline static
0694       void AllocHandler( ConcreteOperation<Derived, false, HdlrFactory, Args...> &me )
0695       {
0696         me.handler.reset( new PipelineHandler() );
0697       }
0698 
0699       //------------------------------------------------------------------------
0700       //! Implements operator| functionality
0701       //!
0702       //! @param me  :  reference to myself (*this)
0703       //! @param op  :  reference to the other operation
0704       //!
0705       //! @return    :  move-copy of myself
0706       //------------------------------------------------------------------------
0707       inline static
0708       Derived<true> PipeImpl( ConcreteOperation<Derived, HasHndl, HdlrFactory,
0709           Args...> &me, Operation<true> &op )
0710       {
0711         AllocHandler( me ); // if HasHndl is false allocate handler
0712         me.AddOperation( op.Move() );
0713         return me.template Transform<true>();
0714       }
0715 
0716       //------------------------------------------------------------------------
0717       //! Implements operator| functionality
0718       //!
0719       //! @param me  :  reference to myself (*this)
0720       //! @param op  :  reference to the other operation
0721       //!
0722       //! @return    :  move-copy of myself
0723       //------------------------------------------------------------------------
0724       inline static
0725       Derived<true> PipeImpl( ConcreteOperation<Derived, HasHndl, HdlrFactory,
0726           Args...> &me, Operation<false> &op )
0727       {
0728         AllocHandler( me ); // if HasHndl is false allocate handler
0729         me.AddOperation( op.ToHandled() );
0730         return me.template Transform<true>();
0731       }
0732 
0733       //------------------------------------------------------------------------
0734       //! Operation arguments
0735       //------------------------------------------------------------------------
0736       std::tuple<Args...> args;
0737 
0738       //------------------------------------------------------------------------
0739       //! Operation timeout
0740       //------------------------------------------------------------------------
0741       uint16_t timeout;
0742     };
0743 
0744   // Out-of-line methods for class Operation
0745 
0746   template <bool HasHndl>
0747   void Operation<HasHndl>::Run(Timeout timeout, std::promise<XRootDStatus> prms,
0748                                std::function<void(const XRootDStatus &)> f)
0749   {
0750     static_assert(HasHndl, "Only an operation that has a handler can be assigned to workflow");
0751 
0752     XRootDStatus st;
0753     handler->Assign(timeout, std::move(prms), std::move(f), this);
0754     PipelineHandler *h = handler.release();
0755 
0756     try {
0757       st = RunImpl(h, timeout);
0758     } catch (const operation_expired &ex) {
0759       st = XRootDStatus(stError, errOperationExpired);
0760     } catch (const PipelineException &ex) { // probably not needed
0761       st = ex.GetError();
0762     } catch (const std::exception &ex) {
0763       st = XRootDStatus(stError, errInternal, 0, ex.what());
0764     }
0765 
0766     if (!st.IsOK()) {
0767       ResponseJob *job = new ResponseJob(h, new XRootDStatus(st), 0, nullptr);
0768       DefaultEnv::GetPostMaster()->GetJobManager()->QueueJob(job);
0769     }
0770   }
0771 
0772   template <bool HasHndl>
0773   void Operation<HasHndl>::AddOperation(Operation<true> *op)
0774   {
0775     if (handler)
0776       handler->AddOperation(op);
0777   }
0778 }
0779 
0780 #endif // __XRD_CL_OPERATIONS_HH__