The figure “Queued Service Invocation” on page 1‑2 shows the queued message being dequeued by the server
TMQFORWARD(5) and sent to an application server for processing (via
tpcall(3c)). When a reply to the
tpcall() is received,
TMQFORWARD enqueues the reply message. Because a major goal of
TMQFORWARD is to provide an interface between the queue space and existing application services, it does not require further application coding. For that reason, this topic concentrates on the client-to-queue space side.
#include <atmi.h>
int tpenqueue(char *qspace, char *
qname, TPQCTL *
ctl,
char *
data, long
len, long
flags)
When a tpenqueue() call is issued, it tells the system to store a message on the queue identified in
qname in the space identified in
qspace. The message is in the buffer pointed to by
data and has a length of
len. By the use of bit settings in
flags, the system is informed how the call to
tpenqueue() is to be handled. Further information about the handling of the enqueued message and replies is provided in the
TMQCTL structure pointed to by
ctl.
qspace identifies a queue space previously created by the administrator. When a server is defined in the
SERVERS section of the configuration file, the service names it offers are aliases for the actual queue space name (which is specified as part of the
OPENINFO parameter in the
GROUPS section). For example, when your application uses the server
TMQUEUE, the value pointed at by the
qspace argument is the name of a service advertised by
TMQUEUE. If no service aliases are defined, the default service is the same as the server name,
TMQUEUE. In this case the configuration file might include:
The entry for server group QUE1 has an
OPENINFO parameter that specifies the resource manager, the pathname of the device and the queue space name. The
qspace argument in a client program then looks like this:
data points to a buffer that contains the message to be processed. The buffer must be one that was allocated with a call to
tpalloc(3c).
len gives the length of the message. Some Oracle Tuxedo buffer types (such as FML) do not require that the length of the message be specified; in such cases, the
len argument is ignored.
data can be NULL; when it is,
len is ignored and the message is enqueued with no data portion.
flags values are used to tell the Oracle Tuxedo system how the
tpenqueue() call is handled; the following are valid flags:
When TPNOBLOCK is not set and a blocking condition exists, the caller blocks until the condition subsides or a timeout occurs (either transaction or blocking timeout). If a timeout occurs, the call fails and
tperrno() is set to
TPETIME.
The third argument to tpenqueue() is a pointer to a structure of type
TPQCTL. The
TPQCTL structure has members that are used by the application and by the Oracle Tuxedo system to pass parameters in both directions between application programs and the queued message facility. The client that calls
tpenqueue() sets flags to mark fields the application wants the system to fill in. The structure is also used by
tpdequeue(); some of the fields do not come into play until the application calls that function. The complete structure is shown in
Listing 3‑1.
If this flag is set, the message is made available after the time specified by ctl->deq_time. The
deq_time is an absolute time value as generated by
time(2) or
mktime(3C), if they are available to your application, or
gp_mktime(3c), provided with the Oracle Tuxedo system. The value set in
ctl->deq_time is the number of seconds since 00:00:00 Universal Coordinated Time—UTC, January 1,1970. The absolute time is set based on the clock on the machine where the queue manager process resides.
TPQTIME_ABS and
TPQTIME_REL are mutually exclusive flags.
If this flag is set, the correlation identifier value specified in ctl->corrid is available when a request is dequeued with
tpdequeue(3c). This identifier accompanies any reply or failure message that is queued so an application can correlate a reply with a particular request. Note that the entire 32 bytes of the correlation identifier value are significant, so the value specified in
ctl->corrid must be completely initialized (for example, padded with NULL characters).
If this flag is set, a reply queue named in ctl->replyqueue is associated with the queued message. Any reply to the message is queued to the named queue within the same queue space as the request message. This string must be NULL-terminated (maximum 127 characters in length). If a reply is generated for the service and a reply queue is not specified or the reply queue does not exist, the reply is dropped.
If this flag is set, a failure queue named in the ctl->failurequeue is associated with the queued message. If (1) the enqueued message is processed by
TMQFORWARD(), (2)
TMQFORWARD was started with the
-d option, and (3) the service fails and returns a non-NULL reply, a failure message consisting of the reply and its associated
tpurcode is enqueued to the named queue within the same queue space as the original request message. This string must be NULL-terminated (maximum 127 characters in length).
If the TPQDELIVERYQOS flag is set, the flags specified by
ctl‑>delivery_qos control the quality of service for delivery of the message. In this case, one of three mutually exclusive flags—
TPQQOSDEFAULTPERSIST,
TPQQOSPERSISTENT, or
TPQQOSNONPERSISTENT—must be set in
ctl‑>delivery_qos. If
TPQDELIVERYQOS is not set, the default delivery policy of the target queue dictates the delivery quality of service for the message.
If the TPQREPLYQOS flag is set, the flags specified by
ctl‑>reply_qos control the quality of service for any reply to the message. In this case, one of three mutually exclusive flags—
TPQQOSDEFAULTPERSIST,
TPQQOSPERSISTENT, or
TPQQOSNONPERSISTENT—must be set in
ctl‑>reply_qos. The
TPQREPLYQOS flag is used when a reply is returned from messages processed by
TMQFORWARD. Applications not using
TMQFORWARD to invoke services may use the
TPQREPLYQOS flag as a hint for their own reply mechanism.
If TPQREPLYQOS is not set, the default delivery policy of the
ctl‑>replyqueue queue dictates the delivery quality of service for any reply. Note that the default delivery policy is determined when the reply to a message is enqueued. That is, if the default delivery policy of the reply queue is modified between the time that the original message is enqueued and the reply to the message is enqueued, the policy used is the one in effect when the reply is finally enqueued.
TPQEXPTIME_ABS,
TPQEXPTIME_REL, and
TPQEXPTIME_NONE are mutually exclusive flags. If none of these flags is set, the default expiration time associated with the target queue is applied to the message.
TPQEXPTIME_ABS,
TPQEXPTIME_REL, and
TPQEXPTIME_NONE are mutually exclusive flags. If none of these flags is set, the default expiration time associated with the target queue is applied to the message.
TPQEXPTIME_ABS,
TPQEXPTIME_REL, and
TPQEXPTIME_NONE are mutually exclusive flags. If none of these flags is set, the default expiration time associated with the target queue is applied to the message.
Additionally, the urcode field of
TPQCTL can be set with a user-return code. This value will be returned to the application that calls
tpdequeue(3c) to dequeue the message.
On output from tpenqueue(), the following fields may be set in the
TPQCTL structure:
The following is a valid bit for the flags parameter controlling output information from
tpenqueue(). If this flag is turned on when
tpenqueue() is called, the /Q server
TMQUEUE(5) populates the associated element in the structure with a message identifier. If this flag is turned off when
tpenqueue() is called,
TMQUEUE() does
not populate the associated element in the structure with a message identifier.
If this flag is set and the call to tpenqueue() is successful, the message identifier is stored in
ctl->msgid. The entire 32 bytes of the message identifier value are significant, so the value stored in
ctl->msgid is completely initialized (for example, padded with null characters). The actual padding character used for initialization varies between releases of the Oracle Tuxedo /Q component.
If the call to tpenqueue() fails and
tperrno(5) is set to
TPEDIAGNOSTIC, a value indicating the reason for failure is returned in
ctl->diagnostic. The possible values are:
If the administrator, in creating a queue, allows tpenqueue() calls to override the order of messages on the queue, you have two mutually exclusive ways to use that capability. You can specify that the message is to be placed at the top of the queue by setting
flags to include
TPQTOP or you can specify that it be placed ahead of a specific message by setting
flags to include
TPQBEFOREMSGID and setting
ctl->msgid to the ID of the message you wish to precede. This assumes that you saved the message-ID from a previous call in order to be able to use it here. Your administrator must tell you what the queue supports; it can be created to allow either or both of these overrides, or to allow neither.
You can set a value in ctl->priority to specify the priority of the message. The value must be in the range 1 to 100; the higher the number the higher the priority. If
priority was not one of the queue ordering parameters, setting a priority here has no effect on the dequeuing order, however the priority value is retained so that the value can be inspected when the message is dequeued.
You can specify in deq_time either an absolute time or a time relative to the completion of the enqueuing operation for the message to be made available. You set
flags to include either
TPQTIME_ABS or
TPQTIME_REL to indicate how the value should be treated. A queue may be created with
time as a queue ordering criterion, in which case the messages are ordered by the message availability time.
Oracle Tuxedo /Q provides a function, gp_mktime(3c), that is used to convert a date and time provided in a
tm structure to the number of seconds since January 1, 1970. The
time(2) and
mktime(3C) functions may also be used instead of
gp_mktime(3c). The value is returned in
time_t, a
typedef'd long. To set an absolute time for the message to be dequeued (we are using 12:00 noon, December 9, 2001), do the following.
2.
|
Call gp_mktime to produce a value for deq_time and set the flags to indicate that an absolute time is being provided.
|
If a caller of tpenqueue() is in transaction mode and
TPNOTRAN is not set, then the enqueuing is done within the caller's transaction. The caller knows for certain from the success or failure of
tpenqueue() whether the message was enqueued or not. If the call succeeds, the message is guaranteed to be on the queue. If the call fails, the transaction is rolled back, including the part where the message was placed on the queue.
If a caller of tpenqueue() is not in transaction mode or if
TPNOTRAN is set, the message is enqueued outside of the caller’s transaction. If the call to
tpenqueue() returns success, the message is guaranteed to be on the queue. If the call to
tpenqueue() fails with a communication error or with a timeout, the caller is left in doubt about whether the failure occurred before or after the message was enqueued.
When this call is issued it tells the system to dequeue a message from the qname queue in the queue space named
qspace. The message is placed in a buffer (originally allocated by
tpalloc(3c)) at the address pointed to by *
data.
len points to the length of the data. If
len is 0 on return from
tpdequeue(), the message had no data portion. By the use of bit settings in
flags, the system is informed how the call to
tpdequeue() is to be handled. The
TPQCTL structure pointed to by
ctl carries further information about how the call should be handled.
qspace identifies a queue space previously created by the administrator. When the
TMQUEUE server is defined in the
SERVERS section of the configuration file, the service names it offers are aliases for the actual queue space name (which is specified as part of the
OPENINFO parameter in the
GROUPS section). For example, when your application uses the server
TMQUEUE, the value pointed at by the
qspace argument is the name of a service advertised by
TMQUEUE. If no service aliases are defined, the default service is the same as the server name,
TMQUEUE. In this case the configuration file may include:
The entry for server group QUE1 has an
OPENINFO parameter that specifies the resource manager, the pathname of the device and the queue space name. The
qspace argument in a client program then looks like this:
When tpdequeue() returns,
len points to a value of type
long that carries information about the length of the data retrieved. If it is 0, it means that the reply had no data portion. This can be a legitimate and successful reply in some applications; receiving even a 0 length reply can be used to show successful processing of the enqueued request. If you wish to know whether the buffer has changed from before the call to
tpdequeue(), save the length prior to the call to
tpdequeue() and compare it to
len after the call completes.
flags values are used to tell the Oracle Tuxedo system how the
tpdequeue() call is handled; the following are valid flags:
When TPNOBLOCK is not set and a blocking condition exists, the caller blocks until the condition subsides or a timeout occurs (either transaction or blocking timeout). This blocking condition does not include blocking on the queue itself if the
TPQWAIT option in
flags (of the
TPQCTL structure) is specified.
When this flag is set, the type of the buffer pointed to by *data is not allowed to change. By default, if a buffer is received that differs in type from the buffer pointed to by *
data, then *
data's buffer type changes to the received buffer's type so long as the receiver recognizes the incoming buffer type. That is, the type and subtype of the received buffer must match the type and subtype of the buffer pointed to by *
data.
The third argument to tpdequeue() is a pointer to a structure of type
TPQCTL. The
TPQCTL structure has members that are used by the application and by the Oracle Tuxedo system to pass parameters in both directions between application programs and the queued message facility. The client that calls
tpdequeue() sets flags to mark fields for which the system should supply values. As described earlier, the structure is also used by
tpenqueue(); some of the members apply only to that function. The entire structure is shown in
“The tpqctl_t Structure” on page 3‑5.
As input to tpdequeue(), the following fields may be set in the
TPQCTL structure:
Setting this flag requests that the message with the message identifier specified by ctl->msgid be dequeued. The message identifier is determined through a prior call to
tpenqueue(). Note that the message identifier changes if the message is moved from one queue to another. Note also that the entire 32 bytes of the message identifier value are significant, so the value specified by
ctl->msgid must be completely initialized (for example, padded with null characters).
Note that each tpdequeue() request specifying the
TPQWAIT control parameter requires that a queue manager (
TMQUEUE) action object be available if a message satisfying the condition is not immediately available. If an action object is not available, the
tpdequeue() request fails. The number of available queue manager actions are specified when a queue space is created or modified. When a waiting dequeue request completes, the associated action object associated is made available for another request.
When a thread is non-destructively dequeuing a message using TPQPEEK, the message may not be seen by other non-blocking dequeuers for the brief time the system is processing the non-destructive dequeue request. This includes dequeuers using specific selection criteria (such as message identifier and correlation identifier) that are looking for the message currently being non-destructively dequeued.
The following is a list of valid bits for the flags parameter controlling output information from
tpdequeue(). For any of these bits, if the flag bit is turned on when
tpdequeue() is called, the associated field in the structure (see
“The tpqctl_t Structure” on page 3‑5) is populated with the value provided when the message was queued, and the bit remains set. If a value is not available (that is, no value was provided when the message was queued) or the bit is not set when
tpdequeue() is called,
tpdequeue() completes with the flag turned off.
If this flag is set, the call to tpdequeue() is successful, and the message was queued with an explicit priority, then the priority is stored in
ctl->priority. The priority is in the range 1 to 100, inclusive, and the higher the number, the higher the priority (that is, a message with a higher number is dequeued before a message with a lower number). For queues not ordered by priority, the value is informational.
If this flag is set and the call to tpdequeue() is successful, the message identifier is stored in
ctl->msgid. The entire 32 bytes of the message identifier value are significant.
If this flag is set, the call to tpdequeue() is successful, and the message was queued with a correlation identifier, then the correlation identifier is stored in
ctl->corrid. The entire 32 bytes of the correlation identifier value are significant. Any Oracle Tuxedo /Q provided reply to a message has the correlation identifier of the original request message.
If this flag is set, the call to tpdequeue() is successful, and the message was queued with a delivery quality of service, then the flag—
TPQQOSDEFAULTPERSIST,
TPQQOSPERSISTENT, or
TPQQOSNONPERSISTENT—is stored in
ctl‑>delivery_qos. If no delivery quality of service was explicitly specified when the message was queued, the default delivery policy of the target queue dictates the delivery quality of service for the message.
If this flag is set, the call to tpdequeue() is successful, and the message was queued with a reply quality of service, then the flag—
TPQQOSDEFAULTPERSIST,
TPQQOSPERSISTENT, or
TPQQOSNONPERSISTENT—is stored in
ctl‑>reply_qos. If no reply quality of service was explicitly specified when the message was queued, the default delivery policy of the
ctl‑>replyqueue queue dictates the delivery quality of service for any reply.
If this flag is set, the call to tpdequeue() is successful, and the message was queued with a reply queue, then the name of the reply queue is stored in
ctl->replyqueue. Any reply to the message should go to the named reply queue within the same queue space as the request message.
If this flag is set, the call to tpdequeue() is successful, and the message was queued with a failure queue, then the name of the failure queue is stored in
ctl->failurequeue. Any failure message should go to the named failure queue within the same queue space as the request message.
The following remaining bits for the flags parameter are cleared (set to zero) when
tpdequeue() is called:
TPQTOP,
TPQBEFOREMSGID,
TPQTIME_ABS,
TPQTIME_REL,
TPQEXPTIME_ABS,
TPQEXPTIME_REL, and
TPQEXPTIME_NONE. These bits are valid bits for the
flags parameter controlling input information for
tpenqueue().
If the call to tpdequeue() failed and
tperrno(5) is set to
TPEDIAGNOSTIC, a value indicating the reason for failure is returned in
ctl->diagnostic. The valid codes for
ctl->diagnostic include those for
tpenqueue() described in
“TPQCTL Structure” on page 3‑5 (except for
QMENOSPACE and
QMERELEASE) and the following additional codes.
When tpdequeue() is called with
flags (of the
TPQCTL structure) set to include
TPQWAIT, if a message is not immediately available, the
TMQUEUE server waits for the arrival, on the queue, of a message that matches the
tpdequeue() request before
tpdequeue() returns control to the caller. The
TMQUEUE process sets the waiting request aside and processes requests from other processes while waiting to satisfy the first request. If
TPQGETBYMSGID and/or
TPQGETBYCORRID are also specified, the server waits until a message with the indicated message identifier and/or correlation identifier becomes available on the queue. If neither of these flags is set, the server waits until any message is put onto the queue. The amount of time it waits is controlled by the caller’s transaction timeout, if the call is in transaction mode, or by the
-t option in the
CLOPT parameter of the
TMQUEUE server, if the call is not in transaction mode.
The TMQUEUE server can handle a number of waiting
tpdequeue() requests at the same time, as long as action resources are available to handle the request. If there are not enough action resources configured for the queue space,
tpdequeue() fails. If this happens on your system, increase the number of action resources for the queue space.
By default, if a message is dequeued within a transaction and the transaction is rolled back, then (if the retry parameter is greater than 0) the message ends up back on the queue and can be dequeued and executed again. It may be desirable to delay for a short period before retrying to dequeue and execute the message, allowing the transient problem to clear (for example, allowing for locks in a database to be released by another transaction). Normally, a limit on the number of retries is also useful to ensure that an application flaw doesn't cause significant waste of resources. When a queue is configured by the administrator, both a retry count and a delay period (in seconds) can be specified. A retry count of 0 implies that no retries are done. After the retry count is reached, the message is moved to an error queue that is configured by the administrator for the queue space. If the error queue is not configured, then messages that have reached the retry count are simply deleted. Messages on the error queue must be handled by the administrator who must work out a way of notifying the originator that meets the requirements of the application. The message handling method chosen should be mostly transparent to the originating program that put the message on the queue. There is a virtual guarantee that once a message is successfully enqueued it will be processed according to the parameters of
tpenqueue() and the attributes of the queue. Notification that a message has been moved to the error queue should be a rare occurrence in a system that has properly tuned its queue parameters.
In the case where the service fails and the transaction must be rolled back, it is not clear whether or not TMQFORWARD should execute a second transaction to remove the message from the queue without further processing. By default,
TMQFORWARD will not delete a message for a service that fails.
TMQFORWARD's transaction is rolled back and the message is restored to the queue. A command-line option may be specified for
TMQFORWARD that indicates that a message should be deleted from the queue if the service fails and a reply message is sent back with length greater than 0. The message is deleted in a second transaction. The queue must be configured with a delay time and retry count for this to work. If the message is associated with a failure queue, the reply data will be enqueued to the failure queue in the same transaction as the one in which the message is deleted from the queue.
2.
|
When you call tpenqueue() to put the message on the queue, set flags to turn on the bits for the following flags:
|
Fill in the values for corrid,
replyqueue and
failurequeue before issuing the call. On return from the call, save
corrid.
3.
|
When you call tpdequeue() to check for a reply, specify the reply queue in the qname argument and set flags to turn on the bits for the following flags:
|
Use the saved correlation identifier to populate corrid before issuing the call. If the call to
tpdequeue() fails and sets
tperrno(5) to
TPEDIAGNOSTIC, then further information is available in
diagnostic. If you receive the error code
QMENOMSG, it means that no message was available for dequeuing.
4.
|
Set up another call to tpdequeue(). This time have qname point to the name of the failure queue and set flags to turn on the bits for the following flags:
|
Populate corrid with the correlation identifier. When the call returns, check
len to see if data has been received and check
urcode to see if the service has returned a user return code.