A Feed Engine receives data and delivers it to one or more Handler instances. Each Handler processes that data for its configured CME MDP channel and notifies your application through event callbacks.
Arrows show data delivery. The boxes do not represent separate threads.
The SDK provides two Feed Engine implementations for live network reception:
| Implementation | Reception | When to use it |
|---|---|---|
| SocketFeedEngine | Standard socket API | Default network reception. |
| SolarflareFeedEngine | Kernel-bypass multicast reception through Solarflare's ef_vi API | Latency-sensitive applications on Linux with supported Solarflare adapters. |
In mixed mode, the Solarflare Feed Engine can fall back to standard sockets when initializing multicast reception; see Mixed mode.
By default, each Handler owns an internally managed Feed Engine backed by OnixS::CME::MDH::SocketFeedEngine and an internal worker thread pool, so no explicit Feed Engine setup is required.
The internally managed default is intended primarily for examples and initial setup. For production applications, prefer an explicit Feed Engine to control reception and processing threads.
To use the Solarflare Feed Engine, construct an explicit engine and bind it to the Handler.
| Configuration | Who owns the engine? | Who runs it? | When to use it |
|---|---|---|---|
| Default | Handler | Internal worker pool | Examples and initial setup. |
| Explicit | Application | Application loop or FeedEngineThreadPool | Control reception and processing threads in production, share an engine between Handlers, or choose another implementation. |
Bind an explicit engine through FeedSettings::engine(NetFeedEngine*) before starting the Handler. The application must run the engine using one of these approaches:
Calling OnixS::CME::MDH::Handler::start alone does not run an explicitly bound engine. The following example constructs an explicit engine, binds it to the Handler, and calls OnixS::CME::MDH::NetFeedEngine::process in an application loop:
The application owns an explicitly bound engine. Keep it alive while it is bound to any Handler and while any processing pool or application-managed worker uses it. OnixS::CME::MDH::Handler::stop stops market data processing but does not remove the engine binding.
One safe shutdown sequence is:
Other destruction orders can also satisfy the lifetime requirements: the engine must outlive all of its bindings and processing workers. For example, the multithreaded example below destroys its stopped Handler before its pool, then destroys the engine last.
When using automatic objects, declaring the engine first, the Handler second, and the pool last ensures that the pool and Handler are destroyed before the engine, including during exception unwinding.
To remove an explicit binding from a stopped Handler, pass nullptr to FeedSettings::engine(NetFeedEngine*). This leaves the Handler without a Feed Engine; bind a valid engine before calling OnixS::CME::MDH::Handler::start again.
Multiple Handler instances can explicitly share a single Feed Engine instance:
If the Feed Engine implementation supports multithreaded processing, it is possible to distribute the Feed Engine logic across multiple threads instead of calling OnixS::CME::MDH::NetFeedEngine::process from one thread only.
OnixS::CME::MDH::FeedEngineThreadPool creates worker threads that repeatedly call OnixS::CME::MDH::NetFeedEngine::process on the engine passed to its constructor. Configure the number of workers through OnixS::CME::MDH::FeedEngineThreadSettings::pool and OnixS::CME::MDH::ThreadPoolSettings::size.
A pool size of 1 is the default and recommended starting point. Increase it only if the Feed Engine implementation supports concurrent processing and measurements show a benefit for your workload.
With the standard OnixS::CME::MDH::SocketFeedEngine, socket reads, data processing and application callbacks for one channel are serialized. While that channel is replaying queued packets or running a callback, additional workers cannot drain its sockets. Incoming traffic accumulates in the operating system receive buffers and can be lost if those buffers fill. Adding workers does not remove a processing bottleneck within that channel. See Keeping callbacks responsive.
The pool reports worker-thread events through OnixS::CME::MDH::FeedEngineThreadPoolListener. Pass a listener when constructing the pool.
The Feed Engine abstraction is represented as a set of abstract classes. Implementing them allows users to build their logic by extracting market data from various sources, including networks, file-based stores, etc.
To implement a custom feed engine, please contact OnixS Support.