<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: b3dvector.hxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: obo $ $Date: 2007-01-25 11:02:48 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _BGFX_VECTOR_B3DVECTOR_HXX
#define _BGFX_VECTOR_B3DVECTOR_HXX

#ifndef _BGFX_TUPLE_B3DTUPLE_HXX
#include <basegfx/tuple/b3dtuple.hxx>
#endif

namespace basegfx
{
    // predeclaration
    class B3DHomMatrix;

    /** Base Point class with three double values

        This class derives all operators and common handling for
        a 3D data class from B3DTuple. All necessary extensions
        which are special for 3D Vectors are added here.

        @see B3DTuple
    */
    class B3DVector : public ::basegfx::B3DTuple
    {
    public:
        /** Create a 3D Vector

            The vector is initialized to (0.0, 0.0, 0.0)
        */
        B3DVector()
        :   B3DTuple()
        {}

        /** Create a 3D Vector

            @param fX
            This parameter is used to initialize the X-coordinate
            of the 3D Vector.

            @param fY
            This parameter is used to initialize the Y-coordinate
            of the 3D Vector.

            @param fZ
            This parameter is used to initialize the Z-coordinate
            of the 3D Vector.
        */
        B3DVector(double fX, double fY, double fZ)
        :   B3DTuple(fX, fY, fZ)
        {}

        /** Create a copy of a 3D Vector

            @param rVec
            The 3D Vector which will be copied.
        */
        B3DVector(const B3DVector& rVec)
        :   B3DTuple(rVec)
        {}

        /** constructor with tuple to allow copy-constructing
            from B3DTuple-based classes
        */
        B3DVector(const ::basegfx::B3DTuple& rTuple)
        :   B3DTuple(rTuple)
        {}

        ~B3DVector()
        {}

        /** *=operator to allow usage from B3DVector, too
        */
        B3DVector& operator*=( const B3DVector& rPnt )
        {
            mfX *= rPnt.mfX;
            mfY *= rPnt.mfY;
            mfZ *= rPnt.mfZ;
            return *this;
        }

        /** *=operator to allow usage from B3DVector, too
        */
        B3DVector& operator*=(double t)
        {
            mfX *= t;
            mfY *= t;
            mfZ *= t;
            return *this;
        }

        /** assignment operator to allow assigning the results
            of B3DTuple calculations
        */
        B3DVector& operator=( const ::basegfx::B3DTuple& rVec )
        {
            mfX = rVec.getX();
            mfY = rVec.getY();
            mfZ = rVec.getZ();
            return *this;
        }

        /** Calculate the length of this 3D Vector

            @return The Length of the 3D Vector
        */
        double getLength(void) const
        {
            double fLen(scalar(*this));
            if((0.0 == fLen) || (1.0 == fLen))
                return fLen;
            return sqrt(fLen);
        }

        /** Calculate the length in the XY-Plane for this 3D Vector

            @return The XY-Plane Length of the 3D Vector
        */
        double getXYLength(void) const
        {
            double fLen((mfX * mfX) + (mfY * mfY));
            if((0.0 == fLen) || (1.0 == fLen))
                return fLen;
            return sqrt(fLen);
        }

        /** Calculate the length in the XZ-Plane for this 3D Vector

            @return The XZ-Plane Length of the 3D Vector
        */
        double getXZLength(void) const
        {
            double fLen((mfX * mfX) + (mfZ * mfZ)); // #i73040#
            if((0.0 == fLen) || (1.0 == fLen))
                return fLen;
            return sqrt(fLen);
        }

        /** Calculate the length in the YZ-Plane for this 3D Vector

            @return The YZ-Plane Length of the 3D Vector
        */
        double getYZLength(void) const
        {
            double fLen((mfY * mfY) + (mfZ * mfZ));
            if((0.0 == fLen) || (1.0 == fLen))
                return fLen;
            return sqrt(fLen);
        }

        /** Set the length of this 3D Vector

            @param fLen
            The to be achieved length of the 3D Vector
        */
        B3DVector& setLength(double fLen)
        {
            double fLenNow(scalar(*this));

            if(!::basegfx::fTools::equalZero(fLenNow))
            {
                const double fOne(1.0);

                if(!::basegfx::fTools::equal(fOne, fLenNow))
                {
                    fLen /= sqrt(fLenNow);
                }

                mfX *= fLen;
                mfY *= fLen;
                mfZ *= fLen;
            }

            return *this;
        }

        /** Normalize this 3D Vector

            The length of the 3D Vector is set to 1.0
        */
        B3DVector& normalize();

        /** Test if this 3D Vector is normalized

            @return
            true if lenth of vector is equal to 1.0
            false else
        */
        bool isNormalized() const
        {
            const double fOne(1.0);
            const double fScalar(scalar(*this));

            return (::basegfx::fTools::equal(fOne, fScalar));
        }

        /** get a 3D Vector which is perpendicular to this and a given 3D Vector

            @attention This only works if this and the given 3D Vector are
            both normalized.

            @param rNormalizedVec
            A normalized 3D Vector.

            @return
            A 3D Vector perpendicular to this and the given one
        */
        B3DVector getPerpendicular(const B3DVector& rNormalizedVec) const;

        /** get the projection of this Vector on the given Plane

            @attention This only works if the given 3D Vector defining
            the Plane is normalized.

            @param rNormalizedPlane
            A normalized 3D Vector defining a Plane.

            @return
            The projected 3D Vector
        */
        B3DVector getProjectionOnPlane(const B3DVector& rNormalizedPlane) const;

        /** Calculate the Scalar product

            This method calculates the Scalar product between this
            and the given 3D Vector.

            @param rVec
            A second 3D Vector.

            @return
            The Scalar Product of two 3D Vectors
        */
        double scalar(const B3DVector& rVec) const
        {
            return ((mfX * rVec.mfX) + (mfY * rVec.mfY) + (mfZ * rVec.mfZ));
        }

        /** Transform vector by given transformation matrix.

            Since this is a vector, translational components of the
            matrix are disregarded.
        */
        B3DVector& operator*=( const B3DHomMatrix& rMat );

        static const B3DVector& getEmptyVector()
        {
            return (const B3DVector&) ::basegfx::B3DTuple::getEmptyTuple();
        }
    };

    // external operators
    //////////////////////////////////////////////////////////////////////////

    /** get a 3D Vector which is in 2D (ignoring
        the Z-Coordinate) perpendicular to a given 3D Vector

        @attention This only works if the given 3D Vector is normalized.

        @param rNormalizedVec
        A normalized 3D Vector.

        @return
        A 3D Vector perpendicular to the given one in X,Y (2D).
    */
    inline B3DVector getPerpendicular2D( const B3DVector& rNormalizedVec )
    {
        B3DVector aPerpendicular(-rNormalizedVec.getY(), rNormalizedVec.getX(), rNormalizedVec.getZ());
        return aPerpendicular;
    }

    /** Transform vector by given transformation matrix.

        Since this is a vector, translational components of the
        matrix are disregarded.
    */
    B3DVector operator*( const B3DHomMatrix& rMat, const B3DVector& rVec );

    /** Calculate the Cross Product of two 3D Vectors

        @param rVecA
        A first 3D Vector.

        @param rVecB
        A second 3D Vector.

        @return
        The Cross Product of both 3D Vectors
    */
    inline B3DVector cross(const B3DVector& rVecA, const B3DVector& rVecB)
    {
        B3DVector aVec(
            rVecA.getY() * rVecB.getZ() - rVecA.getZ() * rVecB.getY(),
            rVecA.getZ() * rVecB.getX() - rVecA.getX() * rVecB.getZ(),
            rVecA.getX() * rVecB.getY() - rVecA.getY() * rVecB.getX());
        return aVec;
    }
} // end of namespace basegfx

#endif /* _BGFX_VECTOR_B3DVECTOR_HXX */
<commit_msg>INTEGRATION: CWS changefileheader (1.10.38); FILE MERGED 2008/04/01 10:48:12 thb 1.10.38.2: #i85898# Stripping all external header guards 2008/03/28 16:05:47 rt 1.10.38.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: b3dvector.hxx,v $
 * $Revision: 1.11 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _BGFX_VECTOR_B3DVECTOR_HXX
#define _BGFX_VECTOR_B3DVECTOR_HXX

#include <basegfx/tuple/b3dtuple.hxx>

namespace basegfx
{
    // predeclaration
    class B3DHomMatrix;

    /** Base Point class with three double values

        This class derives all operators and common handling for
        a 3D data class from B3DTuple. All necessary extensions
        which are special for 3D Vectors are added here.

        @see B3DTuple
    */
    class B3DVector : public ::basegfx::B3DTuple
    {
    public:
        /** Create a 3D Vector

            The vector is initialized to (0.0, 0.0, 0.0)
        */
        B3DVector()
        :   B3DTuple()
        {}

        /** Create a 3D Vector

            @param fX
            This parameter is used to initialize the X-coordinate
            of the 3D Vector.

            @param fY
            This parameter is used to initialize the Y-coordinate
            of the 3D Vector.

            @param fZ
            This parameter is used to initialize the Z-coordinate
            of the 3D Vector.
        */
        B3DVector(double fX, double fY, double fZ)
        :   B3DTuple(fX, fY, fZ)
        {}

        /** Create a copy of a 3D Vector

            @param rVec
            The 3D Vector which will be copied.
        */
        B3DVector(const B3DVector& rVec)
        :   B3DTuple(rVec)
        {}

        /** constructor with tuple to allow copy-constructing
            from B3DTuple-based classes
        */
        B3DVector(const ::basegfx::B3DTuple& rTuple)
        :   B3DTuple(rTuple)
        {}

        ~B3DVector()
        {}

        /** *=operator to allow usage from B3DVector, too
        */
        B3DVector& operator*=( const B3DVector& rPnt )
        {
            mfX *= rPnt.mfX;
            mfY *= rPnt.mfY;
            mfZ *= rPnt.mfZ;
            return *this;
        }

        /** *=operator to allow usage from B3DVector, too
        */
        B3DVector& operator*=(double t)
        {
            mfX *= t;
            mfY *= t;
            mfZ *= t;
            return *this;
        }

        /** assignment operator to allow assigning the results
            of B3DTuple calculations
        */
        B3DVector& operator=( const ::basegfx::B3DTuple& rVec )
        {
            mfX = rVec.getX();
            mfY = rVec.getY();
            mfZ = rVec.getZ();
            return *this;
        }

        /** Calculate the length of this 3D Vector

            @return The Length of the 3D Vector
        */
        double getLength(void) const
        {
            double fLen(scalar(*this));
            if((0.0 == fLen) || (1.0 == fLen))
                return fLen;
            return sqrt(fLen);
        }

        /** Calculate the length in the XY-Plane for this 3D Vector

            @return The XY-Plane Length of the 3D Vector
        */
        double getXYLength(void) const
        {
            double fLen((mfX * mfX) + (mfY * mfY));
            if((0.0 == fLen) || (1.0 == fLen))
                return fLen;
            return sqrt(fLen);
        }

        /** Calculate the length in the XZ-Plane for this 3D Vector

            @return The XZ-Plane Length of the 3D Vector
        */
        double getXZLength(void) const
        {
            double fLen((mfX * mfX) + (mfZ * mfZ)); // #i73040#
            if((0.0 == fLen) || (1.0 == fLen))
                return fLen;
            return sqrt(fLen);
        }

        /** Calculate the length in the YZ-Plane for this 3D Vector

            @return The YZ-Plane Length of the 3D Vector
        */
        double getYZLength(void) const
        {
            double fLen((mfY * mfY) + (mfZ * mfZ));
            if((0.0 == fLen) || (1.0 == fLen))
                return fLen;
            return sqrt(fLen);
        }

        /** Set the length of this 3D Vector

            @param fLen
            The to be achieved length of the 3D Vector
        */
        B3DVector& setLength(double fLen)
        {
            double fLenNow(scalar(*this));

            if(!::basegfx::fTools::equalZero(fLenNow))
            {
                const double fOne(1.0);

                if(!::basegfx::fTools::equal(fOne, fLenNow))
                {
                    fLen /= sqrt(fLenNow);
                }

                mfX *= fLen;
                mfY *= fLen;
                mfZ *= fLen;
            }

            return *this;
        }

        /** Normalize this 3D Vector

            The length of the 3D Vector is set to 1.0
        */
        B3DVector& normalize();

        /** Test if this 3D Vector is normalized

            @return
            true if lenth of vector is equal to 1.0
            false else
        */
        bool isNormalized() const
        {
            const double fOne(1.0);
            const double fScalar(scalar(*this));

            return (::basegfx::fTools::equal(fOne, fScalar));
        }

        /** get a 3D Vector which is perpendicular to this and a given 3D Vector

            @attention This only works if this and the given 3D Vector are
            both normalized.

            @param rNormalizedVec
            A normalized 3D Vector.

            @return
            A 3D Vector perpendicular to this and the given one
        */
        B3DVector getPerpendicular(const B3DVector& rNormalizedVec) const;

        /** get the projection of this Vector on the given Plane

            @attention This only works if the given 3D Vector defining
            the Plane is normalized.

            @param rNormalizedPlane
            A normalized 3D Vector defining a Plane.

            @return
            The projected 3D Vector
        */
        B3DVector getProjectionOnPlane(const B3DVector& rNormalizedPlane) const;

        /** Calculate the Scalar product

            This method calculates the Scalar product between this
            and the given 3D Vector.

            @param rVec
            A second 3D Vector.

            @return
            The Scalar Product of two 3D Vectors
        */
        double scalar(const B3DVector& rVec) const
        {
            return ((mfX * rVec.mfX) + (mfY * rVec.mfY) + (mfZ * rVec.mfZ));
        }

        /** Transform vector by given transformation matrix.

            Since this is a vector, translational components of the
            matrix are disregarded.
        */
        B3DVector& operator*=( const B3DHomMatrix& rMat );

        static const B3DVector& getEmptyVector()
        {
            return (const B3DVector&) ::basegfx::B3DTuple::getEmptyTuple();
        }
    };

    // external operators
    //////////////////////////////////////////////////////////////////////////

    /** get a 3D Vector which is in 2D (ignoring
        the Z-Coordinate) perpendicular to a given 3D Vector

        @attention This only works if the given 3D Vector is normalized.

        @param rNormalizedVec
        A normalized 3D Vector.

        @return
        A 3D Vector perpendicular to the given one in X,Y (2D).
    */
    inline B3DVector getPerpendicular2D( const B3DVector& rNormalizedVec )
    {
        B3DVector aPerpendicular(-rNormalizedVec.getY(), rNormalizedVec.getX(), rNormalizedVec.getZ());
        return aPerpendicular;
    }

    /** Transform vector by given transformation matrix.

        Since this is a vector, translational components of the
        matrix are disregarded.
    */
    B3DVector operator*( const B3DHomMatrix& rMat, const B3DVector& rVec );

    /** Calculate the Cross Product of two 3D Vectors

        @param rVecA
        A first 3D Vector.

        @param rVecB
        A second 3D Vector.

        @return
        The Cross Product of both 3D Vectors
    */
    inline B3DVector cross(const B3DVector& rVecA, const B3DVector& rVecB)
    {
        B3DVector aVec(
            rVecA.getY() * rVecB.getZ() - rVecA.getZ() * rVecB.getY(),
            rVecA.getZ() * rVecB.getX() - rVecA.getX() * rVecB.getZ(),
            rVecA.getX() * rVecB.getY() - rVecA.getY() * rVecB.getX());
        return aVec;
    }
} // end of namespace basegfx

#endif /* _BGFX_VECTOR_B3DVECTOR_HXX */
<|endoftext|>


<commit_before>#include "OfflineIteratingLearner.h"

bool OfflineIteratingLearner::autocalled_initialize() {
  random_iterator_->restart();
  while( random_iterator_->has_next() ) {
    RecDat *rec_dat = random_iterator_->next();
    model_->add(rec_dat);
  }
}

void OfflineIteratingLearner::iterate() {
  initialize();
  if(early_simple_updaters_.size()>0){
    random_iterator_->restart();
    for(uint ui = 0; ui<early_simple_updaters_.size(); ui++){
      early_simple_updaters_[ui]->start_of_updating(NULL);
    }
    while ( random_iterator_->has_next() ) {
      RecDat *rec_dat = random_iterator_->next();
      for(uint ui = 0; ui<early_simple_updaters_.size(); ui++){
        early_simple_updaters_[ui]->update(rec_dat);
      }
    }
    for(uint ui = 0; ui<early_simple_updaters_.size(); ui++){
      early_simple_updaters_[ui]->end_of_updating(NULL);
    }
  }
  if(gradient_updaters_.size()>0){
    int counter = number_of_iterations_+1;
    while (--counter) {
      // cerr << "Beginning of " << number_of_iterations_+1-counter << "th iteration." << endl;
      random_iterator_->shuffle();
      while ( random_iterator_->has_next() ) {
        RecDat *rec_dat = random_iterator_->next();
        double gradient = gradient_computer_->get_gradient(rec_dat);
        for(uint ui = 0; ui<gradient_updaters_.size(); ui++) {
          gradient_updaters_[ui]->update(rec_dat, gradient);
        }
      }
      // cerr << "End of " << number_of_iterations_+1-counter << "th iteration." << endl;
    }
  }
  if(simple_updaters_.size()>0){
    random_iterator_->restart();
    for(uint ui = 0; ui<simple_updaters_.size(); ui++){
      simple_updaters_[ui]->start_of_updating(NULL);
    }
    while ( random_iterator_->has_next() ) {
      RecDat *rec_dat = random_iterator_->next();
      for(uint ui = 0; ui<simple_updaters_.size(); ui++){
        simple_updaters_[ui]->update(rec_dat);
      }
    }
    for(uint ui = 0; ui<simple_updaters_.size(); ui++){
      simple_updaters_[ui]->end_of_updating(NULL);
    }
  }
}
<commit_msg>offline Pop: pytest<commit_after>#include "OfflineIteratingLearner.h"

bool OfflineIteratingLearner::autocalled_initialize() {
  random_iterator_->restart();
  while( random_iterator_->has_next() ) {
    RecDat *rec_dat = random_iterator_->next();
    model_->add(rec_dat);
  }
  return true;
}

void OfflineIteratingLearner::iterate() {
  if(early_simple_updaters_.size()>0){
    random_iterator_->restart();
    for(uint ui = 0; ui<early_simple_updaters_.size(); ui++){
      early_simple_updaters_[ui]->start_of_updating(NULL);
    }
    while ( random_iterator_->has_next() ) {
      RecDat *rec_dat = random_iterator_->next();
      for(uint ui = 0; ui<early_simple_updaters_.size(); ui++){
        early_simple_updaters_[ui]->update(rec_dat);
      }
    }
    for(uint ui = 0; ui<early_simple_updaters_.size(); ui++){
      early_simple_updaters_[ui]->end_of_updating(NULL);
    }
  }
  if(gradient_updaters_.size()>0){
    int counter = number_of_iterations_+1;
    while (--counter) {
      // cerr << "Beginning of " << number_of_iterations_+1-counter << "th iteration." << endl;
      random_iterator_->shuffle();
      while ( random_iterator_->has_next() ) {
        RecDat *rec_dat = random_iterator_->next();
        double gradient = gradient_computer_->get_gradient(rec_dat);
        for(uint ui = 0; ui<gradient_updaters_.size(); ui++) {
          gradient_updaters_[ui]->update(rec_dat, gradient);
        }
      }
      // cerr << "End of " << number_of_iterations_+1-counter << "th iteration." << endl;
    }
  }
  if(simple_updaters_.size()>0){
    random_iterator_->restart();
    for(uint ui = 0; ui<simple_updaters_.size(); ui++){
      simple_updaters_[ui]->start_of_updating(NULL);
    }
    while ( random_iterator_->has_next() ) {
      RecDat *rec_dat = random_iterator_->next();
      for(uint ui = 0; ui<simple_updaters_.size(); ui++){
        simple_updaters_[ui]->update(rec_dat);
      }
    }
    for(uint ui = 0; ui<simple_updaters_.size(); ui++){
      simple_updaters_[ui]->end_of_updating(NULL);
    }
  }
}
<|endoftext|>


<commit_before>// (c) 2011 Cloudera, Inc. All rights reserved.

#include "runtime/plan-fragment-executor.h"

#include <Thrift.h>
#include <protocol/TBinaryProtocol.h>
#include <protocol/TDebugProtocol.h>
#include <transport/TBufferTransports.h>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/unordered_map.hpp>
#include <boost/foreach.hpp>

#include "codegen/llvm-codegen.h"
#include "common/logging.h"
#include "common/object-pool.h"
#include "exec/data-sink.h"
#include "exec/exec-node.h"
#include "exec/exchange-node.h"
#include "exec/scan-node.h"
#include "exec/hbase-table-scanner.h"
#include "exprs/expr.h"
#include "runtime/descriptors.h"
#include "runtime/data-stream-mgr.h"
#include "runtime/row-batch.h"
#include "util/cpu-info.h"
#include "util/debug-util.h"
#include "util/container-util.h"
#include "gen-cpp/ImpalaPlanService_types.h"

DEFINE_bool(serialize_batch, false, "serialize and deserialize each returned row batch");
DEFINE_int32(status_report_interval, 5, "interval between profile reports; in seconds");

using namespace std;
using namespace boost;
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;

namespace impala {

PlanFragmentExecutor::PlanFragmentExecutor(
    ExecEnv* exec_env, const ReportStatusCallback& report_status_cb)
  : exec_env_(exec_env),
    report_status_cb_(report_status_cb),
    report_thread_active_(false),
    done_(false),
    prepared_(false) {
}

PlanFragmentExecutor::~PlanFragmentExecutor() {
  // delete row batch and free up resources, otherwise DiskIoMgr will complain
  // if we try to Close() an HdfsScanNode while still holding
  // DiskIoMgr::BufferDescriptors
  row_batch_.reset(NULL);
  // Prepare may not have been called, which sets runtime_state_
  if (runtime_state_.get() != NULL) {
    plan_->Close(runtime_state_.get());
    if (sink_.get() != NULL) {
      sink_->Close(runtime_state());
    }
  }
  // at this point, the report thread should have been stopped
  DCHECK(!report_thread_active_);
}

Status PlanFragmentExecutor::Prepare(const TExecPlanFragmentParams& request) {
  const TPlanFragmentExecParams& params = request.params;
  query_id_ = params.query_id;

  VLOG_QUERY << "Prepare(): query_id=" << PrintId(query_id_)
             << " instance_id=" << PrintId(params.fragment_instance_id);
  VLOG(2) << "params:\n" << ThriftDebugString(params);

  runtime_state_.reset(
      new RuntimeState(params.fragment_instance_id, request.query_options,
          request.query_globals.now_string, exec_env_));

  // set up desc tbl
  DescriptorTbl* desc_tbl = NULL;
  DCHECK(request.__isset.desc_tbl);
  RETURN_IF_ERROR(DescriptorTbl::Create(obj_pool(), request.desc_tbl, &desc_tbl));
  runtime_state_->set_desc_tbl(desc_tbl);
  VLOG_QUERY << "descriptor table for fragment=" << params.fragment_instance_id << "\n"
             << desc_tbl->DebugString();

  // set up plan
  DCHECK(request.__isset.fragment);
  RETURN_IF_ERROR(
      ExecNode::CreateTree(obj_pool(), request.fragment.plan, *desc_tbl, &plan_));
  profile()->AddChild(plan_->runtime_profile());

  // set #senders of exchange nodes before calling Prepare()
  vector<ExecNode*> exch_nodes;
  plan_->CollectNodes(TPlanNodeType::EXCHANGE_NODE, &exch_nodes);
  BOOST_FOREACH(ExecNode* exch_node, exch_nodes) {
    DCHECK_EQ(exch_node->type(), TPlanNodeType::EXCHANGE_NODE);
    int num_senders = FindWithDefault(params.per_exch_num_senders, exch_node->id(), 0);
    DCHECK_GT(num_senders, 0);
    static_cast<ExchangeNode*>(exch_node)->set_num_senders(num_senders);
  }

  RETURN_IF_ERROR(plan_->Prepare(runtime_state_.get()));

  if (runtime_state_->llvm_codegen() != NULL) {
    // After prepare, all functions should have been code-generated.  At this point
    // we optimize all the functions.
    Status status = runtime_state_->llvm_codegen()->OptimizeModule();
    if (!status.ok()) {
      LOG(ERROR) << "Error with codegen for this query: " << status.GetErrorMsg();
      // TODO: propagate this to the coordinator and user?  Not really actionable
      // for them but we'd like them to let us know.
    }
    // If codegen failed, we automatically fall back to not using codegen.
  }

  // set scan ranges
  vector<ExecNode*> scan_nodes;
  vector<TScanRangeParams> no_scan_ranges;
  plan_->CollectScanNodes(&scan_nodes);
  for (int i = 0; i < scan_nodes.size(); ++i) {
    ScanNode* scan_node = static_cast<ScanNode*>(scan_nodes[i]);
    const vector<TScanRangeParams>& scan_ranges =
        FindWithDefault(params.per_node_scan_ranges, scan_node->id(), no_scan_ranges);
    scan_node->SetScanRanges(scan_ranges);
  }

  PrintVolumeIds(params.per_node_scan_ranges);

  // set up sink, if required
  if (request.fragment.__isset.output_sink) {
    RETURN_IF_ERROR(DataSink::CreateDataSink(
        request.fragment.output_sink, request.fragment.output_exprs, params,
        row_desc(), &sink_));
    RETURN_IF_ERROR(sink_->Init(runtime_state()));
  } else {
    sink_.reset(NULL);
  }

  // set up profile counters
  rows_produced_counter_ = ADD_COUNTER(profile(), "RowsProduced", TCounterType::UNIT);

  row_batch_.reset(new RowBatch(plan_->row_desc(), runtime_state_->batch_size()));
  VLOG(3) << "plan_root=\n" << plan_->DebugString();
  prepared_ = true;
  return Status::OK;
}

void PlanFragmentExecutor::PrintVolumeIds(
    const PerNodeScanRanges& per_node_scan_ranges) {
  if (per_node_scan_ranges.empty()) return;

  // map from volume id to (# of splits, total # bytes) on that volume
  unordered_map<int32_t, pair<int, int64_t> > per_volume_stats;
  pair<int, int64_t> init_value(0, 0);
  BOOST_FOREACH(const PerNodeScanRanges::value_type& entry, per_node_scan_ranges) {
    BOOST_FOREACH(const TScanRangeParams& scan_range_params, entry.second) {
      const TScanRange& scan_range = scan_range_params.scan_range;
      if (!scan_range.__isset.hdfs_file_split) continue;
      const THdfsFileSplit& split = scan_range.hdfs_file_split;
      pair<int, int64_t>* stats =
          FindOrInsert(&per_volume_stats, scan_range_params.volume_id, init_value);
      ++(stats->first);
      stats->second += split.length;
    }
  }

  stringstream str;
  for (unordered_map<int32_t, pair<int, int64_t> >::iterator i = per_volume_stats.begin();
       i != per_volume_stats.end(); ++i) {
     str << i->first << ":" << i->second.first << "/"
         << PrettyPrinter::Print(i->second.second, TCounterType::UNIT) << " ";
  }
  profile()->AddInfoString("Hdfs split stats (<volume id>:<# splits>/<split lengths>)",
     str.str());

  VLOG_FILE << "Hdfs split stats (<volume id>:<# splits>/<split lengths>) for query="
            << query_id_ << ":\n"
            << str.str();
}

Status PlanFragmentExecutor::Open() {
  VLOG_QUERY << "Open(): instance_id=" << runtime_state_->fragment_instance_id();
  // we need to start the profile-reporting thread before calling Open(), since it
  // may block
  // TODO: if no report thread is started, make sure to send a final profile
  // at end, otherwise the coordinator hangs in case we finish w/ an error
  if (!report_status_cb_.empty() && FLAGS_status_report_interval > 0) {
    unique_lock<mutex> l(report_thread_lock_);
    report_thread_ = thread(&PlanFragmentExecutor::ReportProfile, this);
    // make sure the thread started up, otherwise ReportProfile() might get into a race
    // with StopReportThread()
    report_thread_started_cv_.wait(l);
    report_thread_active_ = true;
  }

  Status status = OpenInternal();
  UpdateStatus(status);
  return status;
}

Status PlanFragmentExecutor::OpenInternal() {
  {
    SCOPED_TIMER(profile()->total_time_counter());
    RETURN_IF_ERROR(plan_->Open(runtime_state_.get()));
  }

  if (sink_.get() == NULL) return Status::OK;

  // If there is a sink, do all the work of driving it here, so that
  // when this returns the query has actually finished
  RowBatch* batch;
  while (true) {
    RETURN_IF_ERROR(GetNextInternal(&batch));
    if (batch == NULL) break;
    if (VLOG_ROW_IS_ON) {
      VLOG_ROW << "OpenInternal: #rows=" << batch->num_rows();
      for (int i = 0; i < batch->num_rows(); ++i) {
        TupleRow* row = batch->GetRow(i);
        VLOG_ROW << PrintRow(row, row_desc());
      }
    }
    RETURN_IF_ERROR(sink_->Send(runtime_state(), batch));
  }

  // Close the sink *before* stopping the report thread. Close may
  // need to add some important information to the last report that
  // gets sent. (e.g. table sinks record the files they have written
  // to in this method)
  // The coordinator report channel waits until all backends are
  // either in error or have returned a status report with done =
  // true, so tearing down any data stream state (a separate
  // channel) in Close is safe.

  // TODO: If this returns an error, the d'tor will call Close again. We should
  // audit the sinks to check that this is ok, or change that behaviour.
  RETURN_IF_ERROR(sink_->Close(runtime_state()));

  // Setting to NULL ensures that the d'tor won't double-close the sink.
  sink_.reset(NULL);
  done_ = true;

  StopReportThread();
  SendReport(true);

  return Status::OK;
}

void PlanFragmentExecutor::ReportProfile() {
  VLOG_FILE << "ReportProfile(): instance_id="
            << runtime_state_->fragment_instance_id();
  DCHECK(!report_status_cb_.empty());
  unique_lock<mutex> l(report_thread_lock_);
  // tell Open() that we started
  report_thread_started_cv_.notify_one();

  // Jitter the reporting time of remote fragments by a random amount between
  // 0 and the report_interval.  This way, the coordinator doesn't get all the
  // updates at once so its better for contention as well as smoother progress
  // reporting.
  int report_fragment_offset = rand() % FLAGS_status_report_interval;
  system_time timeout =
      get_system_time() + posix_time::seconds(report_fragment_offset);
  // We don't want to wait longer than it takes to run the entire fragment.
  bool notified = stop_report_thread_cv_.timed_wait(l, timeout);

  while (!notified) {
    system_time timeout =
        get_system_time() + posix_time::seconds(FLAGS_status_report_interval);
    notified = stop_report_thread_cv_.timed_wait(l, timeout);

    if (VLOG_FILE_IS_ON) {
      VLOG_FILE << "Reporting " << (notified ? "final " : " ")
                << "profile for instance " << runtime_state_->fragment_instance_id();
      stringstream ss;
      profile()->PrettyPrint(&ss);
      VLOG_FILE << ss.str();
    }

    if (notified) break;
    SendReport(false);
  }

  VLOG_FILE << "exiting reporting thread: instance_id="
            << runtime_state_->fragment_instance_id();
}

void PlanFragmentExecutor::SendReport(bool done) {
  if (report_status_cb_.empty()) return;

  Status status;
  {
    lock_guard<mutex> l(status_lock_);
    status = status_;
  }
  // don't send a final report if we got cancelled, nobody's going to look at it
  // anyway
  if (!status.IsCancelled()) {
    // notified means someone notified on stop_report_thread_cv_
    report_status_cb_(status, profile(), done || !status.ok());
  }
}

void PlanFragmentExecutor::StopReportThread() {
  if (!report_thread_active_) return;
  {
    lock_guard<mutex> l(report_thread_lock_);
    // notify with lock held: ReportProfile() does a timed_wait() on the cond
    // var, we need to make sure it really is sitting in timed_wait() while
    // we notify()
    stop_report_thread_cv_.notify_one();
  }
  report_thread_.join();
  report_thread_active_ = false;
}

Status PlanFragmentExecutor::GetNext(RowBatch** batch) {
  VLOG_FILE << "GetNext(): instance_id=" << runtime_state_->fragment_instance_id();
  Status status = GetNextInternal(batch);
  UpdateStatus(status);
  if (done_) {
    VLOG_QUERY << "Finished executing fragment query_id=" << PrintId(query_id_)
               << " instance_id=" << PrintId(runtime_state_->fragment_instance_id());
    StopReportThread();
    SendReport(true);
  }
  return status;
}

Status PlanFragmentExecutor::GetNextInternal(RowBatch** batch) {
  if (done_) {
    *batch = NULL;
    return Status::OK;
  }

  while (!done_) {
    row_batch_->Reset();
    SCOPED_TIMER(profile()->total_time_counter());
    RETURN_IF_ERROR(plan_->GetNext(runtime_state_.get(), row_batch_.get(), &done_));
    if (row_batch_->num_rows() > 0) {
      COUNTER_UPDATE(rows_produced_counter_, row_batch_->num_rows());
      *batch = row_batch_.get();
      break;
    }
    *batch = NULL;
  }

  return Status::OK;
}

void PlanFragmentExecutor::UpdateStatus(const Status& status) {
  if (status.ok()) return;
  {
    lock_guard<mutex> l(status_lock_);
    if (status_.ok()) status_ = status;
  }
  StopReportThread();
  SendReport(true);
}

void PlanFragmentExecutor::Cancel() {
  VLOG_QUERY << "Cancel(): instance_id=" << runtime_state_->fragment_instance_id();
  DCHECK(prepared_);
  runtime_state_->set_is_cancelled(true);
  runtime_state_->stream_mgr()->Cancel(runtime_state_->fragment_instance_id());
}

const RowDescriptor& PlanFragmentExecutor::row_desc() {
  return plan_->row_desc();
}

RuntimeProfile* PlanFragmentExecutor::profile() {
  return runtime_state_->runtime_profile();
}

}
<commit_msg>Fix hang in reporting thread.<commit_after>// (c) 2011 Cloudera, Inc. All rights reserved.

#include "runtime/plan-fragment-executor.h"

#include <Thrift.h>
#include <protocol/TBinaryProtocol.h>
#include <protocol/TDebugProtocol.h>
#include <transport/TBufferTransports.h>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/unordered_map.hpp>
#include <boost/foreach.hpp>

#include "codegen/llvm-codegen.h"
#include "common/logging.h"
#include "common/object-pool.h"
#include "exec/data-sink.h"
#include "exec/exec-node.h"
#include "exec/exchange-node.h"
#include "exec/scan-node.h"
#include "exec/hbase-table-scanner.h"
#include "exprs/expr.h"
#include "runtime/descriptors.h"
#include "runtime/data-stream-mgr.h"
#include "runtime/row-batch.h"
#include "util/cpu-info.h"
#include "util/debug-util.h"
#include "util/container-util.h"
#include "gen-cpp/ImpalaPlanService_types.h"

DEFINE_bool(serialize_batch, false, "serialize and deserialize each returned row batch");
DEFINE_int32(status_report_interval, 5, "interval between profile reports; in seconds");

using namespace std;
using namespace boost;
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;

namespace impala {

PlanFragmentExecutor::PlanFragmentExecutor(
    ExecEnv* exec_env, const ReportStatusCallback& report_status_cb)
  : exec_env_(exec_env),
    report_status_cb_(report_status_cb),
    report_thread_active_(false),
    done_(false),
    prepared_(false) {
}

PlanFragmentExecutor::~PlanFragmentExecutor() {
  // delete row batch and free up resources, otherwise DiskIoMgr will complain
  // if we try to Close() an HdfsScanNode while still holding
  // DiskIoMgr::BufferDescriptors
  row_batch_.reset(NULL);
  // Prepare may not have been called, which sets runtime_state_
  if (runtime_state_.get() != NULL) {
    plan_->Close(runtime_state_.get());
    if (sink_.get() != NULL) {
      sink_->Close(runtime_state());
    }
  }
  // at this point, the report thread should have been stopped
  DCHECK(!report_thread_active_);
}

Status PlanFragmentExecutor::Prepare(const TExecPlanFragmentParams& request) {
  const TPlanFragmentExecParams& params = request.params;
  query_id_ = params.query_id;

  VLOG_QUERY << "Prepare(): query_id=" << PrintId(query_id_)
             << " instance_id=" << PrintId(params.fragment_instance_id);
  VLOG(2) << "params:\n" << ThriftDebugString(params);

  runtime_state_.reset(
      new RuntimeState(params.fragment_instance_id, request.query_options,
          request.query_globals.now_string, exec_env_));

  // set up desc tbl
  DescriptorTbl* desc_tbl = NULL;
  DCHECK(request.__isset.desc_tbl);
  RETURN_IF_ERROR(DescriptorTbl::Create(obj_pool(), request.desc_tbl, &desc_tbl));
  runtime_state_->set_desc_tbl(desc_tbl);
  VLOG_QUERY << "descriptor table for fragment=" << params.fragment_instance_id << "\n"
             << desc_tbl->DebugString();

  // set up plan
  DCHECK(request.__isset.fragment);
  RETURN_IF_ERROR(
      ExecNode::CreateTree(obj_pool(), request.fragment.plan, *desc_tbl, &plan_));
  profile()->AddChild(plan_->runtime_profile());

  // set #senders of exchange nodes before calling Prepare()
  vector<ExecNode*> exch_nodes;
  plan_->CollectNodes(TPlanNodeType::EXCHANGE_NODE, &exch_nodes);
  BOOST_FOREACH(ExecNode* exch_node, exch_nodes) {
    DCHECK_EQ(exch_node->type(), TPlanNodeType::EXCHANGE_NODE);
    int num_senders = FindWithDefault(params.per_exch_num_senders, exch_node->id(), 0);
    DCHECK_GT(num_senders, 0);
    static_cast<ExchangeNode*>(exch_node)->set_num_senders(num_senders);
  }

  RETURN_IF_ERROR(plan_->Prepare(runtime_state_.get()));

  if (runtime_state_->llvm_codegen() != NULL) {
    // After prepare, all functions should have been code-generated.  At this point
    // we optimize all the functions.
    Status status = runtime_state_->llvm_codegen()->OptimizeModule();
    if (!status.ok()) {
      LOG(ERROR) << "Error with codegen for this query: " << status.GetErrorMsg();
      // TODO: propagate this to the coordinator and user?  Not really actionable
      // for them but we'd like them to let us know.
    }
    // If codegen failed, we automatically fall back to not using codegen.
  }

  // set scan ranges
  vector<ExecNode*> scan_nodes;
  vector<TScanRangeParams> no_scan_ranges;
  plan_->CollectScanNodes(&scan_nodes);
  for (int i = 0; i < scan_nodes.size(); ++i) {
    ScanNode* scan_node = static_cast<ScanNode*>(scan_nodes[i]);
    const vector<TScanRangeParams>& scan_ranges =
        FindWithDefault(params.per_node_scan_ranges, scan_node->id(), no_scan_ranges);
    scan_node->SetScanRanges(scan_ranges);
  }

  PrintVolumeIds(params.per_node_scan_ranges);

  // set up sink, if required
  if (request.fragment.__isset.output_sink) {
    RETURN_IF_ERROR(DataSink::CreateDataSink(
        request.fragment.output_sink, request.fragment.output_exprs, params,
        row_desc(), &sink_));
    RETURN_IF_ERROR(sink_->Init(runtime_state()));
  } else {
    sink_.reset(NULL);
  }

  // set up profile counters
  rows_produced_counter_ = ADD_COUNTER(profile(), "RowsProduced", TCounterType::UNIT);

  row_batch_.reset(new RowBatch(plan_->row_desc(), runtime_state_->batch_size()));
  VLOG(3) << "plan_root=\n" << plan_->DebugString();
  prepared_ = true;
  return Status::OK;
}

void PlanFragmentExecutor::PrintVolumeIds(
    const PerNodeScanRanges& per_node_scan_ranges) {
  if (per_node_scan_ranges.empty()) return;

  // map from volume id to (# of splits, total # bytes) on that volume
  unordered_map<int32_t, pair<int, int64_t> > per_volume_stats;
  pair<int, int64_t> init_value(0, 0);
  BOOST_FOREACH(const PerNodeScanRanges::value_type& entry, per_node_scan_ranges) {
    BOOST_FOREACH(const TScanRangeParams& scan_range_params, entry.second) {
      const TScanRange& scan_range = scan_range_params.scan_range;
      if (!scan_range.__isset.hdfs_file_split) continue;
      const THdfsFileSplit& split = scan_range.hdfs_file_split;
      pair<int, int64_t>* stats =
          FindOrInsert(&per_volume_stats, scan_range_params.volume_id, init_value);
      ++(stats->first);
      stats->second += split.length;
    }
  }

  stringstream str;
  for (unordered_map<int32_t, pair<int, int64_t> >::iterator i = per_volume_stats.begin();
       i != per_volume_stats.end(); ++i) {
     str << i->first << ":" << i->second.first << "/"
         << PrettyPrinter::Print(i->second.second, TCounterType::UNIT) << " ";
  }
  profile()->AddInfoString("Hdfs split stats (<volume id>:<# splits>/<split lengths>)",
     str.str());

  VLOG_FILE << "Hdfs split stats (<volume id>:<# splits>/<split lengths>) for query="
            << query_id_ << ":\n"
            << str.str();
}

Status PlanFragmentExecutor::Open() {
  VLOG_QUERY << "Open(): instance_id=" << runtime_state_->fragment_instance_id();
  // we need to start the profile-reporting thread before calling Open(), since it
  // may block
  // TODO: if no report thread is started, make sure to send a final profile
  // at end, otherwise the coordinator hangs in case we finish w/ an error
  if (!report_status_cb_.empty() && FLAGS_status_report_interval > 0) {
    unique_lock<mutex> l(report_thread_lock_);
    report_thread_ = thread(&PlanFragmentExecutor::ReportProfile, this);
    // make sure the thread started up, otherwise ReportProfile() might get into a race
    // with StopReportThread()
    report_thread_started_cv_.wait(l);
    report_thread_active_ = true;
  }

  Status status = OpenInternal();
  UpdateStatus(status);
  return status;
}

Status PlanFragmentExecutor::OpenInternal() {
  {
    SCOPED_TIMER(profile()->total_time_counter());
    RETURN_IF_ERROR(plan_->Open(runtime_state_.get()));
  }

  if (sink_.get() == NULL) return Status::OK;

  // If there is a sink, do all the work of driving it here, so that
  // when this returns the query has actually finished
  RowBatch* batch;
  while (true) {
    RETURN_IF_ERROR(GetNextInternal(&batch));
    if (batch == NULL) break;
    if (VLOG_ROW_IS_ON) {
      VLOG_ROW << "OpenInternal: #rows=" << batch->num_rows();
      for (int i = 0; i < batch->num_rows(); ++i) {
        TupleRow* row = batch->GetRow(i);
        VLOG_ROW << PrintRow(row, row_desc());
      }
    }
    RETURN_IF_ERROR(sink_->Send(runtime_state(), batch));
  }

  // Close the sink *before* stopping the report thread. Close may
  // need to add some important information to the last report that
  // gets sent. (e.g. table sinks record the files they have written
  // to in this method)
  // The coordinator report channel waits until all backends are
  // either in error or have returned a status report with done =
  // true, so tearing down any data stream state (a separate
  // channel) in Close is safe.

  // TODO: If this returns an error, the d'tor will call Close again. We should
  // audit the sinks to check that this is ok, or change that behaviour.
  RETURN_IF_ERROR(sink_->Close(runtime_state()));

  // Setting to NULL ensures that the d'tor won't double-close the sink.
  sink_.reset(NULL);
  done_ = true;

  StopReportThread();
  SendReport(true);

  return Status::OK;
}

void PlanFragmentExecutor::ReportProfile() {
  VLOG_FILE << "ReportProfile(): instance_id="
            << runtime_state_->fragment_instance_id();
  DCHECK(!report_status_cb_.empty());
  unique_lock<mutex> l(report_thread_lock_);
  // tell Open() that we started
  report_thread_started_cv_.notify_one();

  // Jitter the reporting time of remote fragments by a random amount between
  // 0 and the report_interval.  This way, the coordinator doesn't get all the
  // updates at once so its better for contention as well as smoother progress
  // reporting.
  int report_fragment_offset = rand() % FLAGS_status_report_interval;
  system_time timeout =
      get_system_time() + posix_time::seconds(report_fragment_offset);
  // We don't want to wait longer than it takes to run the entire fragment.
  stop_report_thread_cv_.timed_wait(l, timeout);

  while (report_thread_active_) {
    system_time timeout =
        get_system_time() + posix_time::seconds(FLAGS_status_report_interval);

    // timed_wait can return because the timeout occurred or the condition variable
    // was signaled.  We can't rely on its return value to distinguish between the
    // two cases (e.g. there is a race here where the wait timed out but before grabbing
    // the lock, the condition variable was signaled).  Instead, we will use an external
    // flag, report_thread_active_, to coordinate this.
    stop_report_thread_cv_.timed_wait(l, timeout);

    if (VLOG_FILE_IS_ON) {
      VLOG_FILE << "Reporting " << (!report_thread_active_ ? "final " : " ")
                << "profile for instance " << runtime_state_->fragment_instance_id();
      stringstream ss;
      profile()->PrettyPrint(&ss);
      VLOG_FILE << ss.str();
    }

    if (!report_thread_active_) break;
    SendReport(false);
  }

  VLOG_FILE << "exiting reporting thread: instance_id="
            << runtime_state_->fragment_instance_id();
}

void PlanFragmentExecutor::SendReport(bool done) {
  if (report_status_cb_.empty()) return;

  Status status;
  {
    lock_guard<mutex> l(status_lock_);
    status = status_;
  }
  // don't send a final report if we got cancelled, nobody's going to look at it
  // anyway
  if (!status.IsCancelled()) {
    report_status_cb_(status, profile(), done || !status.ok());
  }
}

void PlanFragmentExecutor::StopReportThread() {
  if (!report_thread_active_) return;
  {
    lock_guard<mutex> l(report_thread_lock_);
    report_thread_active_ = false;
  }
  stop_report_thread_cv_.notify_one();
  report_thread_.join();
}

Status PlanFragmentExecutor::GetNext(RowBatch** batch) {
  VLOG_FILE << "GetNext(): instance_id=" << runtime_state_->fragment_instance_id();
  Status status = GetNextInternal(batch);
  UpdateStatus(status);
  if (done_) {
    VLOG_QUERY << "Finished executing fragment query_id=" << PrintId(query_id_)
               << " instance_id=" << PrintId(runtime_state_->fragment_instance_id());
    StopReportThread();
    SendReport(true);
  }
  return status;
}

Status PlanFragmentExecutor::GetNextInternal(RowBatch** batch) {
  if (done_) {
    *batch = NULL;
    return Status::OK;
  }

  while (!done_) {
    row_batch_->Reset();
    SCOPED_TIMER(profile()->total_time_counter());
    RETURN_IF_ERROR(plan_->GetNext(runtime_state_.get(), row_batch_.get(), &done_));
    if (row_batch_->num_rows() > 0) {
      COUNTER_UPDATE(rows_produced_counter_, row_batch_->num_rows());
      *batch = row_batch_.get();
      break;
    }
    *batch = NULL;
  }

  return Status::OK;
}

void PlanFragmentExecutor::UpdateStatus(const Status& status) {
  if (status.ok()) return;
  {
    lock_guard<mutex> l(status_lock_);
    if (status_.ok()) status_ = status;
  }
  StopReportThread();
  SendReport(true);
}

void PlanFragmentExecutor::Cancel() {
  VLOG_QUERY << "Cancel(): instance_id=" << runtime_state_->fragment_instance_id();
  DCHECK(prepared_);
  runtime_state_->set_is_cancelled(true);
  runtime_state_->stream_mgr()->Cancel(runtime_state_->fragment_instance_id());
}

const RowDescriptor& PlanFragmentExecutor::row_desc() {
  return plan_->row_desc();
}

RuntimeProfile* PlanFragmentExecutor::profile() {
  return runtime_state_->runtime_profile();
}

}
<|endoftext|>


<commit_before>/*
** Copyright 1993 by Miron Livny, and Mike Litzkow
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted,
** provided that the above copyright notice appear in all copies and that
** both that copyright notice and this permission notice appear in
** supporting documentation, and that the names of the University of
** Wisconsin and the copyright holders not be used in advertising or
** publicity pertaining to distribution of the software without specific,
** written prior permission.  The University of Wisconsin and the
** copyright holders make no representations about the suitability of this
** software for any purpose.  It is provided "as is" without express
** or implied warranty.
**
** THE UNIVERSITY OF WISCONSIN AND THE COPYRIGHT HOLDERS DISCLAIM ALL
** WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE UNIVERSITY OF
** WISCONSIN OR THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT
** OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
** OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
** OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
** OR PERFORMANCE OF THIS SOFTWARE.
**
** Author:  Mike Litzkow
**
*/

/*
Portability
	The code in this file is not POSIX.1 conforming, and is
	therefore not generally portable.  However, this code is
	generally portable across UNIX platforms with little or no
	modification.
*/

#define _POSIX_SOURCE

#if defined(ULTRIX42) || defined(ULTRIX43)
typedef char *  caddr_t;
#endif

#include "condor_common.h"
#include "condor_debug.h"
#if 0
#include "proto.h"
#endif
#include "condor_jobqueue.h"
#include "condor_sys.h"
#include <signal.h>
#include <sys/stat.h>

extern "C" {
	int SetSyscalls( int );
}

static char *_FileName_ = __FILE__;     /* Used by EXCEPT (see except.h)     */

/*
Controlling any of these limits is problematic because the system calls
setrlimit() and getrlimit() do not appear in POSIX.1, but leaving them
to chance in environments where they appear is unacceptable.  Defaults
limits will frequently be handed down by some shell whose
initialization file has been set up by the system administrator.  These
will often not be appropriate for condor operation.  For example the
administrator may have set the limit for COREDUMPSIZE to 0.

Additional complication results from the fact that various platforms
define different sets of limits which may be set.  Here we define a
routine for setting an individual limit.  Code in platform specific
files will call this routine to set up limits as appropriate for that
platform.
*/
void limit( int resource, rlim_t new_limit )
{
	int		scm;
	struct	rlimit lim;

	scm = SetSyscalls( SYS_LOCAL | SYS_RECORDED );

		/* Find out current limits */
	if( getrlimit(resource,&lim) < 0 ) {
		EXCEPT( "getrlimit(%d,0x%x)", resource, &lim );
	}

		/* Don't try to exceed the max */
	if( new_limit > lim.rlim_max ) {
		new_limit = lim.rlim_max;
	}

		/* Set the new limit */
	lim.rlim_cur = new_limit;
	if( setrlimit(resource,&lim) < 0 ) {
		EXCEPT( "setrlimit(%d,0x%x)", resource, &lim );
	}

	(void)SetSyscalls( scm );
}

/*
** Return physical file size in 1024 byte units.  This is the number of
** 1024 byte blocks required to store the file.  This could be more than the
** number of blocks of data due to overhead imposed by the file system
** structure (indirect blocks).  It could also be less than the
** number of data blocks if the filesystem implements "gaps" in the file
** without allocating real disk blocks to them.  This is a traditional
** behavior for UNIX file systems, but is optional in POSIX.
**
** The POSIX definition of "struct stat" does not define any member
** which describes the physical storage requirements of the file, but
** many UNIX systems do have such a member in their stat structure.
** Generally the name of this member is "st_blocks", but the size of
** the blocks is not often documented.  I have seen some code that uses
** the "st_blocksize" member for this value, but that turns out not to
** be generally correct.  The following interpretations come from comparing
** the stat structures associated with actual files against the storage
** requirements of those files as reported by "ls -ls".
*/
off_t
physical_file_size( char *name )
{
	struct stat	buf;

	if( stat(name,&buf) < 0 ) {
		return (off_t)-1;
	}

	   /*  On these systems struct stat member st_blocks is
	       defined, and appears to be in 512 byte blocks. */

#if defined(AIX32) || defined(ULTRIX42) || defined(ULTRIX43) || defined(SUNOS41)
	return buf.st_blocks / 2;
#endif

	/*  On this systems struct stat member st_blocks is
	   defined, and appears to be in 1024 byte blocks. */

#if defined(HPUX8)
	return buf.st_blocks;
#endif

	/*  On this system struct stat member st_blocks is not defined.
		Also, it appears that gaps take up real blocks here.  We just
		return the number of blocks to store the data.  Probably
		there will be some overhead, but it's not clear how to
		determine what it is, so we ignore it.  */

#if defined(IRIX401)
	return (buf.st_size + 1023 ) / 1024;
#endif
}

#if defined(AIX32)
#undef _POSIX_SOURCE
#define _BSD
#include <sys/m_wait.h>
#endif

#if defined(OSF1)
#undef _POSIX_SOURCE
#define _BSD
#define _OSF_SOURCE
#include <sys/wait.h>
#endif

#if defined(ULTRIX42) || defined(ULTRIX43) || defined(SUNOS41)
#undef _POSIX_SOURCE
#include <sys/wait.h>
#endif

#include <errno.h>
#include "user_proc.h"

/*
Encode the status of a user process in the way the shadow is expecting
it.  The encoding is a BSD style "union wait" structure with the
exit status of the process and a few goodies thrown in for special
cases.  We keep the encoding in a static memory area and return a
pointer to it as a "void *" so that POSIX code doesn't have to know
about it.
*/
void *
bsd_status( int posix_st, PROC_STATE state, int ckpt_trans, int core_trans )
{
	static union wait	bsd_status;

	memcpy( &bsd_status, &posix_st, sizeof(bsd_status) );

	switch( state ) {

	  case EXECUTING:
		EXCEPT( "Tried to generate BSD status, but state is EXECUTING\n" );
		break;

	  case SUSPENDED:
		EXCEPT( "Tried to generate BSD status, but state is SUSPENDED\n" );
		break;

	  case NORMAL_EXIT:
		dprintf( D_ALWAYS, "STATUS encoded as NORMAL\n" );
		break;

	  case NEW:
	  case RUNNABLE:
	  case NON_RUNNABLE:
	  case CHECKPOINTING:
		if( ckpt_trans ) {
			bsd_status.w_termsig = SIGQUIT;
			dprintf( D_ALWAYS, "STATUS encoded as CKPT, *IS* TRANSFERRED\n" );
		} else {
			bsd_status.w_termsig = SIGKILL;
			dprintf( D_ALWAYS, "STATUS encoded as CKPT, *NOT* TRANSFERRED\n" );
		}
		break;

	  case ABNORMAL_EXIT:
		if( core_trans ) {
			bsd_status.w_coredump = 1;
			dprintf( D_ALWAYS, "STATUS encoded as ABNORMAL, WITH CORE\n" );
		} else {
			bsd_status.w_coredump = 0;
			dprintf( D_ALWAYS, "STATUS encoded as ABNORMAL, NO CORE\n" );
		}
		break;

	  case BAD_MAGIC:
		bsd_status.w_termsig = 0;
		bsd_status.w_coredump = 1;
		bsd_status.w_retcode = ENOEXEC;
		dprintf( D_ALWAYS, "STATUS encoded as BAD MAGIC\n" );
		break;

	  case BAD_LINK:
		bsd_status.w_termsig = 0;
		bsd_status.w_coredump = 1;
		bsd_status.w_retcode = 0;
		dprintf( D_ALWAYS, "STATUS encoded as BAD LINK\n" );
		break;

	  case CANT_FETCH:
		bsd_status.w_termsig = 0;
		bsd_status.w_coredump = 1;
		bsd_status.w_retcode = posix_st;

	}
	return (void *)&bsd_status;
}

#include <sys/resource.h>
#define _POSIX_SOURCE
#include <time.h>		// to get CLK_TCK
#undef _POSIX_SOURCE

/*
Convert a time value from the POSIX style "clock_t" to a BSD style
"struct timeval".
*/
void
clock_t_to_timeval( clock_t ticks, struct timeval &tv )
{
	static long clock_tick;

	if( !clock_tick ) {
		clock_tick = sysconf( _SC_CLK_TCK );
	}

	tv.tv_sec = ticks / clock_tick;
	tv.tv_usec = ticks % clock_tick;
	tv.tv_usec *= 1000000 / clock_tick;
}

/*
Encode the CPU usage statistics in a BSD style "rusage" structure.  The
structure contains much more information than just CPU times, but we
zero everything except the CPU information because POSIX doesn't provide
it.  We return a pointer to a static data area as a "void *" so
POSIX code doesn't have to know about it.
*/
void *
bsd_rusage( clock_t user, clock_t sys )
{
	static struct rusage bsd_rusage;
	int		sec, usec;

	memset( &bsd_rusage, '\0', sizeof(bsd_rusage) );

	clock_t_to_timeval( user, bsd_rusage.ru_utime );
	clock_t_to_timeval( sys, bsd_rusage.ru_stime );

	dprintf( D_ALWAYS, "User time = %d.%06d seconds\n",
				bsd_rusage.ru_utime.tv_sec, bsd_rusage.ru_utime.tv_usec );
	dprintf( D_ALWAYS, "System time = %d.%06d seconds\n",
				bsd_rusage.ru_stime.tv_sec, bsd_rusage.ru_stime.tv_usec );

	return (void *)&bsd_rusage;
}

/*
  Tell the operating system that we want to operate in "POSIX
  conforming mode".  Isn't it ironic that such a request is itself
  non-POSIX conforming?
*/
#if defined(ULTRIX42) || defined(ULTRIX43)
#include <sys/sysinfo.h>
#define A_POSIX 2		// from exec.h, which I prefer not to include here...
extern "C" {
	int setsysinfo( unsigned, char *, unsigned, unsigned, unsigned );
}
void
set_posix_environment()
{
	int		name_value[2];

	name_value[0] = SSIN_PROG_ENV;
	name_value[1] = A_POSIX;

	if( setsysinfo(SSI_NVPAIRS,(char *)name_value,1,0,0) < 0 ) {
		EXCEPT( "setsysinfo" );
	}
}
#else
void
set_posix_environment() {}
#endif
<commit_msg>For the bytestream checkpointing mechanism we always assume that if the user processes exited with a status of "checkpoint", that checkpoint was transferred successfully.<commit_after>/*
** Copyright 1993 by Miron Livny, and Mike Litzkow
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted,
** provided that the above copyright notice appear in all copies and that
** both that copyright notice and this permission notice appear in
** supporting documentation, and that the names of the University of
** Wisconsin and the copyright holders not be used in advertising or
** publicity pertaining to distribution of the software without specific,
** written prior permission.  The University of Wisconsin and the
** copyright holders make no representations about the suitability of this
** software for any purpose.  It is provided "as is" without express
** or implied warranty.
**
** THE UNIVERSITY OF WISCONSIN AND THE COPYRIGHT HOLDERS DISCLAIM ALL
** WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE UNIVERSITY OF
** WISCONSIN OR THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT
** OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
** OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
** OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
** OR PERFORMANCE OF THIS SOFTWARE.
**
** Author:  Mike Litzkow
**
*/

/*
Portability
	The code in this file is not POSIX.1 conforming, and is
	therefore not generally portable.  However, this code is
	generally portable across UNIX platforms with little or no
	modification.
*/

#define _POSIX_SOURCE

#if defined(ULTRIX42) || defined(ULTRIX43)
typedef char *  caddr_t;
#endif

#include "condor_common.h"
#include "condor_debug.h"
#if 0
#include "proto.h"
#endif
#include "condor_jobqueue.h"
#include "condor_sys.h"
#include <signal.h>
#include <sys/stat.h>

extern "C" {
	int SetSyscalls( int );
}

static char *_FileName_ = __FILE__;     /* Used by EXCEPT (see except.h)     */

/*
Controlling any of these limits is problematic because the system calls
setrlimit() and getrlimit() do not appear in POSIX.1, but leaving them
to chance in environments where they appear is unacceptable.  Defaults
limits will frequently be handed down by some shell whose
initialization file has been set up by the system administrator.  These
will often not be appropriate for condor operation.  For example the
administrator may have set the limit for COREDUMPSIZE to 0.

Additional complication results from the fact that various platforms
define different sets of limits which may be set.  Here we define a
routine for setting an individual limit.  Code in platform specific
files will call this routine to set up limits as appropriate for that
platform.
*/
void limit( int resource, rlim_t new_limit )
{
	int		scm;
	struct	rlimit lim;

	scm = SetSyscalls( SYS_LOCAL | SYS_RECORDED );

		/* Find out current limits */
	if( getrlimit(resource,&lim) < 0 ) {
		EXCEPT( "getrlimit(%d,0x%x)", resource, &lim );
	}

		/* Don't try to exceed the max */
	if( new_limit > lim.rlim_max ) {
		new_limit = lim.rlim_max;
	}

		/* Set the new limit */
	lim.rlim_cur = new_limit;
	if( setrlimit(resource,&lim) < 0 ) {
		EXCEPT( "setrlimit(%d,0x%x)", resource, &lim );
	}

	(void)SetSyscalls( scm );
}

/*
** Return physical file size in 1024 byte units.  This is the number of
** 1024 byte blocks required to store the file.  This could be more than the
** number of blocks of data due to overhead imposed by the file system
** structure (indirect blocks).  It could also be less than the
** number of data blocks if the filesystem implements "gaps" in the file
** without allocating real disk blocks to them.  This is a traditional
** behavior for UNIX file systems, but is optional in POSIX.
**
** The POSIX definition of "struct stat" does not define any member
** which describes the physical storage requirements of the file, but
** many UNIX systems do have such a member in their stat structure.
** Generally the name of this member is "st_blocks", but the size of
** the blocks is not often documented.  I have seen some code that uses
** the "st_blocksize" member for this value, but that turns out not to
** be generally correct.  The following interpretations come from comparing
** the stat structures associated with actual files against the storage
** requirements of those files as reported by "ls -ls".
*/
off_t
physical_file_size( char *name )
{
	struct stat	buf;

	if( stat(name,&buf) < 0 ) {
		return (off_t)-1;
	}

	   /*  On these systems struct stat member st_blocks is
	       defined, and appears to be in 512 byte blocks. */

#if defined(AIX32) || defined(ULTRIX42) || defined(ULTRIX43) || defined(SUNOS41)
	return buf.st_blocks / 2;
#endif

	/*  On this systems struct stat member st_blocks is
	   defined, and appears to be in 1024 byte blocks. */

#if defined(HPUX8)
	return buf.st_blocks;
#endif

	/*  On this system struct stat member st_blocks is not defined.
		Also, it appears that gaps take up real blocks here.  We just
		return the number of blocks to store the data.  Probably
		there will be some overhead, but it's not clear how to
		determine what it is, so we ignore it.  */

#if defined(IRIX401)
	return (buf.st_size + 1023 ) / 1024;
#endif
}

#if defined(AIX32)
#undef _POSIX_SOURCE
#define _BSD
#include <sys/m_wait.h>
#endif

#if defined(OSF1)
#undef _POSIX_SOURCE
#define _BSD
#define _OSF_SOURCE
#include <sys/wait.h>
#endif

#if defined(ULTRIX42) || defined(ULTRIX43) || defined(SUNOS41)
#undef _POSIX_SOURCE
#include <sys/wait.h>
#endif

#include <errno.h>
#include "user_proc.h"

/*
Encode the status of a user process in the way the shadow is expecting
it.  The encoding is a BSD style "union wait" structure with the
exit status of the process and a few goodies thrown in for special
cases.  We keep the encoding in a static memory area and return a
pointer to it as a "void *" so that POSIX code doesn't have to know
about it.
*/
void *
bsd_status( int posix_st, PROC_STATE state, int ckpt_trans, int core_trans )
{
	static union wait	bsd_status;

	memcpy( &bsd_status, &posix_st, sizeof(bsd_status) );

	switch( state ) {

	  case EXECUTING:
		EXCEPT( "Tried to generate BSD status, but state is EXECUTING\n" );
		break;

	  case SUSPENDED:
		EXCEPT( "Tried to generate BSD status, but state is SUSPENDED\n" );
		break;

	  case NORMAL_EXIT:
		dprintf( D_ALWAYS, "STATUS encoded as NORMAL\n" );
		break;

	  case NEW:
	  case RUNNABLE:
	  case NON_RUNNABLE:
	  case CHECKPOINTING:
#if defined(OSF1)
		/*
		  For bytestream checkpointing:
		  the only way the process exits with its state set to CHECKPOINTING
		  is if it has already transferred the checkpoint successfully.
		*/
		ckpt_trans = 1;
#endif
		if( ckpt_trans ) {
			bsd_status.w_termsig = SIGQUIT;
			dprintf( D_ALWAYS, "STATUS encoded as CKPT, *IS* TRANSFERRED\n" );
		} else {
			bsd_status.w_termsig = SIGKILL;
			dprintf( D_ALWAYS, "STATUS encoded as CKPT, *NOT* TRANSFERRED\n" );
		}
		break;

	  case ABNORMAL_EXIT:
		if( core_trans ) {
			bsd_status.w_coredump = 1;
			dprintf( D_ALWAYS, "STATUS encoded as ABNORMAL, WITH CORE\n" );
		} else {
			bsd_status.w_coredump = 0;
			dprintf( D_ALWAYS, "STATUS encoded as ABNORMAL, NO CORE\n" );
		}
		break;

	  case BAD_MAGIC:
		bsd_status.w_termsig = 0;
		bsd_status.w_coredump = 1;
		bsd_status.w_retcode = ENOEXEC;
		dprintf( D_ALWAYS, "STATUS encoded as BAD MAGIC\n" );
		break;

	  case BAD_LINK:
		bsd_status.w_termsig = 0;
		bsd_status.w_coredump = 1;
		bsd_status.w_retcode = 0;
		dprintf( D_ALWAYS, "STATUS encoded as BAD LINK\n" );
		break;

	  case CANT_FETCH:
		bsd_status.w_termsig = 0;
		bsd_status.w_coredump = 1;
		bsd_status.w_retcode = posix_st;

	}
	return (void *)&bsd_status;
}

#include <sys/resource.h>
#define _POSIX_SOURCE
#include <time.h>		// to get CLK_TCK
#undef _POSIX_SOURCE

/*
Convert a time value from the POSIX style "clock_t" to a BSD style
"struct timeval".
*/
void
clock_t_to_timeval( clock_t ticks, struct timeval &tv )
{
	static long clock_tick;

	if( !clock_tick ) {
		clock_tick = sysconf( _SC_CLK_TCK );
	}

	tv.tv_sec = ticks / clock_tick;
	tv.tv_usec = ticks % clock_tick;
	tv.tv_usec *= 1000000 / clock_tick;
}

/*
Encode the CPU usage statistics in a BSD style "rusage" structure.  The
structure contains much more information than just CPU times, but we
zero everything except the CPU information because POSIX doesn't provide
it.  We return a pointer to a static data area as a "void *" so
POSIX code doesn't have to know about it.
*/
void *
bsd_rusage( clock_t user, clock_t sys )
{
	static struct rusage bsd_rusage;
	int		sec, usec;

	memset( &bsd_rusage, '\0', sizeof(bsd_rusage) );

	clock_t_to_timeval( user, bsd_rusage.ru_utime );
	clock_t_to_timeval( sys, bsd_rusage.ru_stime );

	dprintf( D_ALWAYS, "User time = %d.%06d seconds\n",
				bsd_rusage.ru_utime.tv_sec, bsd_rusage.ru_utime.tv_usec );
	dprintf( D_ALWAYS, "System time = %d.%06d seconds\n",
				bsd_rusage.ru_stime.tv_sec, bsd_rusage.ru_stime.tv_usec );

	return (void *)&bsd_rusage;
}

/*
  Tell the operating system that we want to operate in "POSIX
  conforming mode".  Isn't it ironic that such a request is itself
  non-POSIX conforming?
*/
#if defined(ULTRIX42) || defined(ULTRIX43)
#include <sys/sysinfo.h>
#define A_POSIX 2		// from exec.h, which I prefer not to include here...
extern "C" {
	int setsysinfo( unsigned, char *, unsigned, unsigned, unsigned );
}
void
set_posix_environment()
{
	int		name_value[2];

	name_value[0] = SSIN_PROG_ENV;
	name_value[1] = A_POSIX;

	if( setsysinfo(SSI_NVPAIRS,(char *)name_value,1,0,0) < 0 ) {
		EXCEPT( "setsysinfo" );
	}
}
#else
void
set_posix_environment() {}
#endif
<|endoftext|>


<commit_before>/// \file
/// \ingroup tutorial_dataframe
/// \notebook -js

/// In order to display the Platform Distribution of ROOT, we choose to create two TH1F
/// histograms: one that includes all types of platforms, other filtering and classifying them.
/// This procedure is using a lambda expression taking as parameter the values
/// stored in the "Platform" column from the database. At the end, the histograms are filled
/// with their specific demand regarding the platform's type.
///
/// \macro_code
/// \macro_image
///
/// \date August 2018
/// \author Alexandra-Maria Dobrescu

void df029_SQlitePlatformDistribution() {

   auto rdf = ROOT::RDF::MakeSqliteDataFrame( "http://root.cern/files/root_download_stats.sqlite", "SELECT * FROM accesslog;" );

   TH1F hRootPlatform("hrootPlatform", "Platform Distribution", 7, 0, -1);
   TH1F hShortRootPlatform("hShortRootPlatform", "Short Platform Distribution", 7, 0, -1);

   auto fillRootPlatform = [&hRootPlatform, &hShortRootPlatform] ( const std::string &platform ) {
      TString Platform = platform;
      TString Platform_0(Platform(0,5));
      TString Platform_1(Platform(0,6));
      TString Platform_2(Platform(0,8));

      if ( Platform.Contains("win32") ){
        hShortRootPlatform.Fill(Platform_0,1);
      } else if ( Platform.Contains("Linux") ){
        hShortRootPlatform.Fill(Platform_0,1);
      } else if ( Platform.Contains("source") ){
        hShortRootPlatform.Fill(Platform_1,1);
      } else if ( Platform.Contains("macosx64") ){
        hShortRootPlatform.Fill(Platform_2,1);
      } else if ( Platform.Contains("IRIX64") ){
        hShortRootPlatform.Fill(Platform_1,1);
      }

      hRootPlatform.Fill(Platform,1);
   };

   rdf.Foreach( fillRootPlatform, { "Platform" } );

   auto PlatformDistributionHistogram = new TCanvas();

   hRootPlatform.GetXaxis()->LabelsOption("a");
   hRootPlatform.LabelsDeflate("X");
   hRootPlatform.DrawClone();

   auto shortPlatformDistributionHistogram = new TCanvas();

   hShortRootPlatform.GetXaxis()->LabelsOption("a");
   hShortRootPlatform.LabelsDeflate("X");
   hShortRootPlatform.DrawClone();
}
<commit_msg>Extra blank line made doxygen unhappy<commit_after>/// \file
/// \ingroup tutorial_dataframe
/// \notebook -js
///
/// In order to display the Platform Distribution of ROOT, we choose to create two TH1F
/// histograms: one that includes all types of platforms, other filtering and classifying them.
/// This procedure is using a lambda expression taking as parameter the values
/// stored in the "Platform" column from the database. At the end, the histograms are filled
/// with their specific demand regarding the platform's type.
///
/// \macro_code
/// \macro_image
///
/// \date August 2018
/// \author Alexandra-Maria Dobrescu

void df029_SQlitePlatformDistribution() {

   auto rdf = ROOT::RDF::MakeSqliteDataFrame( "http://root.cern/files/root_download_stats.sqlite", "SELECT * FROM accesslog;" );

   TH1F hRootPlatform("hrootPlatform", "Platform Distribution", 7, 0, -1);
   TH1F hShortRootPlatform("hShortRootPlatform", "Short Platform Distribution", 7, 0, -1);

   auto fillRootPlatform = [&hRootPlatform, &hShortRootPlatform] ( const std::string &platform ) {
      TString Platform = platform;
      TString Platform_0(Platform(0,5));
      TString Platform_1(Platform(0,6));
      TString Platform_2(Platform(0,8));

      if ( Platform.Contains("win32") ){
        hShortRootPlatform.Fill(Platform_0,1);
      } else if ( Platform.Contains("Linux") ){
        hShortRootPlatform.Fill(Platform_0,1);
      } else if ( Platform.Contains("source") ){
        hShortRootPlatform.Fill(Platform_1,1);
      } else if ( Platform.Contains("macosx64") ){
        hShortRootPlatform.Fill(Platform_2,1);
      } else if ( Platform.Contains("IRIX64") ){
        hShortRootPlatform.Fill(Platform_1,1);
      }

      hRootPlatform.Fill(Platform,1);
   };

   rdf.Foreach( fillRootPlatform, { "Platform" } );

   auto PlatformDistributionHistogram = new TCanvas();

   hRootPlatform.GetXaxis()->LabelsOption("a");
   hRootPlatform.LabelsDeflate("X");
   hRootPlatform.DrawClone();

   auto shortPlatformDistributionHistogram = new TCanvas();

   hShortRootPlatform.GetXaxis()->LabelsOption("a");
   hShortRootPlatform.LabelsDeflate("X");
   hShortRootPlatform.DrawClone();
}
<|endoftext|>


<commit_before>/**
 *  @author Koen Wolters <koen.wolters@cern.ch>
 *  @author Daniel Hynds <daniel.hynds@cern.ch>
 */

#include <dlfcn.h>

#include "ModuleFactory.hpp"
#include "ModuleManager.hpp"
#include "core/config/Configuration.hpp"
#include "core/utils/log.h"

using namespace allpix;

// Constructor and destructor
ModuleManager::ModuleManager() : modules_(), id_to_module_(), module_to_id_(), global_config_() {}
ModuleManager::~ModuleManager() = default;

// Initialize all modules
void ModuleManager::init() {
    // initialize all modules
    for(auto& mod : modules_) {
        // set init module section header
        std::string old_section_name = Log::getSection();
        std::string section_name = "I:";
        section_name += module_to_id_.at(mod.get()).getName();
        Log::setSection(section_name);
        // init module
        mod->init();
        // reset header
        Log::setSection(old_section_name);
    }
}

// Run all the modules in the queue
void ModuleManager::run() {
    // loop over the number of events
    auto number_of_events = global_config_.get<unsigned int>("number_of_events", 1u);
    for(unsigned int i = 0; i < number_of_events; ++i) {
        // go through each module run method every event
        LOG(DEBUG) << "Running event " << (i + 1) << " of " << number_of_events;
        for(auto& mod : modules_) {
            // set run module section header
            std::string old_section_name = Log::getSection();
            std::string section_name = "R:";
            section_name += module_to_id_.at(mod.get()).getName();
            Log::setSection(section_name);
            // run module
            mod->run();
            // reset header
            Log::setSection(old_section_name);
        }
    }
}

// Finalize the modules
void ModuleManager::finalize() {
    // finalize the modules
    for(auto& mod : modules_) {
        // set finalize module section header
        std::string old_section_name = Log::getSection();
        std::string section_name = "F:";
        section_name += module_to_id_.at(mod.get()).getName();
        Log::setSection(section_name);
        // finalize module
        mod->finalize();
        // reset header
        Log::setSection(old_section_name);
    }
}

// Function that loads the modules specified in the configuration file. Each module is contained within
// its own library, which is first loaded before being passed to the module factory
void ModuleManager::load(Messenger* messenger, ConfigManager* conf_manager, GeometryManager* geo_manager) {

    // Get configurations
    std::vector<Configuration> configs = conf_manager->getConfigurations();

    // NOTE: could add all config parameters from the empty to all configs (if it does not yet exist)
    std::unique_ptr<ModuleFactory> factory = std::make_unique<ModuleFactory>();
    for(auto& conf : configs) {
        // ignore the empty config
        if(conf.getName().empty()) {
            continue;
        }

//         Load library for each module. Libraries are named (by convention + CMAKE) libModuleName.suffix
        std::string libName = std::string("libAllpixModule").append(conf.getName()).append(SHARED_LIBRARY_SUFFIX);
        LOG(INFO) << "Loading library " << libName << std::endl;
        std::string libPath = std::string(std::getenv("ALLPIX_DIR")) + "/lib/";
        std::string fullLibPath = libPath + libName;

        // If library is not loaded then load it
        if(loadedLibraries_.count(libName) == 0) {
            void* lib = nullptr;
            lib = dlopen(fullLibPath.c_str(), RTLD_NOW);
            // If library did not load then throw exception
            if(!lib) {
                LOG(ERROR) << "Library " << libName << " not loaded" << std::endl;
                LOG(ERROR) << " - Did you set the ALLPIX_DIR environmental variable? Library search location: " << libPath
                           << std::endl;
                LOG(ERROR) << " - Did you compile the library? " << std::endl;
                LOG(ERROR) << " - Did you spell the library name correctly? " << std::endl;
                throw allpix::DynamicLibraryError(conf.getName());
            }
            // Remember that this library was loaded
            loadedLibraries_[libName] = lib;
        }

        // Pass the library to the module factory
        factory->setMessenger(messenger);
        factory->setGeometryManager(geo_manager);
        factory->setConfiguration(conf);
        std::vector<std::pair<ModuleIdentifier, Module*>> mod_list =
            factory->createModules(conf.getName(), loadedLibraries_[libName]);

        // Decide which order to place modules in
        for(auto& id_mod : mod_list) {
            Module* mod = id_mod.second;
            ModuleIdentifier identifier = id_mod.first;

            // Need to add delete statements here since move from unique pointer?
            auto iter = id_to_module_.find(identifier);
            if(iter != id_to_module_.end()) {
                // unique name already exists, check if its needs to be replaced
                if(iter->first.getPriority() > identifier.getPriority()) {
                    // priority of new instance is higher, replace the instance
                    module_to_id_.erase(iter->second->get());
                    modules_.erase(iter->second);
                    id_to_module_.erase(iter->first);
                } else {
                    if(iter->first.getPriority() == identifier.getPriority()) {
                        throw AmbiguousInstantiationError(conf.getName());
                    }
                    // priority is lower just ignore
                    continue;
                }
            }

            // insert the new module
            modules_.emplace_back(std::move(mod));
            id_to_module_[identifier] = --modules_.end();
            module_to_id_.emplace(modules_.back().get(), identifier);
        }
        mod_list.clear();
    }
}
<commit_msg>formatting of module manager<commit_after>/**
 *  @author Koen Wolters <koen.wolters@cern.ch>
 *  @author Daniel Hynds <daniel.hynds@cern.ch>
 */

#include <dlfcn.h>

#include "ModuleFactory.hpp"
#include "ModuleManager.hpp"
#include "core/config/Configuration.hpp"
#include "core/utils/log.h"

using namespace allpix;

// Constructor and destructor
ModuleManager::ModuleManager() : modules_(), id_to_module_(), module_to_id_(), global_config_() {}
ModuleManager::~ModuleManager() = default;

// Initialize all modules
void ModuleManager::init() {
    // initialize all modules
    for(auto& mod : modules_) {
        // set init module section header
        std::string old_section_name = Log::getSection();
        std::string section_name = "I:";
        section_name += module_to_id_.at(mod.get()).getName();
        Log::setSection(section_name);
        // init module
        mod->init();
        // reset header
        Log::setSection(old_section_name);
    }
}

// Run all the modules in the queue
void ModuleManager::run() {
    // loop over the number of events
    auto number_of_events = global_config_.get<unsigned int>("number_of_events", 1u);
    for(unsigned int i = 0; i < number_of_events; ++i) {
        // go through each module run method every event
        LOG(DEBUG) << "Running event " << (i + 1) << " of " << number_of_events;
        for(auto& mod : modules_) {
            // set run module section header
            std::string old_section_name = Log::getSection();
            std::string section_name = "R:";
            section_name += module_to_id_.at(mod.get()).getName();
            Log::setSection(section_name);
            // run module
            mod->run();
            // reset header
            Log::setSection(old_section_name);
        }
    }
}

// Finalize the modules
void ModuleManager::finalize() {
    // finalize the modules
    for(auto& mod : modules_) {
        // set finalize module section header
        std::string old_section_name = Log::getSection();
        std::string section_name = "F:";
        section_name += module_to_id_.at(mod.get()).getName();
        Log::setSection(section_name);
        // finalize module
        mod->finalize();
        // reset header
        Log::setSection(old_section_name);
    }
}

// Function that loads the modules specified in the configuration file. Each module is contained within
// its own library, which is first loaded before being passed to the module factory
void ModuleManager::load(Messenger* messenger, ConfigManager* conf_manager, GeometryManager* geo_manager) {

    // Get configurations
    std::vector<Configuration> configs = conf_manager->getConfigurations();

    // NOTE: could add all config parameters from the empty to all configs (if it does not yet exist)
    std::unique_ptr<ModuleFactory> factory = std::make_unique<ModuleFactory>();
    for(auto& conf : configs) {
        // ignore the empty config
        if(conf.getName().empty()) {
            continue;
        }

        // Load library for each module. Libraries are named (by convention + CMAKE) libAllpixModule Name.suffix
        std::string libName = std::string("libAllpixModule").append(conf.getName()).append(SHARED_LIBRARY_SUFFIX);
        LOG(INFO) << "Loading library " << libName << std::endl;
        std::string libPath = std::string(std::getenv("ALLPIX_DIR")) + "/lib/";
        std::string fullLibPath = libPath + libName;

        // If library is not loaded then load it
        if(loadedLibraries_.count(libName) == 0) {
            void* lib = nullptr;
            lib = dlopen(fullLibPath.c_str(), RTLD_NOW);
            // If library did not load then throw exception
            if(!lib) {
                LOG(ERROR) << "Library " << libName << " not loaded" << std::endl;
                LOG(ERROR) << " - Did you set the ALLPIX_DIR environmental variable? Library search location: " << libPath
                           << std::endl;
                LOG(ERROR) << " - Did you compile the library? " << std::endl;
                LOG(ERROR) << " - Did you spell the library name correctly? " << std::endl;
                throw allpix::DynamicLibraryError(conf.getName());
            }
            // Remember that this library was loaded
            loadedLibraries_[libName] = lib;
        }

        // Pass the library to the module factory
        factory->setMessenger(messenger);
        factory->setGeometryManager(geo_manager);
        factory->setConfiguration(conf);
        std::vector<std::pair<ModuleIdentifier, Module*>> mod_list =
            factory->createModules(conf.getName(), loadedLibraries_[libName]);

        // Decide which order to place modules in
        for(auto& id_mod : mod_list) {
            Module* mod = id_mod.second;
            ModuleIdentifier identifier = id_mod.first;

            // Need to add delete statements here since move from unique pointer?
            auto iter = id_to_module_.find(identifier);
            if(iter != id_to_module_.end()) {
                // unique name already exists, check if its needs to be replaced
                if(iter->first.getPriority() > identifier.getPriority()) {
                    // priority of new instance is higher, replace the instance
                    module_to_id_.erase(iter->second->get());
                    modules_.erase(iter->second);
                    id_to_module_.erase(iter->first);
                } else {
                    if(iter->first.getPriority() == identifier.getPriority()) {
                        throw AmbiguousInstantiationError(conf.getName());
                    }
                    // priority is lower just ignore
                    continue;
                }
            }

            // insert the new module
            modules_.emplace_back(std::move(mod));
            id_to_module_[identifier] = --modules_.end();
            module_to_id_.emplace(modules_.back().get(), identifier);
        }
        mod_list.clear();
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Rob Caelers <rob.caelers@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "loopp/ble/BLEScanner.hpp"

#include <sstream>
#include <iomanip>
#include <cstring>

#ifdef CONFIG_BT_ENABLED

#include "esp_bt.h"
#include "esp_log.h"

#include "loopp/core/Task.hpp"

static const char *tag = "BLE";

using namespace loopp;
using namespace loopp::ble;

BLEScanner &
BLEScanner::instance()
{
  static BLEScanner instance;
  return instance;
}

BLEScanner::BLEScanner()
  : ble_scan_params()
{
  init();
}

void
BLEScanner::gap_event_handler_static(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
  BLEScanner::instance().gap_event_handler(event, param);
}

void
BLEScanner::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
  switch (event)
    {
      case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT:
        {
          ESP_LOGI(tag, "Scan param set complete, start scanning.");
          esp_ble_gap_start_scanning(scan_duration);
          break;
        }

      case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT:
        if (param->scan_start_cmpl.status != ESP_BT_STATUS_SUCCESS)
          {
            ESP_LOGE(tag, "Scan start failed.");
          }
        else
          {
            ESP_LOGI(tag, "Scan start successfully.");
          }
        break;

      case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT:
        if (param->scan_stop_cmpl.status != ESP_BT_STATUS_SUCCESS)
          {
            ESP_LOGE(tag, "Scan stop failed.");
          }
        else
          {
            ESP_LOGI(tag, "Scan stop successfully.");
          }
        break;

      case ESP_GAP_BLE_SCAN_RESULT_EVT:
        {
          switch (param->scan_rst.search_evt)
            {
              case ESP_GAP_SEARCH_INQ_RES_EVT:
                {
                  ScanResult beacon(&param->scan_rst);
                  signal_scan_result(beacon);
                  break;
                }

              case ESP_GAP_SEARCH_INQ_CMPL_EVT:
                {
                  ESP_LOGI(tag, "Scan completed, restarting.");
                  signal_scan_complete();
                  esp_ble_gap_set_scan_params(&ble_scan_params);
                  break;
                }

              default:
                ESP_LOGI(tag, "Unhandled scan result %d.", param->scan_rst.search_evt);
                break;
            }
          break;
        }
      default:
        break;
    }
}

void
BLEScanner::init()
{
  ble_scan_params.scan_type = BLE_SCAN_TYPE_PASSIVE;
  ble_scan_params.own_addr_type = BLE_ADDR_TYPE_PUBLIC;
  ble_scan_params.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL;
  ble_scan_params.scan_interval = 0x50;
  ble_scan_params.scan_window = 0x30;

  esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();

  esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
  esp_bt_controller_init(&bt_cfg);
  esp_bt_controller_enable(ESP_BT_MODE_BLE);
  esp_bluedroid_init();
  esp_bluedroid_enable();
}

void
BLEScanner::deinit()
{
  esp_bluedroid_disable();
  esp_bluedroid_deinit();
  esp_bt_controller_disable();
  esp_bt_controller_deinit();
}

void
BLEScanner::set_scan_type(ScanType type)
{
  ble_scan_params.scan_type = (type == ScanType::Active) ? BLE_SCAN_TYPE_ACTIVE : BLE_SCAN_TYPE_PASSIVE;
}

void
BLEScanner::set_scan_interval(uint16_t interval)
{
  ble_scan_params.scan_interval = interval;
}

void
BLEScanner::set_scan_window(uint16_t window)
{
  ble_scan_params.scan_window = window;
}

void
BLEScanner::start()
{
  esp_ble_gap_register_callback(gap_event_handler_static);
  esp_ble_gap_set_scan_params(&ble_scan_params);
}

void
BLEScanner::stop()
{
  esp_ble_gap_stop_scanning();
}

loopp::core::Signal<void()> &
BLEScanner::scan_complete_signal()
{
  return signal_scan_complete;
}

loopp::core::Signal<void(loopp::ble::BLEScanner::ScanResult)> &
BLEScanner::scan_result_signal()
{
  return signal_scan_result;
}

BLEScanner::ScanResult::ScanResult(esp_ble_gap_cb_param_t::ble_scan_result_evt_param *scan_result)
  : adv_data(reinterpret_cast<char *>(scan_result->ble_adv), scan_result->adv_data_len)
  , rssi(scan_result->rssi)
{
  memcpy(bda, scan_result->bda, 6);
}

std::string
BLEScanner::ScanResult::bda_as_string()
{
  std::stringstream stream;
  stream << std::hex << std::setfill('0');
  stream << std::setw(2);

  for (int i = 0; i < 6; i++)
    {
      stream << static_cast<int>(bda[i]);
      if (i != 5)
        {
          stream << ':';
        }
    }

  return stream.str();
}

#endif
<commit_msg>Remove include<commit_after>// Copyright (C) 2017 Rob Caelers <rob.caelers@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "loopp/ble/BLEScanner.hpp"

#include <sstream>
#include <iomanip>
#include <cstring>

#ifdef CONFIG_BT_ENABLED

#include "esp_bt.h"
#include "esp_log.h"

static const char *tag = "BLE";

using namespace loopp;
using namespace loopp::ble;

BLEScanner &
BLEScanner::instance()
{
  static BLEScanner instance;
  return instance;
}

BLEScanner::BLEScanner()
  : ble_scan_params()
{
  init();
}

void
BLEScanner::gap_event_handler_static(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
  BLEScanner::instance().gap_event_handler(event, param);
}

void
BLEScanner::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
  switch (event)
    {
      case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT:
        {
          ESP_LOGI(tag, "Scan param set complete, start scanning.");
          esp_ble_gap_start_scanning(scan_duration);
          break;
        }

      case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT:
        if (param->scan_start_cmpl.status != ESP_BT_STATUS_SUCCESS)
          {
            ESP_LOGE(tag, "Scan start failed.");
          }
        else
          {
            ESP_LOGI(tag, "Scan start successfully.");
          }
        break;

      case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT:
        if (param->scan_stop_cmpl.status != ESP_BT_STATUS_SUCCESS)
          {
            ESP_LOGE(tag, "Scan stop failed.");
          }
        else
          {
            ESP_LOGI(tag, "Scan stop successfully.");
          }
        break;

      case ESP_GAP_BLE_SCAN_RESULT_EVT:
        {
          switch (param->scan_rst.search_evt)
            {
              case ESP_GAP_SEARCH_INQ_RES_EVT:
                {
                  ScanResult beacon(&param->scan_rst);
                  signal_scan_result(beacon);
                  break;
                }

              case ESP_GAP_SEARCH_INQ_CMPL_EVT:
                {
                  ESP_LOGI(tag, "Scan completed, restarting.");
                  signal_scan_complete();
                  esp_ble_gap_set_scan_params(&ble_scan_params);
                  break;
                }

              default:
                ESP_LOGI(tag, "Unhandled scan result %d.", param->scan_rst.search_evt);
                break;
            }
          break;
        }
      default:
        break;
    }
}

void
BLEScanner::init()
{
  ble_scan_params.scan_type = BLE_SCAN_TYPE_PASSIVE;
  ble_scan_params.own_addr_type = BLE_ADDR_TYPE_PUBLIC;
  ble_scan_params.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL;
  ble_scan_params.scan_interval = 0x50;
  ble_scan_params.scan_window = 0x30;

  esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();

  esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
  esp_bt_controller_init(&bt_cfg);
  esp_bt_controller_enable(ESP_BT_MODE_BLE);
  esp_bluedroid_init();
  esp_bluedroid_enable();
}

void
BLEScanner::deinit()
{
  esp_bluedroid_disable();
  esp_bluedroid_deinit();
  esp_bt_controller_disable();
  esp_bt_controller_deinit();
}

void
BLEScanner::set_scan_type(ScanType type)
{
  ble_scan_params.scan_type = (type == ScanType::Active) ? BLE_SCAN_TYPE_ACTIVE : BLE_SCAN_TYPE_PASSIVE;
}

void
BLEScanner::set_scan_interval(uint16_t interval)
{
  ble_scan_params.scan_interval = interval;
}

void
BLEScanner::set_scan_window(uint16_t window)
{
  ble_scan_params.scan_window = window;
}

void
BLEScanner::start()
{
  esp_ble_gap_register_callback(gap_event_handler_static);
  esp_ble_gap_set_scan_params(&ble_scan_params);
}

void
BLEScanner::stop()
{
  esp_ble_gap_stop_scanning();
}

loopp::core::Signal<void()> &
BLEScanner::scan_complete_signal()
{
  return signal_scan_complete;
}

loopp::core::Signal<void(loopp::ble::BLEScanner::ScanResult)> &
BLEScanner::scan_result_signal()
{
  return signal_scan_result;
}

BLEScanner::ScanResult::ScanResult(esp_ble_gap_cb_param_t::ble_scan_result_evt_param *scan_result)
  : adv_data(reinterpret_cast<char *>(scan_result->ble_adv), scan_result->adv_data_len)
  , rssi(scan_result->rssi)
{
  memcpy(bda, scan_result->bda, 6);
}

std::string
BLEScanner::ScanResult::bda_as_string()
{
  std::stringstream stream;
  stream << std::hex << std::setfill('0');
  stream << std::setw(2);

  for (int i = 0; i < 6; i++)
    {
      stream << static_cast<int>(bda[i]);
      if (i != 5)
        {
          stream << ':';
        }
    }

  return stream.str();
}

#endif
<|endoftext|>