nosqlbench/devdocs/docs-for-ebhistoric/async_operations.md

81 lines
4.1 KiB
Markdown
Raw Normal View History

2020-02-20 15:37:57 -06:00
---
title: Async Operations
weight: 35
menu:
main:
parent: Dev Guide
identifier: Async Operations
weight: 12
---
2020-03-26 12:33:46 -05:00
{{< warning >}} This section is out of date, and will be updated after
the next major release with details on building async drivers. {{<
/warning >}}
2020-02-20 15:37:57 -06:00
## Introduction
In nosqlbench, two types of activities are supported: sync or async. Going forward, the async interface will be
refined and hardened, and then the sync interface will be deprecated. This is simply a matter of simplifying the
API over time, and the async interface is the essential one. If you want synchronous behavior with the async
interface, you can easily achieve that, but not the other way around.
### Configuring Async
In an async activity, you still have multiple threads, but in this case, each thread is allowed to juggle one or
more asynchronous operations. The `async=100` parameter, for example, informs an activity that it needs to allocate
100 total operations over the allocated threads. In the case of `async=100 threads=10`, it is the responsibility
of the ActivityType's action dispenser to configure their actions to know that each of them can juggle 10 operations
2020-03-26 12:33:46 -05:00
each.
2020-02-20 15:37:57 -06:00
{{< note >}}The *async* parameter has a standard meaning in nosqlbench. If it is defined, async is enabled. Its
parameter value is the number of total async operations that can be in flight at any one instant, with the number
per-thread divided as evenly as possible over all the threads.
If the async parameter is defined, but the action implementation does *not* implement the async logic,
then an error is thrown to the user. This is to ensure that users are aware of when they are expecting async
behavior but getting something else.
{{</ note >}}
### Async Messaging Flow
The contract between a motor and an action is very basic.
2020-03-26 12:33:46 -05:00
- Each motor submits as many async operations as is allowed to its action, as long as there are
2020-02-20 15:37:57 -06:00
cycles remaining, until the action signals that it is at its limit.
- As long as an action is able to retire an operation by giving a result back to its motor,
the motor keeps providing one more and retiring one more, as long as there are cycles remaining.
- Once there are no more cycles remaining, the motor retires operations from the action until
the action signals that no more are pending.
The basic result of this is that each thread ramps up to its async juggling rate, hovers at that
rate, with a completion rate dependent on the target system, and then ramps down as pending ops
are retired back down to zero.
### Advanced Signaling
Because of differences in client-side APIs and behavior, and the need to do simple and reliable
flow management in nosqlbench, there are a few details about the API that are worth understanding
as a developer.
- There are multiple return or signaling points in the lifetime of an op context:
1. When an action becomes aware that an operation has completed, it is up to the action to
mark the op context with a call to `opcontext.stop(result)` at that time. This is important,
because operations do not complete in the same order that they are submitted, especially
when other async logic is present. A common way to do this is to register a callback on
a listener, for example.
2. The action must still return this op context back to the motor when it is asked. Thus, it
is a common pattern to keep a linked list of operations that are ready to retire and thus
allow the action to control orderly shutdown of the motor without any guesswork about the
completion state of pending operations.
3. The op context can be a sub-type, if you need to specialize the details that you keep for
an in-flight operation. In fact, async actions *must* implement a basic factory method,
but it can return a simple op context if no specialization is needed.
4. op contexts are recycled to avoid heap pressure for high data rates. This makes it relatively
low-cost to use the specialized op context to hold contextual data that may otherwise be
2020-03-26 12:33:46 -05:00
expensive to _malloc_ and _free_.
2020-02-20 15:37:57 -06:00
### Examples
2020-03-26 12:33:46 -05:00
Developers can refer to the Diag activity type implementation for further examples.