Loading BuilderQueue/include/BuilderQueue.h +4 −7 Original line number Diff line number Diff line Loading @@ -12,29 +12,26 @@ public: explicit BuilderQueue(asio::io_service &io_service) : io_service(io_service), max_builders(1), max_available_builders(max_builders), update_in_progress(false) pending_requests(0) {} // Create a new queue reservation and return it to the requester Reservation& enter(); // Attempt to process the queue after an event that adds/removes builders or requests void tick(); void tick(asio::yield_context yield); private: asio::io_service &io_service; // Hold reservations that are to be fulfilled std::list<Reservation> reservations; // List of currently available builders std::set<Builder> available_builders; // Maximum number of active and cached builders const std::size_t max_builders; // Maximum number of builders to spin and keep up in reserve const std::size_t max_available_builders; // Flag to determine if an update is already in progress bool update_in_progress; // Number of build requests that have been submitted but not processed by OpenStack yet int pending_requests; }; No newline at end of file BuilderQueue/src/BuilderQueue.cpp +42 −42 Original line number Diff line number Diff line Loading @@ -7,57 +7,57 @@ Reservation &BuilderQueue::enter() { return reservations.back(); } void BuilderQueue::tick() { // Process pending reservations for (auto &reservation : reservations) { if (reservation.pending() && !available_builders.empty()) { reservation.ready(*available_builders.begin()); available_builders.erase(available_builders.begin()); } } // Update OpenStack by creating and removing builders as required // This section can take quite some time so is done in a coroutine if (!update_in_progress) { update_in_progress = true; asio::spawn(io_service, [&](asio::yield_context yield) { void BuilderQueue::tick(asio::yield_context yield) { // Update list of "Active" OpenStack builders auto all_builders = OpenStackBuilder::get_builders(io_service, yield); std::set<Builder> unavailable_builders; // Update reservation information // Process reservations for (auto &reservation : reservations) { // Set unavailable builders, that is builders which are attached to a reservation if (reservation.builder) { unavailable_builders.insert(reservation.builder.get()); } // If the reservation is complete delete the builder if (reservation.complete()) { asio::spawn(io_service, [&](asio::yield_context yield) { OpenStackBuilder::destroy(reservation.builder.get(), io_service, yield); }; reservation.builder = boost::none; }); } } } // TODO handle error state builders - potentially in destroy script? // Remove all completed reservations reservations.remove_if([](const auto &res) { return res.complete(); // Delete reservations that are completed and don't have an active builder associated with them reservations.remove_if([](const auto &reservation) { return reservation.complete() && !reservation.builder; }); // Available_builders = all_builders - unavailable_builders std::set<Builder> available_builders; std::set_difference(all_builders.begin(), all_builders.end(), unavailable_builders.begin(), unavailable_builders.end(), std::inserter(available_builders, available_builders.begin())); // Spin up builders so we have the requested available auto open_slots = max_builders - all_builders.size(); auto open_available_slots = max_available_builders - available_builders.size(); // Assign builders to any pending reservations for (auto &reservation : reservations) { if (reservation.pending() && !available_builders.empty()) { reservation.ready(*available_builders.begin()); available_builders.erase(available_builders.begin()); } } // Request new builders if slots are open auto open_slots = max_builders - all_builders.size() - pending_requests; auto open_available_slots = max_available_builders - available_builders.size() - pending_requests; auto request_count = std::min(open_slots, open_available_slots); for (auto i=0; i < request_count; i++) { pending_requests++; asio::spawn(io_service, [&](asio::yield_context yield) { OpenStackBuilder::request_create(io_service, yield); } update_in_progress = false; pending_requests--; }); } } No newline at end of file BuilderQueue/src/main.cpp +1 −4 Original line number Diff line number Diff line Loading @@ -36,14 +36,11 @@ int main(int argc, char *argv[]) { }); // Start the queue which ticks at the specified interval boost::asio::deadline_timer timer(io_service); asio::spawn(io_service, [&](asio::yield_context yield) { for (;;) { try { builder_queue.tick(); timer.expires_from_now(boost::posix_time::seconds(1)); timer.async_wait(yield); builder_queue.tick(yield); } catch (std::exception &e) { logger::write(std::string() + "Queue tick error: " + e.what()); } Loading Loading
BuilderQueue/include/BuilderQueue.h +4 −7 Original line number Diff line number Diff line Loading @@ -12,29 +12,26 @@ public: explicit BuilderQueue(asio::io_service &io_service) : io_service(io_service), max_builders(1), max_available_builders(max_builders), update_in_progress(false) pending_requests(0) {} // Create a new queue reservation and return it to the requester Reservation& enter(); // Attempt to process the queue after an event that adds/removes builders or requests void tick(); void tick(asio::yield_context yield); private: asio::io_service &io_service; // Hold reservations that are to be fulfilled std::list<Reservation> reservations; // List of currently available builders std::set<Builder> available_builders; // Maximum number of active and cached builders const std::size_t max_builders; // Maximum number of builders to spin and keep up in reserve const std::size_t max_available_builders; // Flag to determine if an update is already in progress bool update_in_progress; // Number of build requests that have been submitted but not processed by OpenStack yet int pending_requests; }; No newline at end of file
BuilderQueue/src/BuilderQueue.cpp +42 −42 Original line number Diff line number Diff line Loading @@ -7,57 +7,57 @@ Reservation &BuilderQueue::enter() { return reservations.back(); } void BuilderQueue::tick() { // Process pending reservations for (auto &reservation : reservations) { if (reservation.pending() && !available_builders.empty()) { reservation.ready(*available_builders.begin()); available_builders.erase(available_builders.begin()); } } // Update OpenStack by creating and removing builders as required // This section can take quite some time so is done in a coroutine if (!update_in_progress) { update_in_progress = true; asio::spawn(io_service, [&](asio::yield_context yield) { void BuilderQueue::tick(asio::yield_context yield) { // Update list of "Active" OpenStack builders auto all_builders = OpenStackBuilder::get_builders(io_service, yield); std::set<Builder> unavailable_builders; // Update reservation information // Process reservations for (auto &reservation : reservations) { // Set unavailable builders, that is builders which are attached to a reservation if (reservation.builder) { unavailable_builders.insert(reservation.builder.get()); } // If the reservation is complete delete the builder if (reservation.complete()) { asio::spawn(io_service, [&](asio::yield_context yield) { OpenStackBuilder::destroy(reservation.builder.get(), io_service, yield); }; reservation.builder = boost::none; }); } } } // TODO handle error state builders - potentially in destroy script? // Remove all completed reservations reservations.remove_if([](const auto &res) { return res.complete(); // Delete reservations that are completed and don't have an active builder associated with them reservations.remove_if([](const auto &reservation) { return reservation.complete() && !reservation.builder; }); // Available_builders = all_builders - unavailable_builders std::set<Builder> available_builders; std::set_difference(all_builders.begin(), all_builders.end(), unavailable_builders.begin(), unavailable_builders.end(), std::inserter(available_builders, available_builders.begin())); // Spin up builders so we have the requested available auto open_slots = max_builders - all_builders.size(); auto open_available_slots = max_available_builders - available_builders.size(); // Assign builders to any pending reservations for (auto &reservation : reservations) { if (reservation.pending() && !available_builders.empty()) { reservation.ready(*available_builders.begin()); available_builders.erase(available_builders.begin()); } } // Request new builders if slots are open auto open_slots = max_builders - all_builders.size() - pending_requests; auto open_available_slots = max_available_builders - available_builders.size() - pending_requests; auto request_count = std::min(open_slots, open_available_slots); for (auto i=0; i < request_count; i++) { pending_requests++; asio::spawn(io_service, [&](asio::yield_context yield) { OpenStackBuilder::request_create(io_service, yield); } update_in_progress = false; pending_requests--; }); } } No newline at end of file
BuilderQueue/src/main.cpp +1 −4 Original line number Diff line number Diff line Loading @@ -36,14 +36,11 @@ int main(int argc, char *argv[]) { }); // Start the queue which ticks at the specified interval boost::asio::deadline_timer timer(io_service); asio::spawn(io_service, [&](asio::yield_context yield) { for (;;) { try { builder_queue.tick(); timer.expires_from_now(boost::posix_time::seconds(1)); timer.async_wait(yield); builder_queue.tick(yield); } catch (std::exception &e) { logger::write(std::string() + "Queue tick error: " + e.what()); } Loading