Apama 10.15.0 | Developing Apama Applications | Developing Apama Applications in EPL | Using EPL Plug-ins | Using the MemoryStore | Steps for using the MemoryStore | Description of row structures
 
Description of row structures
Schemas
A schema consists of an ordered list of the names and types of fields that define the structure of a row. For example, the following schema consists of one field whose name is times_run and whose type is integer:
Schema schema := new Schema;
schema.fields := ["times_run"];
schema.types := ["integer"];
A valid schema can be created from an event type using schemaFromAny(event). Types that are not supported in the event are converted to string types.
The Schema event has additional members that indicate how to publish the table. See Exposing in-memory or persistent data as DataViews.
The schema does not include the row's key. The key is always a string and it does not have a name. Each row in a table is associated with a key that is unique within the table. The key provides a handle for obtaining a particular row. The row does not contain the key.
Two schemas match when they list the same set of field names and types in the same order and choose the same options for exposing DataViews.
Some distributed MemoryStore drivers (such as TCStore) support getting and setting extra fields that are present in only some individual rows, and are not named in the schema. For stores supporting this feature, it is even possible to specify an empty list of schema fields and access all fields as extra fields if desired. When getting extra fields, it is important to be aware that getting a field that does not exist will result in an exception, so it is usually necessary to add exception handling code, or to check which keys are present in the row (using Row.getKeys()) before attempting to access them. It is also possible to use the Row.getAll or Row.toDictionary actions to get all fields including those named in the schema and any extra fields that are present. Note that RowChanged notifications are not supported for extra fields.
Tables
Table events define actions that do the following:
*Retrieve a row by key. The returned object is a Row event.
*Remove a row by key
*Remove all rows
*Obtain a sequence of keys for all rows in the table
*Obtain an iterator to iterate over the rows in the table
*Determine if any row in the table has a particular key
*Store on disk the changes to the in-memory table
*Subscribe (and unsubscribe) to a table to be notified when a row has changed. (Note, this is only supported for tables in a distributed store, and only if the underlying provider supports this feature.)
*Modify a row by key
*Modify all rows
*Obtain the position in a schema of a specified field.
*Obtain the name of the table
*Obtain the name of the store that contains the table
For details about these Table event actions, see the information for MemoryStore in the API Reference for EPL (ApamaDoc) .
Retrieval of a row from a table by key always succeeds (although retrieving a row from a table in a distributed store can throw an exception). If the row already exists, the MemoryStore returns a Row event that provides a local copy of the row. The content of this Row event does not change if another user modifies the in-memory version of the row in the table. If the row does not already exist, the MemoryStore populates a Row event with default values and returns that with field values as follows:
*boolean types are false
*decimal types are 0.0d
*float types are 0.0
*integer types are 0
*string types are empty ("")
Rows
Row events define actions that do the following:
*Getters and setters. These actions modify only the local copy (your Row event) and not the in-memory version of the row. The in-memory version of the row is available to all monitors. If another user of the table retrieves the same row, that user receives a Row event that contains a copy of the in-memory version of the row; that user does not receive a copy of your modified, local version of the row:
*Get and set boolean, decimal, float, integer, and string fields by name.
*Generic get and set field by name actions which use the any type. These throw an exception if the underlying types do not match the expected field type.
*Get and set all fields. These expect a prototype event whose fields and types match that of the table schema. An exception is thrown if the schemas do not match.
*Commit a modified Row event. That is, you modify your local Row event, and commit the changes, which updates the shared row in the table. This makes the update available to all monitors.
*Get the value of a row's key.
*Determine whether a row was present in the table when the local copy was provided.
*Obtain the name of the table the row is in.
*Obtain the name of the store the row's table is in.
The Row.commit() action modifies only the in-memory copy of the row so it is a synchronous and non-blocking operation. Note, in a distributed store, Row.commit() writes the value to the distributed store, which may be a fast, local operation or it may involve writing data to one or more remote nodes. If any other user of the table modifies the in-memory row between the time you obtain a Row event that represents that row and the time you try to commit your changes to your Row event, the Row.commit() action fails and the monitor instance that called Row.commit() dies. Therefore, if you are sharing the table with other users or using a distributed store, you should call Row.tryCommit() instead of Row.commit(). If it fails you must retry the commit operation by retrieving the row again (that is, obtaining a new Row event that contains the latest content of the in-memory row), reapplying the changes, and then calling the Row.tryCommit() action. This ensures that you always make changes that are consistent and atomic within the shared version of the row.
However, it is not possible to make atomicity guarantees across rows or tables.