00001 //------------------------------------------------------------------------------ 00002 // Copyright (c) 2011-2017 by European Organization for Nuclear Research (CERN) 00003 // Author: Krzysztof Jamrog <krzysztof.piotr.jamrog@cern.ch>, 00004 // Michal Simon <michal.simon@cern.ch> 00005 //------------------------------------------------------------------------------ 00006 // This file is part of the XRootD software suite. 00007 // 00008 // XRootD is free software: you can redistribute it and/or modify 00009 // it under the terms of the GNU Lesser General Public License as published by 00010 // the Free Software Foundation, either version 3 of the License, or 00011 // (at your option) any later version. 00012 // 00013 // XRootD is distributed in the hope that it will be useful, 00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 // GNU General Public License for more details. 00017 // 00018 // You should have received a copy of the GNU Lesser General Public License 00019 // along with XRootD. If not, see <http://www.gnu.org/licenses/>. 00020 // 00021 // In applying this licence, CERN does not waive the privileges and immunities 00022 // granted to it by virtue of its status as an Intergovernmental Organization 00023 // or submit itself to any jurisdiction. 00024 //------------------------------------------------------------------------------ 00025 00026 #ifndef __XRD_CL_OPERATIONS_HH__ 00027 #define __XRD_CL_OPERATIONS_HH__ 00028 00029 #include <memory> 00030 #include <stdexcept> 00031 #include <sstream> 00032 #include <tuple> 00033 #include <future> 00034 #include "XrdCl/XrdClXRootDResponses.hh" 00035 #include "XrdCl/XrdClOperationHandlers.hh" 00036 #include "XrdClArg.hh" 00037 #include "XrdSys/XrdSysPthread.hh" 00038 00039 namespace XrdCl 00040 { 00041 00042 template<bool HasHndl> class Operation; 00043 00044 class Pipeline; 00045 00046 //---------------------------------------------------------------------------- 00049 //---------------------------------------------------------------------------- 00050 class PipelineHandler: public ResponseHandler 00051 { 00052 template<bool> friend class Operation; 00053 00054 public: 00055 00056 //------------------------------------------------------------------------ 00062 //------------------------------------------------------------------------ 00063 PipelineHandler( ResponseHandler *handler, bool own ); 00064 00065 //------------------------------------------------------------------------ 00067 //------------------------------------------------------------------------ 00068 PipelineHandler(); 00069 00070 //------------------------------------------------------------------------ 00072 //------------------------------------------------------------------------ 00073 void HandleResponseWithHosts( XRootDStatus *status, AnyObject *response, 00074 HostList *hostList ); 00075 00076 //------------------------------------------------------------------------ 00078 //------------------------------------------------------------------------ 00079 void HandleResponse( XRootDStatus *status, AnyObject *response ); 00080 00081 //------------------------------------------------------------------------ 00083 //------------------------------------------------------------------------ 00084 ~PipelineHandler(); 00085 00086 //------------------------------------------------------------------------ 00090 //------------------------------------------------------------------------ 00091 void AddOperation( Operation<true> *operation ); 00092 00093 //------------------------------------------------------------------------ 00100 //------------------------------------------------------------------------ 00101 void Assign( std::promise<XRootDStatus> prms, 00102 std::function<void(const XRootDStatus&)> final ); 00103 00104 private: 00105 00106 //------------------------------------------------------------------------ 00108 //------------------------------------------------------------------------ 00109 void HandleResponseImpl( XRootDStatus *status, AnyObject *response, 00110 HostList *hostList = nullptr ); 00111 00112 inline void dealloc( XRootDStatus *status, AnyObject *response, 00113 HostList *hostList ) 00114 { 00115 delete status; 00116 delete response; 00117 delete hostList; 00118 } 00119 00120 //------------------------------------------------------------------------ 00122 //------------------------------------------------------------------------ 00123 ResponseHandler *responseHandler; 00124 00125 //------------------------------------------------------------------------ 00127 //------------------------------------------------------------------------ 00128 bool ownHandler; 00129 00130 //------------------------------------------------------------------------ 00132 //------------------------------------------------------------------------ 00133 std::unique_ptr<Operation<true>> nextOperation; 00134 00135 //------------------------------------------------------------------------ 00137 //------------------------------------------------------------------------ 00138 std::promise<XRootDStatus> prms; 00139 00140 //------------------------------------------------------------------------ 00143 //------------------------------------------------------------------------ 00144 std::function<void(const XRootDStatus&)> final; 00145 }; 00146 00147 //---------------------------------------------------------------------------- 00153 //---------------------------------------------------------------------------- 00154 template<bool HasHndl> 00155 class Operation 00156 { 00157 // Declare friendship between templates 00158 template<bool> 00159 friend class Operation; 00160 00161 friend std::future<XRootDStatus> Async( Pipeline ); 00162 00163 friend class Pipeline; 00164 friend class PipelineHandler; 00165 00166 public: 00167 00168 //------------------------------------------------------------------------ 00170 //------------------------------------------------------------------------ 00171 Operation() : valid( true ) 00172 { 00173 } 00174 00175 //------------------------------------------------------------------------ 00177 //------------------------------------------------------------------------ 00178 template<bool from> 00179 Operation( Operation<from> && op ) : 00180 handler( std::move( op.handler ) ), valid( true ) 00181 { 00182 if( !op.valid ) throw std::invalid_argument( "Cannot construct " 00183 "Operation from an invalid Operation!" ); 00184 op.valid = false; 00185 } 00186 00187 //------------------------------------------------------------------------ 00189 //------------------------------------------------------------------------ 00190 virtual ~Operation() 00191 { 00192 } 00193 00194 //------------------------------------------------------------------------ 00196 //------------------------------------------------------------------------ 00197 virtual std::string ToString() = 0; 00198 00199 //------------------------------------------------------------------------ 00203 //------------------------------------------------------------------------ 00204 virtual Operation<HasHndl>* Move() = 0; 00205 00206 //------------------------------------------------------------------------ 00211 //------------------------------------------------------------------------ 00212 virtual Operation<true>* ToHandled() = 0; 00213 00214 protected: 00215 00216 //------------------------------------------------------------------------ 00226 //------------------------------------------------------------------------ 00227 void Run( std::promise<XRootDStatus> prms, 00228 std::function<void(const XRootDStatus&)> final ) 00229 { 00230 static_assert(HasHndl, "Only an operation that has a handler can be assigned to workflow"); 00231 handler->Assign( std::move( prms ), std::move( final ) ); 00232 XRootDStatus st = RunImpl(); 00233 if( st.IsOK() ) handler.release(); 00234 else 00235 ForceHandler( st ); 00236 } 00237 00238 //------------------------------------------------------------------------ 00245 //------------------------------------------------------------------------ 00246 virtual XRootDStatus RunImpl() = 0; 00247 00248 //------------------------------------------------------------------------ 00255 //------------------------------------------------------------------------ 00256 void ForceHandler( const XRootDStatus &status ) 00257 { 00258 handler->HandleResponse( new XRootDStatus( status ), nullptr ); 00259 // HandleResponse already freed the memory so we have to 00260 // release the unique pointer 00261 handler.release(); 00262 } 00263 00264 //------------------------------------------------------------------------ 00268 //------------------------------------------------------------------------ 00269 void AddOperation( Operation<true> *op ) 00270 { 00271 if( handler ) 00272 { 00273 handler->AddOperation( op ); 00274 } 00275 } 00276 00277 //------------------------------------------------------------------------ 00279 //------------------------------------------------------------------------ 00280 std::unique_ptr<PipelineHandler> handler; 00281 00282 //------------------------------------------------------------------------ 00284 //------------------------------------------------------------------------ 00285 bool valid; 00286 }; 00287 00288 //---------------------------------------------------------------------------- 00294 //---------------------------------------------------------------------------- 00295 class Pipeline 00296 { 00297 template<bool> friend class ParallelOperation; 00298 friend std::future<XRootDStatus> Async( Pipeline ); 00299 00300 public: 00301 00302 //------------------------------------------------------------------------ 00304 //------------------------------------------------------------------------ 00305 Pipeline( Operation<true> *op ) : 00306 operation( op->Move() ) 00307 { 00308 00309 } 00310 00311 //------------------------------------------------------------------------ 00313 //------------------------------------------------------------------------ 00314 Pipeline( Operation<true> &op ) : 00315 operation( op.Move() ) 00316 { 00317 00318 } 00319 00320 //------------------------------------------------------------------------ 00322 //------------------------------------------------------------------------ 00323 Pipeline( Operation<true> &&op ) : 00324 operation( op.Move() ) 00325 { 00326 00327 } 00328 00329 Pipeline( Operation<false> *op ) : 00330 operation( op->ToHandled() ) 00331 { 00332 00333 } 00334 00335 //------------------------------------------------------------------------ 00337 //------------------------------------------------------------------------ 00338 Pipeline( Operation<false> &op ) : 00339 operation( op.ToHandled() ) 00340 { 00341 00342 } 00343 00344 //------------------------------------------------------------------------ 00346 //------------------------------------------------------------------------ 00347 Pipeline( Operation<false> &&op ) : 00348 operation( op.ToHandled() ) 00349 { 00350 00351 } 00352 00353 Pipeline( Pipeline &&pipe ) : 00354 operation( std::move( pipe.operation ) ) 00355 { 00356 00357 } 00358 00359 //------------------------------------------------------------------------ 00361 //------------------------------------------------------------------------ 00362 Pipeline& operator=( Pipeline &&pipe ) 00363 { 00364 operation = std::move( pipe.operation ); 00365 return *this; 00366 } 00367 00368 //------------------------------------------------------------------------ 00372 //------------------------------------------------------------------------ 00373 operator Operation<true>&() 00374 { 00375 if( !bool( operation ) ) throw std::logic_error( "Invalid pipeline." ); 00376 return *operation.get(); 00377 } 00378 00379 //------------------------------------------------------------------------ 00383 //------------------------------------------------------------------------ 00384 operator bool() 00385 { 00386 return bool( operation ); 00387 } 00388 00389 private: 00390 00391 //------------------------------------------------------------------------ 00396 //------------------------------------------------------------------------ 00397 Operation<true>* operator->() 00398 { 00399 return operation.get(); 00400 } 00401 00402 //------------------------------------------------------------------------ 00408 //------------------------------------------------------------------------ 00409 void Run( std::function<void(const XRootDStatus&)> final = nullptr ) 00410 { 00411 if( ftr.valid() ) 00412 throw std::logic_error( "Pipeline is already running" ); 00413 00414 // a promise that the pipe will have a result 00415 std::promise<XRootDStatus> prms; 00416 ftr = prms.get_future(); 00417 operation->Run( std::move( prms ), std::move( final ) ); 00418 } 00419 00420 //------------------------------------------------------------------------ 00422 //------------------------------------------------------------------------ 00423 std::unique_ptr<Operation<true>> operation; 00424 00425 //------------------------------------------------------------------------ 00427 //------------------------------------------------------------------------ 00428 std::future<XRootDStatus> ftr; 00429 00430 }; 00431 00432 //---------------------------------------------------------------------------- 00438 //---------------------------------------------------------------------------- 00439 inline std::future<XRootDStatus> Async( Pipeline pipeline ) 00440 { 00441 pipeline.Run(); 00442 return std::move( pipeline.ftr ); 00443 } 00444 00445 //---------------------------------------------------------------------------- 00452 //---------------------------------------------------------------------------- 00453 inline XRootDStatus WaitFor( Pipeline pipeline ) 00454 { 00455 return Async( std::move( pipeline ) ).get(); 00456 } 00457 00458 //---------------------------------------------------------------------------- 00465 //---------------------------------------------------------------------------- 00466 template<template<bool> class Derived, bool HasHndl, typename HdlrFactory, typename ... Args> 00467 class ConcreteOperation: public Operation<HasHndl> 00468 { 00469 template<template<bool> class, bool, typename, typename ...> 00470 friend class ConcreteOperation; 00471 00472 public: 00473 00474 //------------------------------------------------------------------------ 00478 //------------------------------------------------------------------------ 00479 ConcreteOperation( Args&&... args ) : args( std::tuple<Args...>( std::move( args )... ) ) 00480 { 00481 static_assert( !HasHndl, "It is only possible to construct operation without handler" ); 00482 } 00483 00484 //------------------------------------------------------------------------ 00490 //------------------------------------------------------------------------ 00491 template<bool from> 00492 ConcreteOperation( ConcreteOperation<Derived, from, HdlrFactory, Args...> && op ) : 00493 Operation<HasHndl>( std::move( op ) ), args( std::move( op.args ) ) 00494 { 00495 00496 } 00497 00498 //------------------------------------------------------------------------ 00506 //------------------------------------------------------------------------ 00507 template<typename Hdlr> 00508 Derived<true> operator>>( Hdlr &&hdlr ) 00509 { 00510 // check if the resulting handler should be owned by us or by the user, 00511 // if the user passed us directly a ResponseHandler it's owned by the 00512 // user, otherwise we need to wrap the argument in a handler and in this 00513 // case the resulting handler will be owned by us 00514 constexpr bool own = !IsResponseHandler<Hdlr>::value; 00515 return this->StreamImpl( HdlrFactory::Create( hdlr ), own ); 00516 } 00517 00518 //------------------------------------------------------------------------ 00524 //------------------------------------------------------------------------ 00525 Derived<true> operator|( Operation<true> &op ) 00526 { 00527 return PipeImpl( *this, op ); 00528 } 00529 00530 //------------------------------------------------------------------------ 00536 //------------------------------------------------------------------------ 00537 Derived<true> operator|( Operation<true> &&op ) 00538 { 00539 return PipeImpl( *this, op ); 00540 } 00541 00542 //------------------------------------------------------------------------ 00548 //------------------------------------------------------------------------ 00549 Derived<true> operator|( Operation<false> &op ) 00550 { 00551 return PipeImpl( *this, op ); 00552 } 00553 00554 //------------------------------------------------------------------------ 00560 //------------------------------------------------------------------------ 00561 Derived<true> operator|( Operation<false> &&op ) 00562 { 00563 return PipeImpl( *this, op ); 00564 } 00565 00566 protected: 00567 00568 //------------------------------------------------------------------------ 00572 //------------------------------------------------------------------------ 00573 Operation<HasHndl>* Move() 00574 { 00575 Derived<HasHndl> *me = static_cast<Derived<HasHndl>*>( this ); 00576 return new Derived<HasHndl>( std::move( *me ) ); 00577 } 00578 00579 //------------------------------------------------------------------------ 00583 //------------------------------------------------------------------------ 00584 Operation<true>* ToHandled() 00585 { 00586 this->handler.reset( new PipelineHandler() ); 00587 Derived<HasHndl> *me = static_cast<Derived<HasHndl>*>( this ); 00588 return new Derived<true>( std::move( *me ) ); 00589 } 00590 00591 //------------------------------------------------------------------------ 00595 //------------------------------------------------------------------------ 00596 template<bool to> 00597 Derived<to> Transform() 00598 { 00599 Derived<HasHndl> *me = static_cast<Derived<HasHndl>*>( this ); 00600 return Derived<to>( std::move( *me ) ); 00601 } 00602 00603 //------------------------------------------------------------------------ 00609 //------------------------------------------------------------------------ 00610 inline Derived<true> StreamImpl( ResponseHandler *handler, bool own ) 00611 { 00612 static_assert( !HasHndl, "Operator >> is available only for operation without handler" ); 00613 this->handler.reset( new PipelineHandler( handler, own ) ); 00614 return Transform<true>(); 00615 } 00616 00617 //------------------------------------------------------------------------ 00624 //------------------------------------------------------------------------ 00625 inline static 00626 Derived<true> PipeImpl( ConcreteOperation<Derived, true, HdlrFactory, 00627 Args...> &me, Operation<true> &op ) 00628 { 00629 me.AddOperation( op.Move() ); 00630 return me.template Transform<true>(); 00631 } 00632 00633 //------------------------------------------------------------------------ 00640 //------------------------------------------------------------------------ 00641 inline static 00642 Derived<true> PipeImpl( ConcreteOperation<Derived, true, HdlrFactory, 00643 Args...> &me, Operation<false> &op ) 00644 { 00645 me.AddOperation( op.ToHandled() ); 00646 return me.template Transform<true>(); 00647 } 00648 00649 //------------------------------------------------------------------------ 00656 //------------------------------------------------------------------------ 00657 inline static 00658 Derived<true> PipeImpl( ConcreteOperation<Derived, false, HdlrFactory, 00659 Args...> &me, Operation<true> &op ) 00660 { 00661 me.handler.reset( new PipelineHandler() ); 00662 me.AddOperation( op.Move() ); 00663 return me.template Transform<true>(); 00664 } 00665 00666 //------------------------------------------------------------------------ 00673 //------------------------------------------------------------------------ 00674 inline static 00675 Derived<true> PipeImpl( ConcreteOperation<Derived, false, HdlrFactory, 00676 Args...> &me, Operation<false> &op ) 00677 { 00678 me.handler.reset( new PipelineHandler() ); 00679 me.AddOperation( op.ToHandled() ); 00680 return me.template Transform<true>(); 00681 } 00682 00683 //------------------------------------------------------------------------ 00685 //------------------------------------------------------------------------ 00686 std::tuple<Args...> args; 00687 }; 00688 } 00689 00690 #endif // __XRD_CL_OPERATIONS_HH__