Commit 7f922342 authored by Dominik Charousset's avatar Dominik Charousset

Merge branch 'issue/1399'

Close #1399.
parents d70d3a51 26d23666
......@@ -141,10 +141,20 @@ constexpr auto network_backend = std::string_view{"default"};
namespace caf::defaults::flow {
/// Defines how much demand should accumulate before signaling demand upstream.
/// A minimum demand is used by operators such as `observe_on` to avoid overly
/// frequent signaling across asynchronous barriers.
constexpr auto min_demand = size_t{8};
/// Defines how many items a single batch may contain.
constexpr auto batch_size = size_t{32};
/// Limits how many items an operator buffers internally.
constexpr auto buffer_size = size_t{128};
/// Limits the number of concurrent subscriptions for operators such as `merge`.
constexpr auto max_concurrent = size_t{8};
} // namespace caf::defaults::flow
namespace caf::defaults::net {
......
......@@ -4,6 +4,9 @@
#pragma once
#include <cstddef>
#include <utility>
namespace caf::flow::gen {
/// A generator that emits a single value once.
......
This diff is collapsed.
......@@ -144,7 +144,7 @@ public:
}
void swap(unordered_flat_map& other) {
xs_.swap(other);
xs_.swap(other.xs_);
}
// -- insertion -------------------------------------------------------------
......
......@@ -12,6 +12,7 @@
#include "caf/flow/observable.hpp"
#include "caf/flow/observable_builder.hpp"
#include "caf/flow/scoped_coordinator.hpp"
#include "caf/scheduled_actor/flow.hpp"
using namespace caf;
......@@ -68,4 +69,30 @@ SCENARIO("sum up all the multiples of 3 or 5 below 1000") {
}
}
TEST_CASE("GH-1399 regression") {
// Original issue: flat_map does not limit the demand it signals upstream.
// When running flat_map on an unbound sequence like iota-observable, it
// produces an infinite amount of observables without ever giving downstream
// operators the opportunity to cut off the flow items.
auto worker_fn = []() -> behavior {
return {
[](int x) { return -x; },
};
};
auto worker = sys.spawn(worker_fn);
auto results = std::make_shared<std::vector<int>>();
auto run_fn = [worker, results](caf::event_based_actor* self) {
self->make_observable()
.iota(1)
.flat_map([self, worker](int x) {
return self->request(worker, infinite, x).as_observable<int32_t>();
})
.take(10)
.for_each([results](int value) { results->push_back(value); });
};
sys.spawn(run_fn);
run();
CHECK_EQ(*results, ls(-1, -2, -3, -4, -5, -6, -7, -8, -9, -10));
}
END_FIXTURE_SCOPE()
......@@ -43,8 +43,9 @@ struct fixture : test_coordinator_fixture<> {
template <class T, class... Ts>
auto raw_sub(flow::observer<T> out, Ts&&... xs) {
using flow::observable;
auto ptr = make_counted<flow::op::merge_sub<T>>(ctx.get(), out);
(ptr->subscribe_to(xs), ...);
auto ptr = make_counted<flow::op::merge_sub<T>>(ctx.get(), out,
sizeof...(Ts));
(ptr->on_next(xs), ...);
out.on_subscribe(flow::subscription{ptr});
return ptr;
}
......@@ -54,7 +55,7 @@ struct fixture : test_coordinator_fixture<> {
BEGIN_FIXTURE_SCOPE(fixture)
SCENARIO("the merge operator combine inputs") {
SCENARIO("the merge operator combines inputs") {
GIVEN("two observables") {
WHEN("merging them to a single observable") {
THEN("the observer receives the output of both sources") {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment