diff --git a/src/sim/core/.gitkeep b/src/sim/core/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/sim/core/base_entity.h b/src/sim/core/base_entity.h new file mode 100644 index 0000000..3451266 --- /dev/null +++ b/src/sim/core/base_entity.h @@ -0,0 +1,13 @@ +#pragma once +#include + +class BaseEntity { +public: + explicit BaseEntity(std::string id_) : entity_id(std::move(id_)) {} + virtual ~BaseEntity() = default; + + const std::string& id() const { return entity_id; } + +private: + std::string entity_id; +}; diff --git a/src/sim/core/event_queue.cpp b/src/sim/core/event_queue.cpp new file mode 100644 index 0000000..9cd41c8 --- /dev/null +++ b/src/sim/core/event_queue.cpp @@ -0,0 +1,49 @@ +//event_queue.cpp defines different priority/calender/ladder (for now just pq) queues +//at runtime EventQueue reference may point to any of them (depending on configuration) +#include "event_queue.h" +#include "../events/event.h" +#include +#include + +using std::unique_ptr; +using std::priority_queue; +using std::vector; +using std::move; + +namespace { + +struct EventCompare { + bool operator()( + const unique_ptr& a, + const unique_ptr& b + ) const { + return a->time > b->time; + } +}; + +class PriorityEventQueue : public EventQueue { +private: + priority_queue< + unique_ptr, + vector>, + EventCompare + > pq; + +public: + void push(unique_ptr e) override { + pq.push(move(e)); + } + + unique_ptr pop() override { + auto e = move(pq.top()); + pq.pop(); + return e; + } + + bool empty() const override { + return pq.empty(); + } +}; + +} + diff --git a/src/sim/core/event_queue.h b/src/sim/core/event_queue.h new file mode 100644 index 0000000..bd098f8 --- /dev/null +++ b/src/sim/core/event_queue.h @@ -0,0 +1,14 @@ +//event_queue.h defines the abstract event queue API which will be used by event scheduler +#pragma once +#include + +class Event; + +class EventQueue { +public: + virtual ~EventQueue() = default; + + virtual void push(std::unique_ptr e) = 0; + virtual std::unique_ptr pop() = 0; + virtual bool empty() const = 0; +}; diff --git a/src/sim/core/scheduler.h b/src/sim/core/scheduler.h new file mode 100644 index 0000000..1760ff4 --- /dev/null +++ b/src/sim/core/scheduler.h @@ -0,0 +1,18 @@ +#pragma once +#include + +class Event; +class EventQueue; + +class EventScheduler { +private: + EventQueue& queue; //private as components only schedule the events using scheduler, so they should not be able to inspect it + +public: + explicit EventScheduler(EventQueue& q) : queue(q) {} + + void schedule(std::unique_ptr e) { + queue.push(std::move(e)); + } + +}; \ No newline at end of file diff --git a/src/sim/core/sim_types.h b/src/sim/core/sim_types.h new file mode 100644 index 0000000..de23bfd --- /dev/null +++ b/src/sim/core/sim_types.h @@ -0,0 +1,5 @@ +//this is just for defining alias for uint64_t everywhere +#pragma once +#include + +using SimTime = uint64_t; diff --git a/src/sim/core/simulator.cpp b/src/sim/core/simulator.cpp new file mode 100644 index 0000000..d6e6456 --- /dev/null +++ b/src/sim/core/simulator.cpp @@ -0,0 +1,27 @@ +#include "simulator.h" +#include "event_queue.h" +#include "../events/event.h" + +Simulator::Simulator( + EventQueue& q, + const Context& ctx, + State& st +) + : queue(q), + scheduler(q), + context(ctx), + state(st) {} + +void Simulator::run() { + while (!queue.empty()) { + auto event = queue.pop(); + + current_time = event->time; + + event->execute(context, state, scheduler); + } +} + +SimTime Simulator::now() const { + return current_time; +} diff --git a/src/sim/core/simulator.h b/src/sim/core/simulator.h new file mode 100644 index 0000000..71044d2 --- /dev/null +++ b/src/sim/core/simulator.h @@ -0,0 +1,33 @@ +#pragma once +#include "sim_types.h" +#include "scheduler.h" +#include "event_loop.h" + +#include "../entities/entity_context.h" +#include "../entities/entity_state.h" + +using Context = SimulationContext; +using State = SimulationState; + +class EventQueue; + +class Simulator final : public EventLoop { +private: + SimTime current_time = 0; + + EventQueue& queue; + EventScheduler scheduler; + + const Context& context; + State& state; + +public: + Simulator( + EventQueue& q, + const Context& ctx, + State& st + ); + + void run() override; + SimTime now() const; +}; diff --git a/src/sim/entities/database.h b/src/sim/entities/database.h new file mode 100644 index 0000000..7cafb88 --- /dev/null +++ b/src/sim/entities/database.h @@ -0,0 +1,25 @@ +#pragma once +#include "../core/base_entity.h" + +class DatabaseEntity final : public BaseEntity { +public: + // ---- context ---- + const int capacity; + const double latency_mean; + const double failure_prob; + + // ---- state ---- + bool is_down = false; + int active_connections = 0; + + DatabaseEntity( + std::string id, + int capacity, + double latency_mean, + double failure_prob + ) + : BaseEntity(std::move(id)), + capacity(capacity), + latency_mean(latency_mean), + failure_prob(failure_prob) {} +}; diff --git a/src/sim/entities/networklink.h b/src/sim/entities/networklink.h new file mode 100644 index 0000000..27e5ca4 --- /dev/null +++ b/src/sim/entities/networklink.h @@ -0,0 +1,29 @@ +#pragma once +#include "../core/base_entity.h" +#include + +class NetworkLinkEntity final : public BaseEntity { +public: + // ---- context ---- + const std::string from; + const std::string to; + const double latency_mean; + const double failure_prob; + + // ---- state ---- + bool is_down = false; + int in_flight = 0; + + NetworkLinkEntity( + std::string id, + std::string from, + std::string to, + double latency_mean, + double failure_prob + ) + : BaseEntity(std::move(id)), + from(std::move(from)), + to(std::move(to)), + latency_mean(latency_mean), + failure_prob(failure_prob) {} +}; diff --git a/src/sim/entities/service.h b/src/sim/entities/service.h new file mode 100644 index 0000000..4a5a9ec --- /dev/null +++ b/src/sim/entities/service.h @@ -0,0 +1,26 @@ +#pragma once +#include "../core/base_entity.h" + +class ServiceEntity final : public BaseEntity { +public: + // ---- context (immutable) ---- + const int capacity; + const double latency_mean; + const double failure_prob; + + // ---- state (mutable) ---- + bool is_down = false; + int active_requests = 0; + int queued_requests = 0; + + ServiceEntity( + std::string id, + int capacity, + double latency_mean, + double failure_prob + ) + : BaseEntity(std::move(id)), + capacity(capacity), + latency_mean(latency_mean), + failure_prob(failure_prob) {} +}; diff --git a/src/sim/factory/factory.cpp b/src/sim/factory/factory.cpp new file mode 100644 index 0000000..f8ba87d --- /dev/null +++ b/src/sim/factory/factory.cpp @@ -0,0 +1,62 @@ +#include "entity_factory.h" +#include + +using std::make_unique; +using std::runtime_error; +using std::vector; + +// ---------------- Public ---------------- + +void EntityFactory::build( + const vector& ir, + Simulation& simulation +) { + create_entities(ir, simulation); +} + +// ---------------- Private ---------------- + +void EntityFactory::create_entities( + const vector& ir, + Simulation& simulation +) { + for (const auto& node : ir) { + + switch (node.type) { + + case IRType::SERVICE: + simulation.entities[node.id] = + make_unique( + node.id, + node.capacity, + node.latency_mean, + node.failure_prob + ); + break; + + case IRType::DATABASE: + simulation.entities[node.id] = + make_unique( + node.id, + node.capacity, + node.latency_mean, + node.failure_prob + ); + break; + + case IRType::NETWORK_LINK: + simulation.entities[node.id] = + make_unique( + node.id, + node.from, + node.to, + node.latency_mean, + node.failure_prob + ); + break; + + default: + throw runtime_error("Unknown IRType"); + } + } +} diff --git a/src/sim/factory/factory.h b/src/sim/factory/factory.h new file mode 100644 index 0000000..ec076d4 --- /dev/null +++ b/src/sim/factory/factory.h @@ -0,0 +1,53 @@ +#pragma once +#include +#include +#include +#include + +// Entities +#include "../entities/service.h" +#include "../entities/database.h" +#include "../entities/network_link.h" + +// IR (will be changed after UI -> frontend is finalised) + +enum class IRType { + SERVICE, + DATABASE, + NETWORK_LINK +}; + +struct IRNode { + std::string id; + IRType type; + + // For network links + std::string from; + std::string to; + + // Common parameters + int capacity; + double latency_mean; + double failure_prob; +}; + +// ------------- Simulation Registry ------------- + +struct Simulation { + std::unordered_map> entities; +}; + +// Factory +class EntityFactory { +public: + void build( + const std::vector& ir, + Simulation& simulation + ); + +private: + void create_entities( + const std::vector& ir, + Simulation& simulation + ); +};