Skip to content

Wait for usage sharing records without spinning, and fill a message up to twice the minimum as .NET and Java do - #191

Merged
jwrosewell merged 2 commits into
release/4.5.12from
fix/share-usage-idle-wait
Oct 27, 2026
Merged

jwrosewell merged 2 commits into
release/4.5.12from
fix/share-usage-idle-wait

Conversation

@jwrosewell

@jwrosewell jwrosewell commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Closes #154

Problem

The usage sharing element's background thread waited for each record with recv_timeout(take_timeout), and when the wait ran out it did nothing and waited again (share_usage_element.rs L872-L904). With ShareUsageConfigBuilder::take_timeout(Duration::ZERO) every wait returned at once, so the thread spun and used a whole processor core for as long as the element lived. With the default of 100 milliseconds it woke ten times a second for nothing.

The take timeout had no other effect, and each message held exactly the minimum entries per message. The .NET and Java elements use the take timeout once the minimum is queued, taking more entries until none arrives within it or the message holds twice the minimum (ShareUsageElement.cs L96-L100, ShareUsageElement.java L351-L359).

Change

  • Below the minimum entries per message, the background thread waits for each record with recv, which has no time limit and returns an error only once the element has been dropped and every queued record has been received. An idle element therefore uses no processor time, whatever its take timeout.
  • Once the message holds the minimum, the thread takes more records, waiting up to the take timeout for each, until none arrives in that time or the message holds twice the minimum, then sends it, as the .NET and Java elements do. A take timeout of zero takes only what is already queued.
  • When the element is dropped, the thread sends what remains, even below the minimum, as before.
  • The documentation of the take timeout, the minimum entries per message, the default take timeout constant and the module says so.
  • A unit test, a_message_takes_up_to_twice_the_minimum_within_the_take_timeout, queues five records with a minimum of two and a long take timeout, and checks the messages hold four and then one.
  • A new test binary, pipeline-engines-fiftyone/tests/idle_cpu.rs, leaves an element idle for a second with a take timeout of zero and of 100 milliseconds, and checks the process used less than 250 ms of processor time. It reads the process's processor time on Windows and Linux, and is not built elsewhere. It has a binary of its own so no other test's work is counted.

The first commit of this pull request made the take timeout do nothing and sent exactly the minimum. The second gives the take timeout the role it has in .NET and Java. The specification is being amended to describe that rule (51Degrees/specifications#56).

How it was verified

On Windows 11 with Rust 1.95.0. The new tests were first run against the base commit 9fe201e, with nothing else changed, using cargo test -p fiftyone-pipeline-core -p fiftyone-pipeline-engines-fiftyone --no-fail-fast -- --test-threads=1, and each failed as shown.

  • The test binary idle_cpu.rs came after that run, so the failure was measured with a scratch test doing the same thing, an element left idle for two seconds. It used 1,953 ms of processor time with a take timeout of zero and 0 ms with the default of 100 ms.

With the change, rustfmt --check passes on the changed files. The workspace checks on a local merge of every pull request for 4.5.12 (cargo fmt --all -- --check, cargo clippy --workspace --all-targets -- -D warnings, cargo doc --workspace --no-deps with warnings denied, and cargo test --workspace with the Device Detection Lite and IP Intelligence ASN data files) are added here when they finish.

Behaviour that changes

  • An idle element uses no processor time whatever its take timeout, where a take timeout of zero used a whole core.
  • A message holds from the minimum entries per message to twice that number, where it held exactly the minimum. Once the minimum is queued, the message waits up to the take timeout for each further record, 100 milliseconds by default, before it is sent.

What remains

The background thread waited for each record with the take timeout and
did nothing when it ran out, so a take timeout of zero made it spin and
use a whole processor core for as long as the element lived. It now
waits with no time limit. A message is sent as soon as it holds the
minimum entries, so the take timeout has no role here, and the builder
says so.
@jwrosewell jwrosewell self-assigned this Oct 27, 2026
The .NET and Java pipelines use the take timeout once a message holds the
minimum entries per message, taking more entries until none arrives
within it or the message holds twice the minimum. The usage sharing
element now does the same, so a configuration behaves alike in each
language and the take timeout has its effect again. Below the minimum
the background thread still waits with no time limit, so an idle element
uses no processor time whatever its take timeout.

A new unit test queues five records with a minimum of two and a long
take timeout, and checks the messages hold four and then one.
@jwrosewell jwrosewell changed the title Wait for usage sharing records without a time limit Wait for usage sharing records without spinning, and fill a message up to twice the minimum as .NET and Java do Oct 27, 2026
@jwrosewell
jwrosewell merged commit 0cb1809 into release/4.5.12 Oct 27, 2026
14 checks passed
@jwrosewell
jwrosewell deleted the fix/share-usage-idle-wait branch October 27, 2026 14:42
jwrosewell added a commit that referenced this pull request Oct 27, 2026
@jwrosewell jwrosewell mentioned this pull request Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant