ravel
Deterministic simulation testing for C++. Seed a bug, replay it exact.
Loading...
Searching...
No Matches
network.hpp
1#pragma once
2
3#include <coroutine>
4#include <cstddef>
5#include <deque>
6#include <optional>
7#include <string>
8#include <utility>
9
10#include "ravel/clock.hpp"
11#include "ravel/rng.hpp"
12#include "ravel/scheduler.hpp"
13#include "ravel/trace.hpp"
14
15namespace ravel {
16
17using ChannelId = std::size_t;
18using Message = std::string;
19
33
43class Channel {
44 public:
46 Channel(ChannelId id, std::string from, std::string to, FaultSpec fault,
47 Scheduler& scheduler, VirtualRng& rng, Trace& trace);
48
50 Channel(const Channel&) = delete;
51 Channel& operator=(const Channel&) = delete;
52
54 const std::string& from() const noexcept { return from_; }
56 const std::string& to() const noexcept { return to_; }
58 const FaultSpec& fault() const noexcept { return fault_; }
59
62 void send(Message message);
63
66 public:
67 bool await_ready() const noexcept { return false; }
68 void await_suspend(std::coroutine_handle<>) const { channel_.wait_for_message(); }
69 Message await_resume() const { return channel_.take_message(); }
70
71 private:
72 friend class Channel;
73 explicit ReceiveAwaiter(Channel& channel) noexcept : channel_(channel) {}
74 Channel& channel_;
75 };
76
78 [[nodiscard]] ReceiveAwaiter receive() noexcept { return ReceiveAwaiter(*this); }
79
83 public:
84 bool await_ready() const noexcept { return false; }
85 void await_suspend(std::coroutine_handle<>) const { channel_.wait_for_message(timeout_); }
86 std::optional<Message> await_resume() const { return channel_.take_message_if_any(); }
87
88 private:
89 friend class Channel;
90 TimedReceiveAwaiter(Channel& channel, VirtualClock::Tick timeout) noexcept
91 : channel_(channel), timeout_(timeout) {}
92 Channel& channel_;
93 VirtualClock::Tick timeout_;
94 };
95
98 [[nodiscard]] TimedReceiveAwaiter receive_within(VirtualClock::Tick timeout) noexcept {
99 return TimedReceiveAwaiter(*this, timeout);
100 }
101
106 void clear_inbox() { inbox_.clear(); }
107 private:
108 void deliver(Message message);
109 void wait_for_message(std::optional<VirtualClock::Tick> timeout = std::nullopt);
110 Message take_message();
111 std::optional<Message> take_message_if_any();
112 void record(TraceEventKind kind) { trace_.record({scheduler_.now(), id_, kind}); }
113
114 ChannelId id_;
115 std::string from_;
116 std::string to_;
117 FaultSpec fault_;
118 Scheduler& scheduler_;
119 VirtualRng& rng_;
120 Trace& trace_;
121
122 std::deque<Message> inbox_;
123
124 struct Waiter {
125 TaskId task;
126 std::uint64_t id;
127 };
128 std::optional<Waiter> waiting_receiver_;
129 std::uint64_t waits_started_ = 0;
130 VirtualClock::Tick last_delivery_at_ = 0;
131};
132
133} // namespace ravel
What receive() returns. It is only ever co_awaited.
Definition network.hpp:65
Like ReceiveAwaiter, but gives up: yields nothing if no message has arrived once timeout virtual tick...
Definition network.hpp:82
A virtual, one-way, in-process channel between two named endpoints.
Definition network.hpp:43
Channel(const Channel &)=delete
Pending deliveries refer to this object, so it must never move.
TimedReceiveAwaiter receive_within(VirtualClock::Tick timeout) noexcept
Waits up to timeout ticks for a message: auto m = co_await channel.receive_within(50); The result is ...
Definition network.hpp:98
const FaultSpec & fault() const noexcept
The fault settings this channel was created with.
Definition network.hpp:58
ReceiveAwaiter receive() noexcept
Waits for the next message: ravel::Message m = co_await channel.receive();
Definition network.hpp:78
void clear_inbox()
Throws away messages that were delivered but not yet received.
Definition network.hpp:106
Channel(ChannelId id, std::string from, std::string to, FaultSpec fault, Scheduler &scheduler, VirtualRng &rng, Trace &trace)
Created by Simulation::add_channel; you do not construct one yourself.
void send(Message message)
Applies the fault spec: the message is dropped, or delivered after a random delay.
const std::string & to() const noexcept
The receiving endpoint's name.
Definition network.hpp:56
const std::string & from() const noexcept
The sending endpoint's name.
Definition network.hpp:54
Cooperative, single-threaded task scheduler.
Definition scheduler.hpp:65
VirtualClock::Tick now() const noexcept
The current virtual time.
Definition scheduler.hpp:133
Ordered record of everything that happened during a run (scheduling decisions and message fates),...
Definition trace.hpp:48
void record(const TraceEvent &event)
Appends an event and folds it into the digest.
std::uint64_t Tick
Virtual time, in ticks. A tick has no fixed real-world length.
Definition clock.hpp:15
The one source of randomness a Simulation may use.
Definition rng.hpp:28
Injectable fault behavior for a Channel.
Definition network.hpp:23
double loss_probability
In [0, 1]: chance that a message is dropped.
Definition network.hpp:24
VirtualClock::Tick latency_max
Delay is uniform in [min, max].
Definition network.hpp:27
bool allow_reorder
Off: messages arrive in the order they were sent (delays are raised so none overtakes an earlier one)...
Definition network.hpp:31
VirtualClock::Tick latency_min
The lower end of the delay range: a delivered message takes at least this many ticks.
Definition network.hpp:26