Runtime Control in C

The startup procedure that initializes the eXtremeDB runtime environment in C applications is mco_runtime_start(). It must be called before any database operations can be performed. However, prior to calling mco_runtime_start(), it is common practice to register a fatal error handler by calling mco_error_set_handler()and in some special cases it may be necessary to set runtime options by calling mco_runtime_setoption(). The function mco_get_runtime_info() can be called any time after initialization to obtain the specific configuration details of the current runtime. Then, when finished with database activity (after disconnecting from and closing all databases), C  applications must call mco_runtime_stop() to clean up semaphores and perform an orderly shutdown of the runtime.

The typical sequence of API calls would look like the following:

 
    static void errhandler(MCO_RET n)
    {
        printf("\neXtremeDB runtime fatal error: %d", n);
        getchar();
        exit( 0 );
    }
     
    int main(int argc, char* argv[])
    {
        MCO_RET   rc;
        mco_db_h  db;
         
        mco_error_set_handler(&errhandler);
         
        mco_runtime_start();
         
        // Perform database processing
         
        mco_runtime_stop();
    }

 

Runtime Options

There are a small number of per-process global database runtime options to manage shared memory operating system parameters and other special features. These options are set by calling mco_runtime_setoption() prior to runtime initialization and can be retrieved at any time prior to runtime shutdown by calling mco_runtime_getoption(). (Please refer to the Reference Guide page mco_runtime_setoption() for the list of actual runtime options.)

For example a multi-process shared memory application on a Unix system may need to set the shared memory access mode from the default value of 0666. To do so the application would set this runtime option with code like the following.

 
    mco_runtime_setoption( MCO_RT_OPTION_UNIX_SHM_MASK, 0600 );
    ...
    mco_runtime_start();
    ...
 

Persistent Databases

The runtime options for persistent database applications are the same as for in-memory database applications, however there are important memory device definitions and database open parameters that must be specified for persistent databases. (Please use these links for detailed explanations.)

Runtime Libraries

At a minimum, In-Memory database applications must link with the following basic eXtremeDB libraries:

1. mcolib: basic core runtime functions

2. mcovtmem: “virtual table” memory manager functions

3. mcotmursiw, mcotmvcc or mcotexcl: Transaction Manager functions

4. mcomconv, mcomipc, mcompsx, or mcomw32: memory devices functions

5. synchronization library: functions that synchronize access to database objects as well as internal runtime structures (see below)

6. mcouwrt or mcowrt: utility functions

Persistent Databases

Whereas In-Memory database applications use the “virtual tables” library mcovtmem, persistent database applications use library mcovtdsk and a file system library:

Applications that use the eXtremeDB mco_db_save() or mco_db_load() functions to store and retrieve database image files to or from persistent media, require serialization and file system functions that are provided in the mcoseri library. (Please refer to the runtime libraries reference guide page for further details and examples.)

Synchronization Libraries

The database repository and the database runtime metadata are shared resources. They are read and written by multiple tasks at a time. To ensure the correctness of internal structures and repository data, the eXtremeDB runtime must make sure that those read and write operations are executed in proper order. In other words, access to them must be “synchronized”. For most supported platforms, two synchronization methods are provided. One is based solely on the operating system’s synchronization kernel primitive, such as semaphores. The other method combines atomic instructions with OS synchronization primitives.

A locking algorithm can create a user-space “fast path” by first attempting to lock the resource using an atomic instruction. If the attempt fails, and a thread needs to block, a system call is then executed. But if there is no contention (as is often the case) the kernel doesn't need to be notified. Kernel calls are relatively expensive because they lead to CPU context switching and other activity. So where atomic operations are possible, they provide significant performance advantages.

These synchronization methods are implemented in the synchronization libraries. All applications, except possibly single-threaded applications (see comment on mcosempty.c below) must link with one of the synchronization libraries listed in the package contents by operating system. Where possible, a version of the library is provided that uses “atomic operations” to avoid unnecessary kernel calls.

Most applications, particularly single-threaded or multi-threaded applications with low database activity (on the order of one database update per second), can benefit greatly by using the “+ atomic op.” library if available. But there is no universal general rule. Many factors determine whether the “+ atomic op.” library will work, such as: the application’s database access pattern and rate, the kernel’s scheduler policy, and even hardware.

Where two versions of the synchronization library are provided, the same version must be used by all applications. When more than one application will be accessing the database, or in multi-platform scenarios where database access may be incorporated in different application modules written in C, C++, C# or Java, it is important that all application modules are linked with the same synchronization library.

The file mcosempty.c contains a “hollow” synchronization implementation that can be compiled on any platform. It has no synchronization code, so it is the fastest implementation - but it is valid for single-threaded applications only. If this source file is included in the application build, then no synchronization library is necessary.

The most commonly used synchronization libraries are:

(Again, please refer to the package contents for platform-specific details.)

Direct Pointer Libraries

As mentioned in the Product Overview, eXtremeDB provides two versions of runtime libraries for all-in-memory databases: the optimized “Direct Pointer Arithmetic” version and the “Offset” version. The advantages of the “Offset” libraries are A) that a saved binary image of an in-memory database can be loaded to a different starting address in memory, and, B) two (or more) applications that share an in-memory database in shared memory do not have to map the shared memory segment to the same address space in their local process (which is sometimes impossible). The advantage of the Direct Pointer Arithmetic library is better performance, and is ideal for in-memory databases within a single (possibly multi-threaded) process.

In eXtremeDB packages prior to version 7.1, the package was specifically built for Direct Pointer or for Offset support. For eXtremeDB version 7.1 and later all packages include two versions of the runtime libraries. The Offset version is the default and this version of the runtime libraries is located in directories eXtremeDB/target/bin and eXtremeDB/target/bin.so. The Direct Pointer version of the libraries is located in directories eXtremeDB/target/bin.dptr and eXtremeDB/target/bin.dptr.so.

When building applications on Unix-Linux systems, the make command line option PRJ_DIRECTPTR=YES can be used to cause linking with the Direct Pointer libraries. On Windows, applications are generally developed with Visual Studio which does not have a convenient command line option. So to link with the Direct Pointer libraries, project settings must be properly set to the eXtremeDB/target/bin.dptr or eXtremeDB/target/bin.dptr.so directories.