Page History
...
At first glance each of the above scenarios seems very different. Some of the examples work with already running engines while others dynamically launch engines. Some work with local engines while others connect to engines running on a different machine. Despite these differences, they all use the same basic logic to accomplish their tasks. Therefore, it will be well worth the effort to build a generic or “black box” system for working with multiple engines. This white paper will help you to design this foundation.
Getting Started Anchor Getting Started Getting Started
Getting Started | |
Getting Started |
Our intent is to provide you everything you need in this document to begin designing applications capable of using multiple engines. Nevertheless, you might be interested in getting a copy of the previously mentioned OI 4.1 New Features.pdf document. In some areas it has more detail regarding the new OpenEngine which might be helpful to programmers who desire to dig a little deeper.
...
Error | CreateRequest(hRequest, hQueue, ExecLine, Arg1, Arg2, Argn, …) | ||||
Error | Returns error number or 0 if no error (see the References section below.) | ||||
hRequest | Returns the handle to the request if successful. Variable should be initialized to null beforehand. | ||||
hQueue | The handle returned by the CreateQueue function. | ||||
ExecLine | Remote process to execute. Use the same syntax as when entering commands in the System Monitor and the System Editor’s Exec line:
Note: Any command line that is passed through the ExecLine parameter will be a literal string. Here is an example of how this might look:
As this example demonstrates, parameters are always literals. Addtionally, CreateRequest does not wait for the remote request to finish processing. Therefore we do not have the ability to detect changes that are made to these parameters as we normally would when passing parameters by reference. If this is a requirement then there are two options: 1.) Design the remote request to send back changes through the normal return data process (see the Twiddling Our Thumbs section below), or 2.) use the previously mentioned CallFunction or CallSubroutine commands instead (see the Requests for Dummies section below.) Using these commands, however, means that our local engine will be waiting for the remote engine to finish processing. While this provides us the ability to connect to remote engines, it defeats our purpose of “multitasking”. | ||||
Arg1…Argn | Actual arguments to pass into the ExecLine if replaceable parameters are used. In the example used above we embedded the RoutineName parameters in the ExecLine string. CreateRequest can also work with replaceable parameters. Using the CHECKLEGALUSER command this alternative syntax would look like this:
Note that the replaceable parameters were not quoted. Otherwise, RemoteRequest will treat them as the literal values to be passed. |
...
Error | Returns error number or 0 if no error (see the References section below.) | ||
hQueue | The handle returned by the CreateQueue function. | ||
Subroutine | Remote subroutine to execute. Unlike CreateRequest, the RUN command is not needed nor is it supported. If the function is local to the database that was specified in the CreateQueue function then only the subroutine name is required. Otherwise, append an asterisk and the application name to the subroutine name:
| ||
Arg1…Argn | Arguments (parameters) for the remote subroutine. Unlike RemoteRequest, these arguments can be passed by reference. That is, any changes made to the original values in the remote subroutine will be returned to the variables used in our calling routine. |
Twiddling Our Thumbs Anchor Twiddling Our Thumbs Twiddling Our Thumbs
Twiddling Our Thumbs | |
Twiddling Our Thumbs |
Once RemoteRequest has successfully executed our process, it is our responsibility to monitor the status of the remote engine. Two functions are available for this: WaitForReply and PollForReply. In the Getting the Big Picture chart above only PollForReply is mentioned. This is because WaitForReply does exactly what its name implies; that is, it waits for a reply from the remote engine before proceeding. Therefore, if our remote process is busy performing a long process then our local engine will be forced to wait until it is completed. Actually, to be technically correct, if the remote process uses the Send_Info or Send_Dyn commands to send information back then WaitForReply will allow the local engine to receive it. WaitForReply must then be called again to wait for the next information update or until the remote process has completed. Because many processes do not use Send_Dyn or Send_Info (like RList selects), WaitForReply is only a little better than using CallFunction or CallSubroutine.
...
Error | Returns error number or 0 if no error (see the References section below.) |
hRequest | The handle returned by the CreateRequest function. |
Status | Flag to determine the status of the remote process. These are included in the REVCAPI_EQUATES insert (see the References section below) and are described as follows:equ UNPROCESSED$ to 0 ;* Server has not begun request. |
Reply | This is supposed to contain information that has been returned from the remote engine. However, there is a known bug where this information is actually returned to the Status parameter instead. Fortunately this parameter is optional and we can use two other functions, GetReply and GetResponseText, to get this information. |
...
Code Block |
---|
Loop Error = PollForReply(hRequest, Status) Begin Case Case Error * An error was returned with the PollForReply function. Retrieve * error text and shutdown connection to remote engine. GoSub Process_Error GoSub Request_Done GoSub Return_Results Case Status EQ PROCESSING$ * Only used with PollForReply. Indicates that the remote engine is * still processing our request. Case Status EQ DATA_AVAILABLE$ * Information is available when the remote engine uses the Send_Dyn * routine in the request. GoSub GoSub Process_Status Case Case Status EQ INFO_AVAILABLE$ * Information is available when the remote engine uses the * Send_Info routine in the request. GoSub GoSub Process_Status Case Case Status EQ INFO_REQUEST$ * The remote engine is requesting information from the client using * the Req_Info routine. Use the SendResponse function to reply. Case Status EQ COMPLETED$ * The remote engine has completed our request (i.e. the end of the * program has been reached.) GoSub Process_Status GoSub Request_Done GoSub Return_Results Case Status EQ PROC_ERROR$ * An error occured in the remote engine request. Any Set_Status * error codes will be returned. GoSub Process_Status GoSub Request_Done GoSub Return_Results End Case Yield() Until Error OR Status EQ COMPLETED$ OR Status EQ PROC_ERROR$ Repeat |
...
Whenever any of our functions returns a value other than 0 we need to compare this with the list of errors from the Error Definitions (REVCERRS.H) file (see the [[1]]the References section below for a complete list.) Here is a portion of code that can be used:
...
With this final piece tied together you now have a “black box” approach toward managing remote engines. While this does not exhaust all that is possible with remote engines, we believe this will give many applications a significant enhancement boost in functionality. We hope that you will agree.
References Anchor References References
References | |
References |
Further information we think will be helpful are listed here for your convenience:
...
Code Block |
---|
compile Insert REVCAPI_EQUATES // CreateEngine Constants * Connect to an existing engine if possible, else create a new one. * Use this to create an engine connected to another database. equ CREATE_ENGINE_OPEN_EXISTING$ to 0x000 * Always create a new engine. * Engine will be created on the same machine as the calling engine. equ CREATE_ENGINE_CREATE_NEW$ to 0x001 * Only connect to engines that already exist. * This is the best way to connect to a remote engine. equ CREATE_ENGINE_OPEN_ALWAYS$ to 0x002 * Create an engine in indexing mode. equ CREATE_ENGINE_INDEXER$ to 0x010 * Create an engine that will not shut down when the connections end. equ CREATE_ENGINE_WAIT_ON_CLOSE$ to 0x020 * Keep the engine invisible (e.g. BitOr(CREATE_ENGINE_OPEN_ALWAYS$, REV_CREATE_ENGINE_NO_UI$) equ REV_CREATE_ENGINE_NO_UI$ to 0x040 equ UNPROCESSED$ to 0 ;* Server has not begun request. equ PROCESSING$ to 1 ;* Server is processing request. equ DATA_AVAILABLE$ to 2 ;* Server has data available. equ COMPLETED$ to 3 ;* Server has completed request, status ;* information is available. equ PROC_ERROR$ to 4 ;* Server process failed, status information is ;* available. equ INFO_AVAILABLE$ to 5 ;* Server has intermediate status information ;* available. equ INFO_REQUEST$ to 10 ;* Server is requesting information from client. declaredeclare function CreateEngine declare function CreateQueue declare function CreateRequest declare function PollForReply declare function WaitForReply declare function GetReply declare function SendResponse declare function GetStatusText declare function CloseRequest declare subroutine CloseRequest declare function CallSubroutine declare function CallFunction declare function CloseQueue declare subroutine CloseQueue declare function CloseEngine declare subroutine CloseEngine |
...