diff --git a/CMakeLists.txt b/CMakeLists.txt index fbb7dc0..33c1407 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,6 +119,8 @@ qt_add_executable(softbus_daemon src/core/plugin_system/IProtocolPlugin.h src/core/plugin_system/PluginManager.h src/core/plugin_system/PluginManager.cpp + src/core/plugin_system/builtins/ModbusRtuProtocolPlugin.h + src/core/plugin_system/builtins/ModbusRtuProtocolPlugin.cpp # message bus pipeline src/message_bus/pipeline/PayloadRef.h @@ -126,7 +128,12 @@ qt_add_executable(softbus_daemon src/message_bus/pipeline/PipelineEngine.h src/message_bus/pipeline/PipelineEngine.cpp src/message_bus/pipeline/stages/1_framers/IFramer.h - src/message_bus/pipeline/stages/1_framers/DefaultFramer.cpp + src/message_bus/pipeline/stages/1_framers/ModbusRtuFraming.h + src/message_bus/pipeline/stages/1_framers/ModbusRtuFraming.cpp + src/message_bus/pipeline/stages/1_framers/ModbusRtuFramer.h + src/message_bus/pipeline/stages/1_framers/ModbusRtuFramer.cpp + src/message_bus/pipeline/stages/1_framers/PassthroughFramer.h + src/message_bus/pipeline/stages/1_framers/PassthroughFramer.cpp src/message_bus/pipeline/stages/2_parsers/IParserStage.h src/message_bus/pipeline/stages/3_filters/IFilterStage.h src/message_bus/pipeline/stages/4_validators/IValidator.h @@ -179,6 +186,23 @@ endif() add_subdirectory(plugins) +option(SOFTBUS_BUILD_TESTS "Build unit tests" OFF) +if(SOFTBUS_BUILD_TESTS) + find_package(Qt6 6.5 REQUIRED COMPONENTS Test) + qt_add_executable(softbus_modbus_rtu_framer_test + tests/modbus_rtu_framer_test.cpp + src/message_bus/pipeline/stages/1_framers/ModbusRtuFraming.cpp + src/message_bus/pipeline/stages/1_framers/ModbusRtuFramer.cpp + ) + target_include_directories(softbus_modbus_rtu_framer_test PRIVATE + ${CMAKE_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src + ) + target_link_libraries(softbus_modbus_rtu_framer_test PRIVATE + Qt6::Core + Qt6::Test + ) +endif() install(TARGETS softbus_daemon BUNDLE DESTINATION . diff --git a/bin/softbus_daemon b/bin/softbus_daemon index d1fe3e9..a25886d 100755 Binary files a/bin/softbus_daemon and b/bin/softbus_daemon differ diff --git a/config/daemon_config.json b/config/daemon_config.json index 458aa64..985e3af 100644 --- a/config/daemon_config.json +++ b/config/daemon_config.json @@ -1,5 +1,14 @@ { "plugin_dir": "bin/plugins", + "pipeline": { + "parallelPipeline": false, + "parseWorkerCount": 2, + "orderedEgress": true, + "framedQueueMax": 4096, + "maxReorderDepth": 256, + "modbusRtuMaxFrameBytes": 256, + "modbusRtuInterFrameTimeoutMs": 0 + }, "device_tree": [ { "id": "serial_1", @@ -9,6 +18,7 @@ "driver": "hardware/drivers/serial/SerialQtDriver", "capabilitiesRef": "src/hardware/drivers/serial/parameters.json", "params": { + "protocol": "modbus_rtu", "baudRate": 115200, "dataBits": 8, "parity": "none", diff --git a/plugins/protocols/modbus_rtu/plugin_stub.cpp b/plugins/protocols/modbus_rtu/plugin_stub.cpp index d1966ea..1990c25 100644 --- a/plugins/protocols/modbus_rtu/plugin_stub.cpp +++ b/plugins/protocols/modbus_rtu/plugin_stub.cpp @@ -1 +1,2 @@ -extern "C" void softbus_modbus_rtu_plugin_stub() {} +extern "C" void +softbus_modbus_rtu_plugin_stub() {} diff --git a/src/core/memory/MemoryPool.h b/src/core/memory/MemoryPool.h index c5da7ea..c651ef3 100644 --- a/src/core/memory/MemoryPool.h +++ b/src/core/memory/MemoryPool.h @@ -59,35 +59,7 @@ public: this->release(*b); delete b; }); - BlockPtr allocate(std::size_t requiredSize) - { - if (requiredSize > m_blockSize) { - return {}; - } - - std::size_t slot = 0; - { - std::lock_guard lk(m_mutex); - if (m_freeSlots.empty()) { - return {}; - } - slot = m_freeSlots.front(); - m_freeSlots.pop(); - m_inUse[slot] = true; - } - - auto* raw = new PoolBlock{ - m_storage.data() + slot * m_blockSize, - m_blockSize, - requiredSize, - slot, - }; - return BlockPtr(raw, [this](PoolBlock* b) { - if (!b) return; - this->release(*b); - delete b; - }); - + } void release(const PoolBlock& block) { diff --git a/src/device_bus/manager/DeviceBusManager.cpp b/src/device_bus/manager/DeviceBusManager.cpp index 997602f..e0a6bc9 100644 --- a/src/device_bus/manager/DeviceBusManager.cpp +++ b/src/device_bus/manager/DeviceBusManager.cpp @@ -10,6 +10,7 @@ #include "message_bus/ingress/DriverIngressAdapter.h" #include "message_bus/pipeline/PipelineEngine.h" #include "core/plugin_system/PluginManager.h" +#include "core/plugin_system/builtins/ModbusRtuProtocolPlugin.h" #include "device_bus/manager/SerialDeviceManager.h" #include "devices/DeviceTypes.h" #include "utils/logs/logging.h" @@ -56,7 +57,10 @@ bool DeviceBusManager::initialize(const QJsonObject& rootConfig) if (!m_pluginManager) { m_pluginManager = std::make_shared(); } + m_pluginManager->registerProtocolPlugin(softbus::core::plugin_system::makeModbusRtuProtocolPlugin()); if (m_pipelineEngine) { + m_pipelineEngine->setMemoryPool(m_memoryPool); + m_pipelineEngine->loadRuntimeConfigFromJson(rootConfig.value(QStringLiteral("pipeline")).toObject()); m_pipelineEngine->setPluginManager(m_pluginManager); m_pipelineEngine->start(); } diff --git a/src/device_bus/manager/SerialDeviceManager.cpp b/src/device_bus/manager/SerialDeviceManager.cpp index 6b32a7d..922ae7b 100644 --- a/src/device_bus/manager/SerialDeviceManager.cpp +++ b/src/device_bus/manager/SerialDeviceManager.cpp @@ -128,9 +128,10 @@ bool initializeSerialDeviceWithDeps(const QString& endpoint, const QJsonObject& softbus::devices::DeviceInfo info; info.id = -1; - info.endpoint = endpoint; - info.type = QStringLiteral("serial"); - info.kind = softbus::devices::DeviceKind::Serial; + info.endpoint = endpoint; + info.type = QStringLiteral("serial"); + info.kind = softbus::devices::DeviceKind::Serial; + info.protocol = params.value(QStringLiteral("protocol")).toString(QStringLiteral("modbus_rtu")); softbus::devices::physical::SerialDevice::Config cfg; cfg.endpoint = endpoint; diff --git a/src/devices/physical/SerialDevice.cpp b/src/devices/physical/SerialDevice.cpp index 8f48695..4833e91 100644 --- a/src/devices/physical/SerialDevice.cpp +++ b/src/devices/physical/SerialDevice.cpp @@ -116,6 +116,7 @@ void SerialDevice::onRead(const std::vector& data) softbus::message_bus::pipeline::PipelineContext ctx; ctx.endpoint = m_config.endpoint; ctx.protocolHint = m_info.protocol; + ctx.frameKind = softbus::message_bus::pipeline::FrameKind::StreamChunk; ctx.payload.block = std::move(block); ctx.payload.length = data.size(); ctx.payloadSize = data.size(); diff --git a/src/message_bus/pipeline/PipelineContext.h b/src/message_bus/pipeline/PipelineContext.h index 2301125..f882815 100644 --- a/src/message_bus/pipeline/PipelineContext.h +++ b/src/message_bus/pipeline/PipelineContext.h @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -13,6 +14,19 @@ namespace softbus::message_bus::pipeline { +enum class FrameKind +{ + StreamChunk, + CompleteFrame, +}; + +enum class BusDirection +{ + Unknown, + Upstream, + Downstream, +}; + struct PipelineContext { int deviceId{-1}; // 设备ID @@ -24,6 +38,13 @@ struct PipelineContext PayloadRef payload; // 有效载荷 std::size_t payloadSize{0}; // 有效载荷大小 + + FrameKind frameKind{FrameKind::StreamChunk}; + BusDirection direction{BusDirection::Unknown}; + std::uint64_t frameSeq{0}; + + QJsonObject parsed; + QString framerError; // 成帧/Pipeline 旁路诊断(可选) }; } // namespace softbus::message_bus::pipeline diff --git a/src/message_bus/pipeline/PipelineEngine.cpp b/src/message_bus/pipeline/PipelineEngine.cpp index 9c1ae96..86a24f6 100644 --- a/src/message_bus/pipeline/PipelineEngine.cpp +++ b/src/message_bus/pipeline/PipelineEngine.cpp @@ -1,14 +1,71 @@ #include "message_bus/pipeline/PipelineEngine.h" +#include +#include +#include #include +#include +#include "message_bus/pipeline/stages/1_framers/ModbusRtuFraming.h" #include "utils/logs/logging.h" namespace softbus::message_bus::pipeline { +struct EndpointFramingState +{ + softbus::core::memory::LockFreeQueue chunkQ; + std::atomic running{true}; + std::thread th; + std::uint64_t nextSeq{1}; + QString endpoint; + std::shared_ptr pool; + softbus::message_bus::pipeline::stages::framers::ModbusRtuFramerConfig modbusCfg; + std::shared_ptr pass; + std::function pushFramed; + + explicit EndpointFramingState(std::size_t cap) + : chunkQ(cap) + { + } +}; + +namespace +{ + +void endpointFramerThread(std::shared_ptr st) +{ + using softbus::message_bus::pipeline::stages::framers::ModbusRtuFramer; + using softbus::message_bus::pipeline::stages::framers::protocolHintIsModbusRtu; + + auto modbus = std::make_unique(st->pool, st->modbusCfg, st->endpoint); + + while (st->running.load(std::memory_order_acquire)) { + PipelineContext ch; + if (!st->chunkQ.pop(ch)) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + continue; + } + std::vector out; + if (protocolHintIsModbusRtu(ch.protocolHint)) { + modbus->feed(ch, out); + } else if (st->pass) { + st->pass->feed(ch, out); + } + for (auto& x : out) { + x.frameSeq = st->nextSeq++; + if (st->pushFramed) { + st->pushFramed(std::move(x)); + } + } + } +} + +} // namespace + PipelineEngine::PipelineEngine(std::size_t queueCapacity) - : m_ingressQ(queueCapacity), m_egressQ(queueCapacity) + : m_ingressQ(queueCapacity) + , m_egressQ(queueCapacity) { } @@ -17,12 +74,73 @@ PipelineEngine::~PipelineEngine() stop(); } +void PipelineEngine::setMemoryPool(std::shared_ptr pool) +{ + m_pool = std::move(pool); +} + +void PipelineEngine::setRuntimeConfig(PipelineRuntimeConfig cfg) +{ + m_rtConfig = cfg; +} + +void PipelineEngine::loadRuntimeConfigFromJson(const QJsonObject& obj) +{ + if (obj.isEmpty()) { + LOG_ERROR() << "PipelineEngine: runtime config is empty"; + // return; + } + m_rtConfig.parallelPipeline = obj.value(QStringLiteral("parallelPipeline")).toBool(true); + m_rtConfig.parseWorkerCount = std::max(1, obj.value(QStringLiteral("parseWorkerCount")).toInt(2)); + m_rtConfig.orderedEgress = obj.value(QStringLiteral("orderedEgress")).toBool(true); + m_rtConfig.framedQueueMax = static_cast( + std::max(64, obj.value(QStringLiteral("framedQueueMax")).toInt(4096))); + m_rtConfig.maxReorderDepth = static_cast( + std::max(16, obj.value(QStringLiteral("maxReorderDepth")).toInt(256))); + m_rtConfig.modbus.maxAdu = static_cast( + std::max(8, obj.value(QStringLiteral("modbusRtuMaxFrameBytes")).toInt(256))); + m_rtConfig.modbus.interFrameTimeoutMs = obj.value(QStringLiteral("modbusRtuInterFrameTimeoutMs")).toInt(0); +} + void PipelineEngine::start() { if (m_running.exchange(true)) { return; } - m_worker = std::thread([this]() { run(); }); + + if (!m_pool) { + LOG_ERROR() << "PipelineEngine::start: memory pool not set"; + m_running = false; + return; + } + + m_modbusFramer = + std::make_unique(m_pool, + m_rtConfig.modbus, + QString{}); + m_passthroughFramer = + std::make_shared(m_pool); + + // 如果启用并行管道 则创建帧队列和解析线程 如果启用有序出口 则创建合并队列和合并线程 + // 并行管道是用来处理多个端点的数据流的 + // 有序出口是用来保证数据流的有序性的 + // 帧队列是用来存储帧的 + // 解析线程是用来处理帧的 + // 合并队列是用来存储合并的帧的 + // 合并线程是用来处理合并的帧的 + if (m_rtConfig.parallelPipeline) { + m_framedQ = std::make_unique>( + m_rtConfig.framedQueueMax); + for (int i = 0; i < m_rtConfig.parseWorkerCount; ++i) { + m_parseThreads.emplace_back([this]() { parseWorkerLoop(); }); + } + if (m_rtConfig.orderedEgress) { + m_mergeQ = std::make_unique>(0); + m_mergerThread = std::thread([this]() { mergerLoop(); }); + } + } else { + m_worker = std::thread([this]() { runSingleWorker(); }); + } } void PipelineEngine::stop() @@ -30,20 +148,77 @@ void PipelineEngine::stop() if (!m_running.exchange(false)) { return; } + + { + std::lock_guard lk(m_endpointMutex); + for (auto it = m_endpointFramers.constBegin(); it != m_endpointFramers.constEnd(); ++it) { + if (it.value()) { + it.value()->running.store(false, std::memory_order_release); + } + } + for (auto it = m_endpointFramers.constBegin(); it != m_endpointFramers.constEnd(); ++it) { + if (it.value() && it.value()->th.joinable()) { + it.value()->th.join(); + } + } + m_endpointFramers.clear(); + } + if (m_worker.joinable()) { m_worker.join(); } -} + for (auto& t : m_parseThreads) { + if (t.joinable()) { + t.join(); + } + } + m_parseThreads.clear(); + + if (m_mergerThread.joinable()) { + m_mergerThread.join(); + } + + m_framedQ.reset(); + m_mergeQ.reset(); + m_modbusFramer.reset(); + m_passthroughFramer.reset(); +} +// 功能 :清空 ingress 队列 +// 参数 :无 +// 返回值 :无 +// 逻辑 :从 ingress 队列中取出数据 直到队列为空 void PipelineEngine::drain() { PipelineContext tmp; while (m_ingressQ.pop(tmp)) { } } - +// 功能 :将数据推送到 ingress 队列 +// 参数 :ctx 数据 +// 返回值 :是否成功 +// 逻辑 :如果并行管道启用 则根据端点确保帧解析器 然后推送到帧队列 如果并行管道未启用 则直接推送到 ingress 队列 bool PipelineEngine::enqueueIngress(PipelineContext ctx) { + if (m_rtConfig.parallelPipeline) { + if (ctx.endpoint.isEmpty()) { + ++m_counters.drop; + return false; + } + ensureEndpointFramer(ctx.endpoint); + std::shared_ptr st; + { + std::lock_guard lk(m_endpointMutex); + st = m_endpointFramers.value(ctx.endpoint); + } + if (!st || !st->chunkQ.push(std::move(ctx))) { + ++m_counters.drop; + return false; + } + ++m_counters.in; + return true; + } + if (!m_ingressQ.push(std::move(ctx))) { ++m_counters.drop; return false; @@ -51,41 +226,209 @@ bool PipelineEngine::enqueueIngress(PipelineContext ctx) ++m_counters.in; return true; } - +// 功能 :将数据推送到 egress 队列 +// 参数 :ctx 数据 +// 返回值 :是否成功 +// 逻辑 :将数据推送到 egress 队列 bool PipelineEngine::enqueueEgress(PipelineContext ctx) { return m_egressQ.push(std::move(ctx)); } - +// 功能 :尝试从 egress 队列中取出数据 +// 参数 :out 数据 +// 返回值 :是否成功 +// 逻辑 :从 egress 队列中取出数据 如果队列为空 则返回false 如果队列不为空 则返回true bool PipelineEngine::tryPopEgress(PipelineContext& out) { return m_egressQ.pop(out); } - +// 功能 :设置插件管理器 +// 参数 :pluginManager 插件管理器 +// 返回值 :无 +// 逻辑 :设置插件管理器 void PipelineEngine::setPluginManager(std::shared_ptr pluginManager) { m_pluginManager = std::move(pluginManager); } -// 管道引擎运行线程 从 ingress 队列中取出数据 进行处理 然后推送到 egress 队列中 -void PipelineEngine::run() +// 功能 :确保端点帧解析器 +// 参数 :endpoint 端点 +// 返回值 :无 +// 逻辑 :如果端点帧解析器不存在 则创建端点帧解析器 +void PipelineEngine::ensureEndpointFramer(const QString& endpoint) { - while (m_running.load()) { + std::lock_guard lk(m_endpointMutex); + if (m_endpointFramers.contains(endpoint)) { + return; + } + const std::size_t qcap = m_ingressQ.capacity(); + auto st = std::make_shared(qcap > 0 ? qcap : 4096); + st->endpoint = endpoint; + st->pool = m_pool; + st->modbusCfg = m_rtConfig.modbus; + st->pass = m_passthroughFramer; + st->pushFramed = [this](PipelineContext c) { + if (!m_framedQ) { + return; + } + if (!m_framedQ->tryPush(std::move(c))) { + ++m_counters.drop; + LOG_WARNING() << "PipelineEngine: framed queue full drop"; + } + }; + st->th = std::thread(endpointFramerThread, st); + m_endpointFramers.insert(endpoint, std::move(st)); +} +// 功能 :分发帧解析器 +// 参数 :chunkIn 数据 +// 返回值 :无 +// 逻辑 :根据协议提示 选择合适的帧解析器 进行帧解析 +void PipelineEngine::dispatchFramer(PipelineContext& chunkIn, std::vector& completeFramesOut) +{ + using softbus::message_bus::pipeline::stages::framers::protocolHintIsModbusRtu; + // 根据协议提示 选择合适的帧解析器 进行帧解析 + + if (protocolHintIsModbusRtu(chunkIn.protocolHint)) { + if (m_modbusFramer) { + m_modbusFramer->feed(chunkIn, completeFramesOut); + + } + } else if (m_passthroughFramer) { + m_passthroughFramer->feed(chunkIn, completeFramesOut); + + } +} +// 功能 :分配帧序列号 +void PipelineEngine::assignFrameSequence(PipelineContext& ctx) +{ + std::lock_guard lk(m_seqMutex); + ctx.frameSeq = ++m_nextFrameSeqByEndpoint[ctx.endpoint]; +} + +void PipelineEngine::runSingleWorker() +{ + // 单线程工作线程 从 ingress 队列中取出数据 进行处理 然后推送到 egress 队列中 + while (m_running.load(std::memory_order_acquire)) { PipelineContext ctx; if (!m_ingressQ.pop(ctx)) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); continue; } - const bool framed = stage1Framer(ctx); - // 帧解析 - const bool parsed = framed && stage2Parser(ctx); - // 过滤 - const bool filtered = parsed && stage3Filter(ctx); - // 验证 - const bool valid = filtered && stage4Validator(ctx); - // 如果验证失败 则记录错误 - if (!valid) { + std::vector batch; + dispatchFramer(ctx, batch); + + for (auto& c : batch) { + if (c.frameKind != FrameKind::CompleteFrame) { + continue; + } + // + std::ostringstream oss; + oss << std::hex << std::setfill('0'); + for (std::size_t i = 0; i < c.payload.block->size; ++i) { + oss << std::setw(2) << static_cast(c.payload.block->data[i]); + if (i + 1 < c.payload.block->size) { + oss << ' '; + } + } + const QString hexPreview = QString::fromStdString(oss.str()); + LOG_INFO() << "the data is"<< hexPreview; + // 分配帧序列号 + assignFrameSequence(c); + if (!runStages234(c)) { + ++m_counters.error; + continue; + } + if (!m_egressQ.push(std::move(c))) { + ++m_counters.drop; + continue; + } + ++m_counters.out; + } + } +} + +void PipelineEngine::parseWorkerLoop() +{ + while (true) { + PipelineContext ctx; + + const bool have = m_framedQ && m_framedQ->popWaitFor(ctx, m_running, std::chrono::milliseconds(50)); // 从帧队列中取出帧 , 如果帧队列为空 则等待50毫秒 + if (!have) { + if (!m_running.load(std::memory_order_acquire)) { + break; + } + continue; + } + std::ostringstream oss; + oss << std::hex << std::setfill('0'); + for (std::size_t i = 0; i < ctx.payload.block->size; ++i) { + oss << std::setw(2) << static_cast(ctx.payload.block->data[i]); + if (i + 1 < ctx.payload.block->size) { + oss << ' '; + } + } + const QString hexPreview = QString::fromStdString(oss.str()); + LOG_INFO() << "the data is"<< hexPreview; + + const bool ok = runStages234(ctx); + if (m_rtConfig.orderedEgress && m_mergeQ) { + MergeItem it; + it.endpoint = ctx.endpoint; + it.seq = ctx.frameSeq; + it.pipelineOk = ok; + it.ctx = std::move(ctx); + m_mergeQ->push(std::move(it)); + } else { + if (!ok) { + ++m_counters.error; + continue; + } + if (!m_egressQ.push(std::move(ctx))) { + ++m_counters.drop; + continue; + } + ++m_counters.out; + } + } +} + +void PipelineEngine::mergerLoop() +{ + while (true) { + MergeItem it; + const bool have = m_mergeQ && m_mergeQ->popWaitFor(it, m_running, std::chrono::milliseconds(50)); + if (!have) { + if (!m_running.load(std::memory_order_acquire)) { + break; + } + continue; + } + ingestMergeItem(std::move(it)); + } +} +// 功能 :合并帧 +// 参数 :item 合并项 +// 返回值 :无 +// 逻辑 :将合并项中的数据推送到 egress 队列中 +void PipelineEngine::ingestMergeItem(MergeItem item) +{ + std::lock_guard lk(m_mergeStateMutex); + auto& st = m_mergeByEndpoint[item.endpoint]; + if (m_rtConfig.maxReorderDepth > 0 + && static_cast(st.buffer.size()) >= m_rtConfig.maxReorderDepth) { + ++m_counters.mergeDrop; + LOG_WARNING() << "PipelineEngine: merge reorder depth exceeded endpoint=" << item.endpoint; + return; + } + st.buffer.insert(item.seq, std::make_pair(std::move(item.ctx), item.pipelineOk)); + + while (st.buffer.contains(st.nextExpected)) { + auto pr = st.buffer.take(st.nextExpected); + ++st.nextExpected; + const bool pipelineOk = pr.second; + PipelineContext ctx = std::move(pr.first); + if (!pipelineOk) { ++m_counters.error; continue; } @@ -97,17 +440,31 @@ void PipelineEngine::run() } } -bool PipelineEngine::stage1Framer(PipelineContext& ctx) +// 功能 :运行阶段234 +// 参数 :ctx 数据 +// 返回值 :是否成功 +// 逻辑 :如果帧类型不是完整帧 则返回false 如果阶段2解析失败 则返回false 如果阶段3过滤失败 则返回false 如果阶段4验证失败 则返回false 如果都成功 则返回true +bool PipelineEngine::runStages234(PipelineContext& ctx) { - if (!ctx.payload.valid()) { + if (ctx.frameKind != FrameKind::CompleteFrame) { return false; } - if (ctx.payloadSize == 0) { - ctx.payloadSize = ctx.payload.length; + if (!stage2Parser(ctx)) { + return false; + } + if (!stage3Filter(ctx)) { + return false; + } + if (!stage4Validator(ctx)) { + return false; } return true; } +// 功能 :验证阶段4 +// 参数 :ctx 数据 +// 返回值 :是否成功 +// 逻辑 :如果有效载荷无效 则返回false 如果都成功 则返回true bool PipelineEngine::stage4Validator(PipelineContext& ctx) { if (!ctx.payload.valid()) { @@ -119,9 +476,16 @@ bool PipelineEngine::stage4Validator(PipelineContext& ctx) if (!ctx.timestamp.isValid()) { ctx.timestamp = QDateTime::currentDateTimeUtc(); } + if (ctx.frameKind != FrameKind::CompleteFrame) { + return false; + } return true; } +// 功能 :运行阶段2解析器 +// 参数 :ctx 数据 +// 返回值 :是否成功 +// 逻辑 :如果插件管理器为空 则返回true 如果插件管理器不为空 则选择合适的插件 创建会话 如果会话为空 则返回false 如果会话不为空 则返回true bool PipelineEngine::stage2Parser(PipelineContext& ctx) { if (!m_pluginManager) { diff --git a/src/message_bus/pipeline/PipelineEngine.h b/src/message_bus/pipeline/PipelineEngine.h index fd43a3d..15b168b 100644 --- a/src/message_bus/pipeline/PipelineEngine.h +++ b/src/message_bus/pipeline/PipelineEngine.h @@ -1,21 +1,40 @@ #pragma once // 定义管道引擎 包含队列、运行状态、工作线程、计数器、插件管理器 -// 队列是用来存储管道上下文的 -// 运行状态是用来控制引擎的运行和停止的 -// 工作线程是用来处理管道上下文的 -// 计数器是用来统计管道上下文的数量和错误数量的 -// 插件管理器是用来管理插件的 #include #include #include +#include +#include + +#include +#include +#include #include "core/plugin_system/PluginManager.h" #include "core/memory/LockFreeQueue.h" +#include "core/memory/MemoryPool.h" +#include "core/threading/MutexQueue.h" #include "message_bus/pipeline/PipelineContext.h" +#include "message_bus/pipeline/stages/1_framers/ModbusRtuFramer.h" +#include "message_bus/pipeline/stages/1_framers/PassthroughFramer.h" namespace softbus::message_bus::pipeline { +struct PipelineRuntimeConfig +{ + bool parallelPipeline{false}; + int parseWorkerCount{2}; + bool orderedEgress{true}; + + std::size_t framedQueueMax{4096}; + std::size_t maxReorderDepth{256}; + + softbus::message_bus::pipeline::stages::framers::ModbusRtuFramerConfig modbus; +}; + +struct EndpointFramingState; + class PipelineEngine { public: @@ -25,6 +44,7 @@ public: std::atomic out{0}; std::atomic drop{0}; std::atomic error{0}; + std::atomic mergeDrop{0}; }; explicit PipelineEngine(std::size_t queueCapacity = 4096); @@ -39,12 +59,38 @@ public: bool tryPopEgress(PipelineContext& out); void setPluginManager(std::shared_ptr pluginManager); + void setMemoryPool(std::shared_ptr pool); + void setRuntimeConfig(PipelineRuntimeConfig cfg); + void loadRuntimeConfigFromJson(const QJsonObject& obj); const Counters& counters() const { return m_counters; } private: - void run(); - bool stage1Framer(PipelineContext& ctx); + struct MergeItem + { + QString endpoint; + std::uint64_t seq{0}; + PipelineContext ctx; + bool pipelineOk{false}; + }; + + struct MergeState + { + std::uint64_t nextExpected{1}; + QHash> buffer; + }; + + void runSingleWorker(); + void parseWorkerLoop(); + void mergerLoop(); + + void ensureEndpointFramer(const QString& endpoint); + + void dispatchFramer(PipelineContext& chunkIn, std::vector& completeFramesOut); + void assignFrameSequence(PipelineContext& ctx); + bool runStages234(PipelineContext& ctx); + void ingestMergeItem(MergeItem item); + bool stage2Parser(PipelineContext& ctx); bool stage3Filter(PipelineContext& ctx); bool stage4Validator(PipelineContext& ctx); @@ -53,9 +99,29 @@ private: softbus::core::memory::LockFreeQueue m_ingressQ; softbus::core::memory::LockFreeQueue m_egressQ; std::atomic m_running{false}; - std::thread m_worker; - Counters m_counters; + std::thread m_worker; + Counters m_counters; std::shared_ptr m_pluginManager; + std::shared_ptr m_pool; + + PipelineRuntimeConfig m_rtConfig; + + std::unique_ptr m_modbusFramer; + std::shared_ptr m_passthroughFramer; + + std::mutex m_seqMutex; + QHash m_nextFrameSeqByEndpoint; + + std::unique_ptr> m_framedQ; + std::unique_ptr> m_mergeQ; + std::vector m_parseThreads; + std::thread m_mergerThread; + + std::mutex m_endpointMutex; + QHash> m_endpointFramers; + + std::mutex m_mergeStateMutex; + QHash m_mergeByEndpoint; }; } // namespace softbus::message_bus::pipeline diff --git a/src/message_bus/pipeline/stages/1_framers/DefaultFramer.cpp b/src/message_bus/pipeline/stages/1_framers/DefaultFramer.cpp deleted file mode 100644 index c69ba71..0000000 --- a/src/message_bus/pipeline/stages/1_framers/DefaultFramer.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "message_bus/pipeline/stages/1_framers/IFramer.h" - -namespace softbus::message_bus::pipeline::stages::framers -{ - -// Placeholder TU for stage1 concrete framer implementations. - -} // namespace softbus::message_bus::pipeline::stages::framers diff --git a/src/message_bus/pipeline/stages/1_framers/IFramer.h b/src/message_bus/pipeline/stages/1_framers/IFramer.h index 628fe2b..34209f7 100644 --- a/src/message_bus/pipeline/stages/1_framers/IFramer.h +++ b/src/message_bus/pipeline/stages/1_framers/IFramer.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "message_bus/pipeline/PipelineContext.h" namespace softbus::message_bus::pipeline::stages::framers @@ -9,7 +11,10 @@ class IFramer { public: virtual ~IFramer() = default; - virtual bool frame(softbus::message_bus::pipeline::PipelineContext& ctx) = 0; + + /// Consumes `chunkIn` (StreamChunk 语义);仅在 `completeFramesOut` 中追加 CompleteFrame。 + virtual void feed(softbus::message_bus::pipeline::PipelineContext& chunkIn, + std::vector& completeFramesOut) = 0; }; } // namespace softbus::message_bus::pipeline::stages::framers diff --git a/src/message_bus/pipeline/stages/2_parsers/IParserStage.h b/src/message_bus/pipeline/stages/2_parsers/IParserStage.h index 0e64001..52be947 100644 --- a/src/message_bus/pipeline/stages/2_parsers/IParserStage.h +++ b/src/message_bus/pipeline/stages/2_parsers/IParserStage.h @@ -1,5 +1,5 @@ #pragma once - +// 定义解析器阶段接口 #include "message_bus/pipeline/PipelineContext.h" namespace softbus::message_bus::pipeline::stages::parsers