The easiest way to store rowops is to put them into the Perl arrays, like:
my @ops = ($rowop1, $rowop2); push @ops, $rowop3;
However the C++ internals of Triceps do not know about the Perl arrays. And some of them work directly with the sequences of rowops. So Triceps defines an internal sort-of-equivalent of Perl array for rowops, called a Tray.
The trays have first been used to "catch" the side effects of operations on the stateful elements, so the name "tray" came from the metaphor "put a tray under it to catch the drippings".
The trays get created as:
$tray = $unit->makeTray($rowop, ...) or die "$!";
A tray always stores rowops for only one unit. It can be only used in one thread. A tray can be used in all the scheduling functions, just like the direct rowops:
$unit->call($tray); $unit->fork($tray); $unit->schedule($tray); $unit->loopAt($mark, $tray);
Moreover, the single rowops and trays can be mixed in the multiple arguments of these functions, like:
$unit->call($rowopStartPkg, $tray, $rowopEndPkg);
In this example nothing really stops you from placing the start and end rows into the tray too. A tray may contain the rowops of any types mixed in any order. This is by design, and it's an important feature that allows to build the protocol blocks out of rowops and perform an orderly data exchange. This feature is an absolute necessity for proper inter-process and inter-thread communication.
The ability to send the rows of multiple types through the same channel in order is a must, and its lack makes the communication with some other CEP systems exceedingly difficult. Coral8 supports only one stream per connection. Aleri (and I believe Sybase R5) allows to send multiple streams through the same connection but has no guarantees of order between them. I don't know about the others, check yourself.
To iterate on a tray, it can be converted to a Perl array:
@array = $tray->toArray();
The size of the tray (the count of rowops in it) can be read directly without a conversion, and the unit can be read back too:
$size = $tray->size(); $traysUnit = $tray->getUnit();
Another way to create a tray is by copying an existing one:
$tray2 = $tray1->copy();
This copies the contents (which is the references to the rowops) and does not create any ties between the trays. The copying is really just a more efficient way to do
$tray2 = $tray1->getUnit()->makeTray($tray1->toArray());
The tray references can be checked, whether they point to the same tray object:
$result = $tray1->same($tray2);
The contents of a tray may be cleared. Which is convenient and more efficient than discarding a tray and creating another one:
The data may be added to any tray:
Multiple rowops can be pushed in a single call. There are no other Perl-like operations on a tray: it's either create from a set of rowops, push, or convert to Perl array.
Note that the trays are mutable, unlike the rows and rowops. Multiple references to a tray will see the same contents. If a rowop is added to a tray through one reference, it will be visible through all the others.