RBNB V2.0 FAQ
This document provides a list of Frequently Asked Questions and answers to
those questions for the RBNB V2.0 software. It also addresses differences
between V1.x and V2.0 when the differences are likely to cause misunderstandings.
Table of Contents
How is byte order handled?
Where are automatic time-stamps generated?
What is the ring buffer?
How do I configure the the ring buffer?
When is data written to the archive?
How do I load an archive back into the server?
How do I set V2 timestamps?
How is byte order handled?
Normally, byte order is handled automatically by the RBNB system. The API
automatically determines the source byte order and swaps bytes as needed to
ensure that the sink gets the data in the byte order it expects. For example,
arrays of primitives (shorts, floats, Java longs, etc.) in Java and C can
be put into the RBNB system and then retrieved by any other Java or C application.
So long as the source application has or can convert the data into such an
array, sink applications do not need to handle byte order.
For a complete list of the primitive types supported by the RBNB system,
see the ChannelMap.TYPE_xxx fields.
When the source's byte order is significant and must be maintained (as
with legacy applications), the data should be passed through the RBNB system
in the form of an array of bytes using TYPE_INT8. This turns
off the automatic byte order handling in the RBNB system and leaves the user
responsible for dealing with any byte order issues. Programs such as
rbnbPlot that expect to be informed of the data type are unable to display
such data.
Where are automatic time-stamps generated?
Automatic time-stamps are generated by the client-side API. This is unlike
V1.x, where the server generates automatic time-stamps. In a future
V2 release, we may restore server-side automatic timestamps, as this provides
a convenient way to synchronize multiple source clients. Keep in mind
that automatic timestamps are meant to be a convenient but approximate solution.
Use explicit PutTime methods to more precisely control the timestamps.
What is the ring buffer?
The Ring Buffered part of the "Ring Buffered Network Bus" refers to the way
that data is stored in the RBNB system. A ring buffer stores data in what
appears to be a seamless ring of slots, each slot holding one block (termed
a "frame") of data. At data arrives, it is placed in the next slot in the
ring, replacing any previous frame stored in the slot. Pointers are maintained
to the slot containing the oldest and newest data still stored in the ring
buffer.
In V2.0, as with V1.x, the ring buffer actually consists of two main
parts:
- An in-memory "cache", and
- A disk file "archive".
Unlike V1.x, where a single frame was the unit size for both adding and removing
objects from the cache and archive, V2.0 adds two new hierarchical objects
that increase the granularity of the ring buffer, while reducing the effort
required to maintain its integrity when new data replaces older data. These
two new objects are:
- FrameSets, which are the basic blocks of the cache, and
- FileSets, which are the basic blocks of the archive.
Frames (sent when a source flushes a ChannelMap) are added to the current
active frameset as they arrive in the cache. Once the frameset reaches a
configurable size, it is closed and a new one is created. Framesets are added
to the current active fileset in the archive as they are closed by the cache.
Once the fileset reaches a configurable size, it is closed and a new one
is created. Closed framesets and filesets are read-only; no further frames
or framesets are added, nor are any removed.
When the cache reaches its configured maximum size, a new frameset replaces
the oldest frameset still in the cache. The oldest frameset is simply removed
from the cache. Similarly, when the archive reaches its configured maximum
size, new filesets replace the oldest fileset still in the archive. This is
done by simply deleting the fileset, which consists of a directory containing
several files.
How do I configure the the ring buffer?
The desired sizes of the cache and archive in frames are set by the source
application when creating the source handle via the simple API. The actual
maximum sizes of the cache and archive may be adjusted to maintain efficient
integral relationships between:
- Frameset size for the cache
- Maximum size of the cache (frameset size times number of framesets)
- Fileset size for the archive
- Maximum size of the archive (fileset size times number of filesets)
The simple API does not currently allow the user to directly set the number
of framesets and filesets. Instead, the server starts with a default of 10,
and may adjust this to make sure that every frameset contains one or more
frames, and every fileset contains one or more framesets.
When is data written to the archive?
Data is written to the archive whenever a frameset is closed. At that time,
the contents of the frameset are written to the archive in the current fileset.
This is similar to the asynchronous mode in V1.x and, as with that mode,
there is the danger that frames added to the most current frameset may not
get written out to the archive if the server (or the host machine it is running
on) should crash. This vulnerability will be addressed in a future release.
How do I load an archive back into the server?
When the source application creates its source handle via the constructor
or through the use of the SetRingBuffer method. In addition to the size of
the cache and the archive, there is a archive mode field which can take the
following values:
- None - no archive,
- Load - loads an existing archive read-only,
- Create - creates a new archive using the sizes specified, or
- Append - opens an existing archive and adjusts its size according
to the sizes provided.
When an archive is loaded, no new data can be added to it. When an archive
is opened for append, then the archive size is adjusted to match the new desired
size as closely as possible. The frameset and fileset sizes are not changed.
How do I set V2 timestamps?
In V2 RBNB, timestamps are designed to be simple yet efficient. The
timestamp(s) you specify with the PutTime methods remain the "current" time
that applies to subsequent PutData calls. Thus, for the simplest case,
you can set the time once for all data, as in:
PutTime
BeginLoop
PutData
EndLoop
If you want to explicitly set the time for every PutData, then structure
your code to pair the PutTime/PutData calls, as in:
BeginLoop
PutTime
PutData
EndLoop