Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Database

Using Velocis Extension Modules


Dr. Dobb's Sourcebook July/August 1997: Using Velocis Extension Modules

Walter, a senior project engineer for Heidleberg Finishing Systems, can be contacted at [email protected].


Choosing and implementing a client/ server database system is never simple, and the choices you must make rarely occur in a vacuum. You may have an existing system to convert, cost is always a factor, the platform may already be decided, and even departmental politics take a role. Coming up with a good solution is a challenge that also requires a bit of luck.

The company I work at (Heidleberg Finishing, which provides post-printing services for newspapers), faced this kind of problem three years ago. We build systems that have a significant real-time performance requirement because they interface with machinery controls. Although we had successfully implemented a file-based database at two sites, we still faced performance problems. Even though we had originally built the systems around Raima's DBVista database engine because of its speed, our performance analysis kept pointing to the database. Apparently, DBVista's file-centric design began to work against us as we added more and more workstations.

In some ways, this came as little surprise since DBVista was originally designed for stand-alone PCs. It was extended to run on multiple PCs, accessing a networked database by treating it as a shared file. But all the database processing is done on the local workstation. This leads to limited scalability, complex table locking mechanisms, and synchronized caching processes.

To address the performance issues, we had a couple of options -- we could switch to another vendor's client/server database (such as Sybase or Oracle), or to Velocis, Raima's multithreaded, scalable, SQL client/server database engine. At the time, we thought long and hard about the decision because Raima was not well-known and Velocis was new. In its favor, however, the function calls to Velocis were almost identical to DBVista, minimizing the learning curve, conversion cost, and customer risks.

Velocis supports relational, network, and combined database models, and its server extensions allow processing to occur on either the client or server side. Velocis provides multiple APIs, including those for C, ODBC SQL, and C++. It also supports interfaces to Visual Basic, Delphi, and Perl for direct access to multiple Velocis APIs. Velocis is available on Windows 95/NT, OS/2, HP-UX, SCO, AIX, BSDI, NetWare, MIPS ABI, and other platforms.

Velocis Extension Modules

Although the Velocis API was compatible with the one we were already using, we were still worried that it might not deliver the necessary performance. The Velocis API would link to a centralized database server process via a network. Although the actual file access would be on the server (which would also manage the locking and the cache), the linkage to the application was still one record at a time. We were certain that performance would be significantly improved, but were afraid that it wouldn't be enough. While we could have set up benchmark tests to monitor performance, we didn't have time to convert and test the entire application.

A developer pointed out that Velocis offered another option -- Velocis's "Extension Module" feature, which lets you define your own API to interface to the database. The code in the Extension Module runs within the Velocis server process, so it has direct access to the database. This would allow us to move large blocks of records to and from the database in a single call. And it looked like it would take about the same amount of time to do the conversion.

Consequently, we decided to convert our code to move all of the database-access code into a set of Extension Modules. Most of the time was spent learning the ins-and-outs of the RPC-calling mechanism. The documentation was thin and there were few examples. Even Raima's support staff couldn't answer most of our questions. We finally talked to a developer who pointed us in the right direction. The rest of the existing DBVista code moved over almost without change.

We successfully converted the application over to Velocis in about six weeks, resulting in a dramatic improvement in system performance. For example, a simple system-status query that had taken 20-30 seconds to execute on a loaded system, now took less than a second. And the whole system was much more crisp and responsive.

But we found several extra benefits. Because we define the interface, we can pass large blocks of data over the network rather than having to read or write data a record at a time. This minimized the network traffic. We have a workstation at a remote warehouse that is connected over a 56-KB dialup-link that we share with Novell clients. Except for the initial order download, users can't tell that they aren't directly connected to the main plant network.

The ability to pass large blocks of data also eliminated the need to do record-level locking. Since the block of records could be updated as one pass, we locked the affected tables, did the gang of updates, and unlocked the tables. And since the server was already the fastest machine in the system, we were making the best use of the system resources.

How Does it Work?

The Velocis Extension Module is loosely equivalent to a stored procedure in SQL. It is a library of functions that is loaded on demand into the Velocis server process running on a remote machine. You pass it data and invoke a function. The user code in the Extension Module retrieves the parameters, performs the required action, and returns status and data. Velocis supports Named Pipes, Netbios, IPX/SPX, and TCP/IP interfaces between the client and server. The Extension Module API rides on top of this transport-independent mechanism to invoke functions, pass parameters, and return results -- an RPC mechanism, in other words. To call an Extension Module, you first logon to the database server process and open the required database. You then pass the name of the Extension Module to load. (You can have more than one Extension Module loaded at the same time.) Extension Modules are stored as DLLs on OS/2 and Windows, and NLMs on Novell. Velocis locates the module and loads it. To call a function, you invoke it by number with a matching jump table in the Extension Module used to invoke the function.

Parameters are passed in a somewhat complicated mechanism. Because the server may be running on a machine that has a different processor than the client, Velocis needs to pass the parameter type along with the parameter data so that it can handle any needed conversions such as byte order of integers, float formats, and so on. You first allocate and initialize a parameter block with the number of parameters you plan to pass. You then "put" each parameter into the parameter block along with a description of the parameter. The description supports all the standard C data types, such as int, float, char arrays and Zero-terminated ASCII strings. It also supports defining structures of base types. To simplify processing between two like processor types, Velocis also supports an opaque type that is passed exactly as is. After processing, the Extension Module function passes back parameters in a similar way.

This parameter passing mechanism is straightforward and not time consuming, but can lead to messy code -- not exactly what you want in an RPC mechanism. It would be nicer if the calls looked exactly like function calls to other functions in your program. We built a Velocis access layer that the applications can call that does just that. So, if the application needs to read a list of all valid orders, it would call VelReadValidOrders. That function would be defined in a Vel library that would do all the appropriate parameter passing to the Extension Module and handle all the returns. This makes the client-side code work exactly the way you would want it to. In Listing One you can see that the client code might call VelSetOfflineQueued(Session, hDB, hEM, Date, &Error).

In some cases, we have client calls that pass three parameters and invoke several thousand lines of code in the Extension Module to do hundreds of database operations that only return a status to the client. In other cases, large blocks of data are read as arrays into the client and all the processing occurs there. It depends on how much interaction with the user is needed. As you can see, the code is mostly involved with setting up the calling parameters, and less involved with invoking the rpc_emCall function itself.

To further simplify the parameter passing and code development, one of our developers created a combination of C/C++ macros plus some base code that lets him define both the calling functions and the receiving functions in one code block; see Listing Two. This is driven by some complicated macros and multiple compile passes necessary to generate include files for the client and server sides. This took quite a while to get right. But since then, that work has paid off, as you can tell from the amount of code needed to generate a function call. And the actual call in the client code (see Listing Three) is straightforward.

Challenges

One restriction of the parameter passing is that the size of the parameters being passed is limited. The specifications say 64 KB (I guess so it can support Windows 3.1, since all the other platforms are 32 bit). In practice we have found that anything over 2 KB caused problems. Consequently, we either sidestep the problem by limiting the amount of data passed, or we use multipass calls that pass larger blocks of data in or out of the Extension Module.

It's often hard to remember that the code is running in a separate process and doesn't have access to local variables unless they are passed. It's also harder to verify that the parameters passed are correct since each is defined and passed in a separate putParam call -- no C++ strong typing here.

However, having all the database functions in the Extension Module limited our debugging capabilities, so we had to fall back on printf statements for debugging. We found it even more important to test the Extension Module functions because a significant failure can bring down the whole server.

When we started developing with Extension Modules three years ago, Raima did not support the use of C++ for the Extension Module. It now has a C++ toolkit for database functions, which makes some of the parameter passing functions easier.

Other Uses of Extension Modules

Since the Extension Module is primarily an RPC mechanism to a centralized server process, it can be used in other ways, too. It can access shared memory in a heterogeneous environment. Datatypes otherwise not supported by Velocis, such as bitmaps, could be supported. While the relational database model supports most business data requirements, it really is not suited for multimedia storage, retrieval, and indexing. You could write an Extension Module to provide support for multimedia. In fact, the best feature of the Extension Module mechanism is that it can be extended to deal with new problems in the future.

Conclusion

Overall, we have been happy with the performance and reliability of the Raima Velocis database and the use of the Extension Modules. Our tests indicate that using the Extension Module for database access results in the highest performance. Running the database on a PC means the environment is often not as reliable as we would like, but the Velocis database has proven to be both reliable and resilient. If the plug gets pulled in midtransaction, Velocis cleanly recovers the database back to the last completed transaction.

The only significant issue we have with Velocis is nontechnical -- Velocis is not very well known. When selling our product, the type of database we use inevitably comes up. When we tell a potential customer that we use Raima Velocis, we often get a blank stare. But that hasn't stopped customers from buying from us, and they, too, have come to appreciate Velocis's performance and reliability. Looking back, it appears that we made the right decision.

DDJ

For More Information

Raima Corp.
4800 Columbia Center
701 Fifth Ave.
Seattle, WA 98104
206-515-9477
http://www.raima.com/

Listing One

USHORT EXPENTRY VelSetOfflineQueued( RDM_SESS       rsSession,                                     RDM_DB         rdDbHandle,
                                     short          hEM,
                                     PSZ            pszProductionDate,
                                     SHORT          *sErrorCode )
{
    PDPLDATADESC        inParm;
    PDPLDATADESC        outParm;
    short               stat ;
    RDM_SESS            rsServerSession ;
    RDM_DB              rdServerHandle ;


</p>
    *sErrorCode = S_UNAVAIL ;
    while ( *sErrorCode == S_UNAVAIL ) 
    {
        inParm = rpc_allocParmList( 3 ) ;
        rpc_initParmList( inParm ) ;


</p>
        rsServerSession = rpc_remoteSess(rsSession);
        *sErrorCode = rpc_putParm(inParm,DPL_DT_U_SHORT,&rsServerSession,0);
        if ( *sErrorCode != S_OKAY )
        {
              return FALSE ;
        }
        rdServerHandle = rpc_remoteDb(rdDbHandle);
        *sErrorCode = rpc_putParm(inParm,DPL_DT_U_LONG,&rdServerHandle,0);
        if ( *sErrorCode != S_OKAY )
        {
              return FALSE ;
        }
        *sErrorCode = rpc_putParm( inParm, DPL_DT_CHAR | DPL_DT_MOD_ARRAY,
                (void *)pszProductionDate, SIZEOF_WORKORDER_REALPRODDATE ) ;
        if ( *sErrorCode != S_OKAY )
        {
             return FALSE ;
        }
        stat = rpc_emCall( hEM, SD_SET_OFFLINE_QUEUED, inParm,
                                        &outParm, sErrorCode, rsSession ) ;
        if ( stat != S_OKAY )
        {
            *sErrorCode = stat ;
              return FALSE ;
        }
        rpc_freeParmList( outParm ) ;
        rpc_freeParmList( inParm ) ;
    }
    return TRUE ;
}

Back to Article

Listing Two

RPC_FUNCTION_BEGIN1( Advertiser, Create,  STRUCT(Advertiser, pAdvertiser) )
  #if (RPC_TYPE == RPC_SERVER)
  IFSTAT( d_trbegin( "xact", ctx->hSess  ) )
  IFSTAT( d_rtlock( ADVERTISER, "w", ctx->hDB ) )
  IFSTAT( d_fillnew( ADVERTISER, pAdvertiser, ctx->hDB) )
  END_XACTION
  #endif
RPC_FUNCTION_END

Back to Article

Listing Three

int Advertiser_Read( StructArray * Advertisers, const char *TitleID, short hContext );


</p>

Back to Article


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.