<commit_before>#include <Box2D/Dynamics/b2WorldCallbacks.h>
#include "augs/math/steering.h"
#include "augs/templates/container_templates.h"
#include "augs/templates/algorithm_templates.h"
#include "game/detail/physics/physics_queries.h"
#include "game/detail/entity_scripts.h"
#include "game/components/movement_component.h"
#include "game/components/gun_component.h"
#include "game/components/melee_component.h"
#include "game/components/car_component.h"
#include "game/components/sentience_component.h"
#include "game/components/missile_component.h"
#include "game/components/attitude_component.h"
#include "game/components/container_component.h"
#include "game/components/sender_component.h"
#include "game/detail/inventory/perform_transfer.h"
#include "game/detail/inventory/inventory_slot.h"
#include "game/cosmos/entity_handle.h"
#include "game/cosmos/cosmos.h"

void unset_input_flags_of_orphaned_entity(entity_handle e) {
	if (auto* const car = e.find<components::car>()) {
		car->reset_movement_flags();
	}

	if (auto* const movement = e.find<components::movement>()) {
		movement->reset_movement_flags();
	}

	if (auto* const gun = e.find<components::gun>()) {
		gun->is_trigger_pressed = false;
	}

	if (auto* const melee = e.find<components::melee>()) {
		melee->reset_weapon(e);
	}
}

identified_danger assess_danger(
	const const_entity_handle victim,
	const const_entity_handle danger
) {
	identified_danger result;

	const auto* const sentience = victim.find<components::sentience>();
	if (!sentience) return result;

	result.danger = danger;

	const auto* const missile = danger.find<invariants::missile>();
	const auto* const attitude = danger.find<components::attitude>();

	if ((!missile && !attitude) || (missile && danger.get<components::sender>().is_sender_subject(victim))) {
		return result;
	}

	const auto victim_pos = victim.get_logic_transform().pos;
	const auto danger_pos = danger.get_logic_transform().pos;
	const auto danger_vel = danger.get_owner_of_colliders().get_effective_velocity();
	const auto danger_dir = (danger_pos - victim_pos);
	const float danger_distance = danger_dir.length();

	result.recommended_evasion = augs::danger_avoidance(victim_pos, danger_pos, danger_vel);
	result.recommended_evasion.normalize();

	const auto& sentience_def = victim.get<invariants::sentience>();
	const auto comfort_zone = sentience_def.comfort_zone;
	const auto comfort_zone_disturbance_ratio = augs::disturbance(danger_distance, comfort_zone);

	if (missile) {
		result.amount += comfort_zone_disturbance_ratio * missile->damage_amount*4;
	}

	if (attitude) {
		const auto att = calc_attitude(danger, victim);

		if (is_hostile(att)) {
			result.amount += comfort_zone_disturbance_ratio * sentience_def.danger_amount_from_hostile_attitude;
		}
	}

	return result;
}

attitude_type calc_attitude(const const_entity_handle targeter, const const_entity_handle target) {
	const auto& targeter_attitude = targeter.get<components::attitude>();
	const auto* const target_attitude = target.find<components::attitude>();

	if (target_attitude) {
		if (targeter_attitude.official_faction != target_attitude->official_faction) {
			return attitude_type::WANTS_TO_KILL;
		}
		else {
			return attitude_type::WANTS_TO_HEAL;
		}
	}

	if (found_in(targeter_attitude.specific_hostile_entities, target)) {
		return attitude_type::WANTS_TO_KILL;
	}

	return attitude_type::NEUTRAL;
}

float assess_projectile_velocity_of_weapon(const const_entity_handle weapon) {
	if (weapon.dead()) {
		return 0.f;
	}

	if (const auto* const gun_def = weapon.find<invariants::gun>()) {
		// TODO: Take into consideration the missile invariant found in the chamber
		return (gun_def->muzzle_velocity.first + gun_def->muzzle_velocity.second) / 2;
	}

	return 0.f;
}

ammunition_information get_ammunition_information(const const_entity_handle item) {
	ammunition_information out;

	const auto maybe_magazine_slot = item[slot_function::GUN_DETACHABLE_MAGAZINE];

	if (maybe_magazine_slot.alive() && maybe_magazine_slot.has_items()) {
		auto mag = item.get_cosmos()[maybe_magazine_slot.get_items_inside()[0]];
		auto ammo_depo = mag[slot_function::ITEM_DEPOSIT];
		out.total_charges += count_charges_in_deposit(mag);

		out.total_ammunition_space_available += ammo_depo->space_available;
		out.total_lsa += ammo_depo.calc_local_space_available();
	}

	const auto chamber_slot = item[slot_function::GUN_CHAMBER];

	if (chamber_slot.alive()) {
		out.total_charges += count_charges_inside(chamber_slot);

		out.total_ammunition_space_available += chamber_slot->space_available;
		out.total_lsa += chamber_slot.calc_local_space_available();
	}

	return out;
}

entity_id get_closest_hostile(
	const const_entity_handle subject,
	const const_entity_handle subject_attitude,
	const float radius,
	const b2Filter filter
) {
	const auto& cosmos = subject.get_cosmos();
	const auto si = cosmos.get_si();

	const auto& physics = cosmos.get_solvable_inferred().physics;
	const auto transform = subject.get_logic_transform();

	entity_id closest_hostile;

	float min_distance = std::numeric_limits<float>::max();

	if (subject_attitude.alive()) {
		const auto subject_attitude_transform = subject_attitude.get_logic_transform();

		physics.for_each_in_aabb(
			si,
			transform.pos - vec2(radius, radius),
			transform.pos + vec2(radius, radius),
			filter,
			[&](const b2Fixture* const fix) {
				const const_entity_handle s = cosmos[get_body_entity_that_owns(fix)];

				if (s != subject && s.has<components::attitude>()) {
					const auto calculated_attitude = calc_attitude(s, subject_attitude);

					if (is_hostile(calculated_attitude)) {
						const auto dist = (s.get_logic_transform().pos - subject_attitude_transform.pos).length_sq();

						if (dist < min_distance) {
							closest_hostile = s;
							min_distance = dist;
						}
					}
				}

				return callback_result::CONTINUE;
			}
		);
	}

	return closest_hostile;
}

std::vector<entity_id> get_closest_hostiles(
	const const_entity_handle subject,
	const const_entity_handle subject_attitude,
	const float radius,
	const b2Filter filter
) {
	const auto& cosmos = subject.get_cosmos();
	const auto si = cosmos.get_si();

	const auto& physics = cosmos.get_solvable_inferred().physics;
	const auto transform = subject.get_logic_transform();

	struct hostile_entry {
		entity_id s;
		float dist = 0.f;

		bool operator<(const hostile_entry& b) const {
			return dist < b.dist;
		}

		bool operator==(const hostile_entry& b) const {
			return s == b.s;
		}

		operator entity_id() const {
			return s;
		}
	};

	std::vector<hostile_entry> hostiles;

	if (subject_attitude.alive()) {
		const auto subject_attitude_transform = subject_attitude.get_logic_transform();

		physics.for_each_in_aabb(
			si,
			transform.pos - vec2(radius, radius),
			transform.pos + vec2(radius, radius),
			filter,
			[&](const b2Fixture* const fix) {
				const const_entity_handle s = cosmos[get_body_entity_that_owns(fix)];

				if (s != subject && s.has<components::attitude>()) {
					const auto calculated_attitude = calc_attitude(s, subject_attitude);

					if (is_hostile(calculated_attitude)) {
						const auto dist = (s.get_logic_transform().pos - subject_attitude_transform.pos).length_sq();

						hostile_entry new_entry;
						new_entry.s = s;
						new_entry.dist = dist;

						hostiles.push_back(new_entry);
					}
				}

				return callback_result::CONTINUE;
			}
		);
	}

	sort_range(hostiles);
	remove_duplicates_from_sorted(hostiles);

	return { hostiles.begin(), hostiles.end() };
}<commit_msg>Unset arming_requested on orphaning<commit_after>#include <Box2D/Dynamics/b2WorldCallbacks.h>
#include "augs/math/steering.h"
#include "augs/templates/container_templates.h"
#include "augs/templates/algorithm_templates.h"
#include "game/detail/physics/physics_queries.h"
#include "game/detail/entity_scripts.h"
#include "game/components/movement_component.h"
#include "game/components/gun_component.h"
#include "game/components/melee_component.h"
#include "game/components/car_component.h"
#include "game/components/sentience_component.h"
#include "game/components/missile_component.h"
#include "game/components/attitude_component.h"
#include "game/components/container_component.h"
#include "game/components/sender_component.h"
#include "game/detail/inventory/perform_transfer.h"
#include "game/detail/inventory/inventory_slot.h"
#include "game/cosmos/entity_handle.h"
#include "game/cosmos/cosmos.h"

void unset_input_flags_of_orphaned_entity(entity_handle e) {
	if (auto* const car = e.find<components::car>()) {
		car->reset_movement_flags();
	}

	if (auto* const movement = e.find<components::movement>()) {
		movement->reset_movement_flags();
	}

	if (auto* const gun = e.find<components::gun>()) {
		gun->is_trigger_pressed = false;
	}

	if (auto* const melee = e.find<components::melee>()) {
		melee->reset_weapon(e);
	}

	if (auto* const hand_fuse = e.find<components::hand_fuse>()) {
		hand_fuse->arming_requested = false;
	}
}

identified_danger assess_danger(
	const const_entity_handle victim,
	const const_entity_handle danger
) {
	identified_danger result;

	const auto* const sentience = victim.find<components::sentience>();
	if (!sentience) return result;

	result.danger = danger;

	const auto* const missile = danger.find<invariants::missile>();
	const auto* const attitude = danger.find<components::attitude>();

	if ((!missile && !attitude) || (missile && danger.get<components::sender>().is_sender_subject(victim))) {
		return result;
	}

	const auto victim_pos = victim.get_logic_transform().pos;
	const auto danger_pos = danger.get_logic_transform().pos;
	const auto danger_vel = danger.get_owner_of_colliders().get_effective_velocity();
	const auto danger_dir = (danger_pos - victim_pos);
	const float danger_distance = danger_dir.length();

	result.recommended_evasion = augs::danger_avoidance(victim_pos, danger_pos, danger_vel);
	result.recommended_evasion.normalize();

	const auto& sentience_def = victim.get<invariants::sentience>();
	const auto comfort_zone = sentience_def.comfort_zone;
	const auto comfort_zone_disturbance_ratio = augs::disturbance(danger_distance, comfort_zone);

	if (missile) {
		result.amount += comfort_zone_disturbance_ratio * missile->damage_amount*4;
	}

	if (attitude) {
		const auto att = calc_attitude(danger, victim);

		if (is_hostile(att)) {
			result.amount += comfort_zone_disturbance_ratio * sentience_def.danger_amount_from_hostile_attitude;
		}
	}

	return result;
}

attitude_type calc_attitude(const const_entity_handle targeter, const const_entity_handle target) {
	const auto& targeter_attitude = targeter.get<components::attitude>();
	const auto* const target_attitude = target.find<components::attitude>();

	if (target_attitude) {
		if (targeter_attitude.official_faction != target_attitude->official_faction) {
			return attitude_type::WANTS_TO_KILL;
		}
		else {
			return attitude_type::WANTS_TO_HEAL;
		}
	}

	if (found_in(targeter_attitude.specific_hostile_entities, target)) {
		return attitude_type::WANTS_TO_KILL;
	}

	return attitude_type::NEUTRAL;
}

float assess_projectile_velocity_of_weapon(const const_entity_handle weapon) {
	if (weapon.dead()) {
		return 0.f;
	}

	if (const auto* const gun_def = weapon.find<invariants::gun>()) {
		// TODO: Take into consideration the missile invariant found in the chamber
		return (gun_def->muzzle_velocity.first + gun_def->muzzle_velocity.second) / 2;
	}

	return 0.f;
}

ammunition_information get_ammunition_information(const const_entity_handle item) {
	ammunition_information out;

	const auto maybe_magazine_slot = item[slot_function::GUN_DETACHABLE_MAGAZINE];

	if (maybe_magazine_slot.alive() && maybe_magazine_slot.has_items()) {
		auto mag = item.get_cosmos()[maybe_magazine_slot.get_items_inside()[0]];
		auto ammo_depo = mag[slot_function::ITEM_DEPOSIT];
		out.total_charges += count_charges_in_deposit(mag);

		out.total_ammunition_space_available += ammo_depo->space_available;
		out.total_lsa += ammo_depo.calc_local_space_available();
	}

	const auto chamber_slot = item[slot_function::GUN_CHAMBER];

	if (chamber_slot.alive()) {
		out.total_charges += count_charges_inside(chamber_slot);

		out.total_ammunition_space_available += chamber_slot->space_available;
		out.total_lsa += chamber_slot.calc_local_space_available();
	}

	return out;
}

entity_id get_closest_hostile(
	const const_entity_handle subject,
	const const_entity_handle subject_attitude,
	const float radius,
	const b2Filter filter
) {
	const auto& cosmos = subject.get_cosmos();
	const auto si = cosmos.get_si();

	const auto& physics = cosmos.get_solvable_inferred().physics;
	const auto transform = subject.get_logic_transform();

	entity_id closest_hostile;

	float min_distance = std::numeric_limits<float>::max();

	if (subject_attitude.alive()) {
		const auto subject_attitude_transform = subject_attitude.get_logic_transform();

		physics.for_each_in_aabb(
			si,
			transform.pos - vec2(radius, radius),
			transform.pos + vec2(radius, radius),
			filter,
			[&](const b2Fixture* const fix) {
				const const_entity_handle s = cosmos[get_body_entity_that_owns(fix)];

				if (s != subject && s.has<components::attitude>()) {
					const auto calculated_attitude = calc_attitude(s, subject_attitude);

					if (is_hostile(calculated_attitude)) {
						const auto dist = (s.get_logic_transform().pos - subject_attitude_transform.pos).length_sq();

						if (dist < min_distance) {
							closest_hostile = s;
							min_distance = dist;
						}
					}
				}

				return callback_result::CONTINUE;
			}
		);
	}

	return closest_hostile;
}

std::vector<entity_id> get_closest_hostiles(
	const const_entity_handle subject,
	const const_entity_handle subject_attitude,
	const float radius,
	const b2Filter filter
) {
	const auto& cosmos = subject.get_cosmos();
	const auto si = cosmos.get_si();

	const auto& physics = cosmos.get_solvable_inferred().physics;
	const auto transform = subject.get_logic_transform();

	struct hostile_entry {
		entity_id s;
		float dist = 0.f;

		bool operator<(const hostile_entry& b) const {
			return dist < b.dist;
		}

		bool operator==(const hostile_entry& b) const {
			return s == b.s;
		}

		operator entity_id() const {
			return s;
		}
	};

	std::vector<hostile_entry> hostiles;

	if (subject_attitude.alive()) {
		const auto subject_attitude_transform = subject_attitude.get_logic_transform();

		physics.for_each_in_aabb(
			si,
			transform.pos - vec2(radius, radius),
			transform.pos + vec2(radius, radius),
			filter,
			[&](const b2Fixture* const fix) {
				const const_entity_handle s = cosmos[get_body_entity_that_owns(fix)];

				if (s != subject && s.has<components::attitude>()) {
					const auto calculated_attitude = calc_attitude(s, subject_attitude);

					if (is_hostile(calculated_attitude)) {
						const auto dist = (s.get_logic_transform().pos - subject_attitude_transform.pos).length_sq();

						hostile_entry new_entry;
						new_entry.s = s;
						new_entry.dist = dist;

						hostiles.push_back(new_entry);
					}
				}

				return callback_result::CONTINUE;
			}
		);
	}

	sort_range(hostiles);
	remove_duplicates_from_sorted(hostiles);

	return { hostiles.begin(), hostiles.end() };
}<|endoftext|>


<commit_before>#include "camera_system.hpp"

#include <game/game_engine.hpp>

#include "../physics/transform_comp.hpp"
#include "../physics/physics_comp.hpp"

namespace mo {
namespace sys {
namespace cam {

	using namespace unit_literals;

	Camera_system::Camera_system(ecs::Entity_manager& entity_manager, Game_engine& engine)
		: _engine(engine), _targets(entity_manager.list<Camera_target_comp>()) {
		entity_manager.register_component_type<Camera_target_comp>();

		_cameras.emplace_back(_engine, 48.f);
	}

	void Camera_system::update(Time dt) {
		for(auto& target : _targets) {

			if(target._rotation_zoom_time_left>0_s)
				target._rotation_zoom_time_left-=dt;

			target.owner().get<physics::Transform_comp>().process([&](auto& transform) {
				auto target_pos = transform.position();
				auto target_rot = transform.rotation();
				auto moving = false;

				// TODO[foe]: refactor
				target.owner().get<physics::Physics_comp>().process([&](auto& p){
					target_pos += p.velocity()*100_ms;

					auto tpnt = remove_units(p.velocity()*100_ms);
					moving = tpnt.x*tpnt.x + tpnt.y*tpnt.y >= 0.1f;
				});

				if(std::abs(target._last_rotation-target_rot)>10_deg || moving) {
					target._rotation_zoom_time_left = target._rotation_zoom_time;
					target._last_rotation=target_rot;
				}

				float p = target._rotation_zoom_time_left / target._rotation_zoom_time;

				target_pos += rotate(Position{3_m*p, 0_m}, transform.rotation());

				target.chase(target_pos, dt);
			});

			// TODO: add support for multiple cameras
			_cameras.back().camera.position(remove_units(target.cam_position()));
			_cameras.back().targets.clear();
			_cameras.back().targets.push_back(target.owner_ptr());
		}
	}

}
}
}
<commit_msg>small js-fixed & tweaks<commit_after>#include "camera_system.hpp"

#include <game/game_engine.hpp>

#include "../physics/transform_comp.hpp"
#include "../physics/physics_comp.hpp"

namespace mo {
namespace sys {
namespace cam {

	using namespace unit_literals;

	Camera_system::Camera_system(ecs::Entity_manager& entity_manager, Game_engine& engine)
		: _engine(engine), _targets(entity_manager.list<Camera_target_comp>()) {
		entity_manager.register_component_type<Camera_target_comp>();

		_cameras.emplace_back(_engine, 48.f);
	}

	void Camera_system::update(Time dt) {
		for(auto& target : _targets) {

			if(target._rotation_zoom_time_left>0_s)
				target._rotation_zoom_time_left-=dt;

			target.owner().get<physics::Transform_comp>().process([&](auto& transform) {
				auto target_pos = transform.position();
				auto target_rot = transform.rotation();
				auto moving = false;

				// TODO[foe]: refactor
				target.owner().get<physics::Physics_comp>().process([&](auto& p){
					target_pos += p.velocity()*100_ms;

					auto tpnt = remove_units(p.velocity()*100_ms);
					moving = tpnt.x*tpnt.x + tpnt.y*tpnt.y >= 0.1f;
				});

				if(std::abs(target._last_rotation-target_rot)>10_deg || moving) {
					target._rotation_zoom_time_left = target._rotation_zoom_time;
					target._last_rotation=target_rot;
				}

/*
				float p = target._rotation_zoom_time_left / target._rotation_zoom_time;

				target_pos += rotate(Position{3_m*p, 0_m}, transform.rotation());
				*/

				target.chase(target_pos, dt);
			});

			// TODO: add support for multiple cameras
			_cameras.back().camera.position(remove_units(target.cam_position()));
			_cameras.back().targets.clear();
			_cameras.back().targets.push_back(target.owner_ptr());
		}
	}

}
}
}
<|endoftext|>


<commit_before>/*******************************************************************************
 The MIT License (MIT)

 Copyright (c) 2014 Alexander Zolotarev <me@alex.bio> from Minsk, Belarus

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 *******************************************************************************/

#include "../http_client.h"

#include <stdio.h>  // popen
#include <fstream>

// Used as a test stub for basic HTTP client implementation.

namespace aloha {

std::string RunCurl(const std::string& cmd) {
  FILE* pipe = ::popen(cmd.c_str(), "r");
  assert(pipe);
  char s[8 * 1024];
  ::fgets(s, sizeof(s) / sizeof(s[0]), pipe);
  const int err = ::pclose(pipe);
  if (err) {
    std::cerr << "Error " << err << " while calling " << cmd << std::endl;
  }
  return s;
}

// Not fully implemented.
bool HTTPClientPlatformWrapper::RunHTTPRequest() {
  // Last 3 chars in server's response will be http status code
  std::string cmd = "curl -s -w '%{http_code}' ";
  if (!content_type_.empty()) {
    cmd += "-H 'Content-Type: application/json' ";
  }
  if (!post_body_.empty()) {
    // POST body through tmp file to avoid breaking command line.
    char tmp_file[L_tmpnam];
    ::tmpnam(tmp_file);
    std::ofstream(tmp_file) << post_body_;
    post_file_ = tmp_file;
  }
  if (!post_file_.empty()) {
    cmd += "--data-binary @" + post_file_ + " ";
  }

  cmd += url_requested_;
  server_response_ = RunCurl(cmd);

  // Clean up tmp file if any was created.
  if (!post_body_.empty() && !post_file_.empty()) {
    ::remove(post_file_.c_str());
  }

  // TODO(AlexZ): Detect if we did not make any connection and return false.
  // Extract http status code from the last response line.
  error_code_ = std::stoi(server_response_.substr(server_response_.size() - 3));
  server_response_.resize(server_response_.size() - 4);

  if (!received_file_.empty()) {
    std::ofstream(received_file_) << server_response_;
  }

  return true;
}

}  // namespace aloha
<commit_msg>[linux] Fixed compilation errors.<commit_after>/*******************************************************************************
 The MIT License (MIT)

 Copyright (c) 2014 Alexander Zolotarev <me@alex.bio> from Minsk, Belarus

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 *******************************************************************************/

#include "../http_client.h"

#include <stdio.h>  // popen
#include <fstream>
#include <iostream> // std::cerr

// Used as a test stub for basic HTTP client implementation.

namespace alohalytics {

std::string RunCurl(const std::string& cmd) {
  FILE* pipe = ::popen(cmd.c_str(), "r");
  assert(pipe);
  char s[8 * 1024];
  ::fgets(s, sizeof(s) / sizeof(s[0]), pipe);
  const int err = ::pclose(pipe);
  if (err) {
    std::cerr << "Error " << err << " while calling " << cmd << std::endl;
  }
  return s;
}

// Not fully implemented.
bool HTTPClientPlatformWrapper::RunHTTPRequest() {
  // Last 3 chars in server's response will be http status code
  std::string cmd = "curl -s -w '%{http_code}' ";
  if (!content_type_.empty()) {
    cmd += "-H 'Content-Type: application/json' ";
  }
  if (!post_body_.empty()) {
    // POST body through tmp file to avoid breaking command line.
    char tmp_file[L_tmpnam];
    ::tmpnam(tmp_file);
    std::ofstream(tmp_file) << post_body_;
    post_file_ = tmp_file;
  }
  if (!post_file_.empty()) {
    cmd += "--data-binary @" + post_file_ + " ";
  }

  cmd += url_requested_;
  server_response_ = RunCurl(cmd);

  // Clean up tmp file if any was created.
  if (!post_body_.empty() && !post_file_.empty()) {
    ::remove(post_file_.c_str());
  }

  // TODO(AlexZ): Detect if we did not make any connection and return false.
  // Extract http status code from the last response line.
  error_code_ = std::stoi(server_response_.substr(server_response_.size() - 3));
  server_response_.resize(server_response_.size() - 4);

  if (!received_file_.empty()) {
    std::ofstream(received_file_) << server_response_;
  }

  return true;
}

}  // namespace aloha
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2012 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/group/group_layout_manager.hpp>

// boost
#include <boost/variant.hpp>

// std
#include <cmath>

namespace mapnik
{

// This visitor will process offsets for the given layout
struct process_layout : public boost::static_visitor<>
{
    // The vector containing the existing, centered item bounding boxes
    const vector<bound_box> &member_boxes_;

    // The vector to populate with item offsets
    vector<pixel_position> &member_offsets_;

    // The origin point of the member boxes
    // i.e. The member boxes are positioned around input_origin,
    //      and the offset values should position them around (0,0)
    const pixel_position &input_origin_;

    process_layout(const vector<bound_box> &member_bboxes,
                   vector<pixel_position> &member_offsets,
                   const pixel_position &input_origin)
       : member_boxes_(member_bboxes),
         member_offsets_(member_offsets),
         input_origin_(input_origin)
    {
    }

    // arrange group memebers in centered, horizontal row
    void operator()(simple_row_layout const& layout) const
    {
        double total_width = (member_boxes_.size() - 1) * layout.get_item_margin();
        for (auto const& box : member_boxes_)
        {
            total_width += box.width();
        }

        double x_offset = -(total_width / 2.0);
        for (auto const& box : member_boxes_)
        {
            member_offsets_.push_back(pixel_position(x_offset - box.minx(), -input_origin_.y));
            x_offset += box.width() + layout.get_item_margin();
        }
    }

    // arrange group members in x horizontal pairs of 2,
    // one to the left and one to the right of center in each pair
    void operator()(pair_layout const& layout) const
    {
        member_offsets_.resize(member_boxes_.size());
        double y_margin = layout.get_item_margin();
        double x_margin = y_margin / 2.0;

        if (member_boxes_.size() == 1)
        {
            member_offsets_[0] = pixel_position(0, 0) - input_origin_;
            return;
        }

        bound_box layout_box;
        size_t middle_ifirst = (member_boxes_.size() - 1) >> 1;
        int top_i = 0;
        int bottom_i = 0;
        if (middle_ifirst % 2 == 0)
        {
            layout_box = make_horiz_pair(0, 0.0, 0, x_margin, layout.get_max_difference());
            top_i = middle_ifirst - 2;
            bottom_i = middle_ifirst + 2;
        }
        else
        {
            top_i = middle_ifirst - 1;
            bottom_i = middle_ifirst + 1;
        }

        while (bottom_i >= 0 && top_i < static_cast<int>(member_offsets_.size()))
        {
            layout_box.expand_to_include(make_horiz_pair(top_i, layout_box.miny() - y_margin, -1, x_margin, layout.get_max_difference()));
            layout_box.expand_to_include(make_horiz_pair(bottom_i, layout_box.maxy() + y_margin, 1, x_margin, layout.get_max_difference()));
            top_i -= 2;
            bottom_i += 2;
        }

    }

private:

    // Place member bound boxes at [ifirst] and [ifirst + 1] in a horizontal pairi, vertically
    //   align with pair_y, store corresponding offsets, and return bound box of combined pair
    // Note: x_margin is the distance between box edge and x center
    bound_box make_horiz_pair(size_t ifirst, double pair_y, int y_dir, double x_margin, double max_diff) const
    {
        // two boxes available for pair
        if (ifirst + 1 < member_boxes_.size())
        {
            double x_center = member_boxes_[ifirst].width() - member_boxes_[ifirst + 1].width();
            if (max_diff < 0.0 || std::abs(x_center) <= max_diff)
            {
                x_center = 0.0;
            }

            bound_box pair_box = box_offset_align(ifirst, x_center - x_margin, pair_y, -1, y_dir);
            pair_box.expand_to_include(box_offset_align(ifirst + 1, x_center + x_margin, pair_y, 1, y_dir));
            return pair_box;
        }

        // only one box available for this "pair", so keep x-centered and handle y-offset
        return box_offset_align(ifirst, 0, pair_y, 0, y_dir);
    }

    // Offsets member bound box at [i] and align with (x, y), in direction <x_dir, y_dir>
    // stores corresponding offset, and returns modified bounding box
    bound_box box_offset_align(size_t i, double x, double y, int x_dir, int y_dir) const
    {
        const bound_box &box = member_boxes_[i];
        pixel_position offset((x_dir == 0 ? x - input_origin_.x : x - (x_dir < 0 ? box.maxx() : box.minx())),
                             (y_dir == 0 ? y - input_origin_.y : y - (y_dir < 0 ? box.maxy() : box.miny())));

        member_offsets_[i] = offset;
        return bound_box(box.minx() + offset.x, box.miny() + offset.y, box.maxx() + offset.x, box.maxy() + offset.y);
    }
};

bound_box group_layout_manager::offset_box_at(size_t i)
{
    handle_update();
    const pixel_position &offset = member_offsets_.at(i);
    const bound_box &box = member_boxes_.at(i);
    return box2d<double>(box.minx() + offset.x, box.miny() + offset.y,
                         box.maxx() + offset.x, box.maxy() + offset.y);
}

void group_layout_manager::handle_update()
{
    if (update_layout_)
    {
       member_offsets_.clear();
       boost::apply_visitor(process_layout(member_boxes_, member_offsets_, input_origin_), layout_);
       update_layout_ = false;
    }
}

}
<commit_msg>fix possible crash in mapnik::process_layout::box_offset_align<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2012 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/group/group_layout_manager.hpp>

// boost
#include <boost/variant.hpp>

// std
#include <cmath>

namespace mapnik
{

// This visitor will process offsets for the given layout
struct process_layout : public boost::static_visitor<>
{
    // The vector containing the existing, centered item bounding boxes
    const vector<bound_box> &member_boxes_;

    // The vector to populate with item offsets
    vector<pixel_position> &member_offsets_;

    // The origin point of the member boxes
    // i.e. The member boxes are positioned around input_origin,
    //      and the offset values should position them around (0,0)
    const pixel_position &input_origin_;

    process_layout(const vector<bound_box> &member_bboxes,
                   vector<pixel_position> &member_offsets,
                   const pixel_position &input_origin)
       : member_boxes_(member_bboxes),
         member_offsets_(member_offsets),
         input_origin_(input_origin)
    {
    }

    // arrange group memebers in centered, horizontal row
    void operator()(simple_row_layout const& layout) const
    {
        double total_width = (member_boxes_.size() - 1) * layout.get_item_margin();
        for (auto const& box : member_boxes_)
        {
            total_width += box.width();
        }

        double x_offset = -(total_width / 2.0);
        for (auto const& box : member_boxes_)
        {
            member_offsets_.push_back(pixel_position(x_offset - box.minx(), -input_origin_.y));
            x_offset += box.width() + layout.get_item_margin();
        }
    }

    // arrange group members in x horizontal pairs of 2,
    // one to the left and one to the right of center in each pair
    void operator()(pair_layout const& layout) const
    {
        member_offsets_.resize(member_boxes_.size());
        double y_margin = layout.get_item_margin();
        double x_margin = y_margin / 2.0;

        if (member_boxes_.size() == 1)
        {
            member_offsets_[0] = pixel_position(0, 0) - input_origin_;
            return;
        }

        bound_box layout_box;
        size_t middle_ifirst = (member_boxes_.size() - 1) >> 1;
        int top_i = 0;
        int bottom_i = 0;
        if (middle_ifirst % 2 == 0)
        {
            layout_box = make_horiz_pair(0, 0.0, 0, x_margin, layout.get_max_difference());
            top_i = middle_ifirst - 2;
            bottom_i = middle_ifirst + 2;
        }
        else
        {
            top_i = middle_ifirst - 1;
            bottom_i = middle_ifirst + 1;
        }

        while (bottom_i >= 0 && top_i >= 0 && top_i < static_cast<int>(member_offsets_.size()))
        {
            layout_box.expand_to_include(make_horiz_pair(top_i, layout_box.miny() - y_margin, -1, x_margin, layout.get_max_difference()));
            layout_box.expand_to_include(make_horiz_pair(bottom_i, layout_box.maxy() + y_margin, 1, x_margin, layout.get_max_difference()));
            top_i -= 2;
            bottom_i += 2;
        }

    }

private:

    // Place member bound boxes at [ifirst] and [ifirst + 1] in a horizontal pairi, vertically
    //   align with pair_y, store corresponding offsets, and return bound box of combined pair
    // Note: x_margin is the distance between box edge and x center
    bound_box make_horiz_pair(size_t ifirst, double pair_y, int y_dir, double x_margin, double max_diff) const
    {
        // two boxes available for pair
        if (ifirst + 1 < member_boxes_.size())
        {
            double x_center = member_boxes_[ifirst].width() - member_boxes_[ifirst + 1].width();
            if (max_diff < 0.0 || std::abs(x_center) <= max_diff)
            {
                x_center = 0.0;
            }

            bound_box pair_box = box_offset_align(ifirst, x_center - x_margin, pair_y, -1, y_dir);
            pair_box.expand_to_include(box_offset_align(ifirst + 1, x_center + x_margin, pair_y, 1, y_dir));
            return pair_box;
        }

        // only one box available for this "pair", so keep x-centered and handle y-offset
        return box_offset_align(ifirst, 0, pair_y, 0, y_dir);
    }

    // Offsets member bound box at [i] and align with (x, y), in direction <x_dir, y_dir>
    // stores corresponding offset, and returns modified bounding box
    bound_box box_offset_align(size_t i, double x, double y, int x_dir, int y_dir) const
    {
        const bound_box &box = member_boxes_[i];
        pixel_position offset((x_dir == 0 ? x - input_origin_.x : x - (x_dir < 0 ? box.maxx() : box.minx())),
                             (y_dir == 0 ? y - input_origin_.y : y - (y_dir < 0 ? box.maxy() : box.miny())));

        member_offsets_[i] = offset;
        return bound_box(box.minx() + offset.x, box.miny() + offset.y, box.maxx() + offset.x, box.maxy() + offset.y);
    }
};

bound_box group_layout_manager::offset_box_at(size_t i)
{
    handle_update();
    const pixel_position &offset = member_offsets_.at(i);
    const bound_box &box = member_boxes_.at(i);
    return box2d<double>(box.minx() + offset.x, box.miny() + offset.y,
                         box.maxx() + offset.x, box.maxy() + offset.y);
}

void group_layout_manager::handle_update()
{
    if (update_layout_)
    {
       member_offsets_.clear();
       boost::apply_visitor(process_layout(member_boxes_, member_offsets_, input_origin_), layout_);
       update_layout_ = false;
    }
}

}
<|endoftext|>


<commit_before>// Copyright (c) 2011-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "trafficgraphwidget.h"
#include "clientmodel.h"

#include <QPainter>
#include <QColor>
#include <QTimer>

#include <cmath>

#define DESIRED_SAMPLES         800

#define XMARGIN                 10
#define YMARGIN                 10

TrafficGraphWidget::TrafficGraphWidget(QWidget *parent) :
    QWidget(parent),
    timer(0),
    fMax(0.0f),
    nMins(0),
    vSamplesIn(),
    vSamplesOut(),
    nLastBytesIn(0),
    nLastBytesOut(0),
    clientModel(0)
{
    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), SLOT(updateRates()));
}

void TrafficGraphWidget::setClientModel(ClientModel *model)
{
    clientModel = model;
    if(model) {
        nLastBytesIn = model->getTotalBytesRecv();
        nLastBytesOut = model->getTotalBytesSent();
    }
}

int TrafficGraphWidget::getGraphRangeMins() const
{
    return nMins;
}

void TrafficGraphWidget::paintPath(QPainterPath &path, QQueue<float> &samples)
{
    int h = height() - YMARGIN * 2, w = width() - XMARGIN * 2;
    int sampleCount = samples.size(), x = XMARGIN + w, y;
    if(sampleCount > 0) {
        path.moveTo(x, YMARGIN + h);
        for(int i = 0; i < sampleCount; ++i) {
            x = XMARGIN + w - w * i / DESIRED_SAMPLES;
            y = YMARGIN + h - (int)(h * samples.at(i) / fMax);
            path.lineTo(x, y);
        }
        path.lineTo(x, YMARGIN + h);
    }
}

void TrafficGraphWidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.fillRect(rect(), Qt::black);

    if(fMax <= 0.0f) return;

    QColor axisCol(Qt::gray);
    int h = height() - YMARGIN * 2;
    painter.setPen(axisCol);
    painter.drawLine(XMARGIN, YMARGIN + h, width() - XMARGIN, YMARGIN + h);

    // decide what order of magnitude we are
    int base = floor(log10(fMax));
    float val = pow(10.0f, base);

    const QString units     = tr("KB/s");
    const float yMarginText = 2.0;

    // draw lines
    painter.setPen(axisCol);
    painter.drawText(XMARGIN, YMARGIN + h - h * val / fMax-yMarginText, QString("%1 %2").arg(val).arg(units));
    for(float y = val; y < fMax; y += val) {
        int yy = YMARGIN + h - h * y / fMax;
        painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy);
    }
    // if we drew 3 or fewer lines, break them up at the next lower order of magnitude
    if(fMax / val <= 3.0f) {
        axisCol = axisCol.darker();
        val = pow(10.0f, base - 1);
        painter.setPen(axisCol);
        painter.drawText(XMARGIN, YMARGIN + h - h * val / fMax-yMarginText, QString("%1 %2").arg(val).arg(units));
        int count = 1;
        for(float y = val; y < fMax; y += val, count++) {
            // don't overwrite lines drawn above
            if(count % 10 == 0)
                continue;
            int yy = YMARGIN + h - h * y / fMax;
            painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy);
        }
    }

    if(!vSamplesIn.empty()) {
        QPainterPath p;
        paintPath(p, vSamplesIn);
        painter.fillPath(p, QColor(0, 255, 0, 128));
        painter.setPen(Qt::green);
        painter.drawPath(p);
    }
    if(!vSamplesOut.empty()) {
        QPainterPath p;
        paintPath(p, vSamplesOut);
        painter.fillPath(p, QColor(255, 0, 0, 128));
        painter.setPen(Qt::red);
        painter.drawPath(p);
    }
}

void TrafficGraphWidget::updateRates()
{
    if(!clientModel) return;

    quint64 bytesIn = clientModel->getTotalBytesRecv(),
            bytesOut = clientModel->getTotalBytesSent();
    float inRate = (bytesIn - nLastBytesIn) / 1024.0f * 1000 / timer->interval();
    float outRate = (bytesOut - nLastBytesOut) / 1024.0f * 1000 / timer->interval();
    vSamplesIn.push_front(inRate);
    vSamplesOut.push_front(outRate);
    nLastBytesIn = bytesIn;
    nLastBytesOut = bytesOut;

    while(vSamplesIn.size() > DESIRED_SAMPLES) {
        vSamplesIn.pop_back();
    }
    while(vSamplesOut.size() > DESIRED_SAMPLES) {
        vSamplesOut.pop_back();
    }

    float tmax = 0.0f;
    Q_FOREACH(float f, vSamplesIn) {
        if(f > tmax) tmax = f;
    }
    Q_FOREACH(float f, vSamplesOut) {
        if(f > tmax) tmax = f;
    }
    fMax = tmax;
    update();
}

void TrafficGraphWidget::setGraphRangeMins(int mins)
{
    nMins = mins;
    int msecsPerSample = nMins * 60 * 1000 / DESIRED_SAMPLES;
    timer->stop();
    timer->setInterval(msecsPerSample);

    clear();
}

void TrafficGraphWidget::clear()
{
    timer->stop();

    vSamplesOut.clear();
    vSamplesIn.clear();
    fMax = 0.0f;

    if(clientModel) {
        nLastBytesIn = clientModel->getTotalBytesRecv();
        nLastBytesOut = clientModel->getTotalBytesSent();
    }
    timer->start();
}
<commit_msg>Fixed for Qt 5<commit_after>// Copyright (c) 2011-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "trafficgraphwidget.h"
#include "clientmodel.h"

#include <QPainter>
#include <QPainterPath>
#include <QColor>
#include <QTimer>

#include <cmath>

#define DESIRED_SAMPLES         800

#define XMARGIN                 10
#define YMARGIN                 10

TrafficGraphWidget::TrafficGraphWidget(QWidget *parent) :
    QWidget(parent),
    timer(0),
    fMax(0.0f),
    nMins(0),
    vSamplesIn(),
    vSamplesOut(),
    nLastBytesIn(0),
    nLastBytesOut(0),
    clientModel(0)
{
    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), SLOT(updateRates()));
}

void TrafficGraphWidget::setClientModel(ClientModel *model)
{
    clientModel = model;
    if(model) {
        nLastBytesIn = model->getTotalBytesRecv();
        nLastBytesOut = model->getTotalBytesSent();
    }
}

int TrafficGraphWidget::getGraphRangeMins() const
{
    return nMins;
}

void TrafficGraphWidget::paintPath(QPainterPath &path, QQueue<float> &samples)
{
    int h = height() - YMARGIN * 2, w = width() - XMARGIN * 2;
    int sampleCount = samples.size(), x = XMARGIN + w, y;
    if(sampleCount > 0) {
        path.moveTo(x, YMARGIN + h);
        for(int i = 0; i < sampleCount; ++i) {
            x = XMARGIN + w - w * i / DESIRED_SAMPLES;
            y = YMARGIN + h - (int)(h * samples.at(i) / fMax);
            path.lineTo(x, y);
        }
        path.lineTo(x, YMARGIN + h);
    }
}

void TrafficGraphWidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.fillRect(rect(), Qt::black);

    if(fMax <= 0.0f) return;

    QColor axisCol(Qt::gray);
    int h = height() - YMARGIN * 2;
    painter.setPen(axisCol);
    painter.drawLine(XMARGIN, YMARGIN + h, width() - XMARGIN, YMARGIN + h);

    // decide what order of magnitude we are
    int base = floor(log10(fMax));
    float val = pow(10.0f, base);

    const QString units     = tr("KB/s");
    const float yMarginText = 2.0;

    // draw lines
    painter.setPen(axisCol);
    painter.drawText(XMARGIN, YMARGIN + h - h * val / fMax-yMarginText, QString("%1 %2").arg(val).arg(units));
    for(float y = val; y < fMax; y += val) {
        int yy = YMARGIN + h - h * y / fMax;
        painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy);
    }
    // if we drew 3 or fewer lines, break them up at the next lower order of magnitude
    if(fMax / val <= 3.0f) {
        axisCol = axisCol.darker();
        val = pow(10.0f, base - 1);
        painter.setPen(axisCol);
        painter.drawText(XMARGIN, YMARGIN + h - h * val / fMax-yMarginText, QString("%1 %2").arg(val).arg(units));
        int count = 1;
        for(float y = val; y < fMax; y += val, count++) {
            // don't overwrite lines drawn above
            if(count % 10 == 0)
                continue;
            int yy = YMARGIN + h - h * y / fMax;
            painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy);
        }
    }

    if(!vSamplesIn.empty()) {
        QPainterPath p;
        paintPath(p, vSamplesIn);
        painter.fillPath(p, QColor(0, 255, 0, 128));
        painter.setPen(Qt::green);
        painter.drawPath(p);
    }
    if(!vSamplesOut.empty()) {
        QPainterPath p;
        paintPath(p, vSamplesOut);
        painter.fillPath(p, QColor(255, 0, 0, 128));
        painter.setPen(Qt::red);
        painter.drawPath(p);
    }
}

void TrafficGraphWidget::updateRates()
{
    if(!clientModel) return;

    quint64 bytesIn = clientModel->getTotalBytesRecv(),
            bytesOut = clientModel->getTotalBytesSent();
    float inRate = (bytesIn - nLastBytesIn) / 1024.0f * 1000 / timer->interval();
    float outRate = (bytesOut - nLastBytesOut) / 1024.0f * 1000 / timer->interval();
    vSamplesIn.push_front(inRate);
    vSamplesOut.push_front(outRate);
    nLastBytesIn = bytesIn;
    nLastBytesOut = bytesOut;

    while(vSamplesIn.size() > DESIRED_SAMPLES) {
        vSamplesIn.pop_back();
    }
    while(vSamplesOut.size() > DESIRED_SAMPLES) {
        vSamplesOut.pop_back();
    }

    float tmax = 0.0f;
    Q_FOREACH(float f, vSamplesIn) {
        if(f > tmax) tmax = f;
    }
    Q_FOREACH(float f, vSamplesOut) {
        if(f > tmax) tmax = f;
    }
    fMax = tmax;
    update();
}

void TrafficGraphWidget::setGraphRangeMins(int mins)
{
    nMins = mins;
    int msecsPerSample = nMins * 60 * 1000 / DESIRED_SAMPLES;
    timer->stop();
    timer->setInterval(msecsPerSample);

    clear();
}

void TrafficGraphWidget::clear()
{
    timer->stop();

    vSamplesOut.clear();
    vSamplesIn.clear();
    fMax = 0.0f;

    if(clientModel) {
        nLastBytesIn = clientModel->getTotalBytesRecv();
        nLastBytesOut = clientModel->getTotalBytesSent();
    }
    timer->start();
}
<|endoftext|>


<commit_before>#include "ray/raylet/worker_pool.h"

#include <sys/wait.h>

#include <algorithm>
#include <thread>

#include "ray/status.h"
#include "ray/util/logging.h"

namespace {

// A helper function to get a worker from a list.
std::shared_ptr<ray::raylet::Worker> GetWorker(
    const std::list<std::shared_ptr<ray::raylet::Worker>> &worker_pool,
    const std::shared_ptr<ray::LocalClientConnection> &connection) {
  for (auto it = worker_pool.begin(); it != worker_pool.end(); it++) {
    if ((*it)->Connection() == connection) {
      return (*it);
    }
  }
  return nullptr;
}

// A helper function to remove a worker from a list. Returns true if the worker
// was found and removed.
bool RemoveWorker(std::list<std::shared_ptr<ray::raylet::Worker>> &worker_pool,
                  const std::shared_ptr<ray::raylet::Worker> &worker) {
  for (auto it = worker_pool.begin(); it != worker_pool.end(); it++) {
    if (*it == worker) {
      worker_pool.erase(it);
      return true;
    }
  }
  return false;
}

}  // namespace

namespace ray {

namespace raylet {

/// A constructor that initializes a worker pool with
/// (num_worker_processes * num_workers_per_process) workers for each language.
WorkerPool::WorkerPool(
    int num_worker_processes, int num_workers_per_process,
    int maximum_startup_concurrency,
    const std::unordered_map<Language, std::vector<std::string>> &worker_commands)
    : num_workers_per_process_(num_workers_per_process),
      maximum_startup_concurrency_(maximum_startup_concurrency) {
  RAY_CHECK(num_workers_per_process > 0) << "num_workers_per_process must be positive.";
  RAY_CHECK(maximum_startup_concurrency > 0);
  // Ignore SIGCHLD signals. If we don't do this, then worker processes will
  // become zombies instead of dying gracefully.
  signal(SIGCHLD, SIG_IGN);
  for (const auto &entry : worker_commands) {
    // Initialize the pool state for this language.
    auto &state = states_by_lang_[entry.first];
    // Set worker command for this language.
    state.worker_command = entry.second;
    RAY_CHECK(!state.worker_command.empty()) << "Worker command must not be empty.";
    // Force-start num_workers worker processes for this language.
    for (int i = 0; i < num_worker_processes; i++) {
      StartWorkerProcess(entry.first);
    }
  }
}

WorkerPool::~WorkerPool() {
  std::unordered_set<pid_t> pids_to_kill;
  for (const auto &entry : states_by_lang_) {
    // Kill all registered workers. NOTE(swang): This assumes that the registered
    // workers were started by the pool.
    for (const auto &worker : entry.second.registered_workers) {
      pids_to_kill.insert(worker->Pid());
    }
  }
  // Kill all the workers that have been started but not registered.
  for (const auto &entry : starting_worker_processes_) {
    pids_to_kill.insert(entry.first);
  }
  for (const auto &pid : pids_to_kill) {
    RAY_CHECK(pid > 0);
    kill(pid, SIGKILL);
  }
  // Waiting for the workers to be killed
  for (const auto &pid : pids_to_kill) {
    waitpid(pid, NULL, 0);
  }
}

uint32_t WorkerPool::Size(const Language &language) const {
  const auto state = states_by_lang_.find(language);
  if (state == states_by_lang_.end()) {
    return 0;
  } else {
    return static_cast<uint32_t>(state->second.idle.size() +
                                 state->second.idle_actor.size());
  }
}

void WorkerPool::StartWorkerProcess(const Language &language) {
  // If we are already starting up too many workers, then return without starting
  // more.
  if (static_cast<int>(starting_worker_processes_.size()) >=
      maximum_startup_concurrency_) {
    // Workers have been started, but not registered. Force start disabled -- returning.
    RAY_LOG(DEBUG) << starting_worker_processes_.size()
                   << " worker processes pending registration";
    return;
  }
  auto &state = GetStateForLanguage(language);
  // Either there are no workers pending registration or the worker start is being forced.
  RAY_LOG(DEBUG) << "Starting new worker process, current pool has "
                 << state.idle_actor.size() << " actor workers, and " << state.idle.size()
                 << " non-actor workers";

  // Launch the process to create the worker.
  pid_t pid = fork();
  if (pid != 0) {
    RAY_LOG(DEBUG) << "Started worker process with pid " << pid;
    starting_worker_processes_.emplace(std::make_pair(pid, num_workers_per_process_));
    return;
  }

  // Reset the SIGCHLD handler for the worker.
  signal(SIGCHLD, SIG_DFL);

  // Extract pointers from the worker command to pass into execvp.
  std::vector<const char *> worker_command_args;
  for (auto const &token : state.worker_command) {
    worker_command_args.push_back(token.c_str());
  }
  worker_command_args.push_back(nullptr);

  // Try to execute the worker command.
  int rv = execvp(worker_command_args[0],
                  const_cast<char *const *>(worker_command_args.data()));
  // The worker failed to start. This is a fatal error.
  RAY_LOG(FATAL) << "Failed to start worker with return value " << rv;
}

void WorkerPool::RegisterWorker(std::shared_ptr<Worker> worker) {
  auto pid = worker->Pid();
  RAY_LOG(DEBUG) << "Registering worker with pid " << pid;
  auto &state = GetStateForLanguage(worker->GetLanguage());
  state.registered_workers.push_back(std::move(worker));

  auto it = starting_worker_processes_.find(pid);
  RAY_CHECK(it != starting_worker_processes_.end());
  it->second--;
  if (it->second == 0) {
    starting_worker_processes_.erase(it);
  }
}

void WorkerPool::RegisterDriver(std::shared_ptr<Worker> driver) {
  RAY_CHECK(!driver->GetAssignedTaskId().is_nil());
  auto &state = GetStateForLanguage(driver->GetLanguage());
  state.registered_drivers.push_back(driver);
}

std::shared_ptr<Worker> WorkerPool::GetRegisteredWorker(
    const std::shared_ptr<LocalClientConnection> &connection) const {
  for (const auto &entry : states_by_lang_) {
    auto worker = GetWorker(entry.second.registered_workers, connection);
    if (worker != nullptr) {
      return worker;
    }
  }
  return nullptr;
}

std::shared_ptr<Worker> WorkerPool::GetRegisteredDriver(
    const std::shared_ptr<LocalClientConnection> &connection) const {
  for (const auto &entry : states_by_lang_) {
    auto driver = GetWorker(entry.second.registered_drivers, connection);
    if (driver != nullptr) {
      return driver;
    }
  }
  return nullptr;
}

void WorkerPool::PushWorker(std::shared_ptr<Worker> worker) {
  // Since the worker is now idle, unset its assigned task ID.
  RAY_CHECK(worker->GetAssignedTaskId().is_nil())
      << "Idle workers cannot have an assigned task ID";
  auto &state = GetStateForLanguage(worker->GetLanguage());
  // Add the worker to the idle pool.
  if (worker->GetActorId().is_nil()) {
    state.idle.push_back(std::move(worker));
  } else {
    state.idle_actor[worker->GetActorId()] = std::move(worker);
  }
}

std::shared_ptr<Worker> WorkerPool::PopWorker(const TaskSpecification &task_spec) {
  auto &state = GetStateForLanguage(task_spec.GetLanguage());
  const auto &actor_id = task_spec.ActorId();
  std::shared_ptr<Worker> worker = nullptr;
  if (actor_id.is_nil()) {
    if (!state.idle.empty()) {
      worker = std::move(state.idle.back());
      state.idle.pop_back();
    }
  } else {
    auto actor_entry = state.idle_actor.find(actor_id);
    if (actor_entry != state.idle_actor.end()) {
      worker = std::move(actor_entry->second);
      state.idle_actor.erase(actor_entry);
    }
  }
  return worker;
}

bool WorkerPool::DisconnectWorker(std::shared_ptr<Worker> worker) {
  auto &state = GetStateForLanguage(worker->GetLanguage());
  RAY_CHECK(RemoveWorker(state.registered_workers, worker));
  return RemoveWorker(state.idle, worker);
}

void WorkerPool::DisconnectDriver(std::shared_ptr<Worker> driver) {
  auto &state = GetStateForLanguage(driver->GetLanguage());
  RAY_CHECK(RemoveWorker(state.registered_drivers, driver));
}

inline WorkerPool::State &WorkerPool::GetStateForLanguage(const Language &language) {
  auto state = states_by_lang_.find(language);
  RAY_CHECK(state != states_by_lang_.end()) << "Required Language isn't supported.";
  return state->second;
}

std::vector<std::shared_ptr<Worker>> WorkerPool::GetWorkersRunningTasksForDriver(
    const DriverID &driver_id) const {
  std::vector<std::shared_ptr<Worker>> workers;

  for (const auto &entry : states_by_lang_) {
    for (const auto &worker : entry.second.registered_workers) {
      RAY_LOG(DEBUG) << "worker: pid : " << worker->Pid()
                     << " driver_id: " << worker->GetAssignedDriverId();
      if (worker->GetAssignedDriverId() == driver_id) {
        workers.push_back(worker);
      }
    }
  }

  return workers;
}

}  // namespace raylet

}  // namespace ray
<commit_msg>Improve log message when failing to fork worker process (#2990)<commit_after>#include "ray/raylet/worker_pool.h"

#include <sys/wait.h>

#include <algorithm>
#include <thread>

#include "ray/status.h"
#include "ray/util/logging.h"

namespace {

// A helper function to get a worker from a list.
std::shared_ptr<ray::raylet::Worker> GetWorker(
    const std::list<std::shared_ptr<ray::raylet::Worker>> &worker_pool,
    const std::shared_ptr<ray::LocalClientConnection> &connection) {
  for (auto it = worker_pool.begin(); it != worker_pool.end(); it++) {
    if ((*it)->Connection() == connection) {
      return (*it);
    }
  }
  return nullptr;
}

// A helper function to remove a worker from a list. Returns true if the worker
// was found and removed.
bool RemoveWorker(std::list<std::shared_ptr<ray::raylet::Worker>> &worker_pool,
                  const std::shared_ptr<ray::raylet::Worker> &worker) {
  for (auto it = worker_pool.begin(); it != worker_pool.end(); it++) {
    if (*it == worker) {
      worker_pool.erase(it);
      return true;
    }
  }
  return false;
}

}  // namespace

namespace ray {

namespace raylet {

/// A constructor that initializes a worker pool with
/// (num_worker_processes * num_workers_per_process) workers for each language.
WorkerPool::WorkerPool(
    int num_worker_processes, int num_workers_per_process,
    int maximum_startup_concurrency,
    const std::unordered_map<Language, std::vector<std::string>> &worker_commands)
    : num_workers_per_process_(num_workers_per_process),
      maximum_startup_concurrency_(maximum_startup_concurrency) {
  RAY_CHECK(num_workers_per_process > 0) << "num_workers_per_process must be positive.";
  RAY_CHECK(maximum_startup_concurrency > 0);
  // Ignore SIGCHLD signals. If we don't do this, then worker processes will
  // become zombies instead of dying gracefully.
  signal(SIGCHLD, SIG_IGN);
  for (const auto &entry : worker_commands) {
    // Initialize the pool state for this language.
    auto &state = states_by_lang_[entry.first];
    // Set worker command for this language.
    state.worker_command = entry.second;
    RAY_CHECK(!state.worker_command.empty()) << "Worker command must not be empty.";
    // Force-start num_workers worker processes for this language.
    for (int i = 0; i < num_worker_processes; i++) {
      StartWorkerProcess(entry.first);
    }
  }
}

WorkerPool::~WorkerPool() {
  std::unordered_set<pid_t> pids_to_kill;
  for (const auto &entry : states_by_lang_) {
    // Kill all registered workers. NOTE(swang): This assumes that the registered
    // workers were started by the pool.
    for (const auto &worker : entry.second.registered_workers) {
      pids_to_kill.insert(worker->Pid());
    }
  }
  // Kill all the workers that have been started but not registered.
  for (const auto &entry : starting_worker_processes_) {
    pids_to_kill.insert(entry.first);
  }
  for (const auto &pid : pids_to_kill) {
    RAY_CHECK(pid > 0);
    kill(pid, SIGKILL);
  }
  // Waiting for the workers to be killed
  for (const auto &pid : pids_to_kill) {
    waitpid(pid, NULL, 0);
  }
}

uint32_t WorkerPool::Size(const Language &language) const {
  const auto state = states_by_lang_.find(language);
  if (state == states_by_lang_.end()) {
    return 0;
  } else {
    return static_cast<uint32_t>(state->second.idle.size() +
                                 state->second.idle_actor.size());
  }
}

void WorkerPool::StartWorkerProcess(const Language &language) {
  // If we are already starting up too many workers, then return without starting
  // more.
  if (static_cast<int>(starting_worker_processes_.size()) >=
      maximum_startup_concurrency_) {
    // Workers have been started, but not registered. Force start disabled -- returning.
    RAY_LOG(DEBUG) << starting_worker_processes_.size()
                   << " worker processes pending registration";
    return;
  }
  auto &state = GetStateForLanguage(language);
  // Either there are no workers pending registration or the worker start is being forced.
  RAY_LOG(DEBUG) << "Starting new worker process, current pool has "
                 << state.idle_actor.size() << " actor workers, and " << state.idle.size()
                 << " non-actor workers";

  // Launch the process to create the worker.
  pid_t pid = fork();
  if (pid < 0) {
    // Failure case.
    RAY_LOG(FATAL) << "Failed to fork worker process: " << strerror(errno);
    return;
  } else if (pid > 0) {
    // Parent process case.
    RAY_LOG(DEBUG) << "Started worker process with pid " << pid;
    starting_worker_processes_.emplace(std::make_pair(pid, num_workers_per_process_));
    return;
  }

  // Child process case.
  // Reset the SIGCHLD handler for the worker.
  signal(SIGCHLD, SIG_DFL);

  // Extract pointers from the worker command to pass into execvp.
  std::vector<const char *> worker_command_args;
  for (auto const &token : state.worker_command) {
    worker_command_args.push_back(token.c_str());
  }
  worker_command_args.push_back(nullptr);

  // Try to execute the worker command.
  int rv = execvp(worker_command_args[0],
                  const_cast<char *const *>(worker_command_args.data()));
  // The worker failed to start. This is a fatal error.
  RAY_LOG(FATAL) << "Failed to start worker with return value " << rv << ": "
                 << strerror(errno);
}

void WorkerPool::RegisterWorker(std::shared_ptr<Worker> worker) {
  auto pid = worker->Pid();
  RAY_LOG(DEBUG) << "Registering worker with pid " << pid;
  auto &state = GetStateForLanguage(worker->GetLanguage());
  state.registered_workers.push_back(std::move(worker));

  auto it = starting_worker_processes_.find(pid);
  RAY_CHECK(it != starting_worker_processes_.end());
  it->second--;
  if (it->second == 0) {
    starting_worker_processes_.erase(it);
  }
}

void WorkerPool::RegisterDriver(std::shared_ptr<Worker> driver) {
  RAY_CHECK(!driver->GetAssignedTaskId().is_nil());
  auto &state = GetStateForLanguage(driver->GetLanguage());
  state.registered_drivers.push_back(driver);
}

std::shared_ptr<Worker> WorkerPool::GetRegisteredWorker(
    const std::shared_ptr<LocalClientConnection> &connection) const {
  for (const auto &entry : states_by_lang_) {
    auto worker = GetWorker(entry.second.registered_workers, connection);
    if (worker != nullptr) {
      return worker;
    }
  }
  return nullptr;
}

std::shared_ptr<Worker> WorkerPool::GetRegisteredDriver(
    const std::shared_ptr<LocalClientConnection> &connection) const {
  for (const auto &entry : states_by_lang_) {
    auto driver = GetWorker(entry.second.registered_drivers, connection);
    if (driver != nullptr) {
      return driver;
    }
  }
  return nullptr;
}

void WorkerPool::PushWorker(std::shared_ptr<Worker> worker) {
  // Since the worker is now idle, unset its assigned task ID.
  RAY_CHECK(worker->GetAssignedTaskId().is_nil())
      << "Idle workers cannot have an assigned task ID";
  auto &state = GetStateForLanguage(worker->GetLanguage());
  // Add the worker to the idle pool.
  if (worker->GetActorId().is_nil()) {
    state.idle.push_back(std::move(worker));
  } else {
    state.idle_actor[worker->GetActorId()] = std::move(worker);
  }
}

std::shared_ptr<Worker> WorkerPool::PopWorker(const TaskSpecification &task_spec) {
  auto &state = GetStateForLanguage(task_spec.GetLanguage());
  const auto &actor_id = task_spec.ActorId();
  std::shared_ptr<Worker> worker = nullptr;
  if (actor_id.is_nil()) {
    if (!state.idle.empty()) {
      worker = std::move(state.idle.back());
      state.idle.pop_back();
    }
  } else {
    auto actor_entry = state.idle_actor.find(actor_id);
    if (actor_entry != state.idle_actor.end()) {
      worker = std::move(actor_entry->second);
      state.idle_actor.erase(actor_entry);
    }
  }
  return worker;
}

bool WorkerPool::DisconnectWorker(std::shared_ptr<Worker> worker) {
  auto &state = GetStateForLanguage(worker->GetLanguage());
  RAY_CHECK(RemoveWorker(state.registered_workers, worker));
  return RemoveWorker(state.idle, worker);
}

void WorkerPool::DisconnectDriver(std::shared_ptr<Worker> driver) {
  auto &state = GetStateForLanguage(driver->GetLanguage());
  RAY_CHECK(RemoveWorker(state.registered_drivers, driver));
}

inline WorkerPool::State &WorkerPool::GetStateForLanguage(const Language &language) {
  auto state = states_by_lang_.find(language);
  RAY_CHECK(state != states_by_lang_.end()) << "Required Language isn't supported.";
  return state->second;
}

std::vector<std::shared_ptr<Worker>> WorkerPool::GetWorkersRunningTasksForDriver(
    const DriverID &driver_id) const {
  std::vector<std::shared_ptr<Worker>> workers;

  for (const auto &entry : states_by_lang_) {
    for (const auto &worker : entry.second.registered_workers) {
      RAY_LOG(DEBUG) << "worker: pid : " << worker->Pid()
                     << " driver_id: " << worker->GetAssignedDriverId();
      if (worker->GetAssignedDriverId() == driver_id) {
        workers.push_back(worker);
      }
    }
  }

  return workers;
}

}  // namespace raylet

}  // namespace ray
<|endoftext|>


<commit_before>#include "start_thread.h"
#include "tmd.h"
#include "incline_def_async_qtable.h"
#include "incline_driver_async_qtable.h"
#include "incline_mgr.h"
#include "incline_util.h"

using namespace std;

incline_def*
incline_driver_async_qtable::create_def() const
{
  return new incline_def_async_qtable();
}

vector<string>
incline_driver_async_qtable::create_table_all(bool if_not_exists,
					      tmd::conn_t& dbh) const
{
  vector<string> r;
  for (std::vector<incline_def*>::const_iterator di = mgr_->defs().begin();
       di != mgr_->defs().end();
       ++di) {
    r.push_back(create_table_of(*di, if_not_exists, dbh));
  }
  return r;
}

vector<string>
incline_driver_async_qtable::drop_table_all(bool if_exists) const
{
  vector<string> r;
  for (std::vector<incline_def*>::const_iterator di = mgr_->defs().begin();
       di != mgr_->defs().end();
       ++di) {
    r.push_back(drop_table_of(*di, if_exists));
  }
  return r;
}

string
incline_driver_async_qtable::create_table_of(const incline_def* _def,
					     bool if_not_exists,
					     tmd::conn_t& dbh) const
{
  const incline_def_async_qtable* def
    = dynamic_cast<const incline_def_async_qtable*>(_def);
  assert(def != NULL);
  return _create_table_of(def, def->queue_table(), false, true, dbh);
}

string
incline_driver_async_qtable::drop_table_of(const incline_def* _def,
					   bool if_exists) const
{
  const incline_def_async_qtable* def
    = dynamic_cast<const incline_def_async_qtable*>(_def);
  assert(def != NULL);
  return string("DROP TABLE ") + (if_exists ? "IF EXISTS " : "")
    + def->queue_table();
}

string
incline_driver_async_qtable::_create_table_of(const incline_def_async_qtable*
					      def,
					      const std::string& table_name,
					      bool temporary,
					      bool if_not_exists,
					      tmd::conn_t& dbh) const
{
  vector<string> col_defs, pk_cols;
  for (map<string, string>::const_iterator pi = def->pk_columns().begin();
       pi != def->pk_columns().end();
       ++pi) {
    string table_name = incline_def::table_of_column(pi->first);
    string column_name = pi->first.substr(table_name.size() + 1);
    tmd::query_t res(dbh,
		     "SELECT COLUMN_TYPE,CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='%s' AND TABLE_NAME='%s' AND COLUMN_NAME='%s'",
		     tmd::escape(dbh, mgr_->db_name()).c_str(),
		     tmd::escape(dbh, table_name).c_str(),
		     tmd::escape(dbh, column_name).c_str());
    if (res.fetch().eof()) {
      // TODO throw an exception instead
      cerr << "failed to obtain column definition of: " << pi->first << endl;
      exit(4);
    }
    col_defs.push_back(pi->second + ' ' + res.field(0));
    if (res.field(1) != NULL) {
      col_defs.back() += string(" CHARSET ") + res.field(1);
    }
    pk_cols.push_back(pi->second);
  }
  return string("CREATE ") + (temporary ? "TEMPORARY " : "") + "TABLE "
    + (if_not_exists ? "IF NOT EXISTS " : "") + table_name + " ("
    + incline_util::join(',', col_defs.begin(), col_defs.end())
    + ",_iq_version INT UNSIGNED NOT NULL DEFAULT 0,PRIMARY KEY("
    + incline_util::join(',', pk_cols.begin(), pk_cols.end())
    + ")) ENGINE=InnoDB";
}

vector<string>
incline_driver_async_qtable::do_build_enqueue_sql(const incline_def* _def,
						  const map<string, string>&
						  pk_columns,
						  const vector<string>& tables,
						  const vector<string>& cond)
  const
{
  const incline_def_async_qtable* def
    = dynamic_cast<const incline_def_async_qtable*>(_def);
  vector<string> src_cols, dest_cols;
  for (map<string, string>::const_iterator pi = pk_columns.begin();
       pi != pk_columns.end();
       ++pi) {
    src_cols.push_back(pi->first);
    dest_cols.push_back(pi->second);
  }
  string sql = "INSERT INTO " + def->queue_table() + " ("
    + incline_util::join(',', dest_cols.begin(), dest_cols.end()) + ") SELECT "
    + incline_util::join(',', src_cols.begin(), src_cols.end());
  if (! tables.empty()) {
    sql += " FROM "
      + incline_util::join(" INNER JOIN ", tables.begin(), tables.end());
  }
  if (! cond.empty()) {
    sql += " WHERE "
      + incline_util::join(" AND ", cond.begin(), cond.end());
  }
  sql += " ON DUPLICATE KEY UPDATE _iq_version=_iq_version+1";
  return incline_util::vectorize(sql);
}

incline_driver_async_qtable::forwarder::forwarder(forwarder_mgr* mgr,
						  const
						  incline_def_async_qtable* def,
						  tmd::conn_t* dbh,
						  int poll_interval)
  : mgr_(mgr), def_(def), dbh_(dbh), dest_table_(def->destination()),
    queue_table_(def->queue_table()),
    temp_table_("_qt_" + def->queue_table()),
    src_tables_(def->source()), merge_cond_(def->build_merge_cond("", "")),
    poll_interval_(poll_interval)
{
  // build column names
  for (map<string, string>::const_iterator pi = def->pk_columns().begin();
       pi != def->pk_columns().end();
       ++pi) {
    dest_pk_columns_.push_back(pi->second);
    dest_columns_.push_back(pi->second);
    src_pk_columns_.push_back(pi->first);
    src_columns_.push_back(pi->first);
  }
  for (map<string, string>::const_iterator ni = def->npk_columns().begin();
       ni != def->npk_columns().end();
       ++ni) {
    dest_columns_.push_back(ni->second);
    src_columns_.push_back(ni->first);
  }
  // create temporary table
  tmd::execute(*dbh_,
	       mgr_->driver()->_create_table_of(def, temp_table_, true, false,
						*dbh_));
}

incline_driver_async_qtable::forwarder::~forwarder()
{
  delete dbh_;
}

void* incline_driver_async_qtable::forwarder::run()
{
  while (1) {
    vector<string> pk_values;
    { // poll the queue table
      string extra_cond = do_get_extra_cond();
      tmd::execute(*dbh_,
		   "INSERT INTO " + temp_table_ + " SELECT * FROM "
		   + queue_table_
		   + (extra_cond.empty()
		      ? string()
		      : string(" WHERE ") + extra_cond)
		   + " LIMIT 1");
      if (tmd::affected_rows(*dbh_) == 0) {
	sleep(poll_interval_);
	continue;
      }
    }
    { // fetch the pks
      tmd::query_t res(*dbh_,
		       "SELECT "
		       + incline_util::join(',', dest_pk_columns_.begin(),
					    dest_pk_columns_.end())
		       + " FROM " + temp_table_);
      assert(! res.fetch().eof());
      for (size_t i = 0; i < dest_pk_columns_.size(); ++i) {
	pk_values.push_back(res.field(i));
      }
    }
    // we have a row in queue, handle it
    vector<string> scond(merge_cond_);
    for (size_t i = 0; i < src_pk_columns_.size(); ++i) {
      scond.push_back(src_pk_columns_[i] + "='"
		      + tmd::escape(*dbh_, pk_values[i]) + '\'');
    }
    tmd::query_t res(*dbh_,
		     "SELECT "
		     + incline_util::join(',', src_columns_.begin(),
					  src_columns_.end())
		     + " FROM "
		     + incline_util::join(" INNER JOIN ", src_tables_.begin(),
					  src_tables_.end())
		     + " WHERE "
		     + incline_util::join(" AND ", scond.begin(), scond.end()));
    bool success;
    if (! res.fetch().eof()) {
      success = do_replace_row(res);
    } else {
      success = do_delete_row(pk_values);
    }
    // remove from queue
    if (success) {
      vector<string> dcond;
      for (vector<string>::const_iterator pi = dest_pk_columns_.begin();
	   pi != dest_pk_columns_.end();
	   ++pi) {
	dcond.push_back(queue_table_ + '.' + *pi + '=' + temp_table_ + '.'
			+ *pi);
      }
      dcond.push_back(queue_table_ + "._iq_version=" + temp_table_
		      + "._iq_version");
      tmd::execute(*dbh_,
		   "DELETE FROM " + queue_table_
		   + " WHERE EXISTS (SELECT * FROM " + temp_table_ + " WHERE "
		   + incline_util::join(" AND ", dcond.begin(), dcond.end())
		   + ')');
    }
    tmd::execute(*dbh_, "DELETE FROM " + temp_table_);
  }

  return NULL;
}

bool
incline_driver_async_qtable::forwarder::do_replace_row(tmd::query_t& res)
{
  replace_row(*dbh_, res);
  return true;
}

bool
incline_driver_async_qtable::forwarder::do_delete_row(const vector<string>&
						      pk_values)
{
  delete_row(*dbh_, pk_values);
  return true;
}

string
incline_driver_async_qtable::forwarder::do_get_extra_cond()
{
  return string();
}

void
incline_driver_async_qtable::forwarder::replace_row(tmd::conn_t& dbh,
						    tmd::query_t& res) const
{
  vector<string> values;
  for (size_t i = 0; i < src_columns_.size(); ++i) {
    values.push_back("'" + tmd::escape(dbh, res.field(i)) + '\'');
  }
  tmd::execute(dbh,
	       "REPLACE INTO " + dest_table_ + " ("
	       + incline_util::join(',', dest_columns_.begin(),
				    dest_columns_.end())
	       + ") VALUES ("
	       + incline_util::join(',', values.begin(), values.end())
	       + ')');
}

void
incline_driver_async_qtable::forwarder::delete_row(tmd::conn_t& dbh,
						   const vector<string>&
						   pk_values) const
{
  vector<string> dcond;
  for (size_t i = 0; i < dest_pk_columns_.size(); ++i) {
    dcond.push_back(dest_pk_columns_[i] + "='"
		    + tmd::escape(dbh, pk_values[i]) + '\'');
  }
  tmd::execute(dbh,
	       "DELETE FROM " + dest_table_ + " WHERE "
	       + incline_util::join(" AND ", dcond.begin(), dcond.end()));
}

void*
incline_driver_async_qtable::forwarder_mgr::run()
{
  vector<pthread_t> threads;

  { // create and start forwarders
    const vector<incline_def*>& defs = driver()->mgr()->defs();
    for (vector<incline_def*>::const_iterator di = defs.begin();
	 di != defs.end();
	 ++di) {
      const incline_def_async_qtable* def
	= dynamic_cast<const incline_def_async_qtable*>(*di);
      assert(def != NULL);
      threads.push_back(start_thread(do_create_forwarder(def)));
    }
  }

  // loop
  while (! threads.empty()) {
    pthread_join(threads.back(), NULL);
    threads.pop_back();
  }

  return NULL;
}

incline_driver_async_qtable::forwarder*
incline_driver_async_qtable::forwarder_mgr::do_create_forwarder(const incline_def_async_qtable* def)
{
  tmd::conn_t* dbh = (*connect_)(src_host_.c_str(), src_port_);
  assert(dbh != NULL);
  return new forwarder(this, def, dbh, poll_interval_);
}
<commit_msg>use MEMORY storage engine for temporary tables<commit_after>#include "start_thread.h"
#include "tmd.h"
#include "incline_def_async_qtable.h"
#include "incline_driver_async_qtable.h"
#include "incline_mgr.h"
#include "incline_util.h"

using namespace std;

incline_def*
incline_driver_async_qtable::create_def() const
{
  return new incline_def_async_qtable();
}

vector<string>
incline_driver_async_qtable::create_table_all(bool if_not_exists,
					      tmd::conn_t& dbh) const
{
  vector<string> r;
  for (std::vector<incline_def*>::const_iterator di = mgr_->defs().begin();
       di != mgr_->defs().end();
       ++di) {
    r.push_back(create_table_of(*di, if_not_exists, dbh));
  }
  return r;
}

vector<string>
incline_driver_async_qtable::drop_table_all(bool if_exists) const
{
  vector<string> r;
  for (std::vector<incline_def*>::const_iterator di = mgr_->defs().begin();
       di != mgr_->defs().end();
       ++di) {
    r.push_back(drop_table_of(*di, if_exists));
  }
  return r;
}

string
incline_driver_async_qtable::create_table_of(const incline_def* _def,
					     bool if_not_exists,
					     tmd::conn_t& dbh) const
{
  const incline_def_async_qtable* def
    = dynamic_cast<const incline_def_async_qtable*>(_def);
  assert(def != NULL);
  return _create_table_of(def, def->queue_table(), false, true, dbh);
}

string
incline_driver_async_qtable::drop_table_of(const incline_def* _def,
					   bool if_exists) const
{
  const incline_def_async_qtable* def
    = dynamic_cast<const incline_def_async_qtable*>(_def);
  assert(def != NULL);
  return string("DROP TABLE ") + (if_exists ? "IF EXISTS " : "")
    + def->queue_table();
}

string
incline_driver_async_qtable::_create_table_of(const incline_def_async_qtable*
					      def,
					      const std::string& table_name,
					      bool temporary,
					      bool if_not_exists,
					      tmd::conn_t& dbh) const
{
  vector<string> col_defs, pk_cols;
  for (map<string, string>::const_iterator pi = def->pk_columns().begin();
       pi != def->pk_columns().end();
       ++pi) {
    string table_name = incline_def::table_of_column(pi->first);
    string column_name = pi->first.substr(table_name.size() + 1);
    tmd::query_t res(dbh,
		     "SELECT COLUMN_TYPE,CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='%s' AND TABLE_NAME='%s' AND COLUMN_NAME='%s'",
		     tmd::escape(dbh, mgr_->db_name()).c_str(),
		     tmd::escape(dbh, table_name).c_str(),
		     tmd::escape(dbh, column_name).c_str());
    if (res.fetch().eof()) {
      // TODO throw an exception instead
      cerr << "failed to obtain column definition of: " << pi->first << endl;
      exit(4);
    }
    col_defs.push_back(pi->second + ' ' + res.field(0));
    if (res.field(1) != NULL) {
      col_defs.back() += string(" CHARSET ") + res.field(1);
    }
    pk_cols.push_back(pi->second);
  }
  return string("CREATE ") + (temporary ? "TEMPORARY " : "") + "TABLE "
    + (if_not_exists ? "IF NOT EXISTS " : "") + table_name + " ("
    + incline_util::join(',', col_defs.begin(), col_defs.end())
    + ",_iq_version INT UNSIGNED NOT NULL DEFAULT 0,PRIMARY KEY("
    + incline_util::join(',', pk_cols.begin(), pk_cols.end())
    + ")) ENGINE=" + (temporary ? "MEMORY" : "InnoDB");
}

vector<string>
incline_driver_async_qtable::do_build_enqueue_sql(const incline_def* _def,
						  const map<string, string>&
						  pk_columns,
						  const vector<string>& tables,
						  const vector<string>& cond)
  const
{
  const incline_def_async_qtable* def
    = dynamic_cast<const incline_def_async_qtable*>(_def);
  vector<string> src_cols, dest_cols;
  for (map<string, string>::const_iterator pi = pk_columns.begin();
       pi != pk_columns.end();
       ++pi) {
    src_cols.push_back(pi->first);
    dest_cols.push_back(pi->second);
  }
  string sql = "INSERT INTO " + def->queue_table() + " ("
    + incline_util::join(',', dest_cols.begin(), dest_cols.end()) + ") SELECT "
    + incline_util::join(',', src_cols.begin(), src_cols.end());
  if (! tables.empty()) {
    sql += " FROM "
      + incline_util::join(" INNER JOIN ", tables.begin(), tables.end());
  }
  if (! cond.empty()) {
    sql += " WHERE "
      + incline_util::join(" AND ", cond.begin(), cond.end());
  }
  sql += " ON DUPLICATE KEY UPDATE _iq_version=_iq_version+1";
  return incline_util::vectorize(sql);
}

incline_driver_async_qtable::forwarder::forwarder(forwarder_mgr* mgr,
						  const
						  incline_def_async_qtable* def,
						  tmd::conn_t* dbh,
						  int poll_interval)
  : mgr_(mgr), def_(def), dbh_(dbh), dest_table_(def->destination()),
    queue_table_(def->queue_table()),
    temp_table_("_qt_" + def->queue_table()),
    src_tables_(def->source()), merge_cond_(def->build_merge_cond("", "")),
    poll_interval_(poll_interval)
{
  // build column names
  for (map<string, string>::const_iterator pi = def->pk_columns().begin();
       pi != def->pk_columns().end();
       ++pi) {
    dest_pk_columns_.push_back(pi->second);
    dest_columns_.push_back(pi->second);
    src_pk_columns_.push_back(pi->first);
    src_columns_.push_back(pi->first);
  }
  for (map<string, string>::const_iterator ni = def->npk_columns().begin();
       ni != def->npk_columns().end();
       ++ni) {
    dest_columns_.push_back(ni->second);
    src_columns_.push_back(ni->first);
  }
  // create temporary table
  tmd::execute(*dbh_,
	       mgr_->driver()->_create_table_of(def, temp_table_, true, false,
						*dbh_));
}

incline_driver_async_qtable::forwarder::~forwarder()
{
  delete dbh_;
}

void* incline_driver_async_qtable::forwarder::run()
{
  while (1) {
    vector<string> pk_values;
    { // poll the queue table
      string extra_cond = do_get_extra_cond();
      tmd::execute(*dbh_,
		   "INSERT INTO " + temp_table_ + " SELECT * FROM "
		   + queue_table_
		   + (extra_cond.empty()
		      ? string()
		      : string(" WHERE ") + extra_cond)
		   + " LIMIT 1");
      if (tmd::affected_rows(*dbh_) == 0) {
	sleep(poll_interval_);
	continue;
      }
    }
    { // fetch the pks
      tmd::query_t res(*dbh_,
		       "SELECT "
		       + incline_util::join(',', dest_pk_columns_.begin(),
					    dest_pk_columns_.end())
		       + " FROM " + temp_table_);
      assert(! res.fetch().eof());
      for (size_t i = 0; i < dest_pk_columns_.size(); ++i) {
	pk_values.push_back(res.field(i));
      }
    }
    // we have a row in queue, handle it
    vector<string> scond(merge_cond_);
    for (size_t i = 0; i < src_pk_columns_.size(); ++i) {
      scond.push_back(src_pk_columns_[i] + "='"
		      + tmd::escape(*dbh_, pk_values[i]) + '\'');
    }
    tmd::query_t res(*dbh_,
		     "SELECT "
		     + incline_util::join(',', src_columns_.begin(),
					  src_columns_.end())
		     + " FROM "
		     + incline_util::join(" INNER JOIN ", src_tables_.begin(),
					  src_tables_.end())
		     + " WHERE "
		     + incline_util::join(" AND ", scond.begin(), scond.end()));
    bool success;
    if (! res.fetch().eof()) {
      success = do_replace_row(res);
    } else {
      success = do_delete_row(pk_values);
    }
    // remove from queue
    if (success) {
      vector<string> dcond;
      for (vector<string>::const_iterator pi = dest_pk_columns_.begin();
	   pi != dest_pk_columns_.end();
	   ++pi) {
	dcond.push_back(queue_table_ + '.' + *pi + '=' + temp_table_ + '.'
			+ *pi);
      }
      dcond.push_back(queue_table_ + "._iq_version=" + temp_table_
		      + "._iq_version");
      tmd::execute(*dbh_,
		   "DELETE FROM " + queue_table_
		   + " WHERE EXISTS (SELECT * FROM " + temp_table_ + " WHERE "
		   + incline_util::join(" AND ", dcond.begin(), dcond.end())
		   + ')');
    }
    tmd::execute(*dbh_, "DELETE FROM " + temp_table_);
  }

  return NULL;
}

bool
incline_driver_async_qtable::forwarder::do_replace_row(tmd::query_t& res)
{
  replace_row(*dbh_, res);
  return true;
}

bool
incline_driver_async_qtable::forwarder::do_delete_row(const vector<string>&
						      pk_values)
{
  delete_row(*dbh_, pk_values);
  return true;
}

string
incline_driver_async_qtable::forwarder::do_get_extra_cond()
{
  return string();
}

void
incline_driver_async_qtable::forwarder::replace_row(tmd::conn_t& dbh,
						    tmd::query_t& res) const
{
  vector<string> values;
  for (size_t i = 0; i < src_columns_.size(); ++i) {
    values.push_back("'" + tmd::escape(dbh, res.field(i)) + '\'');
  }
  tmd::execute(dbh,
	       "REPLACE INTO " + dest_table_ + " ("
	       + incline_util::join(',', dest_columns_.begin(),
				    dest_columns_.end())
	       + ") VALUES ("
	       + incline_util::join(',', values.begin(), values.end())
	       + ')');
}

void
incline_driver_async_qtable::forwarder::delete_row(tmd::conn_t& dbh,
						   const vector<string>&
						   pk_values) const
{
  vector<string> dcond;
  for (size_t i = 0; i < dest_pk_columns_.size(); ++i) {
    dcond.push_back(dest_pk_columns_[i] + "='"
		    + tmd::escape(dbh, pk_values[i]) + '\'');
  }
  tmd::execute(dbh,
	       "DELETE FROM " + dest_table_ + " WHERE "
	       + incline_util::join(" AND ", dcond.begin(), dcond.end()));
}

void*
incline_driver_async_qtable::forwarder_mgr::run()
{
  vector<pthread_t> threads;

  { // create and start forwarders
    const vector<incline_def*>& defs = driver()->mgr()->defs();
    for (vector<incline_def*>::const_iterator di = defs.begin();
	 di != defs.end();
	 ++di) {
      const incline_def_async_qtable* def
	= dynamic_cast<const incline_def_async_qtable*>(*di);
      assert(def != NULL);
      threads.push_back(start_thread(do_create_forwarder(def)));
    }
  }

  // loop
  while (! threads.empty()) {
    pthread_join(threads.back(), NULL);
    threads.pop_back();
  }

  return NULL;
}

incline_driver_async_qtable::forwarder*
incline_driver_async_qtable::forwarder_mgr::do_create_forwarder(const incline_def_async_qtable* def)
{
  tmd::conn_t* dbh = (*connect_)(src_host_.c_str(), src_port_);
  assert(dbh != NULL);
  return new forwarder(this, def, dbh, poll_interval_);
}
<|endoftext|>