lintel 0.2.0
Loading...
Searching...
No Matches
EventBus.h
Go to the documentation of this file.
1#ifndef LINTEL_EVENTBUS_H
2#define LINTEL_EVENTBUS_H
3
4#include <atomic>
5#include <cstddef>
6#include <cstdint>
7#include <optional>
8#include <string>
9
12
13namespace lintel {
16{
18 static constexpr std::size_t MAX_TOPICS = 16;
20 static constexpr std::size_t MAX_SUBSCRIBERS = 32;
22 static constexpr std::size_t MAX_CAPACITY = 65534;
23};
24
50
73{
74public:
84 EventBus(const std::string &name, const EventBusConfig &config, ShmSegmentAccessor segment);
85
89
90 EventBus(const EventBus &) = delete;
91 EventBus &operator=(const EventBus &) = delete;
92
94 [[nodiscard]] const char *getName() const;
95
98
100 [[nodiscard]] bool isLockFree() const;
101
105 bool registerTopic(const std::string &topic);
106
109 [[nodiscard]] bool isTopicRegistered(const std::string &topic) const;
110
112 [[nodiscard]] std::size_t topicCount() const;
113
118 bool subscribe(const std::string &topic, const std::string &subscriber);
119
124 bool unsubscribe(const std::string &topic, const std::string &subscriber);
125
129 [[nodiscard]] bool isSubscribed(const std::string &topic, const std::string &subscriber) const;
130
133 [[nodiscard]] std::size_t numberOfSubscribersOf(const std::string &topic) const;
134
136 [[nodiscard]] std::size_t subscriberCount() const;
137
141 bool publish(const Event &event);
142
147
150 [[nodiscard]] std::optional<Event> receive();
151
155 [[nodiscard]] std::optional<Event> receiveOf(const std::string &subscriber);
156
158 [[nodiscard]] bool isEmpty() const;
159
162 [[nodiscard]] bool isEmptyOf(const std::string &subscriber) const;
163
165 [[nodiscard]] std::int64_t sequenceOf() const;
166
168 [[nodiscard]] std::uint64_t droppedEventsOf() const;
169
171 void reset();
172
176 static std::size_t requiredSize(const EventBusConfig &config);
177
178private:
191 class ShmRing
192 {
193 public:
195 static constexpr std::size_t CACHE_LINE = 64;
196
198 struct alignas(CACHE_LINE) Slot
199 {
200 std::atomic<std::uint64_t> sequence{ 0 };
202 };
203
205 ShmRing() = default;
206
211 ShmRing(std::size_t capacity, ShmSegmentAccessor segment);
212
214 ~ShmRing();
215
216 ShmRing(const ShmRing &) = delete;
217 ShmRing &operator=(const ShmRing &) = delete;
218
222 bool push(const Event &event);
223
227 bool pop(Event &out);
228
231 [[nodiscard]] bool empty() const;
232
234 [[nodiscard]] static bool isLockFree();
235
236 private:
237 std::atomic<std::uint64_t> m_head{ 0 };
238 std::byte m_headPadding[CACHE_LINE - sizeof(std::uint64_t)]{};
239 std::atomic<std::uint64_t> m_tail{ 0 };
240 std::byte m_tailPadding[CACHE_LINE - sizeof(std::uint64_t)]{};
241 std::size_t m_capacity = 0;
242 ShmSegmentAccessor m_segment;
243 std::byte *m_allocation = nullptr;
244 std::int64_t m_bufferOffset = 0;
245
246 [[nodiscard]] Slot *buffer();
247 [[nodiscard]] const Slot *buffer() const;
248 };
249
251 struct TopicEntry
252 {
253 char name[Event::NAME_SIZE]{};
254 std::atomic<std::size_t> subscriberCount{ 0 };
255 std::size_t subscribers[EventBusLimits::MAX_SUBSCRIBERS]{};
256 };
257
259 struct SubscriberEntry
260 {
261 char name[Event::NAME_SIZE]{};
262 std::atomic<bool> active{ false };
263 std::atomic<std::size_t> topicRefCount{ 0 };
264 };
265
271 class RegistryLock
272 {
273 public:
274 RegistryLock();
275
277 void acquire() const;
278
280 void release() const;
281
282 private:
283 static constexpr std::uint64_t STALE_THRESHOLD_MS = 500;
284 static constexpr std::uint64_t TIMESTAMP_MASK = 0xFFFFFFFFu;
285
286 mutable std::atomic<std::uint64_t> m_state;
287
288 static std::uint64_t ownerId();
289 static std::uint64_t nowMs();
290 static bool isStale(std::uint64_t state);
291 static std::uint64_t encode();
292 };
293
294 char m_name[Event::NAME_SIZE]{};
295 std::size_t m_busCapacity = 0;
296 std::size_t m_subscriberCapacity = 0;
297 std::size_t m_maxTopics = 0;
298 std::size_t m_maxSubscribers = 0;
299 std::atomic<std::int64_t> m_sequence{ 0 };
300 std::atomic<std::uint64_t> m_droppedEvents{ 0 };
301 std::atomic<std::size_t> m_topicCount{ 0 };
302 std::atomic<std::size_t> m_subscriberCount{ 0 };
303 RegistryLock m_registryLock;
304 ShmRing m_bus;
305 TopicEntry m_topics[EventBusLimits::MAX_TOPICS]{};
306 SubscriberEntry m_subscribers[EventBusLimits::MAX_SUBSCRIBERS]{};
307 alignas(ShmRing) std::byte m_subscriberQueues[EventBusLimits::MAX_SUBSCRIBERS][sizeof(ShmRing)]{};
308
309 [[nodiscard]] int findTopicIndex(const char *topic) const;
310 [[nodiscard]] int findSubscriberIndex(const char *subscriber) const;
311 [[nodiscard]] ShmRing &subscriberQueueOf(std::size_t index);
312 [[nodiscard]] const ShmRing &subscriberQueueOf(std::size_t index) const;
313
314 static void copyInto(char (&destination)[Event::NAME_SIZE], const std::string &value);
315 [[nodiscard]] static bool nameEquals(const char *lhs, const char *rhs);
316};
317
324{
325public:
326 virtual ~IEventBus() = default;
327
329 [[nodiscard]] virtual const char *getName() const = 0;
330
332 [[nodiscard]] virtual EventBusConfig getConfig() const = 0;
333
335 [[nodiscard]] virtual bool isLockFree() const = 0;
336
340 virtual bool registerTopic(const std::string &topic) = 0;
341
344 [[nodiscard]] virtual bool isTopicRegistered(const std::string &topic) const = 0;
345
347 [[nodiscard]] virtual std::size_t topicCount() const = 0;
348
353 virtual bool subscribe(const std::string &topic, const std::string &subscriber) = 0;
354
359 virtual bool unsubscribe(const std::string &topic, const std::string &subscriber) = 0;
360
364 [[nodiscard]] virtual bool isSubscribed(const std::string &topic, const std::string &subscriber) const = 0;
365
368 [[nodiscard]] virtual std::size_t numberOfSubscribersOf(const std::string &topic) const = 0;
369
371 [[nodiscard]] virtual std::size_t subscriberCount() const = 0;
372
376 virtual bool publish(const Event &event) = 0;
377
381 virtual bool publishToSubscribers(const Event &event) = 0;
382
385 [[nodiscard]] virtual std::optional<Event> receive() = 0;
386
390 [[nodiscard]] virtual std::optional<Event> receiveOf(const std::string &subscriber) = 0;
391
393 [[nodiscard]] virtual bool isEmpty() const = 0;
394
397 [[nodiscard]] virtual bool isEmptyOf(const std::string &subscriber) const = 0;
398
400 [[nodiscard]] virtual std::int64_t sequenceOf() const = 0;
401
403 [[nodiscard]] virtual std::uint64_t droppedEventsOf() const = 0;
404
406 virtual void reset() = 0;
407};
408
411{
412public:
415 explicit EventBusView(EventBus &bus) : m_bus(bus) {}
416
417 [[nodiscard]] const char *getName() const override { return m_bus.getName(); }
418
419 [[nodiscard]] EventBusConfig getConfig() const override { return m_bus.getConfig(); }
420
421 [[nodiscard]] bool isLockFree() const override { return m_bus.isLockFree(); }
422
423 bool registerTopic(const std::string &topic) override { return m_bus.registerTopic(topic); }
424
425 [[nodiscard]] bool isTopicRegistered(const std::string &topic) const override
426 {
427 return m_bus.isTopicRegistered(topic);
428 }
429
430 [[nodiscard]] std::size_t topicCount() const override { return m_bus.topicCount(); }
431
432 bool subscribe(const std::string &topic, const std::string &subscriber) override
433 {
434 return m_bus.subscribe(topic, subscriber);
435 }
436
437 bool unsubscribe(const std::string &topic, const std::string &subscriber) override
438 {
439 return m_bus.unsubscribe(topic, subscriber);
440 }
441
442 [[nodiscard]] bool isSubscribed(const std::string &topic, const std::string &subscriber) const override
443 {
444 return m_bus.isSubscribed(topic, subscriber);
445 }
446
447 [[nodiscard]] std::size_t numberOfSubscribersOf(const std::string &topic) const override
448 {
449 return m_bus.numberOfSubscribersOf(topic);
450 }
451
452 [[nodiscard]] std::size_t subscriberCount() const override { return m_bus.subscriberCount(); }
453
454 bool publish(const Event &event) override { return m_bus.publish(event); }
455
456 bool publishToSubscribers(const Event &event) override { return m_bus.publishToSubscribers(event); }
457
458 [[nodiscard]] std::optional<Event> receive() override { return m_bus.receive(); }
459
460 [[nodiscard]] std::optional<Event> receiveOf(const std::string &subscriber) override
461 {
462 return m_bus.receiveOf(subscriber);
463 }
464
465 [[nodiscard]] bool isEmpty() const override { return m_bus.isEmpty(); }
466
467 [[nodiscard]] bool isEmptyOf(const std::string &subscriber) const override { return m_bus.isEmptyOf(subscriber); }
468
469 [[nodiscard]] std::int64_t sequenceOf() const override { return m_bus.sequenceOf(); }
470
471 [[nodiscard]] std::uint64_t droppedEventsOf() const override { return m_bus.droppedEventsOf(); }
472
473 void reset() override { m_bus.reset(); }
474
475private:
476 EventBus &m_bus;
477};
478
479}// namespace lintel
480#endif// LINTEL_EVENTBUS_H
Definition EventBus.h:411
void reset() override
Definition EventBus.h:473
bool isSubscribed(const std::string &topic, const std::string &subscriber) const override
Definition EventBus.h:442
bool isTopicRegistered(const std::string &topic) const override
Definition EventBus.h:425
std::size_t subscriberCount() const override
Definition EventBus.h:452
bool isEmptyOf(const std::string &subscriber) const override
Definition EventBus.h:467
std::optional< Event > receive() override
Definition EventBus.h:458
bool subscribe(const std::string &topic, const std::string &subscriber) override
Definition EventBus.h:432
bool registerTopic(const std::string &topic) override
Definition EventBus.h:423
EventBusView(EventBus &bus)
Definition EventBus.h:415
const char * getName() const override
Definition EventBus.h:417
std::int64_t sequenceOf() const override
Definition EventBus.h:469
std::uint64_t droppedEventsOf() const override
Definition EventBus.h:471
EventBusConfig getConfig() const override
Definition EventBus.h:419
bool isLockFree() const override
Definition EventBus.h:421
std::optional< Event > receiveOf(const std::string &subscriber) override
Definition EventBus.h:460
std::size_t numberOfSubscribersOf(const std::string &topic) const override
Definition EventBus.h:447
std::size_t topicCount() const override
Definition EventBus.h:430
bool isEmpty() const override
Definition EventBus.h:465
bool publishToSubscribers(const Event &event) override
Definition EventBus.h:456
bool publish(const Event &event) override
Definition EventBus.h:454
bool unsubscribe(const std::string &topic, const std::string &subscriber) override
Definition EventBus.h:437
Definition EventBus.h:73
std::size_t topicCount() const
bool unsubscribe(const std::string &topic, const std::string &subscriber)
const char * getName() const
std::optional< Event > receiveOf(const std::string &subscriber)
EventBus(const EventBus &)=delete
EventBus & operator=(const EventBus &)=delete
std::int64_t sequenceOf() const
bool isLockFree() const
bool isEmpty() const
std::optional< Event > receive()
bool registerTopic(const std::string &topic)
bool isEmptyOf(const std::string &subscriber) const
EventBusConfig getConfig() const
bool isTopicRegistered(const std::string &topic) const
bool subscribe(const std::string &topic, const std::string &subscriber)
bool isSubscribed(const std::string &topic, const std::string &subscriber) const
std::uint64_t droppedEventsOf() const
bool publishToSubscribers(const Event &event)
static std::size_t requiredSize(const EventBusConfig &config)
bool publish(const Event &event)
EventBus(const std::string &name, const EventBusConfig &config, ShmSegmentAccessor segment)
std::size_t subscriberCount() const
std::size_t numberOfSubscribersOf(const std::string &topic) const
Definition Event.h:22
static constexpr std::size_t NAME_SIZE
Definition Event.h:25
Definition EventBus.h:324
virtual bool isSubscribed(const std::string &topic, const std::string &subscriber) const =0
virtual std::optional< Event > receive()=0
virtual std::uint64_t droppedEventsOf() const =0
virtual bool publishToSubscribers(const Event &event)=0
virtual const char * getName() const =0
virtual void reset()=0
virtual bool isTopicRegistered(const std::string &topic) const =0
virtual std::optional< Event > receiveOf(const std::string &subscriber)=0
virtual bool isEmpty() const =0
virtual std::int64_t sequenceOf() const =0
virtual std::size_t numberOfSubscribersOf(const std::string &topic) const =0
virtual bool unsubscribe(const std::string &topic, const std::string &subscriber)=0
virtual ~IEventBus()=default
virtual bool publish(const Event &event)=0
virtual bool isEmptyOf(const std::string &subscriber) const =0
virtual bool subscribe(const std::string &topic, const std::string &subscriber)=0
virtual bool isLockFree() const =0
virtual std::size_t subscriberCount() const =0
virtual std::size_t topicCount() const =0
virtual EventBusConfig getConfig() const =0
virtual bool registerTopic(const std::string &topic)=0
Definition ShmSegmentAccessor.h:21
Definition BaseFeature.h:6
constexpr std::string_view type_name()
Definition TypeName.h:9
Definition EventBus.h:31
std::size_t busCapacity
Definition EventBus.h:33
std::size_t maxTopics
Definition EventBus.h:37
std::size_t maxSubscribers
Definition EventBus.h:39
bool isValid() const
Definition EventBus.h:42
std::size_t subscriberCapacity
Definition EventBus.h:35
Definition EventBus.h:16
static constexpr std::size_t MAX_SUBSCRIBERS
Definition EventBus.h:20
static constexpr std::size_t MAX_CAPACITY
Definition EventBus.h:22
static constexpr std::size_t MAX_TOPICS
Definition EventBus.h:18
Definition EventBus.h:199
Event value
Definition EventBus.h:201