LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/base - work_pipeline.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 5 6 83.3 %
Date: 2026-11-09 02:10:49 Functions: 9 20 45.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : /*
       7             :  * work_pipeline.h
       8             :  * 
       9             :  *  This file provides some templates that can be used to manage processing.
      10             :  *  
      11             :  *  The user creates a WorkPipeline, with multiple WorkStage's inside it.
      12             :  *
      13             :  *  The stages will execute in sequence. A stage has an execution phase, where
      14             :  *  multiple threads (instances) can do processing in parallel, and an optional
      15             :  *  merge phase where the results of the parallel execution can be consolidated.
      16             :  *  For each stage, the user provides the execution function (of type ExecuteFn) 
      17             :  *  (optionally) a merge function (of type MergeFn).
      18             :  *
      19             :  *  The execution function runs in parallel over a number of instances. Each 
      20             :  *  instance executes in steps. During a step, the ExecuteFn is expected to 
      21             :  *  provide the external command that needs to be run to get information (e.g. 
      22             :  *  cassandra or redis, or another WorkPipleline) . ExecuteFn will called again
      23             :  *  (as a next step) when the results of the external command are available. In
      24             :  *  that next step, ExecuteFn can consolidate the external result into the
      25             :  *  instances' subresult. The user can run multiple such steps within the
      26             :  *  instance.
      27             :  *
      28             :  *  After the subresults from all instances of that stage are available, MergeFn 
      29             :  *  will run which can consolidate the subresults into the final result for
      30             :  *  that stage. If a stage has a single instance, then MergeFn is not needed 
      31             :  *  for that stage.
      32             :  *  
      33             :  *  After all stages have been executed, the user's callback function is called.
      34             :  *  The user can then access the final result of the WorkPipeline. 
      35             :  *
      36             :  *  Here are some of the features:
      37             :  *
      38             :  *    - Buffers are shared and transferred wherever possible (instead of copy)
      39             :  *
      40             :  *    - A generic mechanism is provided to get information from any source. 
      41             :  *      Both Async and Sync processing is allowed for the external sources.
      42             :  *
      43             :  *    - Strong typechecking for Input Type, Subresult Type and Result type 
      44             :  *      across stages.
      45             :  *
      46             :  *    - TaskId and TaskInstance can be customized for ExecuteFn (for every 
      47             :  *      instance of every stage) and MergeFn (for every stage)
      48             :  *
      49             :  *
      50             :  *  This file has the interfaces provided by WorkPipeline and WorkStage.
      51             :  *  Most of the implementation is split across two other files -
      52             :  *  work_processor-inl.h and work_pipeline-inl.h       
      53             :  *
      54             :  */
      55             : 
      56             : #ifndef __WORK_PIPELINE_H__
      57             : #define __WORK_PIPELINE_H__
      58             : 
      59             : #include <vector>
      60             : #include <limits>
      61             : #include <sstream>
      62             : #include <atomic> 
      63             : 
      64             : #include <boost/function.hpp>
      65             : #include <boost/bind/bind.hpp>
      66             : #include <boost/shared_ptr.hpp>
      67             : #include <boost/scoped_ptr.hpp>
      68             : #include <boost/assign/list_of.hpp>
      69             : #include <boost/type_traits.hpp>
      70             : #include <boost/mpl/assert.hpp>
      71             : #include <boost/tuple/tuple.hpp>
      72             : #include "base/task.h"
      73             : 
      74             : using namespace boost::placeholders;
      75             : 
      76             : // When the WorkPipeline is done, it will call this function back
      77             : // to indicate that the result is ready.
      78             : // The bool indicates success or failure.
      79             : typedef boost::function<void(bool)> FinFn;
      80             : 
      81             : 
      82             : // This is the interface to the external command execution that
      83             : // can be requested by the user in ExecuteFn
      84             : //
      85             : // The user provides the function ExternalBase::Efn that the
      86             : // WorkStage can call with a single argument (ExternalBase *)
      87             : //
      88             : // The user should ensure that when the command is done, the
      89             : // argument is cast into  ExternalProcIf *, and the
      90             : // Response function is called with the result of the the
      91             : // external command 
      92             : struct ExternalBase {
      93             :     typedef boost::function<bool(ExternalBase *)> Efn;
      94           0 :     static bool Incomplete(void *) { assert(0); }
      95             : };
      96             : template<typename ExternalT>
      97             : struct ExternalProcIf : public ExternalBase {
      98             :     virtual std::string Key() const = 0;
      99             :     virtual void Response(std::unique_ptr<ExternalT>) = 0;
     100      109309 :     virtual ~ExternalProcIf() {}
     101             : };
     102             : 
     103             : #include "work_processor-inl.h"
     104             : 
     105             : // When creating the WorkPipeline, the user needs to supply it 
     106             : // constructed WorkStage objects.
     107             : // The Constructor of this class is the only function
     108             : // that the client needs to call.
     109             : template<typename InputT, typename ResultT, typename ExternalT, typename SubResultT = ResultT>
     110             : class WorkStage : public WorkStageIf<InputT, ResultT> {
     111             : public:
     112             : 
     113             :     // A WorkStage executes multiple instances in parallel by calling ExecuteFn
     114             :     // Each execution run of ExecuteFn is called a "step". 
     115             :     // - If the client returns ExternalBase::Incomplete, the step is incomplete.
     116             :     //   After yielding, ExecuteFn will be called again to continue the step.
     117             :     // - If the client returns NULL, the step ends, and so does the instance.
     118             :     // - Otherwise, WorkStage will call the returned callback function
     119             :     //   and move to the next step when the client calls ExternalProcIf's
     120             :     //   Response function. The buffer passed in the Response function is added
     121             :     //   to the exts vector before calling ExecuteFn for the next step.
     122             :     // 
     123             :     // The client should fill in the final result in subRes before the 
     124             :     // instance ends.
     125             :     typedef boost::function<
     126             :         ExternalBase::Efn( // Client returns External fn to call and
     127             :                            // whether processing is incomplete.
     128             :         uint32_t inst,     // Instance num. (the instances execute in parallel)
     129             :         const std::vector<ExternalT*>
     130             :                             & exts, // Info for previous steps of this stage
     131             :         const InputT & inp, // Info from previous stage
     132             :         SubResultT & subRes // Access to final result of this instance
     133             :         )> ExecuteFn;
     134             : 
     135             :     // When all the ExecuteFn instances end, the Execute phase of the stage
     136             :     // is over. At that time, WorkStage calls MergeFn. MergeFn is expected to 
     137             :     // aggregate the SubResults from the ExecuteFn instances into the final
     138             :     // Result for the stage.
     139             :     // If the SubResult type and Result type is the same, MergeFn is optional.
     140             :     // If no MergeFn is supplied, the SubResult of the 1st instance will be 
     141             :     // used as the final result of the stage. 
     142             :     typedef boost::function<
     143             :        bool(              // Client returns whether processing is incomplete.
     144             :        const std::vector<boost::shared_ptr<SubResultT> >
     145             :                            & subs, // Subresults from this stage's instances
     146             :        const boost::shared_ptr<InputT> & inp, // Info from previous stage
     147             :        ResultT & res               // Final result to be reported by this stage
     148             :        )> MergeFn;
     149             : 
     150             :     // The client needs to constuct WorkStages.
     151             :     //   tinfo is a vector of TaskId,TaskInstance pairs for ExecuteFn
     152             :     //   ExecuteFn and MergeFn were explained above
     153             :     //   tid and tinst are the TaskId and TaskInstance used for MergeFn
     154             :     WorkStage(std::vector<std::pair<int,int> > tinfo,
     155             :             ExecuteFn efn, MergeFn mfn = 0, int tid = 0, int tinst = -1); 
     156             : 
     157             :     void Start(uint32_t stage, FinFn finFn, const boost::shared_ptr<InputT> & inp);
     158             : 
     159             :     boost::shared_ptr<ResultT> Result() const;
     160             : 
     161             :     void Release();
     162             : 
     163             : private:
     164             :     uint32_t stage_;
     165             :     std::atomic<uint32_t> remainingInst_;
     166             :     FinFn finFn_;
     167             :     boost::shared_ptr<InputT> inp_;
     168             :     boost::shared_ptr<ResultT> res_;
     169             :     std::vector<boost::shared_ptr<WorkProcessor<InputT,SubResultT,ExternalT> > > workers_;
     170             :     std::vector<boost::shared_ptr<SubResultT> > subRes_;
     171             :     const MergeFn merger_;
     172             :     const ExecuteFn efn_;
     173             :     bool finished_;
     174             :     bool running_;   
     175             :     const int tid_;
     176             :     const int tinst_;
     177             :     const std::vector<std::pair<int,int> > tinfo_;    
     178             : 
     179             :     bool Runner(void);
     180             :     void WorkProcCb(uint32_t inst, bool ret_code);
     181         126 :     void StageProceed(boost::true_type) { res_ = subRes_[0]; }
     182        1928 :     void StageProceed(boost::false_type) { assert(!merger_.empty()); }
     183             : 
     184             : };
     185             : 
     186             : 
     187             : template<typename T0, typename T1, typename T2 = T1,
     188             :     typename T3 = T2, typename T4 = T3,
     189             :     typename T5 = T4, typename T6 = T5>
     190             : class WorkPipeline {
     191             : public:
     192             :     typedef T6 ResT;
     193             :     typedef WorkPipeline<T0,T1,T2,T3,T4,T5,T6> SelfT;
     194             : 
     195             :     // The client should instantiate the WorkPipeline with instances
     196             :     // of WorkStage. The WorkPipeline accomodates a minimum of 1 and
     197             :     // maximum of 6 stages. Each stage has an Input and Output type.
     198             :     // The Output type of a stage must match the Input type of the 
     199             :     // next stage. This sequence of types must be used to instantiate
     200             :     // the WorkPipeline template. 
     201             :     WorkPipeline(
     202             :         WorkStageIf<T0,T1> * s0,
     203             :         WorkStageIf<T1,T2> * s1 = NULL,
     204             :         WorkStageIf<T2,T3> * s2 = NULL,
     205             :         WorkStageIf<T3,T4> * s3 = NULL,
     206             :         WorkStageIf<T4,T5> * s4 = NULL,
     207             :         WorkStageIf<T5,T6> * s5 = NULL);
     208             : 
     209             :     // The client should call this function to start the WorkPipeline
     210             :     // "finFn" is the callback function that WorkPipeline will call when
     211             :     // the last stage ends. "inp" is the Input to the 1st stage.
     212             :     // The WorkPipeline will retain a shared_ptr to the initial 
     213             :     // input for the lifetime of the WorkPipeline object. 
     214             :     void Start(FinFn finFn, const boost::shared_ptr<T0> & inp);
     215             : 
     216             :     // After "finFn" has been called by WorkPipeline, the client can
     217             :     // access the final result by calling this function
     218             :     // The WorkPipeline will retain a shared_ptr to the final result
     219             :     // for the lifetime of the WorkPipeline object.
     220             :     boost::shared_ptr<ResT> Result() const;
     221             : 
     222             : private:
     223             :     typedef boost::tuple<
     224             :         const boost::shared_ptr<WorkStageIf<T0,T1> >,
     225             :         const boost::shared_ptr<WorkStageIf<T1,T2> >,
     226             :         const boost::shared_ptr<WorkStageIf<T2,T3> >,
     227             :         const boost::shared_ptr<WorkStageIf<T3,T4> >,
     228             :         const boost::shared_ptr<WorkStageIf<T4,T5> >,
     229             :         const boost::shared_ptr<WorkStageIf<T5,T6> > > sg_type;
     230             : 
     231             :     bool finished_;
     232             :     FinFn finFn_;
     233             :     boost::shared_ptr<T0> inp_;
     234             :     boost::shared_ptr<ResT> res_;
     235             :     sg_type sg_;
     236             : 
     237             :     template<int kS, bool same> struct PipeProceed {};
     238             : 
     239             :     template<int kS> struct PipeProceed<kS, true> {
     240        1928 :         static void Do(SelfT * wp) { wp->res_ = boost::get<kS>(wp->sg_)->Result(); }
     241             :     };
     242             : 
     243             :     template<int kS> struct PipeProceed<kS, false> {
     244         126 :         static void Do(SelfT * wp) { assert(boost::get<kS+1>(wp->sg_)); }
     245             :     };
     246             : 
     247             :     void WorkStageCb(uint32_t stage, bool ret_code);
     248             :     template<int kS,typename NextT> void NextStage();
     249             : 
     250             : };
     251             : 
     252             : #include "work_pipeline-inl.h"
     253             : 
     254             : 
     255             : #endif

Generated by: LCOV version 1.14