initial implementation
This commit is contained in:
commit
532d48529f
29 changed files with 2329 additions and 0 deletions
93
src/reactor/AbstractEventProcessor.cpp
Normal file
93
src/reactor/AbstractEventProcessor.cpp
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/* @file AbstractEventProcessor.cp */
|
||||
|
||||
#include "AbstractEventProcessor.hpp"
|
||||
#include "xo/indentlog/print/tostr.hpp"
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
|
||||
namespace xo {
|
||||
using ref::rp;
|
||||
using ref::brw;
|
||||
using xo::tostr;
|
||||
using std::uint32_t;
|
||||
|
||||
namespace reactor {
|
||||
namespace {
|
||||
/* search all event processors ep reachable (dowstream) from x,
|
||||
* add to *m;
|
||||
*/
|
||||
void
|
||||
map_network_helper(brw<AbstractEventProcessor> x,
|
||||
uint32_t * tsort_ix,
|
||||
std::unordered_map<AbstractEventProcessor*, uint32_t> * m)
|
||||
{
|
||||
if (m->contains(x.get()))
|
||||
return;
|
||||
|
||||
auto fn = [tsort_ix, m]
|
||||
(brw<AbstractEventProcessor> ep)
|
||||
{
|
||||
map_network_helper(ep, tsort_ix, m);
|
||||
};
|
||||
|
||||
x->visit_direct_consumers(fn);
|
||||
|
||||
/* postorder! */
|
||||
(*m)[x.get()] = ++(*tsort_ix);
|
||||
|
||||
} /*map_network_helper*/
|
||||
} /*namespace*/
|
||||
|
||||
std::vector<rp<AbstractEventProcessor>>
|
||||
AbstractEventProcessor::map_network(rp<AbstractEventProcessor> const & x)
|
||||
{
|
||||
std::unordered_map<AbstractEventProcessor *, std::uint32_t> network_map;
|
||||
|
||||
/* index event processors in reverse topological order:
|
||||
* if B is (directly or indirectly) downstream from A,
|
||||
* then tsort_ix(B) < tsort_ix(A)
|
||||
*/
|
||||
uint32_t tsort_ix = 0;
|
||||
|
||||
/* depth-first traversal, detect and short-circuit on dup paths */
|
||||
map_network_helper(x.borrow(), &tsort_ix, &network_map);
|
||||
|
||||
/* invariant: tsort_ix = #of event processors in network */
|
||||
uint32_t n = tsort_ix;
|
||||
|
||||
/* network_map, now in a topologically sorted order */
|
||||
std::map<uint32_t, AbstractEventProcessor *> tsorted_map;
|
||||
{
|
||||
for(auto const & x : network_map) {
|
||||
uint32_t tsort_ix = x.second;
|
||||
AbstractEventProcessor * ep = x.first;
|
||||
|
||||
tsorted_map[n - tsort_ix] = ep;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<rp<AbstractEventProcessor>> retval;
|
||||
{
|
||||
for(auto const & x : tsorted_map)
|
||||
retval.push_back(x.second);
|
||||
}
|
||||
|
||||
return retval;
|
||||
} /*map_network*/
|
||||
|
||||
void
|
||||
AbstractEventProcessor::display(std::ostream & os) const
|
||||
{
|
||||
os << "<AbstractSource>";
|
||||
} /*display*/
|
||||
|
||||
std::string
|
||||
AbstractEventProcessor::display_string() const
|
||||
{
|
||||
return tostr(*this);
|
||||
} /*display_string*/
|
||||
|
||||
} /*namespace reactor*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end AbstractEventProcessor.cpp */
|
||||
84
src/reactor/AbstractSource.cpp
Normal file
84
src/reactor/AbstractSource.cpp
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/* @file AbstractSource.cpp */
|
||||
|
||||
#include "AbstractSource.hpp"
|
||||
#include "xo/indentlog/scope.hpp"
|
||||
#include "xo/webutil/StreamEndpointDescr.hpp"
|
||||
//#include "indentlog/scope.hpp"
|
||||
|
||||
namespace xo {
|
||||
using xo::web::StreamEndpointDescr;
|
||||
using xo::reactor::AbstractSink;
|
||||
using xo::ref::rp;
|
||||
//using xo::scope;
|
||||
//using xo::tostr;
|
||||
|
||||
namespace reactor {
|
||||
StreamEndpointDescr
|
||||
AbstractSource::stream_endpoint_descr(std::string const & url_prefix)
|
||||
{
|
||||
auto subscribe_fn
|
||||
= ([this]
|
||||
(rp<AbstractSink> const & ws_sink)
|
||||
{
|
||||
//scope lscope("AbstractSource::stream_endpoint_descr.subscribe_fn");
|
||||
|
||||
/* ws_sink created by websocket, sends events to websocket as json
|
||||
* see [websock/WebsocketSink]
|
||||
*/
|
||||
return this->attach_sink(ws_sink);
|
||||
});
|
||||
|
||||
auto unsubscribe_fn
|
||||
= ([this]
|
||||
(CallbackId id)
|
||||
{
|
||||
this->detach_sink(id);
|
||||
});
|
||||
|
||||
return StreamEndpointDescr(url_prefix,
|
||||
subscribe_fn,
|
||||
unsubscribe_fn);
|
||||
} /*stream_endpoint_descr*/
|
||||
|
||||
uint64_t
|
||||
AbstractSource::deliver_n(uint64_t n)
|
||||
{
|
||||
uint64_t retval = 0;
|
||||
|
||||
for (uint64_t i=0; i<n; ++i) {
|
||||
uint64_t n1 = this->deliver_one();
|
||||
|
||||
if (n1 == 0) {
|
||||
/* short-circuit if source has less than n
|
||||
* events available
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
retval += n1;
|
||||
}
|
||||
|
||||
return retval;
|
||||
} /*deliver_n*/
|
||||
|
||||
uint64_t
|
||||
AbstractSource::deliver_all()
|
||||
{
|
||||
uint64_t retval = 0;
|
||||
|
||||
for (;;) {
|
||||
uint64_t n1 = this->deliver_one();
|
||||
|
||||
if (n1 == 0)
|
||||
break;
|
||||
|
||||
retval += n1;
|
||||
}
|
||||
|
||||
return retval;
|
||||
} /*deliver_all*/
|
||||
|
||||
} /*namespace reactor*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end AbstractSource.cpp */
|
||||
21
src/reactor/CMakeLists.txt
Normal file
21
src/reactor/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# xo-reactor/src/reactor/CMakeLists.txt
|
||||
|
||||
set(SELF_LIB reactor)
|
||||
set(SELF_SRCS
|
||||
AbstractEventProcessor.cpp AbstractSource.cpp ReactorSource.cpp
|
||||
Sink.cpp
|
||||
Reactor.cpp PollingReactor.cpp
|
||||
init_reactor.cpp)
|
||||
|
||||
xo_add_shared_library(${SELF_LIB} ${PROJECT_VERSION} 1 ${SELF_SRCS})
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# external dependencies
|
||||
|
||||
# note: changes to xo_dependency() calls here
|
||||
# must coordinate with find_dependency() calls
|
||||
# in xo-reactor/cmake/reactorConfig.cmake.in
|
||||
#
|
||||
xo_dependency(${SELF_LIB} reflect)
|
||||
xo_dependency(${SELF_LIB} webutil)
|
||||
xo_dependency(${SELF_LIB} callback)
|
||||
88
src/reactor/PollingReactor.cpp
Normal file
88
src/reactor/PollingReactor.cpp
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/* @file PollingReactor.cpp */
|
||||
|
||||
#include "PollingReactor.hpp"
|
||||
|
||||
namespace xo {
|
||||
using ref::brw;
|
||||
using std::size_t;
|
||||
using std::uint64_t;
|
||||
using std::int64_t;
|
||||
|
||||
namespace reactor {
|
||||
bool
|
||||
PollingReactor::add_source(brw<ReactorSource> src)
|
||||
{
|
||||
/* make sure src does not already appear in .source_v[] */
|
||||
for(ReactorSourcePtr const & x : this->source_v_) {
|
||||
if(x.get() == src.get()) {
|
||||
throw std::runtime_error("PollingReactor::add_source; source already present");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
src->notify_reactor_add(this);
|
||||
|
||||
this->source_v_.push_back(src.get());
|
||||
|
||||
return true;
|
||||
} /*add_source*/
|
||||
|
||||
bool
|
||||
PollingReactor::remove_source(brw<ReactorSource> src)
|
||||
{
|
||||
auto ix = std::find(this->source_v_.begin(),
|
||||
this->source_v_.end(),
|
||||
src);
|
||||
|
||||
if(ix != this->source_v_.end()) {
|
||||
src->notify_reactor_remove(this);
|
||||
|
||||
this->source_v_.erase(ix);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} /*remove_source*/
|
||||
|
||||
int64_t
|
||||
PollingReactor::find_nonempty_source(size_t start_ix)
|
||||
{
|
||||
size_t z = this->source_v_.size();
|
||||
|
||||
/* search sources [ix .. z) */
|
||||
for(size_t ix = start_ix; ix < z; ++ix) {
|
||||
brw<ReactorSource> src = this->source_v_[ix];
|
||||
|
||||
if(src->is_nonempty())
|
||||
return ix;
|
||||
}
|
||||
|
||||
/* search source [0 .. ix) */
|
||||
for(size_t ix = 0, n = std::min(start_ix, z); ix < n; ++ix) {
|
||||
brw<ReactorSource> src = this->source_v_[ix];
|
||||
|
||||
if(src->is_nonempty())
|
||||
return ix;
|
||||
}
|
||||
|
||||
return -1;
|
||||
} /*find_nonempty_source*/
|
||||
|
||||
uint64_t
|
||||
PollingReactor::run_one()
|
||||
{
|
||||
int64_t ix = this->find_nonempty_source(this->next_ix_);
|
||||
|
||||
if(ix >= 0) {
|
||||
brw<ReactorSource> src = this->source_v_[ix];
|
||||
|
||||
return src->deliver_one();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} /*run_one*/
|
||||
} /*namespace reactor*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end PollingReactor.cpp */
|
||||
26
src/reactor/Reactor.cpp
Normal file
26
src/reactor/Reactor.cpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/* file Reactor.cpp
|
||||
*
|
||||
* author: Roland Conybeare, Sep 2022
|
||||
*/
|
||||
|
||||
#include "Reactor.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace reactor {
|
||||
void
|
||||
Reactor::run_n(int32_t n)
|
||||
{
|
||||
if (n == -1) {
|
||||
for (;;) {
|
||||
this->run_one();
|
||||
}
|
||||
} else {
|
||||
for (int32_t i=0; i<n; ++i) {
|
||||
this->run_one();
|
||||
}
|
||||
}
|
||||
} /*run_n*/
|
||||
} /*namespace reactor*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end Reactor.cpp */
|
||||
34
src/reactor/ReactorSource.cpp
Normal file
34
src/reactor/ReactorSource.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/* @file Source.cpp */
|
||||
|
||||
#include "ReactorSource.hpp"
|
||||
#include "xo/indentlog/print/time.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
using xo::time::utc_nanos;
|
||||
|
||||
namespace reactor {
|
||||
utc_nanos
|
||||
ReactorSource::online_current_tm() const
|
||||
{
|
||||
/* for an online source:
|
||||
* .is_exhausted() must always be false;
|
||||
* this implies that .sim_current_tm() should
|
||||
* not be called in the first place
|
||||
*/
|
||||
|
||||
assert(false);
|
||||
|
||||
return time::timeutil::epoch();
|
||||
} /*online_current_tm*/
|
||||
|
||||
std::uint64_t
|
||||
ReactorSource::online_advance_until(utc_nanos /*tm*/,
|
||||
bool /*replay_flag*/)
|
||||
{
|
||||
return 0;
|
||||
} /*online_advance_until*/
|
||||
} /*namespace reactor*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end Source.cpp */
|
||||
18
src/reactor/Sink.cpp
Normal file
18
src/reactor/Sink.cpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/* @file Sink.cpp */
|
||||
|
||||
#include "Sink.hpp"
|
||||
#include "xo/refcnt/Refcounted.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace reactor {
|
||||
#ifdef NOT_USING
|
||||
ref::rp<SinkToConsole<std::pair<xo::time::utc_nanos, double>>>
|
||||
TemporaryTest::realization_printer()
|
||||
{
|
||||
return new SinkToConsole<std::pair<xo::time::utc_nanos, double>>();
|
||||
} /*realization_printer*/
|
||||
#endif
|
||||
} /*namespace reactor*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end Sink.cpp */
|
||||
31
src/reactor/init_reactor.cpp
Normal file
31
src/reactor/init_reactor.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/* file init_reactor.cpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2022
|
||||
*/
|
||||
|
||||
#include "init_reactor.hpp"
|
||||
#include "xo/reflect/init_reflect.hpp"
|
||||
|
||||
namespace xo {
|
||||
void
|
||||
InitSubsys<S_reactor_tag>::init()
|
||||
{
|
||||
/* TODO: reflect reactor types */
|
||||
} /*init*/
|
||||
|
||||
InitEvidence
|
||||
InitSubsys<S_reactor_tag>::require()
|
||||
{
|
||||
InitEvidence retval;
|
||||
|
||||
/* subsystem dependencies for reactor/ */
|
||||
retval ^= InitSubsys<S_reflect_tag>::require();
|
||||
|
||||
/* reactor/'s own initialization code */
|
||||
retval ^= Subsystem::provide<S_reactor_tag>("reactor", &init);
|
||||
|
||||
return retval;
|
||||
} /*require*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end init_reactor.cpp */
|
||||
Loading…
Add table
Add a link
Reference in a new issue