The TARDIS input is from multiple sources including GPS receivers and radar systems and includes tactical data, such as the position of other aircraft, ships and vehicles. Inside are multiple COTS PowerPC-based SBCs running Wind River's VxWorks 5.5 RTOS. A recently added software component is McObject's eXtremeDB in-memory embedded database, which manages the tactical information and is updated in real-time. The eXtremeDB uses a schema compiler and a self-diagnostic API, to configure databases and tables and create high-quality applications (Figure 1).
Matching database and API
Most database systems have a pre-configured API, usually a static library of functions that are applied across all applications. This means that they are not aware of the data structures of a specific database implementation. As a result, C/C++ compilers are unable to pick up the application developers' mistakes in assigning types to functions when using the database.
The eXtremeDB generates a unique API for every database, with knowledge of the data structures, as part of the database development process (Figure 2). Using an object-oriented approach, the developer uses a database definition language to create a database schema, which would include classes and their elements with their type property, structures and indexes. The schema is processed by the compiler, which reviews them for syntactic accuracy and then generates both the API and the database dictionary.
An application needing to read, store or manipulate data in the database will use the API. In other databases, data normally passes through the API as void pointers. This provides ample opportunity for programmer errors in creating an incorrect argument, and neither the C/C++ compiler nor the database at runtime can catch these.
Systematic development
The example associated with an application that is processing radar data. It should be noted that these are not the designs used in the TARDIS application, but are highly simplified examples, presented for instruction.
#define int2 signed<2>
#define int4 signed<4>
declare database radar;
struct points {
rect point[2];
};
The shorthand refers to int2 and int4 for the 2- and 4byte signed integers from which database objects will be constructed. The database name, radar, also becomes the basename of the output files generated by the schema compiler: radar.c and radar.h.
The schema declares a structure containing a two-element array of rectangle co-ordinates expressed as 2byte integers. Programmers can define a rectangle by referring to the X/Y co-ordinates of the upper left and lower right corners.
Next, the schema declares two classes (or tables, in relational database parlance): track and target. The target class could represent the immediate position of a blip on the radar. A target is declared to have an identifier (called target_id and of the int4 type), a name ( target_name , of string data type), and a bounding rectangle, target_loc that represents its position.
Within the target class, two indexes are declared: a b-tree index on target_id to enforce uniqueness and provide for speedy searches, and an r-tree on target_loc to find targets within specified bounding rectangles, e.g. find all targets within the box that has upper-left co-ordinates of 400,200 and lower-right co-ordinates of 100,400.
The track class could represent the path that a given target has followed over a period of time. In this definition, each track has an identifier (track_id); is associated with a specific target (target_id); can be given a name, and has an arbitrarily long array of co-ordinates (vector) that have been recorded as the target moves along its path. A hash index is declared for fast look-up of a track by track_id. The value 1000 represents an estimate of the number of tracks that will be stored in the database,and is used to determine the initial size of the hash table.
The schema is saved in a text file that is compiled by mcocomp, the database schema compiler. This generates two files: radar.h and radar.c.
The .h file has the function prototypes, several of which are shown in Example 2. A function prototype defines the name of the function, the data type of arguments that are passed into it, and the data type of the value returned by the function. The .c file (not shown) contains the database dictionary (the binary form of the readable database schema).
/*-----------------------------------------------------------------*/
/* class target methods */
MCO_RET target_new(mco_trans_h t, /*OUT*/ target *handle );
MCO_RET target_delete(target *handle );
MCO_RET target_target_id_get(target *handle, /*OUT*/ int4 * result);
MCO_RET target_target_id_put(target *handle, int4 value );
MCO_RET target_by_target_loc_search(mco_trans_h t_,
/*IN*/ MCO_OPCODE op_ ,
/*INOUT*/ mco_cursor_h c_,
const int2* target_loc );
/*-----------------------------------------------------------------*/
/* class track methods */
MCO_RET track_new(mco_trans_h t, /*OUT*/ track *handle );
MCO_RET track_delete(track *handle );
MCO_RET track_track_id_get(track *handle, /*OUT*/ int4 * result);
MCO_RET track_track_id_put(track *handle, int4 value );
MCO_RET track_by_track_id_find(mco_trans_h t,
int4 track_id,
/*OUT*/ track *handle_);
Every argument type is matched to its corresponding data type in the database design. When the programmer creates an entry for a new radar track:
MCO_RET track_new( mco_trans_h t, track *handle );
the function MCO_RET track_new requires handles to a database transaction and to a track object. If a programmer codes a handle to any other type of object, the ANSI C/C++ compiler issues a fatal error.
Figure 1: In-memory database systems were created with the database's schema compiler and diagnostic API.
Figure 2: Flow diagram illustrates the composition of APIs for embedded applications.