From 60e854f8f56dc0c0dbc28ff8a938f7b61a219fb2 Mon Sep 17 00:00:00 2001 From: Balazs Racz <balazs.racz@gmail.com> Date: Sun, 15 Nov 2020 00:27:52 +0100 Subject: [PATCH] Adds support for conflict handling in the bulk alias allocator. --- src/openlcb/AliasAllocator.cxxtest | 110 +++++++++++++++++++++++------ src/openlcb/BulkAliasAllocator.cxx | 21 ++++++ 2 files changed, 109 insertions(+), 22 deletions(-) diff --git a/src/openlcb/AliasAllocator.cxxtest b/src/openlcb/AliasAllocator.cxxtest index 44080c417..621c6559b 100644 --- a/src/openlcb/AliasAllocator.cxxtest +++ b/src/openlcb/AliasAllocator.cxxtest @@ -50,9 +50,55 @@ protected: } } + /// Pre-generates some aliases into a vector. + void generate_aliases(AliasAllocator *alloc, unsigned count) + { + set_seed(0x555, alloc); + run_x([this, count, alloc]() { + for (unsigned i = 0; i < count; i++) + { + auto a = alloc->get_new_seed(); + LOG(INFO, "alias %03X", a); + aliases_.push_back(a); + } + }); + set_seed(0x555, alloc); + } + + /// Expects that CID frames are sent to the bus. + /// @param begin iterator into alias array + /// @param end iterator (end) into alias array + template <typename It> void expect_cid(It begin, It end) + { + for (auto it = begin; it != end; ++it) + { + NodeAlias a = *it; + string msg = StringPrintf("cid %03X", a); + LOG(INFO, "cid %03X", a); + expect_packet(StringPrintf(":X17020%03XN;", a)); + expect_packet(StringPrintf(":X1610D%03XN;", a)); + expect_packet(StringPrintf(":X15000%03XN;", a)); + expect_packet(StringPrintf(":X14003%03XN;", a)); + } + } + + /// Expects that RID frames are sent to the bus. + /// @param begin iterator into alias array + /// @param end iterator (end) into alias array + template <typename It> void expect_rid(It begin, It end) + { + for (auto it = begin; it != end; ++it) + { + NodeAlias a = *it; + LOG(INFO, "rid %03X", a); + expect_packet(StringPrintf(":X10700%03XN;", a)); + } + } + Buffer<AliasInfo> *b_; AliasAllocator alias_allocator_; std::unique_ptr<BulkAliasAllocatorInterface> bulkAllocator_; + std::vector<NodeAlias> aliases_; }; TEST_F(AsyncAliasAllocatorTest, SetupTeardown) @@ -224,34 +270,15 @@ TEST_F(AsyncAliasAllocatorTest, DifferentGenerated) TEST_F(AsyncAliasAllocatorTest, BulkFew) { - set_seed(0x555, ifCan_->alias_allocator()); - std::vector<NodeAlias> aliases; - run_x([this, &aliases]() { - for (unsigned i = 0; i < 5; i++) - { - auto a = ifCan_->alias_allocator()->get_new_seed(); - aliases.push_back(a); - } - }); - for (unsigned i = 0; i < 5; i++) { - auto a = aliases[i]; - LOG(INFO, "alias %03X", a); - expect_packet(StringPrintf(":X17020%03XN;", a)); - expect_packet(StringPrintf(":X1610D%03XN;", a)); - expect_packet(StringPrintf(":X15000%03XN;", a)); - expect_packet(StringPrintf(":X14003%03XN;", a)); - } + generate_aliases(ifCan_->alias_allocator(), 5); + expect_cid(aliases_.begin(), aliases_.end()); LOG(INFO, "invoke"); - set_seed(0x555, ifCan_->alias_allocator()); auto start_time = os_get_time_monotonic(); auto invocation = invoke_flow_nowait(bulkAllocator_.get(), 5); wait(); LOG(INFO, "expect RIDs"); clear_expect(true); - for (unsigned i = 0; i < 5; i++) { - auto a = aliases[i]; - expect_packet(StringPrintf(":X10700%03XN;", a)); - } + expect_rid(aliases_.begin(), aliases_.end()); LOG(INFO, "wait for complete"); invocation->wait(); clear_expect(true); @@ -259,4 +286,43 @@ TEST_F(AsyncAliasAllocatorTest, BulkFew) EXPECT_LT(MSEC_TO_NSEC(200), end_time - start_time); } +TEST_F(AsyncAliasAllocatorTest, BulkConflict) +{ + generate_aliases(ifCan_->alias_allocator(), 7); + clear_expect(true); + expect_cid(aliases_.begin(), aliases_.begin() + 5); + LOG(INFO, "invoke"); + auto invocation = invoke_flow_nowait(bulkAllocator_.get(), 5); + wait(); + LOG(INFO, "send conflicts"); + clear_expect(true); + expect_cid(aliases_.begin()+5, aliases_.end()); + send_packet(StringPrintf(":X10700%03XN;", aliases_[0])); + send_packet(StringPrintf(":X10700%03XN;", aliases_[1])); + wait(); + usleep(10000); + wait(); + LOG(INFO, "expect RIDs"); + clear_expect(true); + expect_rid(aliases_.begin() + 2, aliases_.end()); + LOG(INFO, "wait for complete"); + invocation->wait(); + clear_expect(true); +} + +TEST_F(AsyncAliasAllocatorTest, BulkMany) +{ + generate_aliases(ifCan_->alias_allocator(), 150); + expect_cid(aliases_.begin(), aliases_.end()); + LOG(INFO, "invoke"); + auto invocation = invoke_flow_nowait(bulkAllocator_.get(), 150); + wait(); + LOG(INFO, "expect RIDs"); + clear_expect(true); + expect_rid(aliases_.begin(), aliases_.end()); + LOG(INFO, "wait for complete"); + invocation->wait(); + clear_expect(true); +} + } // namespace openlcb diff --git a/src/openlcb/BulkAliasAllocator.cxx b/src/openlcb/BulkAliasAllocator.cxx index c19e5855e..ba9deafca 100644 --- a/src/openlcb/BulkAliasAllocator.cxx +++ b/src/openlcb/BulkAliasAllocator.cxx @@ -53,6 +53,7 @@ class BulkAliasAllocator : public CallableFlow<BulkAliasRequest> pendingAliasesByKey_.clear(); nextToStampTime_ = 0; nextToClaim_ = 0; + if_can()->frame_dispatcher()->register_handler(&conflictHandler_, 0, 0); return call_immediately(STATE(send_cid_frames)); } @@ -103,6 +104,11 @@ class BulkAliasAllocator : public CallableFlow<BulkAliasRequest> { return complete(); } + if (request()->numAliases_) + { + // Some conflicts were identified, go and allocate more. + return call_immediately(STATE(send_cid_frames)); + } auto ctime = relative_time(); unsigned num_sent = 0; bn_.reset(this); @@ -140,12 +146,27 @@ class BulkAliasAllocator : public CallableFlow<BulkAliasRequest> Action complete() { + if_can()->frame_dispatcher()->unregister_handler_all(&conflictHandler_); pendingAliasesByTime_.clear(); pendingAliasesByKey_.clear(); return return_ok(); } private: + void handle_conflict(Buffer<CanMessageData> *message) + { + auto rb = get_buffer_deleter(message); + auto alias = CanDefs::get_src(GET_CAN_FRAME_ID_EFF(*message->data())); + auto it = pendingAliasesByKey_.find(alias); + if (it != pendingAliasesByKey_.end() && !it->hasConflict_) { + it->hasConflict_ = 1; + ++request()->numAliases_; + } + } + + /// Listens to incoming CAN frames and handles alias conflicts. + IncomingFrameHandler::GenericHandler conflictHandler_{this, &BulkAliasAllocator::handle_conflict}; + /// How many count to wait before sending out the RID frames. One count is /// 10 msec (see { \link relative_time } ). static constexpr unsigned ALLOCATE_DELAY = 20;