<commit_before>#include <aerial_autonomy/state_machines/pick_place_state_machine.h>
#include <aerial_autonomy/trackers/simple_tracker.h>
#include <arm_parsers/arm_simulator.h>
#include <gtest/gtest.h>
// Timer stuff
#include <chrono>
#include <thread>
// Quad Simulator
#include <quad_simulator_parser/quad_simulator.h>

/**
* @brief Namespace for UAV Simulator Hardware
*/
using namespace quad_simulator;

/**
* @brief Visual servoing events such as TrackROI, GoHome
*/
namespace vse = visual_servoing_events;

/**
* @brief Namespace for pick place events
*/
namespace pe = pick_place_events;

/**
* @brief Namespace for basic events such as takeoff, land.
*/
namespace be = uav_basic_events;

class PickPlaceStateMachineTests : public ::testing::Test {
public:
  PickPlaceStateMachineTests() : goal_tolerance_position(0.5) {
    auto uav_vision_system_config = config.mutable_uav_vision_system_config();
    for (int i = 0; i < 6; ++i) {
      uav_vision_system_config->add_camera_transform(0.0);
    }
    uav_vision_system_config->set_desired_visual_servoing_distance(1.0);
    auto uav_arm_system_config =
        uav_vision_system_config->mutable_uav_arm_system_config();
    for (int i = 0; i < 6; ++i) {
      uav_arm_system_config->add_arm_transform(0);
    }
    for (int i = 0; i < 12; ++i) {
      uav_arm_system_config->add_arm_goal_transform(0);
    }
    auto depth_config =
        uav_vision_system_config
            ->mutable_constant_heading_depth_controller_config();
    depth_config->set_radial_gain(0.5);
    depth_config->mutable_position_controller_config()
        ->set_goal_position_tolerance(goal_tolerance_position);
    tf::Transform camera_transform = math::getTransformFromVector(
        uav_vision_system_config->camera_transform());
    tracker.reset(new SimpleTracker(drone_hardware, camera_transform));
    uav_arm_system.reset(
        new UAVArmSystem(*tracker, drone_hardware, arm, config));
    logic_state_machine.reset(
        new PickPlaceStateMachine(boost::ref(*uav_arm_system)));
    logic_state_machine->start();
    // Move to landed state
    logic_state_machine->process_event(InternalTransitionEvent());
  }

  ~PickPlaceStateMachineTests() {
    logic_state_machine->stop();
    uav_arm_system.reset();
    logic_state_machine.reset();
  }

protected:
  QuadSimulator drone_hardware;
  ArmSimulator arm;
  UAVSystemConfig config;
  std::unique_ptr<SimpleTracker> tracker;
  std::unique_ptr<UAVArmSystem> uav_arm_system;
  std::unique_ptr<PickPlaceStateMachine> logic_state_machine;
  double goal_tolerance_position;

  void GoToHoverFromLanded() {
    drone_hardware.setBatteryPercent(100);
    logic_state_machine->process_event(be::Takeoff());
    // Powers on arm and folds it; Starts takeoff
    logic_state_machine->process_event(InternalTransitionEvent());
    // Completes takeoff and goes to hovering
    logic_state_machine->process_event(InternalTransitionEvent());
  }
};

TEST_F(PickPlaceStateMachineTests, InitialState) {
  // Validate
  ASSERT_STREQ(pstate(*logic_state_machine), "Landed");
  GoToHoverFromLanded();
}

/// \brief Test Arm folding during landing and takeoff
TEST_F(PickPlaceStateMachineTests, HoveringandLanding) {
  // Takeoff
  drone_hardware.setBatteryPercent(100);
  logic_state_machine->process_event(be::Takeoff());
  ASSERT_STREQ(pstate(*logic_state_machine), "ArmPreTakeoffFolding");
  // Powers on arm and folds it; Starts takeoff
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Takingoff");
  // Completes takeoff and goes to hovering
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Hovering");
  logic_state_machine->process_event(be::Land());
  ASSERT_STREQ(pstate(*logic_state_machine), "ArmPreLandingFolding");
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Landing");
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Landed");
}
///
/// \brief Test Pick Place
// Try Pick
TEST_F(PickPlaceStateMachineTests, PickPlace) {
  // Timeout for running controller
  int time_out = 5000;  // Milliseconds
  int time_period = 20; // Milliseconds
  int max_count = time_out / time_period;
  // First takeoff
  GoToHoverFromLanded();
  // Set goal for simple tracker
  Position roi_goal(2, 0, 0.5);
  tracker->setTargetPositionGlobalFrame(roi_goal);
  // Initialize event to vse::TrackROI
  logic_state_machine->process_event(pe::Pick());
  // Check we are in PrePick state
  ASSERT_STREQ(pstate(*logic_state_machine), "PrePickState");
  // Check controllers are active
  ASSERT_EQ(uav_arm_system->getStatus<VisualServoingControllerDroneConnector>(),
            ControllerStatus::Active);
  ASSERT_EQ(uav_arm_system->getStatus<VisualServoingControllerArmConnector>(),
            ControllerStatus::Active);
  // Keep running the controller until its completed or timeout
  int temp_count = 0;
  while (uav_arm_system->getStatus<VisualServoingControllerArmConnector>() ==
             ControllerStatus::Active &&
         ++temp_count < max_count) {
    uav_arm_system->runActiveController(HardwareType::UAV);
    uav_arm_system->runActiveController(HardwareType::Arm);
    logic_state_machine->process_event(InternalTransitionEvent());
    std::this_thread::sleep_for(std::chrono::milliseconds(time_period));
  }
  // Make sure controllers are aborted
  ControllerStatus controller_status;
  ASSERT_FALSE(uav_arm_system->getActiveControllerStatus(HardwareType::Arm,
                                                         controller_status));
  ASSERT_FALSE(uav_arm_system->getActiveControllerStatus(HardwareType::UAV,
                                                         controller_status));
  // Check we are back in Hovering state
  ASSERT_STREQ(pstate(*logic_state_machine), "Hovering");
}
// Abort due to arm not enabled
TEST_F(PickPlaceStateMachineTests, PrePickPlaceArmAbort) {
  // First takeoff
  GoToHoverFromLanded();
  // Set goal for simple tracker
  Position roi_goal(2, 0, 0.5);
  tracker->setTargetPositionGlobalFrame(roi_goal);
  // Initialize event to vse::TrackROI
  logic_state_machine->process_event(pe::Pick());
  // Check we are in pre-pick state
  ASSERT_STREQ(pstate(*logic_state_machine), "PrePickState");
  // Power off arm
  arm.sendCmd(ArmParser::Command::POWER_OFF);
  // Check we are in Hovering
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Hovering");
}

// Abort due to arm not enabled
TEST_F(PickPlaceStateMachineTests, PickPlaceArmAbort) {
  // First takeoff
  GoToHoverFromLanded();
  // Set goal for simple tracker
  Position roi_goal(2, 0, 0.5);
  tracker->setTargetPositionGlobalFrame(roi_goal);
  // Initialize event to vse::TrackROI
  logic_state_machine->process_event(pe::Pick());
  // Check we are in pre-pick state
  ASSERT_STREQ(pstate(*logic_state_machine), "PrePickState");
  // Go to pick
  logic_state_machine->process_event(Completed());
  // Check we are in pick state
  ASSERT_STREQ(pstate(*logic_state_machine), "PickState");
  // Power off arm
  arm.sendCmd(ArmParser::Command::POWER_OFF);
  // Check we are in Hovering
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Hovering");
}
// Abort due to tracking becoming invalid
TEST_F(PickPlaceStateMachineTests, PrePickPlaceInvalidTrackingAbort) {
  // First takeoff
  GoToHoverFromLanded();
  // Set goal for simple tracker
  Position roi_goal(2, 0, 0.5);
  tracker->setTargetPositionGlobalFrame(roi_goal);
  // Initialize event to vse::TrackROI
  logic_state_machine->process_event(pe::Pick());
  // Check we are in pre-pick state
  ASSERT_STREQ(pstate(*logic_state_machine), "PrePickState");
  // Set tracker to invalid
  tracker->setTrackingIsValid(false);
  // Run active controllers
  for (int i = 0; i < 2; ++i) {
    uav_arm_system->runActiveController(HardwareType::UAV);
    uav_arm_system->runActiveController(HardwareType::Arm);
  }
  // Check we are in Hovering
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Hovering");
}
// Abort due to tracking becoming invalid
TEST_F(PickPlaceStateMachineTests, PickPlaceInvalidTrackingAbort) {
  // First takeoff
  GoToHoverFromLanded();
  // Set goal for simple tracker
  Position roi_goal(2, 0, 0.5);
  tracker->setTargetPositionGlobalFrame(roi_goal);
  // Initialize event to vse::TrackROI
  logic_state_machine->process_event(pe::Pick());
  // Check we are in pre-pick state
  ASSERT_STREQ(pstate(*logic_state_machine), "PrePickState");
  // Go to pick state
  logic_state_machine->process_event(Completed());
  // Check we are in pick state
  ASSERT_STREQ(pstate(*logic_state_machine), "PickState");
  // Set tracker to invalid
  tracker->setTrackingIsValid(false);
  // Run active controllers
  for (int i = 0; i < 2; ++i) {
    uav_arm_system->runActiveController(HardwareType::UAV);
    uav_arm_system->runActiveController(HardwareType::Arm);
  }
  // Check we are in Hovering
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Hovering");
}
// Manual rc abort
TEST_F(PickPlaceStateMachineTests, PrePickPlaceManualControlAbort) {
  // First takeoff
  GoToHoverFromLanded();
  // Set goal for simple tracker
  Position roi_goal(2, 0, 0.5);
  tracker->setTargetPositionGlobalFrame(roi_goal);
  // Initialize event to vse::TrackROI
  logic_state_machine->process_event(pe::Pick());
  // Check we are in pre-pick state
  ASSERT_STREQ(pstate(*logic_state_machine), "PrePickState");
  // Disable SDK
  drone_hardware.flowControl(false);
  // Check we are in Hovering
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Hovering");
  // And finally in manual control state
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "ManualControlArmState");
  // Enable SDK
  drone_hardware.flowControl(true);
  // Check we are back in hovering
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Hovering");
}
// Manual rc abort
TEST_F(PickPlaceStateMachineTests, PickPlaceManualControlAbort) {
  // First takeoff
  GoToHoverFromLanded();
  // Set goal for simple tracker
  Position roi_goal(2, 0, 0.5);
  tracker->setTargetPositionGlobalFrame(roi_goal);
  // Initialize event to vse::TrackROI
  logic_state_machine->process_event(pe::Pick());
  // Check we are in pre-pick state
  ASSERT_STREQ(pstate(*logic_state_machine), "PrePickState");
  // Go to pick state
  logic_state_machine->process_event(Completed());
  // Check we are in pick state
  ASSERT_STREQ(pstate(*logic_state_machine), "PickState");
  // Disable SDK
  drone_hardware.flowControl(false);
  // Check we are in Hovering
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Hovering");
  // And finally in manual control state
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "ManualControlArmState");
  // Enable SDK
  drone_hardware.flowControl(true);
  // Check we are back in hovering
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Hovering");
}
// Manual control internal actions
TEST_F(PickPlaceStateMachineTests, PickPlaceManualControlInternalActions) {
  // Disable SDK
  drone_hardware.flowControl(false);
  // Move to manual control state
  logic_state_machine->process_event(InternalTransitionEvent());
  // Check we are in manual control state
  ASSERT_STREQ(pstate(*logic_state_machine), "ManualControlArmState");
  // Enable arm
  uav_arm_system->power(true);
  // Process Poweroff
  logic_state_machine->process_event(arm_events::PowerOff());
  // Check arm is powered off
  ASSERT_FALSE(uav_arm_system->enabled());
  // Process Poweron
  logic_state_machine->process_event(arm_events::PowerOn());
  // Check arm is powered on
  ASSERT_TRUE(uav_arm_system->enabled());
  // Check command status is false
  ASSERT_FALSE(arm.getCommandStatus());
  // Check we can process fold
  logic_state_machine->process_event(arm_events::Fold());
  ASSERT_TRUE(arm.getCommandStatus());
  // Check we can process right fold
  logic_state_machine->process_event(arm_events::RightAngleFold());
  ASSERT_TRUE(arm.getCommandStatus());
  // Check we are still in Manual Control State
  ASSERT_STREQ(pstate(*logic_state_machine), "ManualControlArmState");
}
///

int main(int argc, char **argv) {
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<commit_msg>Fix pick place state machine tests<commit_after>#include <aerial_autonomy/state_machines/pick_place_state_machine.h>
#include <aerial_autonomy/trackers/simple_tracker.h>
#include <arm_parsers/arm_simulator.h>
#include <gtest/gtest.h>
// Timer stuff
#include <chrono>
#include <thread>
// Quad Simulator
#include <quad_simulator_parser/quad_simulator.h>

/**
* @brief Namespace for UAV Simulator Hardware
*/
using namespace quad_simulator;

/**
* @brief Visual servoing events such as TrackROI, GoHome
*/
namespace vse = visual_servoing_events;

/**
* @brief Namespace for pick place events
*/
namespace pe = pick_place_events;

/**
* @brief Namespace for basic events such as takeoff, land.
*/
namespace be = uav_basic_events;

class PickPlaceStateMachineTests : public ::testing::Test {
public:
  PickPlaceStateMachineTests() : goal_tolerance_position(0.5) {
    auto uav_vision_system_config = config.mutable_uav_vision_system_config();
    for (int i = 0; i < 6; ++i) {
      uav_vision_system_config->add_camera_transform(0.0);
    }
    uav_vision_system_config->set_desired_visual_servoing_distance(1.0);
    auto uav_arm_system_config =
        uav_vision_system_config->mutable_uav_arm_system_config();
    for (int i = 0; i < 6; ++i) {
      uav_arm_system_config->add_arm_transform(0);
    }
    for (int i = 0; i < 12; ++i) {
      uav_arm_system_config->add_arm_goal_transform(0);
    }
    auto depth_config =
        uav_vision_system_config
            ->mutable_constant_heading_depth_controller_config();
    depth_config->set_radial_gain(0.5);
    depth_config->mutable_position_controller_config()
        ->set_goal_position_tolerance(goal_tolerance_position);
    tf::Transform camera_transform = math::getTransformFromVector(
        uav_vision_system_config->camera_transform());
    tracker.reset(new SimpleTracker(drone_hardware, camera_transform));
    uav_arm_system.reset(
        new UAVArmSystem(*tracker, drone_hardware, arm, config));
    logic_state_machine.reset(
        new PickPlaceStateMachine(boost::ref(*uav_arm_system)));
    logic_state_machine->start();
    // Move to landed state
    logic_state_machine->process_event(InternalTransitionEvent());
  }

  ~PickPlaceStateMachineTests() {
    logic_state_machine->stop();
    uav_arm_system.reset();
    logic_state_machine.reset();
  }

protected:
  QuadSimulator drone_hardware;
  ArmSimulator arm;
  UAVSystemConfig config;
  std::unique_ptr<SimpleTracker> tracker;
  std::unique_ptr<UAVArmSystem> uav_arm_system;
  std::unique_ptr<PickPlaceStateMachine> logic_state_machine;
  double goal_tolerance_position;

  void GoToHoverFromLanded() {
    drone_hardware.setBatteryPercent(100);
    logic_state_machine->process_event(be::Takeoff());
    // Powers on arm and folds it; Starts takeoff
    logic_state_machine->process_event(InternalTransitionEvent());
    // Completes takeoff and goes to hovering
    logic_state_machine->process_event(InternalTransitionEvent());
  }
};

TEST_F(PickPlaceStateMachineTests, InitialState) {
  // Validate
  ASSERT_STREQ(pstate(*logic_state_machine), "Landed");
  GoToHoverFromLanded();
}

/// \brief Test Arm folding during landing and takeoff
TEST_F(PickPlaceStateMachineTests, HoveringandLanding) {
  // Takeoff
  drone_hardware.setBatteryPercent(100);
  logic_state_machine->process_event(be::Takeoff());
  ASSERT_STREQ(pstate(*logic_state_machine), "ArmPreTakeoffFolding");
  // Powers on arm and folds it; Starts takeoff
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Takingoff");
  // Completes takeoff and goes to hovering
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Hovering");
  logic_state_machine->process_event(be::Land());
  ASSERT_STREQ(pstate(*logic_state_machine), "ArmPreLandingFolding");
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Landing");
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Landed");
}
///
/// \brief Test Pick Place
// Try Pick
TEST_F(PickPlaceStateMachineTests, PickPlace) {
  // Timeout for running controller
  int time_out = 5000;  // Milliseconds
  int time_period = 20; // Milliseconds
  int max_count = time_out / time_period;
  // First takeoff
  GoToHoverFromLanded();
  // Set goal for simple tracker
  Position roi_goal(2, 0, 0.5);
  tracker->setTargetPositionGlobalFrame(roi_goal);
  // Initialize event to vse::TrackROI
  logic_state_machine->process_event(pe::Pick());
  // Check we are in PrePick state
  ASSERT_STREQ(pstate(*logic_state_machine), "PrePickState");
  // Check controllers are active
  ASSERT_EQ(uav_arm_system->getStatus<VisualServoingControllerDroneConnector>(),
            ControllerStatus::Active);
  ASSERT_EQ(uav_arm_system->getStatus<VisualServoingControllerArmConnector>(),
            ControllerStatus::Active);
  // Keep running the controller until its completed or timeout
  int temp_count = 0;
  while (uav_arm_system->getStatus<VisualServoingControllerArmConnector>() ==
             ControllerStatus::Active &&
         ++temp_count < max_count) {
    uav_arm_system->runActiveController(HardwareType::UAV);
    uav_arm_system->runActiveController(HardwareType::Arm);
    logic_state_machine->process_event(InternalTransitionEvent());
    std::this_thread::sleep_for(std::chrono::milliseconds(time_period));
  }
  // Make sure controllers are aborted
  ASSERT_EQ(uav_arm_system->getActiveControllerStatus(HardwareType::Arm),
            ControllerStatus::NotEngaged);
  ASSERT_EQ(uav_arm_system->getActiveControllerStatus(HardwareType::UAV),
            ControllerStatus::NotEngaged);
  // Check we are back in Hovering state
  ASSERT_STREQ(pstate(*logic_state_machine), "Hovering");
}
// Abort due to arm not enabled
TEST_F(PickPlaceStateMachineTests, PrePickPlaceArmAbort) {
  // First takeoff
  GoToHoverFromLanded();
  // Set goal for simple tracker
  Position roi_goal(2, 0, 0.5);
  tracker->setTargetPositionGlobalFrame(roi_goal);
  // Initialize event to vse::TrackROI
  logic_state_machine->process_event(pe::Pick());
  // Check we are in pre-pick state
  ASSERT_STREQ(pstate(*logic_state_machine), "PrePickState");
  // Power off arm
  arm.sendCmd(ArmParser::Command::POWER_OFF);
  // Check we are in Hovering
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Hovering");
}

// Abort due to arm not enabled
TEST_F(PickPlaceStateMachineTests, PickPlaceArmAbort) {
  // First takeoff
  GoToHoverFromLanded();
  // Set goal for simple tracker
  Position roi_goal(2, 0, 0.5);
  tracker->setTargetPositionGlobalFrame(roi_goal);
  // Initialize event to vse::TrackROI
  logic_state_machine->process_event(pe::Pick());
  // Check we are in pre-pick state
  ASSERT_STREQ(pstate(*logic_state_machine), "PrePickState");
  // Go to pick
  logic_state_machine->process_event(Completed());
  // Check we are in pick state
  ASSERT_STREQ(pstate(*logic_state_machine), "PickState");
  // Power off arm
  arm.sendCmd(ArmParser::Command::POWER_OFF);
  // Check we are in Hovering
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Hovering");
}
// Abort due to tracking becoming invalid
TEST_F(PickPlaceStateMachineTests, PrePickPlaceInvalidTrackingAbort) {
  // First takeoff
  GoToHoverFromLanded();
  // Set goal for simple tracker
  Position roi_goal(2, 0, 0.5);
  tracker->setTargetPositionGlobalFrame(roi_goal);
  // Initialize event to vse::TrackROI
  logic_state_machine->process_event(pe::Pick());
  // Check we are in pre-pick state
  ASSERT_STREQ(pstate(*logic_state_machine), "PrePickState");
  // Set tracker to invalid
  tracker->setTrackingIsValid(false);
  // Run active controllers
  for (int i = 0; i < 2; ++i) {
    uav_arm_system->runActiveController(HardwareType::UAV);
    uav_arm_system->runActiveController(HardwareType::Arm);
  }
  // Check we are in Hovering
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Hovering");
}
// Abort due to tracking becoming invalid
TEST_F(PickPlaceStateMachineTests, PickPlaceInvalidTrackingAbort) {
  // First takeoff
  GoToHoverFromLanded();
  // Set goal for simple tracker
  Position roi_goal(2, 0, 0.5);
  tracker->setTargetPositionGlobalFrame(roi_goal);
  // Initialize event to vse::TrackROI
  logic_state_machine->process_event(pe::Pick());
  // Check we are in pre-pick state
  ASSERT_STREQ(pstate(*logic_state_machine), "PrePickState");
  // Go to pick state
  logic_state_machine->process_event(Completed());
  // Check we are in pick state
  ASSERT_STREQ(pstate(*logic_state_machine), "PickState");
  // Set tracker to invalid
  tracker->setTrackingIsValid(false);
  // Run active controllers
  for (int i = 0; i < 2; ++i) {
    uav_arm_system->runActiveController(HardwareType::UAV);
    uav_arm_system->runActiveController(HardwareType::Arm);
  }
  // Check we are in Hovering
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Hovering");
}
// Manual rc abort
TEST_F(PickPlaceStateMachineTests, PrePickPlaceManualControlAbort) {
  // First takeoff
  GoToHoverFromLanded();
  // Set goal for simple tracker
  Position roi_goal(2, 0, 0.5);
  tracker->setTargetPositionGlobalFrame(roi_goal);
  // Initialize event to vse::TrackROI
  logic_state_machine->process_event(pe::Pick());
  // Check we are in pre-pick state
  ASSERT_STREQ(pstate(*logic_state_machine), "PrePickState");
  // Disable SDK
  drone_hardware.flowControl(false);
  // Check we are in Hovering
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Hovering");
  // And finally in manual control state
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "ManualControlArmState");
  // Enable SDK
  drone_hardware.flowControl(true);
  // Check we are back in hovering
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Hovering");
}
// Manual rc abort
TEST_F(PickPlaceStateMachineTests, PickPlaceManualControlAbort) {
  // First takeoff
  GoToHoverFromLanded();
  // Set goal for simple tracker
  Position roi_goal(2, 0, 0.5);
  tracker->setTargetPositionGlobalFrame(roi_goal);
  // Initialize event to vse::TrackROI
  logic_state_machine->process_event(pe::Pick());
  // Check we are in pre-pick state
  ASSERT_STREQ(pstate(*logic_state_machine), "PrePickState");
  // Go to pick state
  logic_state_machine->process_event(Completed());
  // Check we are in pick state
  ASSERT_STREQ(pstate(*logic_state_machine), "PickState");
  // Disable SDK
  drone_hardware.flowControl(false);
  // Check we are in Hovering
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Hovering");
  // And finally in manual control state
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "ManualControlArmState");
  // Enable SDK
  drone_hardware.flowControl(true);
  // Check we are back in hovering
  logic_state_machine->process_event(InternalTransitionEvent());
  ASSERT_STREQ(pstate(*logic_state_machine), "Hovering");
}
// Manual control internal actions
TEST_F(PickPlaceStateMachineTests, PickPlaceManualControlInternalActions) {
  // Disable SDK
  drone_hardware.flowControl(false);
  // Move to manual control state
  logic_state_machine->process_event(InternalTransitionEvent());
  // Check we are in manual control state
  ASSERT_STREQ(pstate(*logic_state_machine), "ManualControlArmState");
  // Enable arm
  uav_arm_system->power(true);
  // Process Poweroff
  logic_state_machine->process_event(arm_events::PowerOff());
  // Check arm is powered off
  ASSERT_FALSE(uav_arm_system->enabled());
  // Process Poweron
  logic_state_machine->process_event(arm_events::PowerOn());
  // Check arm is powered on
  ASSERT_TRUE(uav_arm_system->enabled());
  // Check command status is false
  ASSERT_FALSE(arm.getCommandStatus());
  // Check we can process fold
  logic_state_machine->process_event(arm_events::Fold());
  ASSERT_TRUE(arm.getCommandStatus());
  // Check we can process right fold
  logic_state_machine->process_event(arm_events::RightAngleFold());
  ASSERT_TRUE(arm.getCommandStatus());
  // Check we are still in Manual Control State
  ASSERT_STREQ(pstate(*logic_state_machine), "ManualControlArmState");
}
///

int main(int argc, char **argv) {
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>/****************************************************************************
 * Copyright (c) 2012-2018 by the DataTransferKit authors                   *
 * All rights reserved.                                                     *
 *                                                                          *
 * This file is part of the DataTransferKit library. DataTransferKit is     *
 * distributed under a BSD 3-clause license. For the licensing terms see    *
 * the LICENSE file in the top-level directory.                             *
 *                                                                          *
 * SPDX-License-Identifier: BSD-3-Clause                                    *
 ****************************************************************************/

#ifndef DTK_DISTRIBUTED_SEARCH_TREE_DECL_HPP
#define DTK_DISTRIBUTED_SEARCH_TREE_DECL_HPP

#include <Kokkos_View.hpp>

#include <Teuchos_Comm.hpp>
#include <Teuchos_RCP.hpp>

#include <DTK_DBC.hpp>
#include <DTK_DetailsDistributedSearchTreeImpl.hpp>
#include <DTK_LinearBVH.hpp>

#include "DTK_ConfigDefs.hpp"

namespace DataTransferKit
{

/** \brief Distributed search tree
 *
 *  \note query() must be called as collective over all processes in the
 *  communicator passed to the constructor.
 */
template <typename DeviceType>
class DistributedSearchTree
{
  public:
    using bounding_volume_type = typename BVH<DeviceType>::bounding_volume_type;
    using size_type = typename BVH<DeviceType>::size_type;

    DistributedSearchTree(
        Teuchos::RCP<Teuchos::Comm<int> const> comm,
        Kokkos::View<Box const *, DeviceType> bounding_boxes );

    /** Returns the smallest axis-aligned box able to contain all the objects
     *  stored in the tree or an invalid box if the tree is empty.
     */
    inline bounding_volume_type bounds() const { return _top_tree.bounds(); }

    /** Returns the global number of objects stored in the tree.
     */
    inline size_type size() const { return _top_tree_size; }

    /** Indicates whether the tree is empty on all processes.
     */
    inline bool empty() const { return size() == 0; }

    /** \brief Finds object satisfying the passed predicates (e.g. nearest to
     *  some point or overlaping with some box)
     *
     *  This query function performs a batch of spatial or k-nearest neighbors
     *  searches.  The results give indices of the objects that satisfy
     *  predicates (as given to the constructor).  They are organized in a
     *  distributed compressed row storage format.
     *
     *  \c indices stores the indices of the objects that satisfy the
     *  predicates.  \c offset stores the locations in the \c indices view that
     *  start a predicate, that is, \c queries(q) is satisfied by \c indices(o)
     *  for objects(q) <= o < objects(q+1) that live on processes
     *  \c ranks(o) respectively.  Following the usual convention,
     *  offset(n) = nnz, where \c n is the number of queries that
     *  were performed and \c nnz is the total number of collisions.
     *
     *  \note The views \c indices, \c offset, and \c ranks are passed by
     *  reference because \c Kokkos::realloc() calls the assignment operator.
     *
     *  \param[in] queries Collection of predicates of the same type.  These
     *  may be spatial predicates or nearest predicates.
     *  \param[out] indices Object local indices that satisfy the predicates.
     *  \param[out] offset Array of predicate offsets for one-dimensional
     *  storage.
     *  \param[out] ranks Process ranks that own objects.
     */
    template <typename Query>
    void query( Kokkos::View<Query *, DeviceType> queries,
                Kokkos::View<int *, DeviceType> &indices,
                Kokkos::View<int *, DeviceType> &offset,
                Kokkos::View<int *, DeviceType> &ranks ) const;

    template <typename Query>
    typename std::enable_if<
        std::is_same<typename Query::Tag, Details::NearestPredicateTag>::value,
        void>::type
    query( Kokkos::View<Query *, DeviceType> queries,
           Kokkos::View<int *, DeviceType> &indices,
           Kokkos::View<int *, DeviceType> &offset,
           Kokkos::View<int *, DeviceType> &ranks,
           Kokkos::View<double *, DeviceType> &distances ) const;

  private:
    friend struct Details::DistributedSearchTreeImpl<DeviceType>;
    Teuchos::RCP<Teuchos::Comm<int> const> _comm;
    BVH<DeviceType> _top_tree;    // replicated
    BVH<DeviceType> _bottom_tree; // local
    size_type _top_tree_size;
    Kokkos::View<size_type *, DeviceType> _bottom_tree_sizes;
};

template <typename DeviceType>
template <typename Query>
void DistributedSearchTree<DeviceType>::query(
    Kokkos::View<Query *, DeviceType> queries,
    Kokkos::View<int *, DeviceType> &indices,
    Kokkos::View<int *, DeviceType> &offset,
    Kokkos::View<int *, DeviceType> &ranks ) const
{
    using Tag = typename Query::Tag;
    Details::DistributedSearchTreeImpl<DeviceType>::queryDispatch(
        *this, queries, indices, offset, ranks, Tag{} );
}

template <typename DeviceType>
template <typename Query>
typename std::enable_if<
    std::is_same<typename Query::Tag, Details::NearestPredicateTag>::value,
    void>::type
DistributedSearchTree<DeviceType>::query(
    Kokkos::View<Query *, DeviceType> queries,
    Kokkos::View<int *, DeviceType> &indices,
    Kokkos::View<int *, DeviceType> &offset,
    Kokkos::View<int *, DeviceType> &ranks,
    Kokkos::View<double *, DeviceType> &distances ) const
{
    using Tag = typename Query::Tag;
    Details::DistributedSearchTreeImpl<DeviceType>::queryDispatch(
        *this, queries, indices, offset, ranks, Tag{}, &distances );
}

} // namespace DataTransferKit

#endif
<commit_msg>Move DistributedSearchTree::query() definition inside the class declaration and inline it<commit_after>/****************************************************************************
 * Copyright (c) 2012-2018 by the DataTransferKit authors                   *
 * All rights reserved.                                                     *
 *                                                                          *
 * This file is part of the DataTransferKit library. DataTransferKit is     *
 * distributed under a BSD 3-clause license. For the licensing terms see    *
 * the LICENSE file in the top-level directory.                             *
 *                                                                          *
 * SPDX-License-Identifier: BSD-3-Clause                                    *
 ****************************************************************************/

#ifndef DTK_DISTRIBUTED_SEARCH_TREE_DECL_HPP
#define DTK_DISTRIBUTED_SEARCH_TREE_DECL_HPP

#include <Kokkos_View.hpp>

#include <Teuchos_Comm.hpp>
#include <Teuchos_RCP.hpp>

#include <DTK_DBC.hpp>
#include <DTK_DetailsDistributedSearchTreeImpl.hpp>
#include <DTK_LinearBVH.hpp>

#include "DTK_ConfigDefs.hpp"

namespace DataTransferKit
{

/** \brief Distributed search tree
 *
 *  \note query() must be called as collective over all processes in the
 *  communicator passed to the constructor.
 */
template <typename DeviceType>
class DistributedSearchTree
{
  public:
    using bounding_volume_type = typename BVH<DeviceType>::bounding_volume_type;
    using size_type = typename BVH<DeviceType>::size_type;

    DistributedSearchTree(
        Teuchos::RCP<Teuchos::Comm<int> const> comm,
        Kokkos::View<Box const *, DeviceType> bounding_boxes );

    /** Returns the smallest axis-aligned box able to contain all the objects
     *  stored in the tree or an invalid box if the tree is empty.
     */
    inline bounding_volume_type bounds() const { return _top_tree.bounds(); }

    /** Returns the global number of objects stored in the tree.
     */
    inline size_type size() const { return _top_tree_size; }

    /** Indicates whether the tree is empty on all processes.
     */
    inline bool empty() const { return size() == 0; }

    /** \brief Finds object satisfying the passed predicates (e.g. nearest to
     *  some point or overlaping with some box)
     *
     *  This query function performs a batch of spatial or k-nearest neighbors
     *  searches.  The results give indices of the objects that satisfy
     *  predicates (as given to the constructor).  They are organized in a
     *  distributed compressed row storage format.
     *
     *  \c indices stores the indices of the objects that satisfy the
     *  predicates.  \c offset stores the locations in the \c indices view that
     *  start a predicate, that is, \c queries(q) is satisfied by \c indices(o)
     *  for objects(q) <= o < objects(q+1) that live on processes
     *  \c ranks(o) respectively.  Following the usual convention,
     *  offset(n) = nnz, where \c n is the number of queries that
     *  were performed and \c nnz is the total number of collisions.
     *
     *  \note The views \c indices, \c offset, and \c ranks are passed by
     *  reference because \c Kokkos::realloc() calls the assignment operator.
     *
     *  \param[in] queries Collection of predicates of the same type.  These
     *  may be spatial predicates or nearest predicates.
     *  \param[out] indices Object local indices that satisfy the predicates.
     *  \param[out] offset Array of predicate offsets for one-dimensional
     *  storage.
     *  \param[out] ranks Process ranks that own objects.
     */
    template <typename Query>
    inline void query( Kokkos::View<Query *, DeviceType> queries,
                       Kokkos::View<int *, DeviceType> &indices,
                       Kokkos::View<int *, DeviceType> &offset,
                       Kokkos::View<int *, DeviceType> &ranks ) const
    {
        using Tag = typename Query::Tag;
        Details::DistributedSearchTreeImpl<DeviceType>::queryDispatch(
            *this, queries, indices, offset, ranks, Tag{} );
    }

    template <typename Query>
    inline typename std::enable_if<
        std::is_same<typename Query::Tag, Details::NearestPredicateTag>::value,
        void>::type
    query( Kokkos::View<Query *, DeviceType> queries,
           Kokkos::View<int *, DeviceType> &indices,
           Kokkos::View<int *, DeviceType> &offset,
           Kokkos::View<int *, DeviceType> &ranks,
           Kokkos::View<double *, DeviceType> &distances ) const
    {
        using Tag = typename Query::Tag;
        Details::DistributedSearchTreeImpl<DeviceType>::queryDispatch(
            *this, queries, indices, offset, ranks, Tag{}, &distances );
    }

  private:
    friend struct Details::DistributedSearchTreeImpl<DeviceType>;
    Teuchos::RCP<Teuchos::Comm<int> const> _comm;
    BVH<DeviceType> _top_tree;    // replicated
    BVH<DeviceType> _bottom_tree; // local
    size_type _top_tree_size;
    Kokkos::View<size_type *, DeviceType> _bottom_tree_sizes;
};

} // namespace DataTransferKit

#endif
<|endoftext|>


<commit_before>/****************************************************************************
 * Copyright (c) 2012-2018 by the DataTransferKit authors                   *
 * All rights reserved.                                                     *
 *                                                                          *
 * This file is part of the DataTransferKit library. DataTransferKit is     *
 * distributed under a BSD 3-clause license. For the licensing terms see    *
 * the LICENSE file in the top-level directory.                             *
 *                                                                          *
 * SPDX-License-Identifier: BSD-3-Clause                                    *
 ****************************************************************************/
#ifndef DTK_DETAILS_DISTRIBUTOR_HPP
#define DTK_DETAILS_DISTRIBUTOR_HPP

#include <DTK_DBC.hpp>

#include <Kokkos_Core.hpp> // FIXME

#include <mpi.h>

#include <algorithm> // max_element
#include <numeric>   // iota
#include <vector>

#define REORDER_RECV YES

namespace DataTransferKit
{
namespace Details
{

// clang-format off
// copy/paste from https://github.com/kokkos/kokkos-tutorials/blob/ee619447cee9e57b831e34b151d0868958b6b1e5/Intro-Full/Exercises/mpi_exch/mpi_exch.cpp
// * added Experimental nested namespace qualifier for Max
// * declared function static to avoid multiple definition error at link time
// * return early if input argument is empty
// * replace parallel_reduce with std::max_element because I couldn't get it to compile
// * append size to offsets in main driver but might want to handle it here
static void extract_and_sort_ranks(
    Kokkos::View<int*, Kokkos::HostSpace> destination_ranks,
    Kokkos::View<int*, Kokkos::HostSpace> permutation,
    std::vector<int>& unique_ranks,
    std::vector<int>& offsets,
    std::vector<int>& counts) {
  int mpi_rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
  auto n = destination_ranks.extent(0);
if ( n == 0 ) return;
  using ST = decltype(n);
  Kokkos::View<int*, Kokkos::HostSpace> tmp_ranks("tmp ranks", destination_ranks.extent(0));
  Kokkos::deep_copy(tmp_ranks, destination_ranks);
  int offset = 0;
  // this implements a "sort" which is O(N * R) where (R) is
  // the total number of unique destination ranks.
  // it performs better than other algorithms in
  // the case when (R) is small, but results may vary
  while (true) {
    int next_biggest_rank;
    //Kokkos::parallel_reduce("find next biggest rank", n, KOKKOS_LAMBDA(ST i, int& local_max) {
    //  auto r = tmp_ranks(i);
    //  local_max = (r > local_max) ? r : local_max;
    //}, Kokkos::Experimental::Max<int, Kokkos::HostSpace>(next_biggest_rank));
    next_biggest_rank = *std::max_element(tmp_ranks.data(), tmp_ranks.data() + n);
    if (next_biggest_rank == -1) break;
    unique_ranks.push_back(next_biggest_rank);
    offsets.push_back(offset);
    Kokkos::View<int, Kokkos::HostSpace> total("total");
    Kokkos::parallel_scan("process biggest rank items", Kokkos::RangePolicy<Kokkos::Serial>(0, n),
    KOKKOS_LAMBDA(ST i, int& index, const bool last_pass) {
      if (last_pass && (tmp_ranks(i) == next_biggest_rank)) {
        permutation(i) = index + offset;
      }
      if (tmp_ranks(i) == next_biggest_rank) ++index;
      if (last_pass) {
        if (i + 1 == tmp_ranks.extent(0)) {
          total() = index;
        }
        if (tmp_ranks(i) == next_biggest_rank) {
          tmp_ranks(i) = -1;
        }
      }
    });
    auto host_total = Kokkos::create_mirror_view_and_copy(
        Kokkos::HostSpace(), total);
    auto count = host_total();
    counts.push_back(count);
    offset += count;
  }
}
// clang-format on

class Distributor
{
  public:
    Distributor( MPI_Comm comm )
        : _comm( comm )
    {
    }

    template <typename T>
    static T *notNullPtr( T *p )
    {
        return p ? p : reinterpret_cast<T *>( -1 );
    }

    template <typename View>
    size_t createFromSends( View const &tmp )
    {
        static_assert( View::rank == 1, "" );
        static_assert(
            std::is_same<typename View::non_const_value_type, int>::value, "" );
        int comm_rank;
        MPI_Comm_rank( _comm, &comm_rank );

        auto const n = tmp.size();
        Kokkos::View<int *, Kokkos::HostSpace> destination_ranks(
            "destination_ranks", n );
        Kokkos::deep_copy( destination_ranks, tmp );
        _permute = Kokkos::View<int *, Kokkos::HostSpace>( "permute", n );
        std::vector<int> destinations;
        extract_and_sort_ranks( destination_ranks, _permute, destinations,
                                _dest_offsets, _dest_counts );

        if ( _dest_counts.empty() )
            _dest_offsets.push_back( 0 );
        else
            _dest_offsets.push_back( _dest_offsets.back() +
                                     _dest_counts.back() );

        {
            int const reorder = 0; // Ranking may *not* be reordered
            int const sources[1] = {comm_rank};
            int const degrees[1] = {static_cast<int>( destinations.size() )};

            MPI_Dist_graph_create(
                _comm, 1, sources, degrees, notNullPtr( destinations.data() ),
                MPI_UNWEIGHTED, MPI_INFO_NULL, reorder, &_comm_dist_graph );
        }

        int indegrees;
        int outdegrees;
        int weighted;
        MPI_Dist_graph_neighbors_count( _comm_dist_graph, &indegrees,
                                        &outdegrees, &weighted );
        DTK_ENSURE( weighted == 0 );
        DTK_ENSURE( outdegrees == (int)destinations.size() );

        std::vector<int> sources( indegrees );
        MPI_Dist_graph_neighbors( _comm_dist_graph, indegrees,
                                  notNullPtr( sources.data() ), MPI_UNWEIGHTED,
                                  outdegrees, notNullPtr( destinations.data() ),
                                  MPI_UNWEIGHTED );

        _src_counts.resize( indegrees );
        MPI_Neighbor_alltoall( _dest_counts.data(), 1, MPI_INT,
                               _src_counts.data(), 1, MPI_INT,
                               _comm_dist_graph );

        _src_offsets.resize( indegrees + 1 );
        // exclusive scan
        _src_offsets[0] = 0;
        for ( int i = 0; i < indegrees; ++i )
            _src_offsets[i + 1] = _src_offsets[i] + _src_counts[i];

#if defined( REORDER_RECV )
        int comm_size = -1;
        MPI_Comm_size( _comm, &comm_size );
        _permute_recv.resize( _src_offsets.back() );
        int offset = 0;
        for ( int i = 0; i < comm_size; ++i )
        {
            auto const it = std::find( sources.begin(), sources.end(), i );
            if ( it != sources.end() )
            {
                int const j = std::distance( sources.begin(), it );
                std::iota( &_permute_recv[offset],
                           &_permute_recv[offset] + _src_counts[j],
                           _src_offsets[j] );
                offset += _src_counts[j];
            }
        }
        DTK_ENSURE( offset == (int)_permute_recv.size() );
#endif

        return _src_offsets.back();
    }
    template <typename View>
    void doPostsAndWaits( typename View::const_type const &exports,
                          size_t numPackets, View const &imports ) const
    {
        using ValueType = typename View::value_type;
        static_assert( View::rank == 1, "" );

        std::vector<int> dest_counts = _dest_counts;
        std::vector<int> dest_offsets = _dest_offsets;
        std::vector<int> src_counts = _src_counts;
        std::vector<int> src_offsets = _src_offsets;
        for ( auto pv :
              {&dest_counts, &dest_offsets, &src_counts, &src_offsets} )
            for ( auto &x : *pv )
                x *= numPackets * sizeof( ValueType );

        std::vector<ValueType> dest_buffer( exports.size() );
        std::vector<ValueType> src_buffer( imports.size() );

        DTK_REQUIRE( (size_t)src_offsets.back() ==
                     imports.size() * sizeof( ValueType ) );
        DTK_REQUIRE( (size_t)dest_offsets.back() ==
                     exports.size() * sizeof( ValueType ) );

        for ( int i = 0; i < _dest_offsets.back(); ++i )
            std::copy( &exports[numPackets * i],
                       &exports[numPackets * i] + numPackets,
                       &dest_buffer[numPackets * _permute[i]] );

        MPI_Neighbor_alltoallv(
            notNullPtr( dest_buffer.data() ), notNullPtr( dest_counts.data() ),
            dest_offsets.data(), MPI_BYTE, notNullPtr( src_buffer.data() ),
            notNullPtr( src_counts.data() ), src_offsets.data(), MPI_BYTE,
            _comm_dist_graph );

#if defined( REORDER_RECV )
        for ( int i = 0; i < _src_offsets.back(); ++i )
            std::copy( &src_buffer[numPackets * _permute_recv[i]],
                       &src_buffer[numPackets * _permute_recv[i]] + numPackets,
                       &imports[numPackets * i] );
#else
        std::copy( src_buffer.begin(), src_buffer.end(), imports.data() );
#endif
    }
    size_t getTotalReceiveLength() const { return _src_offsets.back(); }
    size_t getTotalSendLength() const { return _dest_offsets.back(); }

  private:
    MPI_Comm _comm;
    MPI_Comm _comm_dist_graph;
    Kokkos::View<int *, Kokkos::HostSpace> _permute;
    std::vector<int> _dest_offsets;
    std::vector<int> _dest_counts;
    std::vector<int> _src_offsets;
    std::vector<int> _src_counts;
#if defined( REORDER_RECV )
    std::vector<int> _permute_recv;
#endif
};

} // namespace Details
} // namespace DataTransferKit

#endif
<commit_msg>Prefer static_cast to C-style cast<commit_after>/****************************************************************************
 * Copyright (c) 2012-2018 by the DataTransferKit authors                   *
 * All rights reserved.                                                     *
 *                                                                          *
 * This file is part of the DataTransferKit library. DataTransferKit is     *
 * distributed under a BSD 3-clause license. For the licensing terms see    *
 * the LICENSE file in the top-level directory.                             *
 *                                                                          *
 * SPDX-License-Identifier: BSD-3-Clause                                    *
 ****************************************************************************/
#ifndef DTK_DETAILS_DISTRIBUTOR_HPP
#define DTK_DETAILS_DISTRIBUTOR_HPP

#include <DTK_DBC.hpp>

#include <Kokkos_Core.hpp> // FIXME

#include <mpi.h>

#include <algorithm> // max_element
#include <numeric>   // iota
#include <vector>

#define REORDER_RECV YES

namespace DataTransferKit
{
namespace Details
{

// clang-format off
// copy/paste from https://github.com/kokkos/kokkos-tutorials/blob/ee619447cee9e57b831e34b151d0868958b6b1e5/Intro-Full/Exercises/mpi_exch/mpi_exch.cpp
// * added Experimental nested namespace qualifier for Max
// * declared function static to avoid multiple definition error at link time
// * return early if input argument is empty
// * replace parallel_reduce with std::max_element because I couldn't get it to compile
// * append size to offsets in main driver but might want to handle it here
static void extract_and_sort_ranks(
    Kokkos::View<int*, Kokkos::HostSpace> destination_ranks,
    Kokkos::View<int*, Kokkos::HostSpace> permutation,
    std::vector<int>& unique_ranks,
    std::vector<int>& offsets,
    std::vector<int>& counts) {
  int mpi_rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
  auto n = destination_ranks.extent(0);
if ( n == 0 ) return;
  using ST = decltype(n);
  Kokkos::View<int*, Kokkos::HostSpace> tmp_ranks("tmp ranks", destination_ranks.extent(0));
  Kokkos::deep_copy(tmp_ranks, destination_ranks);
  int offset = 0;
  // this implements a "sort" which is O(N * R) where (R) is
  // the total number of unique destination ranks.
  // it performs better than other algorithms in
  // the case when (R) is small, but results may vary
  while (true) {
    int next_biggest_rank;
    //Kokkos::parallel_reduce("find next biggest rank", n, KOKKOS_LAMBDA(ST i, int& local_max) {
    //  auto r = tmp_ranks(i);
    //  local_max = (r > local_max) ? r : local_max;
    //}, Kokkos::Experimental::Max<int, Kokkos::HostSpace>(next_biggest_rank));
    next_biggest_rank = *std::max_element(tmp_ranks.data(), tmp_ranks.data() + n);
    if (next_biggest_rank == -1) break;
    unique_ranks.push_back(next_biggest_rank);
    offsets.push_back(offset);
    Kokkos::View<int, Kokkos::HostSpace> total("total");
    Kokkos::parallel_scan("process biggest rank items", Kokkos::RangePolicy<Kokkos::Serial>(0, n),
    KOKKOS_LAMBDA(ST i, int& index, const bool last_pass) {
      if (last_pass && (tmp_ranks(i) == next_biggest_rank)) {
        permutation(i) = index + offset;
      }
      if (tmp_ranks(i) == next_biggest_rank) ++index;
      if (last_pass) {
        if (i + 1 == tmp_ranks.extent(0)) {
          total() = index;
        }
        if (tmp_ranks(i) == next_biggest_rank) {
          tmp_ranks(i) = -1;
        }
      }
    });
    auto host_total = Kokkos::create_mirror_view_and_copy(
        Kokkos::HostSpace(), total);
    auto count = host_total();
    counts.push_back(count);
    offset += count;
  }
}
// clang-format on

class Distributor
{
  public:
    Distributor( MPI_Comm comm )
        : _comm( comm )
    {
    }

    template <typename T>
    static T *notNullPtr( T *p )
    {
        return p ? p : reinterpret_cast<T *>( -1 );
    }

    template <typename View>
    size_t createFromSends( View const &tmp )
    {
        static_assert( View::rank == 1, "" );
        static_assert(
            std::is_same<typename View::non_const_value_type, int>::value, "" );
        int comm_rank;
        MPI_Comm_rank( _comm, &comm_rank );

        auto const n = tmp.size();
        Kokkos::View<int *, Kokkos::HostSpace> destination_ranks(
            "destination_ranks", n );
        Kokkos::deep_copy( destination_ranks, tmp );
        _permute = Kokkos::View<int *, Kokkos::HostSpace>( "permute", n );
        std::vector<int> destinations;
        extract_and_sort_ranks( destination_ranks, _permute, destinations,
                                _dest_offsets, _dest_counts );

        if ( _dest_counts.empty() )
            _dest_offsets.push_back( 0 );
        else
            _dest_offsets.push_back( _dest_offsets.back() +
                                     _dest_counts.back() );

        {
            int const reorder = 0; // Ranking may *not* be reordered
            int const sources[1] = {comm_rank};
            int const degrees[1] = {static_cast<int>( destinations.size() )};

            MPI_Dist_graph_create(
                _comm, 1, sources, degrees, notNullPtr( destinations.data() ),
                MPI_UNWEIGHTED, MPI_INFO_NULL, reorder, &_comm_dist_graph );
        }

        int indegrees;
        int outdegrees;
        int weighted;
        MPI_Dist_graph_neighbors_count( _comm_dist_graph, &indegrees,
                                        &outdegrees, &weighted );
        DTK_ENSURE( weighted == 0 );
        DTK_ENSURE( outdegrees == static_cast<int>( destinations.size() ) );

        std::vector<int> sources( indegrees );
        MPI_Dist_graph_neighbors( _comm_dist_graph, indegrees,
                                  notNullPtr( sources.data() ), MPI_UNWEIGHTED,
                                  outdegrees, notNullPtr( destinations.data() ),
                                  MPI_UNWEIGHTED );

        _src_counts.resize( indegrees );
        MPI_Neighbor_alltoall( _dest_counts.data(), 1, MPI_INT,
                               _src_counts.data(), 1, MPI_INT,
                               _comm_dist_graph );

        _src_offsets.resize( indegrees + 1 );
        // exclusive scan
        _src_offsets[0] = 0;
        for ( int i = 0; i < indegrees; ++i )
            _src_offsets[i + 1] = _src_offsets[i] + _src_counts[i];

#if defined( REORDER_RECV )
        int comm_size = -1;
        MPI_Comm_size( _comm, &comm_size );
        _permute_recv.resize( _src_offsets.back() );
        int offset = 0;
        for ( int i = 0; i < comm_size; ++i )
        {
            auto const it = std::find( sources.begin(), sources.end(), i );
            if ( it != sources.end() )
            {
                int const j = std::distance( sources.begin(), it );
                std::iota( &_permute_recv[offset],
                           &_permute_recv[offset] + _src_counts[j],
                           _src_offsets[j] );
                offset += _src_counts[j];
            }
        }
        DTK_ENSURE( offset == static_cast<int>( _permute_recv.size() ) );
#endif

        return _src_offsets.back();
    }
    template <typename View>
    void doPostsAndWaits( typename View::const_type const &exports,
                          size_t numPackets, View const &imports ) const
    {
        using ValueType = typename View::value_type;
        static_assert( View::rank == 1, "" );

        std::vector<int> dest_counts = _dest_counts;
        std::vector<int> dest_offsets = _dest_offsets;
        std::vector<int> src_counts = _src_counts;
        std::vector<int> src_offsets = _src_offsets;
        for ( auto pv :
              {&dest_counts, &dest_offsets, &src_counts, &src_offsets} )
            for ( auto &x : *pv )
                x *= numPackets * sizeof( ValueType );

        std::vector<ValueType> dest_buffer( exports.size() );
        std::vector<ValueType> src_buffer( imports.size() );

        DTK_REQUIRE( static_cast<size_t>( src_offsets.back() ) ==
                     imports.size() * sizeof( ValueType ) );
        DTK_REQUIRE( static_cast<size_t>( dest_offsets.back() ) ==
                     exports.size() * sizeof( ValueType ) );

        for ( int i = 0; i < _dest_offsets.back(); ++i )
            std::copy( &exports[numPackets * i],
                       &exports[numPackets * i] + numPackets,
                       &dest_buffer[numPackets * _permute[i]] );

        MPI_Neighbor_alltoallv(
            notNullPtr( dest_buffer.data() ), notNullPtr( dest_counts.data() ),
            dest_offsets.data(), MPI_BYTE, notNullPtr( src_buffer.data() ),
            notNullPtr( src_counts.data() ), src_offsets.data(), MPI_BYTE,
            _comm_dist_graph );

#if defined( REORDER_RECV )
        for ( int i = 0; i < _src_offsets.back(); ++i )
            std::copy( &src_buffer[numPackets * _permute_recv[i]],
                       &src_buffer[numPackets * _permute_recv[i]] + numPackets,
                       &imports[numPackets * i] );
#else
        std::copy( src_buffer.begin(), src_buffer.end(), imports.data() );
#endif
    }
    size_t getTotalReceiveLength() const { return _src_offsets.back(); }
    size_t getTotalSendLength() const { return _dest_offsets.back(); }

  private:
    MPI_Comm _comm;
    MPI_Comm _comm_dist_graph;
    Kokkos::View<int *, Kokkos::HostSpace> _permute;
    std::vector<int> _dest_offsets;
    std::vector<int> _dest_counts;
    std::vector<int> _src_offsets;
    std::vector<int> _src_counts;
#if defined( REORDER_RECV )
    std::vector<int> _permute_recv;
#endif
};

} // namespace Details
} // namespace DataTransferKit

#endif
<|endoftext|>


<commit_before>/*
 * cvlan.cpp
 *
 *  Created on: 07.08.2014
 *      Author: andreas
 */

#include "cvlan.hpp"

using namespace roflibs::eth;

void
cvlan::handle_dpt_open(
		rofl::crofdpt& dpt)
{
	try {
		state = STATE_ATTACHED;
		group_id = dpt.get_next_idle_group_id();

		// set flooding group entry itself
		update_group_entry_buckets(rofl::openflow::OFPGC_ADD);

		// set redirecting entry for this vlan's flooding group entry
		rofl::openflow::cofflowmod fm(dpt.get_version());
		fm.set_command(rofl::openflow::OFPFC_ADD);
		fm.set_table_id(table_id_eth_dst);
		fm.set_buffer_id(rofl::openflow::OFP_NO_BUFFER);
		fm.set_idle_timeout(0);
		fm.set_hard_timeout(0);
		fm.set_priority(0x8000);
		fm.set_match().set_vlan_vid(vid | rofl::openflow::OFPVID_PRESENT);
		fm.set_instructions().set_inst_apply_actions().
				set_actions().add_action_group(rofl::cindex(0)).set_group_id(group_id);
		dpt.send_flow_mod_message(rofl::cauxid(0), fm);

		// set broadcast entry in src stage
		fm.set_table_id(table_id_eth_src);
		fm.set_priority(0x8100);
		fm.set_match().set_eth_dst(rofl::caddress_ll("01:00:00:00:00:00"), rofl::caddress_ll("01:00:00:00:00:00"));
		fm.set_instructions().set_inst_goto_table().set_table_id(table_id_eth_local);
		dpt.send_flow_mod_message(rofl::cauxid(0), fm);

		// send notification to all ethernet endpoints
		for (std::map<rofl::caddress_ll, cethendpnt>::iterator
				it = ethendpnts.begin(); it != ethendpnts.end(); ++it) {
			it->second.handle_dpt_open(dpt);
		}

		// send notification to all member ports
		for (std::map<uint32_t, cmemberport>::iterator
				it = phyports.begin(); it != phyports.end(); ++it) {
			it->second.handle_dpt_open(dpt);
		}

		// send notification to all fib entries
		for (std::map<rofl::caddress_ll, cfibentry>::iterator
				it = fib.begin(); it != fib.end(); ++it) {
			it->second.handle_dpt_open(dpt);
		}

	} catch (rofl::eRofSockTxAgain& e) {
		rofcore::logging::debug << "[cvlan][handle_dpt_open] control channel congested" << std::endl;
	} catch (rofl::eRofBaseNotConnected& e) {
		rofcore::logging::debug << "[cvlan][handle_dpt_open] control channel not connected" << std::endl;
	}
}

void
cvlan::handle_dpt_close(
		rofl::crofdpt& dpt)
{
	try {
		// send notification to all fib entries
		for (std::map<rofl::caddress_ll, cfibentry>::iterator
				it = fib.begin(); it != fib.end(); ++it) {
			it->second.handle_dpt_close(dpt);
		}

		// send notification to all member ports
		for (std::map<uint32_t, cmemberport>::iterator
				it = phyports.begin(); it != phyports.end(); ++it) {
			it->second.handle_dpt_close(dpt);
		}

		// send notification to all ethernet endpoints
		for (std::map<rofl::caddress_ll, cethendpnt>::iterator
				it = ethendpnts.begin(); it != ethendpnts.end(); ++it) {
			it->second.handle_dpt_close(dpt);
		}

		// remove redirecting entry for this vlan's flooding group entry
		rofl::openflow::cofflowmod fm(dpt.get_version());
		fm.set_command(rofl::openflow::OFPFC_DELETE_STRICT);
		fm.set_table_id(table_id_eth_dst);
		fm.set_buffer_id(rofl::openflow::OFP_NO_BUFFER);
		fm.set_idle_timeout(0);
		fm.set_hard_timeout(0);
		fm.set_priority(0x8000);
		fm.set_match().set_vlan_vid(vid | rofl::openflow::OFPVID_PRESENT);
		dpt.send_flow_mod_message(rofl::cauxid(0), fm);

		// remove broadcast entry in src stage
		fm.set_table_id(table_id_eth_src);
		fm.set_priority(0x8100);
		fm.set_match().set_eth_dst(rofl::caddress_ll("01:00:00:00:00:00"), rofl::caddress_ll("01:00:00:00:00:00"));
		dpt.send_flow_mod_message(rofl::cauxid(0), fm);

		// remove flooding group entry itself
		rofl::openflow::cofgroupmod gm(dpt.get_version());
		gm.set_command(rofl::openflow::OFPGC_DELETE);
		gm.set_group_id(group_id);
		gm.set_type(rofl::openflow::OFPGT_ALL);

	} catch (rofl::eRofSockTxAgain& e) {
		rofcore::logging::debug << "[cvlan][handle_dpt_close] control channel congested" << std::endl;
	} catch (rofl::eRofBaseNotConnected& e) {
		rofcore::logging::debug << "[cvlan][handle_dpt_close] control channel not connected" << std::endl;
	} catch(...) {

	}

	state = STATE_DETACHED;
	dpt.release_group_id(group_id); group_id = 0;
}

void
cvlan::handle_packet_in(
		rofl::crofdpt& dpt, const rofl::cauxid& auxid, rofl::openflow::cofmsg_packet_in& msg)
{
	try {
		assert(dpid == dpt.get_dpid());
		assert(vid == (msg.get_match().get_vlan_vid_value() & (uint16_t)(~rofl::openflow::OFPVID_PRESENT)));

		uint32_t in_port = msg.get_match().get_in_port();
		const rofl::caddress_ll& lladdr = msg.get_match().get_eth_src_addr();
		if (lladdr.is_multicast() || lladdr.is_null()) {
			rofcore::logging::debug << "[cvlan][handle_packet_in] invalid source lladdr found" << std::endl << msg;
			dpt.drop_buffer(auxid, msg.get_buffer_id());
			return;
		}

		set_fib_entry(lladdr, in_port).handle_packet_in(dpt, auxid, msg);

	} catch (rofl::openflow::eOxmNotFound& e) {
		rofcore::logging::debug << "[cvlan][handle_packet_in] match(es) not found" << std::endl << msg;
		dpt.drop_buffer(auxid, msg.get_buffer_id());
	} catch (eFibEntryPortNotMember& e) {
		rofcore::logging::debug << "[cvlan][handle_packet_in] packet-in on invalid port" << std::endl << msg;
		dpt.drop_buffer(auxid, msg.get_buffer_id());
	}
}

void
cvlan::handle_flow_removed(
		rofl::crofdpt& dpt, const rofl::cauxid& auxid, rofl::openflow::cofmsg_flow_removed& msg)
{
	try {
		assert(dpid == dpt.get_dpid());
		assert(vid == (msg.get_match().get_vlan_vid_value() & (uint16_t)(~rofl::openflow::OFPVID_PRESENT)));

		// TODO: check port here?

		rofl::caddress_ll lladdr;

		if (msg.get_table_id() == 1) {
			lladdr = msg.get_match().get_eth_src_addr();
		} else
		if (msg.get_table_id() == 2) {
			lladdr = msg.get_match().get_eth_dst_addr();
		} else {
			return;
		}

		if (lladdr.is_multicast() || lladdr.is_null()) {
			rofcore::logging::debug << "[cvlan][handle_flow_removed] invalid source lladdr found" << std::endl << msg;
			return;
		}

		if (has_fib_entry(lladdr)) {
			set_fib_entry(lladdr).handle_flow_removed(dpt, auxid, msg); // notify fib entry
		}

	} catch (rofl::openflow::eOxmNotFound& e) {
		rofcore::logging::debug << "[cvlan][handle_flow_removed] match(es) not found" << std::endl << msg;
	}
}

void
cvlan::handle_port_status(
		rofl::crofdpt& dpt, const rofl::cauxid& auxid, rofl::openflow::cofmsg_port_status& msg)
{
	try {
		uint32_t portno = msg.get_port().get_port_no();

		if (not has_phy_port(portno)) {
			return;
		}

		set_phy_port(portno).handle_port_status(dpt, auxid, msg);

		for (std::map<rofl::caddress_ll, cfibentry>::iterator
				it = fib.begin(); it != fib.end(); ++it) {
			it->second.handle_port_status(dpt, auxid, msg);
		}

	} catch (rofl::openflow::eOxmNotFound& e) {
		rofcore::logging::debug << "[cvlan][handle_port_status] port not found" << std::endl << msg;
	}
}

void
cvlan::handle_error_message(
		rofl::crofdpt& dpt, const rofl::cauxid& auxid, rofl::openflow::cofmsg_error& msg)
{
	// TODO
}

void
cvlan::update_group_entry_buckets(uint16_t command)
{
	try {
		if (STATE_ATTACHED != state) {
			return;
		}

		if (rofl::openflow::OFP_VERSION_UNKNOWN == rofl::crofdpt::get_dpt(dpid).get_version()) {
			return;
		}

		// update flooding group entry
		rofl::openflow::cofgroupmod gm(rofl::crofdpt::get_dpt(dpid).get_version());
		gm.set_command(command);
		gm.set_group_id(group_id);
		gm.set_type(rofl::openflow::OFPGT_ALL);
		unsigned int bucket_id = 0;
		for (std::map<uint32_t, cmemberport>::iterator
				it = phyports.begin(); it != phyports.end(); ++it) {
			rofl::cindex index(0);
			if (not it->second.get_tagged()) {
				gm.set_buckets().add_bucket(bucket_id).set_actions().
						add_action_pop_vlan(index++);
			}
			gm.set_buckets().set_bucket(bucket_id).set_actions().
						add_action_output(index++).set_port_no(it->second.get_port_no());
			bucket_id++;
		}

#if 0
		// NO!!!

		// this sends Packet-Ins for each single ethernet endpoint
		// TODO: rethink this strategy???
		for (std::map<rofl::caddress_ll, cethendpnt>::iterator
				it = ethendpnts.begin(); it != ethendpnts.end(); ++it) {
			rofl::cindex index(0);
			if (not it->second.get_tagged()) {
				gm.set_buckets().add_bucket(bucket_id).set_actions().
						add_action_pop_vlan(index++);
			}
			gm.set_buckets().set_bucket(bucket_id).set_actions().
						add_action_output(index).set_max_len(1526);
			gm.set_buckets().set_bucket(bucket_id).set_actions().
						set_action_output(index++).set_port_no(rofl::openflow::OFPP_CONTROLLER);
			bucket_id++;
		}
#endif

		rofl::crofdpt::get_dpt(dpid).send_group_mod_message(rofl::cauxid(0), gm);

	} catch (rofl::eRofBaseCongested& e) {
		rofcore::logging::debug << "[cvlan][update_group_entry_buckets] control channel congested" << std::endl;
	} catch (rofl::eRofSockTxAgain& e) {
		rofcore::logging::debug << "[cvlan][update_group_entry_buckets] control channel congested" << std::endl;
	} catch (rofl::eRofBaseNotConnected& e) {
		rofcore::logging::debug << "[cvlan][update_group_entry_buckets] control channel not connected" << std::endl;
	} catch (rofl::eRofDptNotFound& e) {
		rofcore::logging::debug << "[cvlan][update_group_entry_buckets] dpt not found" << std::endl;
	}
}

<commit_msg>cvlan::handle_port_status() => added more debug output<commit_after>/*
 * cvlan.cpp
 *
 *  Created on: 07.08.2014
 *      Author: andreas
 */

#include "cvlan.hpp"

using namespace roflibs::eth;

void
cvlan::handle_dpt_open(
		rofl::crofdpt& dpt)
{
	try {
		state = STATE_ATTACHED;
		group_id = dpt.get_next_idle_group_id();

		// set flooding group entry itself
		update_group_entry_buckets(rofl::openflow::OFPGC_ADD);

		// set redirecting entry for this vlan's flooding group entry
		rofl::openflow::cofflowmod fm(dpt.get_version());
		fm.set_command(rofl::openflow::OFPFC_ADD);
		fm.set_table_id(table_id_eth_dst);
		fm.set_buffer_id(rofl::openflow::OFP_NO_BUFFER);
		fm.set_idle_timeout(0);
		fm.set_hard_timeout(0);
		fm.set_priority(0x8000);
		fm.set_match().set_vlan_vid(vid | rofl::openflow::OFPVID_PRESENT);
		fm.set_instructions().set_inst_apply_actions().
				set_actions().add_action_group(rofl::cindex(0)).set_group_id(group_id);
		dpt.send_flow_mod_message(rofl::cauxid(0), fm);

		// set broadcast entry in src stage
		fm.set_table_id(table_id_eth_src);
		fm.set_priority(0x8100);
		fm.set_match().set_eth_dst(rofl::caddress_ll("01:00:00:00:00:00"), rofl::caddress_ll("01:00:00:00:00:00"));
		fm.set_instructions().set_inst_goto_table().set_table_id(table_id_eth_local);
		dpt.send_flow_mod_message(rofl::cauxid(0), fm);

		// send notification to all ethernet endpoints
		for (std::map<rofl::caddress_ll, cethendpnt>::iterator
				it = ethendpnts.begin(); it != ethendpnts.end(); ++it) {
			it->second.handle_dpt_open(dpt);
		}

		// send notification to all member ports
		for (std::map<uint32_t, cmemberport>::iterator
				it = phyports.begin(); it != phyports.end(); ++it) {
			it->second.handle_dpt_open(dpt);
		}

		// send notification to all fib entries
		for (std::map<rofl::caddress_ll, cfibentry>::iterator
				it = fib.begin(); it != fib.end(); ++it) {
			it->second.handle_dpt_open(dpt);
		}

	} catch (rofl::eRofSockTxAgain& e) {
		rofcore::logging::debug << "[cvlan][handle_dpt_open] control channel congested" << std::endl;
	} catch (rofl::eRofBaseNotConnected& e) {
		rofcore::logging::debug << "[cvlan][handle_dpt_open] control channel not connected" << std::endl;
	}
}

void
cvlan::handle_dpt_close(
		rofl::crofdpt& dpt)
{
	try {
		// send notification to all fib entries
		for (std::map<rofl::caddress_ll, cfibentry>::iterator
				it = fib.begin(); it != fib.end(); ++it) {
			it->second.handle_dpt_close(dpt);
		}

		// send notification to all member ports
		for (std::map<uint32_t, cmemberport>::iterator
				it = phyports.begin(); it != phyports.end(); ++it) {
			it->second.handle_dpt_close(dpt);
		}

		// send notification to all ethernet endpoints
		for (std::map<rofl::caddress_ll, cethendpnt>::iterator
				it = ethendpnts.begin(); it != ethendpnts.end(); ++it) {
			it->second.handle_dpt_close(dpt);
		}

		// remove redirecting entry for this vlan's flooding group entry
		rofl::openflow::cofflowmod fm(dpt.get_version());
		fm.set_command(rofl::openflow::OFPFC_DELETE_STRICT);
		fm.set_table_id(table_id_eth_dst);
		fm.set_buffer_id(rofl::openflow::OFP_NO_BUFFER);
		fm.set_idle_timeout(0);
		fm.set_hard_timeout(0);
		fm.set_priority(0x8000);
		fm.set_match().set_vlan_vid(vid | rofl::openflow::OFPVID_PRESENT);
		dpt.send_flow_mod_message(rofl::cauxid(0), fm);

		// remove broadcast entry in src stage
		fm.set_table_id(table_id_eth_src);
		fm.set_priority(0x8100);
		fm.set_match().set_eth_dst(rofl::caddress_ll("01:00:00:00:00:00"), rofl::caddress_ll("01:00:00:00:00:00"));
		dpt.send_flow_mod_message(rofl::cauxid(0), fm);

		// remove flooding group entry itself
		rofl::openflow::cofgroupmod gm(dpt.get_version());
		gm.set_command(rofl::openflow::OFPGC_DELETE);
		gm.set_group_id(group_id);
		gm.set_type(rofl::openflow::OFPGT_ALL);

	} catch (rofl::eRofSockTxAgain& e) {
		rofcore::logging::debug << "[cvlan][handle_dpt_close] control channel congested" << std::endl;
	} catch (rofl::eRofBaseNotConnected& e) {
		rofcore::logging::debug << "[cvlan][handle_dpt_close] control channel not connected" << std::endl;
	} catch(...) {

	}

	state = STATE_DETACHED;
	dpt.release_group_id(group_id); group_id = 0;
}

void
cvlan::handle_packet_in(
		rofl::crofdpt& dpt, const rofl::cauxid& auxid, rofl::openflow::cofmsg_packet_in& msg)
{
	try {
		assert(dpid == dpt.get_dpid());
		assert(vid == (msg.get_match().get_vlan_vid_value() & (uint16_t)(~rofl::openflow::OFPVID_PRESENT)));

		uint32_t in_port = msg.get_match().get_in_port();
		const rofl::caddress_ll& lladdr = msg.get_match().get_eth_src_addr();
		if (lladdr.is_multicast() || lladdr.is_null()) {
			rofcore::logging::debug << "[cvlan][handle_packet_in] invalid source lladdr found" << std::endl << msg;
			dpt.drop_buffer(auxid, msg.get_buffer_id());
			return;
		}

		set_fib_entry(lladdr, in_port).handle_packet_in(dpt, auxid, msg);

	} catch (rofl::openflow::eOxmNotFound& e) {
		rofcore::logging::debug << "[cvlan][handle_packet_in] match(es) not found" << std::endl << msg;
		dpt.drop_buffer(auxid, msg.get_buffer_id());
	} catch (eFibEntryPortNotMember& e) {
		rofcore::logging::debug << "[cvlan][handle_packet_in] packet-in on invalid port" << std::endl << msg;
		dpt.drop_buffer(auxid, msg.get_buffer_id());
	}
}

void
cvlan::handle_flow_removed(
		rofl::crofdpt& dpt, const rofl::cauxid& auxid, rofl::openflow::cofmsg_flow_removed& msg)
{
	try {
		assert(dpid == dpt.get_dpid());
		assert(vid == (msg.get_match().get_vlan_vid_value() & (uint16_t)(~rofl::openflow::OFPVID_PRESENT)));

		// TODO: check port here?

		rofl::caddress_ll lladdr;

		if (msg.get_table_id() == 1) {
			lladdr = msg.get_match().get_eth_src_addr();
		} else
		if (msg.get_table_id() == 2) {
			lladdr = msg.get_match().get_eth_dst_addr();
		} else {
			return;
		}

		if (lladdr.is_multicast() || lladdr.is_null()) {
			rofcore::logging::debug << "[cvlan][handle_flow_removed] invalid source lladdr found" << std::endl << msg;
			return;
		}

		if (has_fib_entry(lladdr)) {
			set_fib_entry(lladdr).handle_flow_removed(dpt, auxid, msg); // notify fib entry
		}

	} catch (rofl::openflow::eOxmNotFound& e) {
		rofcore::logging::debug << "[cvlan][handle_flow_removed] match(es) not found" << std::endl << msg;
	}
}

void
cvlan::handle_port_status(
		rofl::crofdpt& dpt, const rofl::cauxid& auxid, rofl::openflow::cofmsg_port_status& msg)
{
	try {
		uint32_t portno = msg.get_port().get_port_no();

		if (not has_phy_port(portno)) {
			rofcore::logging::debug << "[cvlan][handle_port_status] no entry for portno:" << (unsigned int)portno
					<< " found in portdb" << std::endl << msg;
			return;
		}

		set_phy_port(portno).handle_port_status(dpt, auxid, msg);

		for (std::map<rofl::caddress_ll, cfibentry>::iterator
				it = fib.begin(); it != fib.end(); ++it) {
			it->second.handle_port_status(dpt, auxid, msg);
		}

	} catch (rofl::openflow::eOxmNotFound& e) {
		rofcore::logging::debug << "[cvlan][handle_port_status] port not found" << std::endl << msg;
	}
}

void
cvlan::handle_error_message(
		rofl::crofdpt& dpt, const rofl::cauxid& auxid, rofl::openflow::cofmsg_error& msg)
{
	// TODO
}

void
cvlan::update_group_entry_buckets(uint16_t command)
{
	try {
		if (STATE_ATTACHED != state) {
			return;
		}

		if (rofl::openflow::OFP_VERSION_UNKNOWN == rofl::crofdpt::get_dpt(dpid).get_version()) {
			return;
		}

		// update flooding group entry
		rofl::openflow::cofgroupmod gm(rofl::crofdpt::get_dpt(dpid).get_version());
		gm.set_command(command);
		gm.set_group_id(group_id);
		gm.set_type(rofl::openflow::OFPGT_ALL);
		unsigned int bucket_id = 0;
		for (std::map<uint32_t, cmemberport>::iterator
				it = phyports.begin(); it != phyports.end(); ++it) {
			rofl::cindex index(0);
			if (not it->second.get_tagged()) {
				gm.set_buckets().add_bucket(bucket_id).set_actions().
						add_action_pop_vlan(index++);
			}
			gm.set_buckets().set_bucket(bucket_id).set_actions().
						add_action_output(index++).set_port_no(it->second.get_port_no());
			bucket_id++;
		}

#if 0
		// NO!!!

		// this sends Packet-Ins for each single ethernet endpoint
		// TODO: rethink this strategy???
		for (std::map<rofl::caddress_ll, cethendpnt>::iterator
				it = ethendpnts.begin(); it != ethendpnts.end(); ++it) {
			rofl::cindex index(0);
			if (not it->second.get_tagged()) {
				gm.set_buckets().add_bucket(bucket_id).set_actions().
						add_action_pop_vlan(index++);
			}
			gm.set_buckets().set_bucket(bucket_id).set_actions().
						add_action_output(index).set_max_len(1526);
			gm.set_buckets().set_bucket(bucket_id).set_actions().
						set_action_output(index++).set_port_no(rofl::openflow::OFPP_CONTROLLER);
			bucket_id++;
		}
#endif

		rofl::crofdpt::get_dpt(dpid).send_group_mod_message(rofl::cauxid(0), gm);

	} catch (rofl::eRofBaseCongested& e) {
		rofcore::logging::debug << "[cvlan][update_group_entry_buckets] control channel congested" << std::endl;
	} catch (rofl::eRofSockTxAgain& e) {
		rofcore::logging::debug << "[cvlan][update_group_entry_buckets] control channel congested" << std::endl;
	} catch (rofl::eRofBaseNotConnected& e) {
		rofcore::logging::debug << "[cvlan][update_group_entry_buckets] control channel not connected" << std::endl;
	} catch (rofl::eRofDptNotFound& e) {
		rofcore::logging::debug << "[cvlan][update_group_entry_buckets] dpt not found" << std::endl;
	}
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2011 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
 * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "core/xml/parser/XMLErrors.h"

#include "core/HTMLNames.h"
#include "core/SVGNames.h"
#include "core/dom/Document.h"
#include "core/dom/Element.h"
#include "core/dom/Text.h"
#include "core/xml/DocumentXSLT.h"
#include "wtf/text/WTFString.h"

namespace blink {

using namespace HTMLNames;

const int maxErrors = 25;

XMLErrors::XMLErrors(Document* document)
    : m_document(document)
    , m_errorCount(0)
    , m_lastErrorPosition(TextPosition::belowRangePosition())
{
}

DEFINE_TRACE(XMLErrors)
{
    visitor->trace(m_document);
}

void XMLErrors::handleError(ErrorType type, const char* message, int lineNumber, int columnNumber)
{
    handleError(type, message, TextPosition(OrdinalNumber::fromOneBasedInt(lineNumber), OrdinalNumber::fromOneBasedInt(columnNumber)));
}

void XMLErrors::handleError(ErrorType type, const char* message, TextPosition position)
{
    if (type == ErrorTypeFatal || (m_errorCount < maxErrors && m_lastErrorPosition.m_line != position.m_line && m_lastErrorPosition.m_column != position.m_column)) {
        switch (type) {
        case ErrorTypeWarning:
            appendErrorMessage("warning", position, message);
            break;
        case ErrorTypeFatal:
        case ErrorTypeNonFatal:
            appendErrorMessage("error", position, message);
        }

        m_lastErrorPosition = position;
        ++m_errorCount;
    }
}

void XMLErrors::appendErrorMessage(const String& typeString, TextPosition position, const char* message)
{
    // <typeString> on line <lineNumber> at column <columnNumber>: <message>
    m_errorMessages.append(typeString);
    m_errorMessages.appendLiteral(" on line ");
    m_errorMessages.appendNumber(position.m_line.oneBasedInt());
    m_errorMessages.appendLiteral(" at column ");
    m_errorMessages.appendNumber(position.m_column.oneBasedInt());
    m_errorMessages.appendLiteral(": ");
    m_errorMessages.append(message);
}

static inline PassRefPtrWillBeRawPtr<Element> createXHTMLParserErrorHeader(Document* doc, const String& errorMessages)
{
    RefPtrWillBeRawPtr<Element> reportElement = doc->createElement(QualifiedName(nullAtom, "parsererror", xhtmlNamespaceURI), true);

    Vector<Attribute> reportAttributes;
    reportAttributes.append(Attribute(styleAttr, "display: block; white-space: pre; border: 2px solid #c77; padding: 0 1em 0 1em; margin: 1em; background-color: #fdd; color: black"));
    reportElement->parserSetAttributes(reportAttributes);

    RefPtrWillBeRawPtr<Element> h3 = doc->createElement(h3Tag, true);
    reportElement->parserAppendChild(h3.get());
    h3->parserAppendChild(doc->createTextNode("This page contains the following errors:"));

    RefPtrWillBeRawPtr<Element> fixed = doc->createElement(divTag, true);
    Vector<Attribute> fixedAttributes;
    fixedAttributes.append(Attribute(styleAttr, "font-family:monospace;font-size:12px"));
    fixed->parserSetAttributes(fixedAttributes);
    reportElement->parserAppendChild(fixed.get());

    fixed->parserAppendChild(doc->createTextNode(errorMessages));

    h3 = doc->createElement(h3Tag, true);
    reportElement->parserAppendChild(h3.get());
    h3->parserAppendChild(doc->createTextNode("Below is a rendering of the page up to the first error."));

    return reportElement.release();
}

void XMLErrors::insertErrorMessageBlock()
{
    // One or more errors occurred during parsing of the code. Display an error block to the user above
    // the normal content (the DOM tree is created manually and includes line/col info regarding
    // where the errors are located)

    // Create elements for display
    RefPtrWillBeRawPtr<Element> documentElement = m_document->documentElement();
    if (!documentElement) {
        RefPtrWillBeRawPtr<Element> rootElement = m_document->createElement(htmlTag, true);
        RefPtrWillBeRawPtr<Element> body = m_document->createElement(bodyTag, true);
        rootElement->parserAppendChild(body);
        m_document->parserAppendChild(rootElement);
        documentElement = body.get();
    } else if (documentElement->namespaceURI() == SVGNames::svgNamespaceURI) {
        RefPtrWillBeRawPtr<Element> rootElement = m_document->createElement(htmlTag, true);
        RefPtrWillBeRawPtr<Element> head = m_document->createElement(headTag, true);
        RefPtrWillBeRawPtr<Element> style = m_document->createElement(styleTag, true);
        head->parserAppendChild(style);
        style->parserAppendChild(m_document->createTextNode("html, body { height: 100% } parsererror + svg { width: 100%; height: 100% }"));
        style->finishParsingChildren();
        rootElement->parserAppendChild(head);
        RefPtrWillBeRawPtr<Element> body = m_document->createElement(bodyTag, true);
        rootElement->parserAppendChild(body);

        m_document->parserRemoveChild(*documentElement);

        body->parserAppendChild(documentElement);
        m_document->parserAppendChild(rootElement);

        documentElement = body.get();
    }

    String errorMessages = m_errorMessages.toString();
    RefPtrWillBeRawPtr<Element> reportElement = createXHTMLParserErrorHeader(m_document, errorMessages);

#ifdef MINIBLINK_NOT_IMPLEMENTED
    if (DocumentXSLT::hasTransformSourceDocument(*m_document)) {
        Vector<Attribute> attributes;
        attributes.append(Attribute(styleAttr, "white-space: normal"));
        RefPtrWillBeRawPtr<Element> paragraph = m_document->createElement(pTag, true);
        paragraph->parserSetAttributes(attributes);
        paragraph->parserAppendChild(m_document->createTextNode("This document was created as the result of an XSL transformation. The line and column numbers given are from the transformed result."));
        reportElement->parserAppendChild(paragraph.release());
    }
#endif // MINIBLINK_NOT_IMPLEMENTED
    notImplemented();

    Node* firstChild = documentElement->firstChild();
    if (firstChild)
        documentElement->parserInsertBefore(reportElement, *firstChild);
    else
        documentElement->parserAppendChild(reportElement);

    // FIXME: Why do we need to call this manually?
    m_document->updateLayoutTreeIfNeeded();
}

} // namespace blink
<commit_msg>* 去掉notImplemented<commit_after>/*
 * Copyright (C) 2011 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
 * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "core/xml/parser/XMLErrors.h"

#include "core/HTMLNames.h"
#include "core/SVGNames.h"
#include "core/dom/Document.h"
#include "core/dom/Element.h"
#include "core/dom/Text.h"
#include "core/xml/DocumentXSLT.h"
#include "wtf/text/WTFString.h"

namespace blink {

using namespace HTMLNames;

const int maxErrors = 25;

XMLErrors::XMLErrors(Document* document)
    : m_document(document)
    , m_errorCount(0)
    , m_lastErrorPosition(TextPosition::belowRangePosition())
{
}

DEFINE_TRACE(XMLErrors)
{
    visitor->trace(m_document);
}

void XMLErrors::handleError(ErrorType type, const char* message, int lineNumber, int columnNumber)
{
    handleError(type, message, TextPosition(OrdinalNumber::fromOneBasedInt(lineNumber), OrdinalNumber::fromOneBasedInt(columnNumber)));
}

void XMLErrors::handleError(ErrorType type, const char* message, TextPosition position)
{
    if (type == ErrorTypeFatal || (m_errorCount < maxErrors && m_lastErrorPosition.m_line != position.m_line && m_lastErrorPosition.m_column != position.m_column)) {
        switch (type) {
        case ErrorTypeWarning:
            appendErrorMessage("warning", position, message);
            break;
        case ErrorTypeFatal:
        case ErrorTypeNonFatal:
            appendErrorMessage("error", position, message);
        }

        m_lastErrorPosition = position;
        ++m_errorCount;
    }
}

void XMLErrors::appendErrorMessage(const String& typeString, TextPosition position, const char* message)
{
    // <typeString> on line <lineNumber> at column <columnNumber>: <message>
    m_errorMessages.append(typeString);
    m_errorMessages.appendLiteral(" on line ");
    m_errorMessages.appendNumber(position.m_line.oneBasedInt());
    m_errorMessages.appendLiteral(" at column ");
    m_errorMessages.appendNumber(position.m_column.oneBasedInt());
    m_errorMessages.appendLiteral(": ");
    m_errorMessages.append(message);
}

static inline PassRefPtrWillBeRawPtr<Element> createXHTMLParserErrorHeader(Document* doc, const String& errorMessages)
{
    RefPtrWillBeRawPtr<Element> reportElement = doc->createElement(QualifiedName(nullAtom, "parsererror", xhtmlNamespaceURI), true);

    Vector<Attribute> reportAttributes;
    reportAttributes.append(Attribute(styleAttr, "display: block; white-space: pre; border: 2px solid #c77; padding: 0 1em 0 1em; margin: 1em; background-color: #fdd; color: black"));
    reportElement->parserSetAttributes(reportAttributes);

    RefPtrWillBeRawPtr<Element> h3 = doc->createElement(h3Tag, true);
    reportElement->parserAppendChild(h3.get());
    h3->parserAppendChild(doc->createTextNode("This page contains the following errors:"));

    RefPtrWillBeRawPtr<Element> fixed = doc->createElement(divTag, true);
    Vector<Attribute> fixedAttributes;
    fixedAttributes.append(Attribute(styleAttr, "font-family:monospace;font-size:12px"));
    fixed->parserSetAttributes(fixedAttributes);
    reportElement->parserAppendChild(fixed.get());

    fixed->parserAppendChild(doc->createTextNode(errorMessages));

    h3 = doc->createElement(h3Tag, true);
    reportElement->parserAppendChild(h3.get());
    h3->parserAppendChild(doc->createTextNode("Below is a rendering of the page up to the first error."));

    return reportElement.release();
}

void XMLErrors::insertErrorMessageBlock()
{
    // One or more errors occurred during parsing of the code. Display an error block to the user above
    // the normal content (the DOM tree is created manually and includes line/col info regarding
    // where the errors are located)

    // Create elements for display
    RefPtrWillBeRawPtr<Element> documentElement = m_document->documentElement();
    if (!documentElement) {
        RefPtrWillBeRawPtr<Element> rootElement = m_document->createElement(htmlTag, true);
        RefPtrWillBeRawPtr<Element> body = m_document->createElement(bodyTag, true);
        rootElement->parserAppendChild(body);
        m_document->parserAppendChild(rootElement);
        documentElement = body.get();
    } else if (documentElement->namespaceURI() == SVGNames::svgNamespaceURI) {
        RefPtrWillBeRawPtr<Element> rootElement = m_document->createElement(htmlTag, true);
        RefPtrWillBeRawPtr<Element> head = m_document->createElement(headTag, true);
        RefPtrWillBeRawPtr<Element> style = m_document->createElement(styleTag, true);
        head->parserAppendChild(style);
        style->parserAppendChild(m_document->createTextNode("html, body { height: 100% } parsererror + svg { width: 100%; height: 100% }"));
        style->finishParsingChildren();
        rootElement->parserAppendChild(head);
        RefPtrWillBeRawPtr<Element> body = m_document->createElement(bodyTag, true);
        rootElement->parserAppendChild(body);

        m_document->parserRemoveChild(*documentElement);

        body->parserAppendChild(documentElement);
        m_document->parserAppendChild(rootElement);

        documentElement = body.get();
    }

    String errorMessages = m_errorMessages.toString();
    RefPtrWillBeRawPtr<Element> reportElement = createXHTMLParserErrorHeader(m_document, errorMessages);

#ifdef MINIBLINK_NOT_IMPLEMENTED
    if (DocumentXSLT::hasTransformSourceDocument(*m_document)) {
        Vector<Attribute> attributes;
        attributes.append(Attribute(styleAttr, "white-space: normal"));
        RefPtrWillBeRawPtr<Element> paragraph = m_document->createElement(pTag, true);
        paragraph->parserSetAttributes(attributes);
        paragraph->parserAppendChild(m_document->createTextNode("This document was created as the result of an XSL transformation. The line and column numbers given are from the transformed result."));
        reportElement->parserAppendChild(paragraph.release());
    }
#endif // MINIBLINK_NOT_IMPLEMENTED

    Node* firstChild = documentElement->firstChild();
    if (firstChild)
        documentElement->parserInsertBefore(reportElement, *firstChild);
    else
        documentElement->parserAppendChild(reportElement);

    // FIXME: Why do we need to call this manually?
    m_document->updateLayoutTreeIfNeeded();
}

} // namespace blink
<|endoftext|>


<commit_before>#include <Carbon/Carbon.h>
#include "SkApplication.h"
#include "SkWindow.h"

int main(int argc, char* argv[])
{
    WindowRef			window;
    OSStatus			err = noErr;

    Rect bounds = {100, 100, 500, 500};
    WindowAttributes attrs = kWindowStandardHandlerAttribute |
                             kWindowLiveResizeAttribute |
                             kWindowInWindowMenuAttribute |
                             kWindowCompositingAttribute |
                             kWindowAsyncDragAttribute |
                             kWindowFullZoomAttribute |
                             kWindowFrameworkScaledAttribute;
                             //kWindowDoesNotCycleAttribute;
    CreateNewWindow(kDocumentWindowClass, attrs, &bounds, &window);

    MenuRef menu;
    CreateNewMenu(0, 0, &menu);

    // if we get here, we can start our normal Skia sequence
    {
        application_init();
        (void)create_sk_window(window, argc, argv);
        SizeWindow(window, 640, 480, false);
    }

    // The window was created hidden so show it.
    ShowWindow( window );

    // Call the event loop
    RunApplicationEventLoop();

	application_term();

CantCreateWindow:
CantGetNibRef:
	return err;
}

<commit_msg>make the mac window resizeable again<commit_after>#include <Carbon/Carbon.h>
#include "SkApplication.h"
#include "SkWindow.h"

int main(int argc, char* argv[])
{
    WindowRef			window;
    OSStatus			err = noErr;

    Rect bounds = {100, 100, 500, 500};
    WindowAttributes attrs = kWindowStandardHandlerAttribute |
                             kWindowResizableAttribute |
                             kWindowLiveResizeAttribute |
                             kWindowInWindowMenuAttribute |
                             kWindowCompositingAttribute |
                             kWindowAsyncDragAttribute |
                             kWindowFullZoomAttribute |
                             kWindowFrameworkScaledAttribute;
                             //kWindowDoesNotCycleAttribute;
    CreateNewWindow(kDocumentWindowClass, attrs, &bounds, &window);

    MenuRef menu;
    CreateNewMenu(0, 0, &menu);

    // if we get here, we can start our normal Skia sequence
    {
        application_init();
        (void)create_sk_window(window, argc, argv);
        SizeWindow(window, 640, 480, false);
    }

    // The window was created hidden so show it.
    ShowWindow( window );

    // Call the event loop
    RunApplicationEventLoop();

	application_term();

CantCreateWindow:
CantGetNibRef:
	return err;
}

<|endoftext|>


<commit_before>// Copyright (c) 2016, Baidu.com, Inc. All Rights Reserved
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "setting_utils.h"

#include <glog/logging.h>

namespace baidu {
namespace galaxy {

void SetupLog(const std::string& name) {
    // log info/warning/error/fatal to galaxy.log
    // log warning/error/fatal to galaxy.wf
    std::string program_name = "galaxy";
    if (!name.empty()) {
        program_name = name;
    }
    if (FLAGS_log_dir.empty()){
        FLAGS_log_dir = ".";
    }
    google::SetStderrLogging(google::GLOG_INFO);
    std::string log_filename = FLAGS_log_dir + "/" + program_name + ".INFO.";
    std::string wf_filename = FLAGS_log_dir + "/" + program_name + ".WARNING.";
    google::SetLogDestination(google::INFO, log_filename.c_str());
    google::SetLogDestination(google::WARNING, wf_filename.c_str());
    google::SetLogDestination(google::ERROR, "");
    google::SetLogDestination(google::FATAL, "");

    google::SetLogSymlink(google::INFO, program_name.c_str());
    google::SetLogSymlink(google::WARNING, program_name.c_str());
    google::SetLogSymlink(google::ERROR, "");
    google::SetLogSymlink(google::FATAL, "");
    google::InstallFailureSignalHandler();
}

} //namespace galaxy
} //namespace baidu
<commit_msg>not to put info-log on stderr<commit_after>// Copyright (c) 2016, Baidu.com, Inc. All Rights Reserved
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "setting_utils.h"

#include <glog/logging.h>

namespace baidu {
namespace galaxy {

void SetupLog(const std::string& name) {
    // log info/warning/error/fatal to galaxy.log
    // log warning/error/fatal to galaxy.wf
    std::string program_name = "galaxy";
    if (!name.empty()) {
        program_name = name;
    }
    if (FLAGS_log_dir.empty()){
        FLAGS_log_dir = ".";
    }
    std::string log_filename = FLAGS_log_dir + "/" + program_name + ".INFO.";
    std::string wf_filename = FLAGS_log_dir + "/" + program_name + ".WARNING.";
    google::SetLogDestination(google::INFO, log_filename.c_str());
    google::SetLogDestination(google::WARNING, wf_filename.c_str());
    google::SetLogDestination(google::ERROR, "");
    google::SetLogDestination(google::FATAL, "");

    google::SetLogSymlink(google::INFO, program_name.c_str());
    google::SetLogSymlink(google::WARNING, program_name.c_str());
    google::SetLogSymlink(google::ERROR, "");
    google::SetLogSymlink(google::FATAL, "");
    google::InstallFailureSignalHandler();
}

} //namespace galaxy
} //namespace baidu
<|endoftext|>


<commit_before>//#include <nan.h>
#include "../node_modules/nan/nan.h"
#include "v8.h"

#include "atomicops.h"
#include "flags.h"
#include <node.h>

namespace i = v8::internal;

/* v8 flag-definitions.h not properly cleaning this one up */
#undef DEFINE_float
#undef DEFINE_args
#undef FLAG
#define DEFINE_bool(nam, def, cmt)   FLAG(Boolean, nam)
#define DEFINE_int(nam, def, cmt)    FLAG(Integer, nam)
#define DEFINE_float(nam, def, cmt)  FLAG( Number, nam)
#define DEFINE_string(nam, def, cmt) FLAG(String, nam)
#define DEFINE_implication(x, y)
#define DEFINE_args(nam, def, cmt)

#define FLAG_FULL(type, nam)                         \
  NAN_METHOD(Get_##nam) {                            \
    NanScope();                                      \
    NanReturnValue(NanNew<v8::type>(i::FLAG_##nam)); \
  }                                                  \
                                                     \
  NAN_METHOD(Set_##nam) {                            \
    NanScope();                                      \
    NanReturnValue(NanNew<v8::type>(i::FLAG_##nam)); \
  }

#define FLAG_READONLY(type, nam)                     \
  NAN_METHOD(Get_##nam) {                            \
    NanScope();                                      \
    NanReturnValue(NanNew<v8::type>(i::FLAG_##nam)); \
  }

#if (NODE_VERSION_AT_LEAST(0, 10, 28))
  #include "v8_flag_definitions_0.10.h"
#elif (NODE_VERSION_AT_LEAST(0, 8, 26))
  #include "v8_flag_definitions_0.8.h"
#endif

#undef FLAG_FULL
#undef FLAG_READONLY
#undef FLAG
#define S(x) #x

#define FLAG_FULL(type, nam)                                                                        \
  exports->Set(NanNew<v8::String>(S(nam)), NanNew<v8::FunctionTemplate>(Get_##nam)->GetFunction()); \
  exports->Set(NanNew<v8::String>("set_" S(nam)), NanNew<v8::FunctionTemplate>(Set_##nam)->GetFunction());

#define FLAG_READONLY(type, nam) \
  exports->Set(NanNew<v8::String>(S(nam)), NanNew<v8::FunctionTemplate>(Get_##nam)->GetFunction());

void init(v8::Handle<v8::Object> exports) {
#if (NODE_VERSION_AT_LEAST(0, 10, 28))
  #include "v8_flag_definitions_0.10.h"
#elif (NODE_VERSION_AT_LEAST(0, 8, 26))
  #include "v8_flag_definitions_0.8.h"
#endif
}

NODE_MODULE(v8_flag_definitions, init)

#undef DEFINE_bool
#undef DEFINE_int
#undef DEFINE_float
#undef DEFINE_string
#undef FLAG_FULL
#undef FLAG_READONLY
#undef S
#undef DEFINE_implication
<commit_msg>providing getters for readonly flags and getters/setters for full flags<commit_after>//#include <nan.h>
#include "../node_modules/nan/nan.h"
#include "v8.h"

#include "atomicops.h"
#include "flags.h"
#include <node.h>

namespace i = v8::internal;

bool convert(v8::Handle<v8::Boolean> arg) {
  return arg->BooleanValue();
}

int32_t convert(v8::Handle<v8::Integer> arg) {
  return arg->Int32Value();
}

double convert(v8::Handle<v8::Number> arg) {
  return arg->NumberValue();
}

char* convert(v8::Handle<v8::String> arg) {
  size_t len;
  return NanCString(arg, &len);
}

/* v8 flag-definitions.h not properly cleaning this one up */
#undef DEFINE_float
#undef DEFINE_args
#undef FLAG
#define DEFINE_bool(nam, def, cmt)   FLAG(Boolean, nam)
#define DEFINE_int(nam, def, cmt)    FLAG(Integer, nam)
#define DEFINE_float(nam, def, cmt)  FLAG(Number, nam)
#define DEFINE_string(nam, def, cmt) FLAG(String, nam)
#define DEFINE_implication(x, y)
#define DEFINE_args(nam, def, cmt)

#define FLAG_FULL(type, nam)                           \
  NAN_METHOD(Get_##nam) {                              \
    NanScope();                                        \
    NanReturnValue(NanNew<v8::type>(i::FLAG_##nam));   \
  }                                                    \
                                                       \
  NAN_METHOD(Set_##nam) {                              \
    NanScope();                                        \
    v8::Handle<v8::type> flag =  args[0]->To##type();  \
    i::FLAG_##nam = convert(flag);                     \
    NanReturnUndefined();                              \
  }

#define FLAG_READONLY(type, nam)                       \
  NAN_METHOD(Get_##nam) {                              \
    NanScope();                                        \
    NanReturnValue(NanNew<v8::type>(i::FLAG_##nam));   \
  }

#if (NODE_VERSION_AT_LEAST(0, 10, 28))
  #include "v8_flag_definitions_0.10.h"
#elif (NODE_VERSION_AT_LEAST(0, 8, 26))
  #include "v8_flag_definitions_0.8.h"
#endif

#undef FLAG_FULL
#undef FLAG_READONLY
#undef FLAG
#define S(x) #x

#define FLAG_FULL(type, nam)                                                                        \
  exports->Set(NanNew<v8::String>(S(nam)), NanNew<v8::FunctionTemplate>(Get_##nam)->GetFunction()); \
  exports->Set(NanNew<v8::String>("set_" S(nam)), NanNew<v8::FunctionTemplate>(Set_##nam)->GetFunction());

#define FLAG_READONLY(type, nam) \
  exports->Set(NanNew<v8::String>(S(nam)), NanNew<v8::FunctionTemplate>(Get_##nam)->GetFunction());

void init(v8::Handle<v8::Object> exports) {
#if (NODE_VERSION_AT_LEAST(0, 10, 28))
  #include "v8_flag_definitions_0.10.h"
#elif (NODE_VERSION_AT_LEAST(0, 8, 26))
  #include "v8_flag_definitions_0.8.h"
#endif
}

NODE_MODULE(v8_flag_definitions, init)

#undef DEFINE_bool
#undef DEFINE_int
#undef DEFINE_float
#undef DEFINE_string
#undef FLAG_FULL
#undef FLAG_READONLY
#undef S
#undef DEFINE_implication
<|endoftext|>