IBM Support

CWBDQ: Q&A for the Optimized Data Queue API

Troubleshooting


Problem

This document contains frequently asked questions about the IBM i Access Client Solutions Windows Application Package data queue API support and automation objects and controls.

Resolving The Problem

Q: Data queue performance is very slow when switching between different data queue handles or attribute handles.

A: The data queue API DLL manages IBM System i products connections for the user. Before R320, there was no API to directly control when the DLL started or ended the job on the system. By default, the DLL starts a conversation the first time a data queue handle is used on an API that requires information from the system (send, receive, attributes, and so on). The IBM OS/400 or IBM i5/OS server job ends when the last data queue handle to a specific system is closed. APIs that use attribute handles start and end a job on each API call.

Starting and stopping jobs on the System i has significant CPU usage and can slow application response time. To avoid the expense of ending and starting data queue jobs, consider one of the following methods:
  • Client Access R320 and later contain new APIs (cwbDQ_StartSystem and cwbDQ_StopSystem) that manage the connection at a system level rather than at a data queue level.
  • Leave at least one data queue handle open always. If using multiple data queue handles or attribute handles, do the following:
    - Open the second data queue handle before deleting the old one.
    - Open the data queue handle first. Then, use the attribute handle. The attribute API uses the existing job.
Note: This technique does not work with the data queue OCX or OLE automation objects.

This example starts only one job for better performance:
//This will start the System i job
cwbDQ_Open("Queue1", "LIB1", "MYSYS",  queueHandle1, errHandle);
//do work here
// use attribute handles here
cwbDQ_Create("QUEUE2", "LIB1", "MYSYS", queueAttr, errHandle);
cwbDQ_Open("Queue2", "LIB1", "MYSYS",  queueHandle2, errHandle);
cwbDQ_Close(queueHandle1);
//do work here
//This will end the System i job since there are no longer any open handles....
cwbDQ_Close(queueHandle2);

The same program with APIs in a different order starts and stops six jobs and runs much slower with more CPU usage:
 
//This will start and end a job
cwbDQ_Create("QUEUE2", "LIB1", "MYSYS", queueAttr, errHandle);

//This will start the second job
cwbDQ_Open("Queue1", "LIB1", "MYSYS",  queueHandle1, errHandle);
//do work here
// use attribute handles here
//This will end the job
cwbDQ_Close(queueHandle1);

//This will start a third job
cwbDQ_Open("Queue2", "LIB1", "MYSYS",  queueHandle2, errHandle);
//do work here
//This will end the third job
cwbDQ_Close(queueHandle2);


Q: Certain invariant characters are not converted correctly with SetConvert TRUE

A: Applications written for 32-bit Microsoft Windows operating systems most often use the Windows ANSI code page. The default for Client Access APIs (other than ODBC) is the OEM or DOS code page which can cause character corruption if the convert API is set to TRUE.

R313 and later of Client Access added a version of cwbDQ_SetConvert API so that the conversion can now support Unicode and ANSI code pages. Define CWB_ANSI (before the header file include) or call the cwbDQ_SetConvertA API. The data queue API uses the default ANSI code page. See the API Overview chapter of the Client Access API Reference for further information.

Q: Is the data queue API thread safe?

A: Yes, the data queue API is intended to be thread safe; however, a few fixes were created. Be sure you have Client Access R313 with Fix Pack SF48155 or later (SA65417).

Q: What is the best method to do multiple reads or writes?

A: The typical method would be to create and set up only one data object and then repetitively call the read or write API. Note each CreateData must have a corresponding DeleteData. For example:
 
//open the queue
rc = cwbDQ_Open(szDQName, szLibName, szSysName, &queueHandle, hCwbErr);
if (rc != CWB_OK) goto dqerror;

//create one data object
queueData = cwbDQ_CreateData();
if (queueData == 0) goto dqerror;

//Set the ASCII/EBCDIC data conversion attribute if desired
rc = cwbDQ_SetConvert(queueData, TRUE);
if (rc != CWB_OK) goto dqerror;

//This "binds" the data queue data object pointer to the variable myData
//Note that no copy of the data is made.  The Data queue read and write
//api's will read/write directly to this memory location.  The programmer is
//responsible for ensuring that the pointer points to a valid memory location.
rc = cwbDQ_SetDataAddr(queueData, //data object handle
myData, // pointer to memory location where data resides
sizeof(myData));      // size of data to read/write
if (rc != CWB_OK) goto dqerror;

for (i = 0; i < lNumWrites; i++)
{
//Set the data you want to write at the memory location
//used above (address of myData)
memset(myData, CharData[i%36], sizeof(myData));
rc = cwbDQ_Write(queueHandle,
queueData,
CWB_TRUE,
hCwbErr);
if (rc != CWB_OK) goto dqerror;
printf("Wrote record %d to data queue\n", i);
}
//Delete the Data object to free memory
rc = cwbDQ_DeleteData(queueData);
//close the data queue handle
rc = cwbDQ_Close(queueHandle);


Q: Is it true that cwbDQ_Write appears to have a memory leak when commit is FALSE?

A: SA66344 corrected one defect regarding this; however, programmers need to be aware of an undocumented behavior when using this setting. When commit is set to FALSE, internal memory allocated for the write is not released until a response is received from the System i system. The System i does not send a response until another API is called that requires a response. Therefore, when using this API on multiple calls, it is the responsibility of the programmer to periodically call another API requiring a response. For example, every 500 writes, the programmer could call cwbDQ_Write with commit set to TRUE. This gives the program the performance advantage of using commit FALSE while still limiting total memory use.

Q: I am attempting to read from a keyed data queue. Although the data has been written to the data queue, my read never returns. Why?

A: A common mistake is to assume that if cwbDQ_SetConvert has been used to set the convert attribute to TRUE then the key and data will be converted from EBCDIC to ASCII. This is not the case. The convert APIs state that all "data" being read or written will be converted. This does not imply that the key is also converted. The reason for this is that keys are binary values, not necessarily text (there is no associated CCSID to a key). If the application involves both the operating system and Client Access programs accessing the data queue, then the programmers must agree on a format of the key. If strings are going to be used, then one of the programs needs to handle conversion between ASCII and EBCDIC. String conversions can be done on the PC by using the Client Access NLS (national language support) APIs.

Q: Why do the APIs fail when I try to use a data queue in QTEMP?

A: See the previous answer. QTEMP is a temporary library with a scope of that particular job only. It is destroyed when the job ends and cannot be accessed from any other job. If a handle is closed so the job is ended and started again, the library (and its contents) is deleted.

Q: Why does the user profile of the job need authority to QGPL library?

A: If the user profile used for the data queue job does not have authority to QGPL, the data queue job fails to start. A communication trace shows an FMH-7 with a 0864 (program error) sense code. The job log has a message indicating that either the user profile does not have authority to QGPL or the user profile exceeded its maximum storage.

Following is a technical description of the reason that QGPL needs to be used rather than other job-related, temporary storage areas. Note the optimized data queue server uses two conversations per job or process. Two IBM i data queue jobs are started per PC data queue process. The second job starts, passes its conversation to the first job, and ends. The result is two conversations (as displayed in WRKCFGSTS) for the same OS/400 job.
  • - Technical Details



    To establish two APPC conversations between the Windows 95 client and the optimized data queue server, both connections must be initiated from the client. The communications stack shipped with the Windows 95 client does not support an incoming allocate to an active TP.

    Both connections start jobs on IBM i. To pass the second conversation to the first job, a method was needed to tell the second job what MI Request Queue pointer it will use. With Windows 95, it is also possible for multiple client jobs to be started from the same PC (or APPC Device). This feature eliminated the use of a MIRQ pointer field that is in the LUD. We chose to use a temporary space, whose name is ZHQxxxxxx, where xxxxxx is the job number of the first job (which was passed back to the client after the first connection was established).

    For V3R1, we initially created this space in QUSRSYS. Due to changes in how the *PUBLIC authority was set up for libraries, we changed the library that is used. The most logical libraries were QGPL or QTEMP. Each process (job) has its own QTEMP. Therefore, creating a space in the QTEMP of one job would not make it accessible to the other job. Therefore, we selected QGPL.

    If the data queue server is going to be used, the connecting user must be authorized to QGPL.



Q: What data queue return codes are directly mapped to OS/400 messages?

A: For data queue return codes, see CWBDQ: Optimized Data Queue API Return Code and Host Error Messages

Q: Where are the samples, and what samples are available?

A: Note: Samples are not submitted to any formal test and are distributed as is. They are not supported. The Microsoft visual basic API declares are also provided as is, without support.
  • Client Access for Windows 95/NT API and Technical Reference (SC41-3513-0x) CD: A visual C++ MFC document/view based applet sample.
  • Client Access for Windows 95/NT API and Technical Reference (SC41-3513-0x) CD: A visual Basic version of the applet sample.
  • Via Support Line: A visual C++ MFC menu-based API tester.
  • Via Support Line: A C console application showing how to use all basic API functions.
  • Via Support Line: A C console application showing how to use the asynchronous read and check data APIs.
  • Via Support Line: A C console application sample of multi-threaded reads.
  • Via Support Line: A visual Basic sample demonstrating use of various functions.

[{"Business Unit":{"code":"BU054","label":"Systems w\/TPS"},"Product":{"code":"SWG60","label":"IBM i"},"Component":"Data Access","Platform":[{"code":"PF012","label":"IBM i"}],"Version":"Version Independent","Edition":"","Line of Business":{"code":"LOB08","label":"Cognitive Systems"}}]

Historical Number

8724047

Document Information

Modified date:
01 January 2020

UID

nas8N1010116