XTA: API Reference for C language

xta_transaction.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2009-2019, Christian Ferrari <tiian@users.sourceforge.net>
3  * All rights reserved.
4  *
5  * This file is part of LIXA.
6  *
7  * LIXA is free software: you can redistribute this file and/or modify
8  * it under the terms of the GNU Lesser General Public License version 2.1 as
9  * published by the Free Software Foundation.
10  *
11  * LIXA is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with LIXA. If not, see <http://www.gnu.org/licenses/>.
18  */
19 #include "config.h"
20 
21 
22 
23 /* system includes */
24 #ifdef HAVE_GLIB_H
25 # include <glib.h>
26 #endif
27 #ifdef HAVE_SYSLOG_H
28 # include <syslog.h>
29 #endif
30 
31 
32 
33 /* LIXA includes */
34 #include "lixa_errors.h"
35 #include "lixa_trace.h"
36 #include "client_conn.h"
37 #include "client_config.h"
38 #include "client_status.h"
39 #include "lixa_xa.h"
40 #include "lixa_syslog.h"
41 /* XTA includes */
42 #include "xta_transaction.h"
43 
44 
45 
46 /* set module trace flag */
47 #ifdef LIXA_TRACE_MODULE
48 # undef LIXA_TRACE_MODULE
49 #endif /* LIXA_TRACE_MODULE */
50 #define LIXA_TRACE_MODULE LIXA_TRACE_MOD_XTA
51 
52 
53 
55 {
56  enum Exception { G_TRY_MALLOC_ERROR1
57  , G_TRY_MALLOC_ERROR2
58  , G_TRY_MALLOC_ERROR3
59  , CLIENT_CONFIG_DUP_ERROR
60  , CLIENT_CONFIG_DISPLAY_ERROR
61  , CLIENT_CONNECT_ERROR
62  , CLIENT_CONFIG_JOB_ERROR
63  , NONE } excp;
64  int ret_cod = LIXA_RC_INTERNAL_ERROR;
65  xta_transaction_t *this = NULL;
66 
67  LIXA_TRACE(("xta_transaction_new\n"));
68  TRY {
69  /* allocate the object */
70  if (NULL == (this = (xta_transaction_t *)
71  g_try_malloc0(sizeof(xta_transaction_t))))
72  THROW(G_TRY_MALLOC_ERROR1);
73  /* reset already_open flag */
74  this->already_opened = FALSE;
75  /* reset multiple_branches flag */
76  this->multiple_branches = FALSE;
77  /* allocate a client_status object */
78  if (NULL == (this->client_status =
79  g_try_malloc0(sizeof(client_status_t))))
80  THROW(G_TRY_MALLOC_ERROR2);
81  /* initialize the LIXA client status */
82  client_status_init(this->client_status);
83  client_status_active(this->client_status);
84  /* allocate a client_config_coll to store a local copy of the
85  * global configuration */
86  if (NULL == (this->local_ccc =
87  g_try_malloc0(sizeof(client_config_coll_t))))
88  THROW(G_TRY_MALLOC_ERROR3);
89  /*
90  * copy the configuration for the LIXA client from the static one.
91  * Static configuration must be initialized by xta_transaction_manager
92  */
93  if (LIXA_RC_OK != (ret_cod = client_config_dup(
94  &global_ccc, this->local_ccc)))
95  THROW(CLIENT_CONFIG_DUP_ERROR);
96  /* display on trace the duplicated configuration */
97  if (LIXA_RC_OK != (ret_cod = client_config_display(this->local_ccc)))
98  THROW(CLIENT_CONFIG_DISPLAY_ERROR);
99  /* connect to LIXA state server */
100  if (LIXA_RC_OK != (ret_cod = client_connect(
101  this->client_status, this->local_ccc))) {
102  LIXA_TRACE(("xta_transaction_new/client_connect: ret_cod=%d "
103  "('%s')\n", ret_cod, lixa_strerror(ret_cod)));
104  THROW(CLIENT_CONNECT_ERROR);
105  }
106  /* configure the LIXA (transactional) job (if necessary) */
107  if (LIXA_RC_OK != (ret_cod = client_config_job(
108  this->local_ccc, client_status_get_sockfd(
109  this->client_status))))
110  THROW(CLIENT_CONFIG_JOB_ERROR);
111  /* reset the XID reference */
112  this->xid = NULL;
113  /* reset flag */
114  this->commit_suspended = FALSE;
115 
116  THROW(NONE);
117  } CATCH {
118  switch (excp) {
119  case G_TRY_MALLOC_ERROR1:
120  case G_TRY_MALLOC_ERROR2:
121  ret_cod = LIXA_RC_G_TRY_MALLOC_ERROR;
122  break;
123  case CLIENT_CONFIG_DUP_ERROR:
124  case CLIENT_CONFIG_DISPLAY_ERROR:
125  case CLIENT_CONNECT_ERROR:
126  case CLIENT_CONFIG_JOB_ERROR:
127  break;
128  case NONE:
129  ret_cod = LIXA_RC_OK;
130  break;
131  default:
132  ret_cod = LIXA_RC_INTERNAL_ERROR;
133  } /* switch (excp) */
134  /* if something went wrong, release allocated memory and return
135  NULL */
136  if (excp < NONE) {
137  LIXA_TRACE(("xta_transaction_new: an internal error "
138  "occurred, releasing allocated memory...\n"));
139  if (excp > G_TRY_MALLOC_ERROR2) {
140  LIXA_TRACE(("xta_transaction_new: releasing client "
141  "status objects...\n"));
142  /* free the memory associated to client status */
143  client_status_free(this->client_status);
144  }
145  if (excp > CLIENT_CONFIG_DUP_ERROR) {
146  LIXA_TRACE(("xta_transaction_new: releasing "
147  "configuration objects...\n"));
148  /* free the memory associated to client configuration */
149  client_unconfig(this->local_ccc, FALSE);
150  }
151  if (excp > G_TRY_MALLOC_ERROR3) {
152  LIXA_TRACE(("xta_transaction_new: an internal error "
153  "occurred, destroying local_ccc object and "
154  "returning NULL\n"));
155  /* free the memory associated to this object */
156  g_free(this->local_ccc);
157  this->local_ccc = NULL;
158  }
159  if (excp > G_TRY_MALLOC_ERROR2) {
160  LIXA_TRACE(("xta_transaction_new: an internal error "
161  "occurred, destroying client_status object and "
162  "returning NULL\n"));
163  /* free the memory associated to this object */
164  g_free(this->client_status);
165  this->client_status = NULL;
166  }
167  if (excp > G_TRY_MALLOC_ERROR1) {
168  LIXA_TRACE(("xta_transaction_new: an internal error "
169  "occurred, destroying this object and returning "
170  "NULL\n"));
171  /* free the memory associated to this object */
172  g_free(this);
173  this = NULL;
174  }
175  } /* if (excp < NONE) */
176  } /* TRY-CATCH */
177  LIXA_TRACE(("xta_transaction_new/excp=%d/"
178  "ret_cod=%d/errno=%d\n", excp, ret_cod, errno));
179  return this;
180 }
181 
182 
183 
185 {
186  enum Exception { CLIENT_UNCONFIG_ERROR
187  , NONE } excp;
188  int ret_cod = LIXA_RC_INTERNAL_ERROR;
189 
190  LIXA_TRACE(("xta_transaction_delete: destroying %p...\n", transact));
191  TRY {
192  /* call close if not already done */
193  if (transact->already_opened)
194  if (LIXA_RC_OK != (ret_cod = xta_transaction_close_internal(
195  transact))) {
196  LIXA_TRACE(("xta_transaction_delete/"
197  "xta_transaction_close_internal: ret_cod=%d\n",
198  ret_cod));
199  }
200  /* close the client connection */
201  if (LIXA_RC_OK != (ret_cod = client_disconnect(
202  transact->client_status))) {
203  LIXA_TRACE(("xta_transaction_delete/client_disconnect: "
204  "rec_cod=%d\n", ret_cod));
205  }
206  /* unconfigure and release the memory related to client configuration
207  collection */
208  if (LIXA_RC_OK != (ret_cod = client_unconfig(
209  transact->local_ccc, FALSE)))
210  THROW(CLIENT_UNCONFIG_ERROR);
211  /* free the memory associated to local_ccc */
212  g_free(transact->local_ccc);
213 
214  /* free the memory associated to client status */
215  client_status_free(transact->client_status);
216  g_free(transact->client_status);
217 
218  /* release the memory of the XID */
219  if (NULL != transact->xid)
220  xta_xid_delete(transact->xid);
221 
222  /* release the memory of this object */
223  g_free(transact);
224 
225  THROW(NONE);
226  } CATCH {
227  switch (excp) {
228  case CLIENT_UNCONFIG_ERROR:
229  break;
230  case NONE:
231  ret_cod = LIXA_RC_OK;
232  break;
233  default:
234  ret_cod = LIXA_RC_INTERNAL_ERROR;
235  } /* switch (excp) */
236  } /* TRY-CATCH */
237  LIXA_TRACE(("xta_transaction_delete/excp=%d/"
238  "ret_cod=%d/errno=%d\n", excp, ret_cod, errno));
239  return;
240 }
241 
242 
243 
245 {
246  enum Exception { NULL_OBJECT
247  , INVALID_STATUS
248  , INTERNAL_ERROR
249  , NONE } excp;
250  int ret_cod = LIXA_RC_INTERNAL_ERROR;
251  int result = FALSE;
252 
253  LIXA_TRACE(("xta_transaction_safe_delete\n"));
254  TRY {
255  int txstate;
256 
257  if (NULL == transact)
258  THROW(NULL_OBJECT);
259  txstate = client_status_get_txstate(transact->client_status);
260  switch (txstate) {
261  /* these states are safe */
262  case TX_STATE_S0:
263  case TX_STATE_S1:
264  result = TRUE;
265  break;
266  /* these states should never be used with XTA */
267  case TX_STATE_S2:
268  case TX_STATE_S4:
269  THROW(INVALID_STATUS);
270  break;
271  /* these states are not safe */
272  case TX_STATE_S3:
273  case TX_STATE_S5:
274  break;
275  default:
276  THROW(INTERNAL_ERROR);
277  } /* switch (txstate) */
278  LIXA_TRACE(("xta_transaction_safe_delete: status=%d, result=%d\n",
279  txstate, result));
280 
281  THROW(NONE);
282  } CATCH {
283  switch (excp) {
284  case NULL_OBJECT:
285  ret_cod = LIXA_RC_NULL_OBJECT;
286  break;
287  case INVALID_STATUS:
288  ret_cod = LIXA_RC_INVALID_STATUS;
289  break;
290  case INTERNAL_ERROR:
291  ret_cod = LIXA_RC_INTERNAL_ERROR;
292  break;
293  case NONE:
294  ret_cod = LIXA_RC_OK;
295  break;
296  default:
297  ret_cod = LIXA_RC_INTERNAL_ERROR;
298  } /* switch (excp) */
299  } /* TRY-CATCH */
300  LIXA_TRACE(("xta_transaction_safe_delete/excp=%d/"
301  "ret_cod=%d/errno=%d\n", excp, ret_cod, errno));
302  return result;
303 }
304 
305 
306 
308 {
309  enum Exception { NULL_OBJECT
310  , NONE } excp;
311  int ret_cod = LIXA_RC_INTERNAL_ERROR;
312  client_config_coll_t *ccc = NULL;
313 
314  LIXA_TRACE(("xta_transaction_get_config\n"));
315  TRY {
316  if (NULL == transact)
317  THROW(NULL_OBJECT);
318  ccc = transact->local_ccc;
319 
320  THROW(NONE);
321  } CATCH {
322  switch (excp) {
323  case NULL_OBJECT:
324  ret_cod = LIXA_RC_NULL_OBJECT;
325  break;
326  case NONE:
327  ret_cod = LIXA_RC_OK;
328  break;
329  default:
330  ret_cod = LIXA_RC_INTERNAL_ERROR;
331  } /* switch (excp) */
332  } /* TRY-CATCH */
333  LIXA_TRACE(("xta_transaction_get_config/excp=%d/"
334  "ret_cod=%d/errno=%d\n", excp, ret_cod, errno));
335  return ccc;
336 }
337 
338 
339 
341  xta_xa_resource_t *xa_res)
342 {
343  enum Exception { NULL_OBJECT1
344  , NULL_OBJECT2
345  , INVALID_STATUS
346  , NULL_OBJECT3
347  , G_TRY_MALLOC_ERROR
348  , CLIENT_CONFIG_DUP_ERROR
349  , REDIGEST_ERROR
350  , XA_RESOURCE_REGISTERED
351  , NONE } excp;
352  int ret_cod = LIXA_RC_INTERNAL_ERROR;
353 
354  const xta_xa_resource_config_t *config = NULL;
355  struct rsrmgr_config_s *rsrmgr = NULL;
356  struct act_rsrmgr_config_s act_rsrmgr;
357 
358  LIXA_TRACE(("xta_transaction_enlist_resource\n"));
359  TRY {
360  /* check the transaction object is not NULL */
361  if (NULL == transact)
362  THROW(NULL_OBJECT1);
363  /* check the XA Resource object is not NULL */
364  if (NULL == xa_res)
365  THROW(NULL_OBJECT2);
366  /* check transaction state before going on */
367  if (TX_STATE_S0 != client_status_get_txstate(
368  transact->client_status)) {
369  LIXA_TRACE(("xta_transaction_enlist_resource: expected client "
370  "status %d, current client status %d\n", TX_STATE_S0,
371  client_status_get_txstate(transact->client_status)));
372  THROW(INVALID_STATUS);
373  }
374  /* if the XA Resource is not dynamic, the following steps are not
375  * necessary */
376  if (xta_xa_resource_is_dynamic(xa_res)) {
377  /* retrieve the configuration related to the XA resource that's
378  * registering to this transaction manager */
379  if (NULL == (config = xta_xa_resource_get_config(xa_res)))
380  THROW(NULL_OBJECT3);
381  /* allocate a new record for the Resource Manager description */
382  if (NULL == (rsrmgr = g_try_malloc(
383  sizeof(struct rsrmgr_config_s))))
384  THROW(G_TRY_MALLOC_ERROR);
385  /* duplicate the configuration structs to avoid dependency from the
386  * resource object (it's necessary to preserve compatibility with
387  * the LIXA legacy non object oriented legacy functions */
388  if (LIXA_RC_OK != (ret_cod = client_config_rsrmgr_dup(
389  config, rsrmgr, &act_rsrmgr)))
390  THROW(CLIENT_CONFIG_DUP_ERROR);
391  /* append the resource manager to the list of actual configured
392  resource managers */
393  client_config_append_rsrmgr(transact->local_ccc, rsrmgr,
394  &act_rsrmgr);
395  /* compute again the configuration digest (fingerprint) because
396  a new resource has been added */
397  if (LIXA_RC_OK != (ret_cod = xta_transaction_redigest(
398  transact, config)))
399  THROW(REDIGEST_ERROR);
400  /* reset the record pointer */
401  rsrmgr = NULL;
402  } else {
403  LIXA_TRACE(("xta_transaction_enlist_resource: this is a static "
404  "resource, skipping config dup...\n"));
405  } /* if (!xta_xa_resource_is_dynamic(xa_res)) */
406  /* send a registration message to the XA Resource */
407  if (LIXA_RC_OK != (ret_cod = xta_xa_resource_enlisted(
408  xa_res, transact)))
409  THROW(XA_RESOURCE_REGISTERED);
410 
411  THROW(NONE);
412  } CATCH {
413  switch (excp) {
414  case NULL_OBJECT1:
415  case NULL_OBJECT2:
416  case NULL_OBJECT3:
417  ret_cod = LIXA_RC_NULL_OBJECT;
418  break;
419  case INVALID_STATUS:
420  ret_cod = LIXA_RC_INVALID_STATUS;
421  break;
422  case G_TRY_MALLOC_ERROR:
423  ret_cod = LIXA_RC_G_TRY_MALLOC_ERROR;
424  break;
425  case REDIGEST_ERROR:
426  break;
427  case CLIENT_CONFIG_DUP_ERROR:
428  break;
429  case XA_RESOURCE_REGISTERED:
430  break;
431  case NONE:
432  ret_cod = LIXA_RC_OK;
433  break;
434  default:
435  ret_cod = LIXA_RC_INTERNAL_ERROR;
436  } /* switch (excp) */
437  /* recovery memory if necessary */
438  if (NULL != rsrmgr) {
439  LIXA_TRACE(("xta_transaction_enlist_resource: recoverying "
440  "record memory\n"));
441  g_free(rsrmgr);
442  }
443  } /* TRY-CATCH */
444  LIXA_TRACE(("xta_transaction_enlist_resource/excp=%d/"
445  "ret_cod=%d/errno=%d\n", excp, ret_cod, errno));
446  return ret_cod;
447 }
448 
449 
450 
452  const xta_xa_resource_config_t *xrc)
453 {
454  enum Exception { NULL_OBJECT1
455  , NULL_OBJECT2
456  , NULL_OBJECT3
457  , G_CHECKSUM_NEW_ERROR
458  , G_CHECKSUM_GET_STRING_ERROR
459  , JOB_SET_SOURCE_IP_ERROR
460  , NONE } excp;
461  int ret_cod = LIXA_RC_INTERNAL_ERROR;
462  gchar *config_tostring = NULL;
463  GChecksum *checksum = NULL;
464  client_config_coll_t *local_ccc = NULL;
465 
466  LIXA_TRACE(("xta_transaction_redigest\n"));
467  TRY {
468  const gchar *checksum_string = NULL;
469 
470  /* check the transaction is not NULL */
471  if (NULL == transact)
472  THROW(NULL_OBJECT1);
473  local_ccc = (client_config_coll_t *)transact->local_ccc;
474  /* check the configuration is not NULL */
475  if (NULL == xrc)
476  THROW(NULL_OBJECT2);
477  /* retrieve the serialized version of the configuration */
478  if (NULL == (config_tostring = client_config_tostring_rsrmgr(xrc)))
479  THROW(NULL_OBJECT3);
480  LIXA_TRACE(("xta_transaction_redigest: config_tostring = '%s'\n",
481  config_tostring));
482  /* trace old values */
483  LIXA_TRACE(("xta_transaction_redigest: old digest is '%s'\n",
484  local_ccc->config_digest));
485  LIXA_TRACE(("xta_transaction_redigest: old job id for this "
486  "transaction is '%s'\n",
487  lixa_job_get_raw(local_ccc->job)));
488  /* create a new checksum */
489  if (NULL == (checksum = g_checksum_new(G_CHECKSUM_MD5)))
490  THROW(G_CHECKSUM_NEW_ERROR);
491  /* use current digest as the initial content */
492  g_checksum_update(checksum, (guchar *)local_ccc->config_digest,
493  sizeof(md5_digest_hex_t));
494  /* append the config of the current resource */
495  g_checksum_update(checksum, (guchar *)config_tostring,
496  strlen(config_tostring));
497  if (NULL == (checksum_string = g_checksum_get_string(checksum)))
498  THROW(G_CHECKSUM_GET_STRING_ERROR);
499  /* copy back the new digest */
500  strncpy(local_ccc->config_digest,
501  (const char *)checksum_string, MD5_DIGEST_LENGTH * 2);
502  local_ccc->config_digest[MD5_DIGEST_LENGTH * 2] = '\0';
503  /* re compute LIXA job id for this transaction */
504  lixa_job_reset(local_ccc->job);
505  lixa_job_set_config_digest(local_ccc->job, local_ccc->config_digest);
506  if (LIXA_RC_OK != (ret_cod = lixa_job_set_source_ip(
507  local_ccc->job,
508  client_status_get_sockfd(
509  transact->client_status))))
510  THROW(JOB_SET_SOURCE_IP_ERROR);
511  /* trace new values */
512  LIXA_TRACE(("xta_transaction_redigest: new digest is '%s'\n",
513  local_ccc->config_digest));
514  LIXA_TRACE(("xta_transaction_redigest: new job id for this "
515  "transaction is '%s'\n",
516  lixa_job_get_raw(local_ccc->job)));
517 
518  THROW(NONE);
519  } CATCH {
520  switch (excp) {
521  case NULL_OBJECT1:
522  case NULL_OBJECT2:
523  case NULL_OBJECT3:
524  ret_cod = LIXA_RC_NULL_OBJECT;
525  break;
526  case G_CHECKSUM_NEW_ERROR:
528  break;
529  case G_CHECKSUM_GET_STRING_ERROR:
531  break;
532  case JOB_SET_SOURCE_IP_ERROR:
533  break;
534  case NONE:
535  ret_cod = LIXA_RC_OK;
536  break;
537  default:
538  ret_cod = LIXA_RC_INTERNAL_ERROR;
539  } /* switch (excp) */
540  /* recover dynamically allocated memory */
541  if (NULL != config_tostring)
542  g_free(config_tostring);
543  if (NULL != checksum)
544  g_checksum_free(checksum);
545  } /* TRY-CATCH */
546  LIXA_TRACE(("xta_transaction_redigest/excp=%d/"
547  "ret_cod=%d/errno=%d\n", excp, ret_cod, errno));
548  return ret_cod;
549 }
550 
551 
552 
554 {
555  return xta_transaction_open_internal(transact);
556 }
557 
558 
559 
561 {
562  enum Exception { NULL_OBJECT
563  , INVALID_STATUS
564  , LIXA_XA_OPEN_ERROR
565  , INTERNAL_ERROR
566  , NONE } excp;
567  int ret_cod = LIXA_RC_INTERNAL_ERROR;
568 
569  LIXA_TRACE(("xta_transaction_open_internal\n"));
570  TRY {
571  int next_txstate, txrc;
572 
573  /* check object */
574  if (NULL == transact)
575  THROW(NULL_OBJECT);
576  /* check transaction state before going on */
577  if (TX_STATE_S0 != client_status_get_txstate(
578  transact->client_status)) {
579  LIXA_TRACE(("xta_transaction_open_internal: expected client "
580  "status %d, current client status %d\n", TX_STATE_S0,
581  client_status_get_txstate(transact->client_status)));
582  THROW(INVALID_STATUS);
583  }
584  next_txstate = TX_STATE_S1;
585  /* open statically defined XA Resource Managers */
586  if (LIXA_RC_OK != (ret_cod = lixa_xa_open(
587  transact->local_ccc, transact->client_status,
588  &txrc, next_txstate, FALSE)))
589  THROW(LIXA_XA_OPEN_ERROR);
590  transact->already_opened = TRUE;
591  /* set new state after RMs are open... */
592  client_status_set_txstate(transact->client_status, next_txstate);
593 
594  /* this should never happen! */
595  if (NULL != transact->xid)
596  THROW(INTERNAL_ERROR);
597 
598  THROW(NONE);
599  } CATCH {
600  switch (excp) {
601  case NULL_OBJECT:
602  ret_cod = LIXA_RC_NULL_OBJECT;
603  break;
604  case INVALID_STATUS:
605  ret_cod = LIXA_RC_INVALID_STATUS;
606  break;
607  case LIXA_XA_OPEN_ERROR:
608  break;
609  case INTERNAL_ERROR:
610  ret_cod = LIXA_RC_INTERNAL_ERROR;
611  break;
612  case NONE:
613  ret_cod = LIXA_RC_OK;
614  break;
615  default:
616  ret_cod = LIXA_RC_INTERNAL_ERROR;
617  } /* switch (excp) */
618  } /* TRY-CATCH */
619  LIXA_TRACE(("xta_transaction_open_internal/excp=%d/"
620  "ret_cod=%d/errno=%d\n", excp, ret_cod, errno));
621  return ret_cod;
622 }
623 
624 
625 
627 {
628  return xta_transaction_close_internal(transact);
629 }
630 
631 
632 
634 {
635  enum Exception { NULL_OBJECT
636  , ALREADY_CLOSED
637  , PROTOCOL_ERROR
638  , INVALID_STATUS
639  , LIXA_XA_CLOSE_ERROR
640  , NONE } excp;
641  int ret_cod = LIXA_RC_INTERNAL_ERROR;
642 
643  LIXA_TRACE(("xta_transaction_close_internal\n"));
644  TRY {
645  int txstate, next_txstate, txrc;
646 
647  /* check object */
648  if (NULL == transact)
649  THROW(NULL_OBJECT);
650  /* check transaction state before going on */
651  txstate = client_status_get_txstate(transact->client_status);
652  switch (txstate) {
653  case TX_STATE_S0:
654  LIXA_TRACE(("xta_transaction_close_internal: already "
655  "close, skipping...\n"));
656  THROW(ALREADY_CLOSED);
657  case TX_STATE_S1:
658  break;
659  case TX_STATE_S3:
660  THROW(PROTOCOL_ERROR);
661  case TX_STATE_S5:
662  break;
663  default:
664  THROW(INVALID_STATUS);
665  }
666 
667  next_txstate = TX_STATE_S0;
668  /* close statically defined XA Resource Managers */
669  if (LIXA_RC_OK != (ret_cod = lixa_xa_close(
670  transact->local_ccc, transact->client_status,
671  &txrc)))
672  THROW(LIXA_XA_CLOSE_ERROR);
673  /* reset already_opened flag */
674  transact->already_opened = FALSE;
675  /* set new state after RMs are open... */
676  client_status_set_txstate(transact->client_status, next_txstate);
677 
678  THROW(NONE);
679  } CATCH {
680  switch (excp) {
681  case NULL_OBJECT:
682  ret_cod = LIXA_RC_NULL_OBJECT;
683  break;
684  case ALREADY_CLOSED:
685  ret_cod = LIXA_RC_OK;
686  break;
687  case PROTOCOL_ERROR:
688  ret_cod = LIXA_RC_PROTOCOL_ERROR;
689  break;
690  case INVALID_STATUS:
691  ret_cod = LIXA_RC_INVALID_STATUS;
692  break;
693  case LIXA_XA_CLOSE_ERROR:
694  break;
695  case NONE:
696  ret_cod = LIXA_RC_OK;
697  break;
698  default:
699  ret_cod = LIXA_RC_INTERNAL_ERROR;
700  } /* switch (excp) */
701  } /* TRY-CATCH */
702  LIXA_TRACE(("xta_transaction_close_internal/excp=%d/"
703  "ret_cod=%d/errno=%d\n", excp, ret_cod, errno));
704  return ret_cod;
705 }
706 
707 
708 
710 {
711  enum Exception { NULL_OBJECT
712  , OPEN_INTERNAL
713  , CLOSE_INTERNAL
714  , NONE } excp;
715  int ret_cod = LIXA_RC_INTERNAL_ERROR;
716 
717  LIXA_TRACE(("xta_transaction_recover\n"));
718  TRY {
719  /* check object */
720  if (NULL == transact)
721  THROW(NULL_OBJECT);
722  /* open enlisted resources */
723  if (LIXA_RC_OK != (ret_cod = xta_transaction_open_internal(transact)))
724  THROW(OPEN_INTERNAL);
725  /* close enlisted resources */
726  if (LIXA_RC_OK != (ret_cod = xta_transaction_close_internal(transact)))
727  THROW(CLOSE_INTERNAL);
728 
729  THROW(NONE);
730  } CATCH {
731  switch (excp) {
732  case NULL_OBJECT:
733  ret_cod = LIXA_RC_NULL_OBJECT;
734  break;
735  case OPEN_INTERNAL:
736  case CLOSE_INTERNAL:
737  break;
738  case NONE:
739  ret_cod = LIXA_RC_OK;
740  break;
741  default:
742  ret_cod = LIXA_RC_INTERNAL_ERROR;
743  } /* switch (excp) */
744  } /* TRY-CATCH */
745  LIXA_TRACE(("xta_transaction_recover/excp=%d/"
746  "ret_cod=%d/errno=%d\n", excp, ret_cod, errno));
747  return ret_cod;
748 }
749 
750 
751 
752 int xta_transaction_start(xta_transaction_t *transact, int multiple_branches)
753 {
754  enum Exception { NULL_OBJECT1
755  , NON_REUSABLE_TX
756  , OPEN_INTERNAL_ERROR
757  , INVALID_STATUS
758  , NULL_OBJECT2
759  , LIXA_XA_START_ERROR
760  , NONE } excp;
761  int ret_cod = LIXA_RC_INTERNAL_ERROR;
762 
763  LIXA_TRACE(("xta_transaction_start\n"));
764  TRY {
765  int txstate, next_txstate, dupid_or_proto = FALSE;
766  int txrc = 0;
767  client_config_coll_t *local_ccc = NULL;
768 
769  /* check object */
770  if (NULL == transact)
771  THROW(NULL_OBJECT1);
772  local_ccc = (client_config_coll_t *)transact->local_ccc;
773  /* multiple branches transaction require a new object */
774  if (transact->already_opened && multiple_branches)
775  THROW(NON_REUSABLE_TX);
776  /* call open if not already done */
777  if (!transact->already_opened)
778  if (LIXA_RC_OK != (ret_cod = xta_transaction_open_internal(
779  transact)))
780  THROW(OPEN_INTERNAL_ERROR);
781  /* check TX state */
782  txstate = client_status_get_txstate(transact->client_status);
783  if (TX_STATE_S1 != txstate) {
784  LIXA_TRACE(("xta_transaction_start: expected client status %d, "
785  "current client status %d\n", TX_STATE_S1, txstate));
786  THROW(INVALID_STATUS);
787  } else
788  next_txstate = TX_STATE_S3;
789  /* create a new xid */
790  if (NULL == (transact->xid = xta_xid_new(local_ccc->config_digest,
791  multiple_branches)))
792  THROW(NULL_OBJECT2);
793  /* set multiple branches */
794  transact->multiple_branches = multiple_branches;
795  /* start the transaction in all the XA Resource Managers */
796  if (LIXA_RC_OK != (ret_cod = lixa_xa_start(
797  local_ccc, transact->client_status,
798  &txrc,
799  xta_xid_get_xa_xid(transact->xid), txstate,
800  next_txstate, &dupid_or_proto, TMNOFLAGS)))
801  THROW(LIXA_XA_START_ERROR);
802  /* update the TX state */
803  client_status_set_txstate(transact->client_status, next_txstate);
804 
805  THROW(NONE);
806  } CATCH {
807  switch (excp) {
808  case NULL_OBJECT1:
809  ret_cod = LIXA_RC_NULL_OBJECT;
810  break;
811  case NON_REUSABLE_TX:
812  ret_cod = LIXA_RC_NON_REUSABLE_TX;
813  break;
814  case OPEN_INTERNAL_ERROR:
815  break;
816  case INVALID_STATUS:
817  ret_cod = LIXA_RC_INVALID_STATUS;
818  break;
819  case NULL_OBJECT2:
820  ret_cod = LIXA_RC_NULL_OBJECT;
821  break;
822  case LIXA_XA_START_ERROR:
823  break;
824  case NONE:
825  ret_cod = LIXA_RC_OK;
826  break;
827  default:
828  ret_cod = LIXA_RC_INTERNAL_ERROR;
829  } /* switch (excp) */
830  } /* TRY-CATCH */
831  LIXA_TRACE(("xta_transaction_start/excp=%d/"
832  "ret_cod=%d/errno=%d\n", excp, ret_cod, errno));
833  return ret_cod;
834 }
835 
836 
837 
838 int xta_transaction_commit(xta_transaction_t *transact, int non_blocking)
839 {
840  enum Exception { NULL_OBJECT
841  , INVALID_STATUS
842  , GET_BQUAL_ASCII
843  , LIXA_XA_END_ERROR
844  , LIXA_XA_PREPARE_WAIT_BRANCHES_ERROR
845  , COMMIT_SUSPENDED
846  , LIXA_XA_PREPARE_ERROR
847  , LIXA_XA_COMMIT_ERROR
848  , INVALID_STATE1
849  , INVALID_TXRC1
850  , LIXA_XA_ROLLBACK_ERROR
851  , INVALID_STATE2
852  , INVALID_TXRC2
853  , LIXA_XA_FORGET_ERROR
854  , NONE } excp;
855  int ret_cod = LIXA_RC_INTERNAL_ERROR;
856  char *bqual = NULL;
857 
858  LIXA_TRACE(("xta_transaction_commit\n"));
859  int txrc = TX_OK;
860  TRY {
861  int one_phase_commit = FALSE, commit = TRUE, finished = TRUE;
862  int txstate, prepare_txrc, next_txstate;
863 
864  /* check object */
865  if (NULL == transact)
866  THROW(NULL_OBJECT);
867  /* check TX state */
868  txstate = client_status_get_txstate(transact->client_status);
869  if (TX_STATE_S3 != txstate) {
870  LIXA_TRACE(("xta_transaction_commit: expected client status %d, "
871  "current client status %d\n", TX_STATE_S3, txstate));
872  THROW(INVALID_STATUS);
873  }
874  if (transact->commit_suspended) {
875  LIXA_TRACE(("xta_transaction_commit: a previously suspended "
876  "commit must be completed\n"));
877  } else {
878  /* check if One Phase Commit optimization can be applied */
879  one_phase_commit = (client_status_could_one_phase(
880  transact->client_status,
881  transact->local_ccc));
882  if (one_phase_commit) {
883  /* check if the transaction has been create with the multiple
884  branches option */
885  if (NULL == (bqual = lixa_xid_get_bqual_ascii(
886  xta_xid_get_xa_xid(transact->xid))))
887  THROW(GET_BQUAL_ASCII);
889  LIXA_TRACE(("xta_transaction_commit: forcing "
890  "one_phase_commit to FALSE because the branch "
891  "qualifier (%s) of this transaction is "
892  "related to a multiple branches transaction\n",
893  bqual));
894  one_phase_commit = FALSE;
895  }
896  } /* if (one_phase_commit) */
897  /* detach the transaction */
898  if (LIXA_RC_OK != (ret_cod = lixa_xa_end(
899  transact->local_ccc,
900  transact->client_status,
901  xta_xid_get_xa_xid(transact->xid), &txrc,
902  commit, TMSUCCESS))) {
903  if (TX_ROLLBACK == txrc)
904  commit = FALSE;
905  else
906  THROW(LIXA_XA_END_ERROR);
907  } /* if (LIXA_RC_OK != (ret_cod = lixa_xa_end( */
908  } /* if (transact->commit_suspended) */
909  /* prepare (skip if we are rollbacking) */
910  if (commit) {
911  /* check if multiple branches prepare must be waited */
912  if (transact->commit_suspended) {
913  ret_cod = lixa_xa_prepare_wait_branches(
914  transact->local_ccc, transact->client_status);
915  if (LIXA_RC_OTHER_BRANCH_ERROR == ret_cod) {
916  /* force rollback */
917  txrc = TX_ROLLBACK;
918  commit = FALSE;
919  } else if (LIXA_RC_OK != ret_cod)
920  THROW(LIXA_XA_PREPARE_WAIT_BRANCHES_ERROR);
921  } else if (!one_phase_commit) {
922  /* bypass xa_prepare if one_phase_commit is TRUE or xa_prepare
923  * has been already performed in the previous suspended commit */
924  ret_cod = lixa_xa_prepare(
925  transact->local_ccc, transact->client_status,
926  xta_xid_get_xa_xid(transact->xid), non_blocking,
927  &txrc, &commit);
928  switch (ret_cod) {
929  case LIXA_RC_OK:
930  break;
931  case LIXA_RC_WOULD_BLOCK:
932  transact->commit_suspended = TRUE;
933  THROW(COMMIT_SUSPENDED);
934  break;
935  case LIXA_RC_OTHER_BRANCH_ERROR: /* force rollback */
936  txrc = TX_ROLLBACK;
937  commit = FALSE;
938  break;
939  default:
940  THROW(LIXA_XA_PREPARE_ERROR);
941  } /* switch (ret_cod) */
942  } /* if (!one_phase_commit) */
943  } /* if (commit) */
944  prepare_txrc = txrc;
945  /* commit or rollback the transaction */
946  if (commit) {
947  LIXA_TRACE(("xta_transaction_commit: go on with commit...\n"));
948  if (LIXA_RC_OK != (ret_cod = lixa_xa_commit(
949  transact->local_ccc,
950  transact->client_status,
951  xta_xid_get_xa_xid(transact->xid),
952  &txrc, one_phase_commit)))
953  THROW(LIXA_XA_COMMIT_ERROR);
954  switch (txrc) {
955  case TX_OK:
956  case TX_ROLLBACK:
957  case TX_ERROR:
958  case TX_MIXED:
959  case TX_HAZARD:
960  next_txstate = TX_STATE_S1;
961  break;
962  case TX_NO_BEGIN:
963  case TX_ROLLBACK_NO_BEGIN:
964  case TX_MIXED_NO_BEGIN:
965  case TX_HAZARD_NO_BEGIN:
966  THROW(INVALID_STATE1);
967  break;
968  case TX_FAIL:
969  next_txstate = txstate;
970  finished = FALSE;
971  break;
972  default:
973  THROW(INVALID_TXRC1);
974  } /* switch */
975  } else {
976  LIXA_TRACE(("xta_transaction_commit: go on with rollback...\n"));
977  if (LIXA_RC_OK != (ret_cod = lixa_xa_rollback(
978  transact->local_ccc,
979  transact->client_status,
980  xta_xid_get_xa_xid(transact->xid),
981  &txrc, TRUE)))
982  THROW(LIXA_XA_ROLLBACK_ERROR);
983  if (TX_FAIL == prepare_txrc) {
984  LIXA_TRACE(("xta_transaction_commit: txrc=%d, "
985  "prepare_txrc=%d, "
986  "returning TX_FAIL to Application Program\n",
987  txrc, prepare_txrc));
988  txrc = TX_FAIL;
989  }
990  LIXA_TRACE(("xta_transaction_commit: txrc=%d\n", txrc));
991  switch (txrc) {
992  case TX_OK:
993  case TX_ROLLBACK:
994  case TX_MIXED:
995  case TX_HAZARD:
996  next_txstate = TX_STATE_S1;
997  break;
998  case TX_NO_BEGIN:
999  case TX_ROLLBACK_NO_BEGIN:
1000  case TX_MIXED_NO_BEGIN:
1001  case TX_HAZARD_NO_BEGIN:
1002  case TX_COMMITTED_NO_BEGIN:
1003  THROW(INVALID_STATE2);
1004  break;
1005  case TX_FAIL:
1006  next_txstate = txstate;
1007  finished = FALSE;
1008  break;
1009  default:
1010  THROW(INVALID_TXRC2);
1011  } /* switch */
1012  } /* else */
1013 
1014  /* clean Heurstically Completed states... */
1015  if (LIXA_RC_OK != (ret_cod = lixa_xa_forget(
1016  transact->local_ccc, transact->client_status,
1017  xta_xid_get_xa_xid(transact->xid), finished)))
1018  THROW(LIXA_XA_FORGET_ERROR);
1019 
1020  /* update the TX state, now TX_STATE_S0 */
1021  client_status_set_txstate(transact->client_status, next_txstate);
1022  /* reset the transaction id */
1023  xta_xid_reset(transact->xid);
1024 
1025  THROW(NONE);
1026  } CATCH {
1027  switch (excp) {
1028  case NULL_OBJECT:
1029  ret_cod = LIXA_RC_NULL_OBJECT;
1030  break;
1031  case INVALID_STATUS:
1032  ret_cod = LIXA_RC_INVALID_STATUS;
1033  break;
1034  case GET_BQUAL_ASCII:
1035  ret_cod = LIXA_RC_NULL_OBJECT;
1036  break;
1037  case LIXA_XA_END_ERROR:
1038  case LIXA_XA_PREPARE_WAIT_BRANCHES_ERROR:
1039  case LIXA_XA_PREPARE_ERROR:
1040  case COMMIT_SUSPENDED:
1041  case LIXA_XA_COMMIT_ERROR:
1042  break;
1043  case INVALID_STATE1:
1044  case INVALID_TXRC1:
1045  ret_cod = LIXA_RC_INVALID_STATUS;
1046  break;
1047  case LIXA_XA_ROLLBACK_ERROR:
1048  break;
1049  case INVALID_STATE2:
1050  case INVALID_TXRC2:
1051  ret_cod = LIXA_RC_INVALID_STATUS;
1052  break;
1053  case LIXA_XA_FORGET_ERROR:
1054  break;
1055  case NONE:
1056  switch (txrc) {
1057  case TX_OK:
1058  ret_cod = LIXA_RC_OK;
1059  break;
1060  case TX_ROLLBACK:
1061  ret_cod = LIXA_RC_TX_ROLLBACK;
1062  break;
1063  case TX_MIXED:
1064  ret_cod = LIXA_RC_TX_MIXED;
1065  break;
1066  case TX_HAZARD:
1067  ret_cod = LIXA_RC_TX_HAZARD;
1068  break;
1069  default:
1070  ret_cod = LIXA_RC_INTERNAL_ERROR;
1071  } /* switch (txrc) */
1072  break;
1073  default:
1074  ret_cod = LIXA_RC_INTERNAL_ERROR;
1075  } /* switch (excp) */
1076  /* LIXA backward compatibility, but it might be useless */
1077  if (TX_FAIL == txrc && NULL != transact->client_status)
1078  client_status_failed(transact->client_status);
1079  } /* TRY-CATCH */
1080  /* memory recovery */
1081  if (NULL != bqual) {
1082  free(bqual);
1083  bqual = NULL;
1084  }
1085  LIXA_TRACE(("xta_transaction_commit/excp=%d/"
1086  "ret_cod=%d/errno=%d\n", excp, ret_cod, errno));
1087  return ret_cod;
1088 }
1089 
1090 
1091 
1093 {
1094  enum Exception { NULL_OBJECT
1095  , INVALID_STATUS
1096  , LIXA_XA_END_ERROR
1097  , LIXA_XA_ROLLBACK_ERROR
1098  , INVALID_STATE
1099  , INVALID_TXRC
1100  , LIXA_XA_FORGET_ERROR
1101  , NONE } excp;
1102  int ret_cod = LIXA_RC_INTERNAL_ERROR;
1103 
1104  LIXA_TRACE(("xta_transaction_rollback\n"));
1105  int txrc = TX_OK;
1106  TRY {
1107  int txstate, next_txstate, finished = TRUE;
1108 
1109  /* check object */
1110  if (NULL == transact)
1111  THROW(NULL_OBJECT);
1112  /* check TX state */
1113  txstate = client_status_get_txstate(transact->client_status);
1114  if (TX_STATE_S3 != txstate) {
1115  LIXA_TRACE(("xta_transaction_commit: expected client status %d, "
1116  "current client status %d\n", TX_STATE_S3, txstate));
1117  THROW(INVALID_STATUS);
1118  }
1119  /* detach the transaction */
1120  ret_cod = lixa_xa_end(transact->local_ccc, transact->client_status,
1121  xta_xid_get_xa_xid(transact->xid), &txrc,
1122  FALSE, TMSUCCESS);
1123  if (LIXA_RC_OK != ret_cod && TX_ROLLBACK != txrc)
1124  THROW(LIXA_XA_END_ERROR);
1125  /* rollback the transaction */
1126  if (LIXA_RC_OK != (ret_cod = lixa_xa_rollback(
1127  transact->local_ccc, transact->client_status,
1128  xta_xid_get_xa_xid(transact->xid), &txrc,
1129  FALSE)))
1130  THROW(LIXA_XA_ROLLBACK_ERROR);
1131  switch (txrc) {
1132  case TX_OK:
1133  case TX_MIXED:
1134  case TX_HAZARD:
1135  case TX_COMMITTED:
1136  case TX_ERROR:
1137  next_txstate = TX_STATE_S1;
1138  break;
1139  case TX_NO_BEGIN:
1140  case TX_MIXED_NO_BEGIN:
1141  case TX_HAZARD_NO_BEGIN:
1142  case TX_COMMITTED_NO_BEGIN:
1143  THROW(INVALID_STATE);
1144  break;
1145  case TX_FAIL:
1146  next_txstate = txstate;
1147  finished = FALSE;
1148  break;
1149  default:
1150  THROW(INVALID_TXRC);
1151  } /* switch */
1152 
1153  /* clean Heurstically Completed states... */
1154  if (LIXA_RC_OK != (ret_cod = lixa_xa_forget(
1155  transact->local_ccc, transact->client_status,
1156  xta_xid_get_xa_xid(transact->xid), finished)))
1157  THROW(LIXA_XA_FORGET_ERROR);
1158 
1159  /* update the TX state, now TX_STATE_S0 */
1160  client_status_set_txstate(transact->client_status, next_txstate);
1161  /* reset the transaction id */
1162  xta_xid_reset(transact->xid);
1163 
1164  THROW(NONE);
1165  } CATCH {
1166  switch (excp) {
1167  case NULL_OBJECT:
1168  ret_cod = LIXA_RC_NULL_OBJECT;
1169  break;
1170  case INVALID_STATUS:
1171  ret_cod = LIXA_RC_INVALID_STATUS;
1172  break;
1173  case LIXA_XA_END_ERROR:
1174  case LIXA_XA_ROLLBACK_ERROR:
1175  break;
1176  case INVALID_STATE:
1177  case INVALID_TXRC:
1178  ret_cod = LIXA_RC_INVALID_STATUS;
1179  break;
1180  case LIXA_XA_FORGET_ERROR:
1181  break;
1182  case NONE:
1183  switch (txrc) {
1184  case TX_OK:
1185  case TX_ROLLBACK:
1186  ret_cod = LIXA_RC_OK;
1187  break;
1188  case TX_MIXED:
1189  ret_cod = LIXA_RC_TX_MIXED;
1190  break;
1191  case TX_HAZARD:
1192  ret_cod = LIXA_RC_TX_HAZARD;
1193  break;
1194  default:
1195  ret_cod = LIXA_RC_INTERNAL_ERROR;
1196  } /* switch (txrc) */
1197  break;
1198  default:
1199  ret_cod = LIXA_RC_INTERNAL_ERROR;
1200  } /* switch (excp) */
1201  } /* TRY-CATCH */
1202  LIXA_TRACE(("xta_transaction_rollback/excp=%d/"
1203  "ret_cod=%d/errno=%d\n", excp, ret_cod, errno));
1204  return ret_cod;
1205 }
1206 
1207 
1208 
1209 int xta_transaction_suspend(xta_transaction_t *transact, long flags)
1210 {
1211  enum Exception { NULL_OBJECT
1212  , PROTOCOL_ERROR
1213  , INVALID_STATUS
1214  , INVALID_FLAGS
1215  , LIXA_XA_END_ERROR
1216  , NONE } excp;
1217  int ret_cod = LIXA_RC_INTERNAL_ERROR;
1218 
1219  LIXA_TRACE(("xta_transaction_suspend\n"));
1220  TRY {
1221  int txstate, next_txstate, txrc;
1222 
1223  /* check object */
1224  if (NULL == transact)
1225  THROW(NULL_OBJECT);
1226  /* check transaction state before going on */
1227  txstate = client_status_get_txstate(transact->client_status);
1228  switch (txstate) {
1229  case TX_STATE_S0:
1230  case TX_STATE_S1:
1231  THROW(PROTOCOL_ERROR);
1232  case TX_STATE_S3:
1233  break;
1234  default:
1235  THROW(INVALID_STATUS);
1236  }
1237  /* check flags */
1238  if (TMMIGRATE == flags) {
1239  LIXA_TRACE(("xta_transaction_suspend: flags=TMMIGRATE, "
1240  "suspend for resume\n"));
1241  } else if (TMNOFLAGS == flags) {
1242  LIXA_TRACE(("xta_transaction_suspend: flags=TMNOFLAGS, "
1243  "suspend for join\n"));
1244  } else
1245  THROW(INVALID_FLAGS);
1246  /* add suspend flag */
1247  flags |= TMSUSPEND;
1248  /* detach the transaction */
1249  if (LIXA_RC_OK != (ret_cod = lixa_xa_end(
1250  transact->local_ccc, transact->client_status,
1251  xta_xid_get_xa_xid(transact->xid), &txrc,
1252  FALSE, flags)))
1253  THROW(LIXA_XA_END_ERROR);
1254 
1255  next_txstate = TX_STATE_S5;
1256  /* set new state after RMs are suspended... */
1257  client_status_set_txstate(transact->client_status, next_txstate);
1258 
1259  THROW(NONE);
1260  } CATCH {
1261  switch (excp) {
1262  case NULL_OBJECT:
1263  ret_cod = LIXA_RC_NULL_OBJECT;
1264  break;
1265  case PROTOCOL_ERROR:
1266  ret_cod = LIXA_RC_PROTOCOL_ERROR;
1267  break;
1268  case INVALID_STATUS:
1269  ret_cod = LIXA_RC_INVALID_STATUS;
1270  break;
1271  case INVALID_FLAGS:
1272  ret_cod = LIXA_RC_INVALID_OPTION;
1273  break;
1274  case LIXA_XA_END_ERROR:
1275  break;
1276  case NONE:
1277  ret_cod = LIXA_RC_OK;
1278  break;
1279  default:
1280  ret_cod = LIXA_RC_INTERNAL_ERROR;
1281  } /* switch (excp) */
1282  } /* TRY-CATCH */
1283  LIXA_TRACE(("xta_transaction_suspend/excp=%d/"
1284  "ret_cod=%d/errno=%d\n", excp, ret_cod, errno));
1285  return ret_cod;
1286 }
1287 
1288 
1289 
1291  const char *xid_string, long flags)
1292 {
1293  enum Exception { NULL_OBJECT1
1294  , INVALID_STATUS
1295  , OPEN_INTERNAL_ERROR
1296  , PROTOCOL_ERROR
1297  , INVALID_FLAGS
1298  , NULL_OBJECT2
1299  , LIXA_XA_START_ERROR
1300  , NONE } excp;
1301  int ret_cod = LIXA_RC_INTERNAL_ERROR;
1302 
1303  LIXA_TRACE(("xta_transaction_resume\n"));
1304  TRY {
1305  int txstate, next_txstate, dupid_or_proto = FALSE;
1306  int txrc = 0;
1307 
1308  /* check object and serialized XID */
1309  if (NULL == transact || NULL == xid_string)
1310  THROW(NULL_OBJECT1);
1311  /* check current XID is not set */
1312  if (NULL != transact->xid)
1313  THROW(INVALID_STATUS);
1314  /* call open if not already done */
1315  if (!transact->already_opened)
1316  if (LIXA_RC_OK != (ret_cod = xta_transaction_open_internal(
1317  transact)))
1318  THROW(OPEN_INTERNAL_ERROR);
1319  /* check transaction state before going on */
1320  txstate = client_status_get_txstate(transact->client_status);
1321  switch (txstate) {
1322  case TX_STATE_S0:
1323  case TX_STATE_S3:
1324  THROW(PROTOCOL_ERROR);
1325  case TX_STATE_S1:
1326  case TX_STATE_S5:
1327  break;
1328  default:
1329  THROW(PROTOCOL_ERROR);
1330  }
1331  next_txstate = TX_STATE_S3;
1332  /* check flags */
1333  if (TMRESUME == flags) {
1334  LIXA_TRACE(("xta_transaction_resume: flags=TMRESUME, "
1335  "resuming after possible migration\n"));
1336  } else if (TMJOIN == flags) {
1337  LIXA_TRACE(("xta_transaction_resume: flags=TMJOIN, "
1338  "joining an existent transaction\n"));
1339  } else
1340  THROW(INVALID_FLAGS);
1341  /* deserialize the passed XID */
1342  if (NULL == (transact->xid = xta_xid_new_from_string(xid_string)))
1343  THROW(NULL_OBJECT2);
1344  /* start the transaction in all the XA Resource Managers */
1345  if (LIXA_RC_OK != (ret_cod = lixa_xa_start(
1346  transact->local_ccc, transact->client_status,
1347  &txrc,
1348  xta_xid_get_xa_xid(transact->xid), txstate,
1349  next_txstate, &dupid_or_proto, flags)))
1350  THROW(LIXA_XA_START_ERROR);
1351  /* update the TX state */
1352  client_status_set_txstate(transact->client_status, next_txstate);
1353 
1354  THROW(NONE);
1355  } CATCH {
1356  switch (excp) {
1357  case NULL_OBJECT1:
1358  ret_cod = LIXA_RC_NULL_OBJECT;
1359  break;
1360  case INVALID_STATUS:
1361  ret_cod = LIXA_RC_INVALID_STATUS;
1362  break;
1363  case OPEN_INTERNAL_ERROR:
1364  break;
1365  case PROTOCOL_ERROR:
1366  ret_cod = LIXA_RC_PROTOCOL_ERROR;
1367  break;
1368  case INVALID_FLAGS:
1369  ret_cod = LIXA_RC_INVALID_OPTION;
1370  break;
1371  case NULL_OBJECT2:
1372  ret_cod = LIXA_RC_NULL_OBJECT;
1373  break;
1374  case LIXA_XA_START_ERROR:
1375  break;
1376  case NONE:
1377  ret_cod = LIXA_RC_OK;
1378  break;
1379  default:
1380  ret_cod = LIXA_RC_INTERNAL_ERROR;
1381  } /* switch (excp) */
1382  } /* TRY-CATCH */
1383  LIXA_TRACE(("xta_transaction_resume/excp=%d/"
1384  "ret_cod=%d/errno=%d\n", excp, ret_cod, errno));
1385  return ret_cod;
1386 }
1387 
1388 
1389 
1390 int xta_transaction_branch(xta_transaction_t *transact, const char *xid_string)
1391 {
1392  enum Exception { NULL_OBJECT1
1393  , OPEN_INTERNAL_ERROR
1394  , INVALID_STATUS
1395  , XID_DESERIALIZE
1396  , GET_BQUAL_ASCII
1397  , NON_BRANCHABLE_TX
1398  , XID_SERIALIZE
1399  , NULL_OBJECT2
1400  , LIXA_XA_START_ERROR
1401  , NONE } excp;
1402  int ret_cod = LIXA_RC_INTERNAL_ERROR;
1403  int warning = LIXA_RC_OK;
1404  char *bqual = NULL;
1405 
1406  LIXA_TRACE(("xta_transaction_branch\n"));
1407  TRY {
1408  XID superior, subordinate;
1409  lixa_ser_xid_t lsx;
1410  int txstate, next_txstate, dupid_or_proto = FALSE;
1411  int txrc = 0;
1412 
1413  /* check object */
1414  if (NULL == transact)
1415  THROW(NULL_OBJECT1);
1416  /* call open if not already done */
1417  if (!transact->already_opened)
1418  if (LIXA_RC_OK != (ret_cod = xta_transaction_open_internal(
1419  transact)))
1420  THROW(OPEN_INTERNAL_ERROR);
1421  /* check TX state */
1422  txstate = client_status_get_txstate(transact->client_status);
1423  if (TX_STATE_S1 != txstate) {
1424  LIXA_TRACE(("xta_transaction_branch: expected client status %d, "
1425  "current client status %d\n", TX_STATE_S1, txstate));
1426  THROW(INVALID_STATUS);
1427  } else
1428  next_txstate = TX_STATE_S3;
1429 
1430  /* deserialize superior XID */
1431  if (!lixa_xid_deserialize(&superior, xid_string)) {
1432  LIXA_TRACE(("xta_transaction_branch: unable to deserialize "
1433  "superior XID '%s'\n", xid_string));
1434  THROW(XID_DESERIALIZE);
1435  }
1436  /* retrieve the branch qualifier to check it's for multiple branches */
1437  if (NULL == (bqual = lixa_xid_get_bqual_ascii(&superior)))
1438  THROW(GET_BQUAL_ASCII);
1440  LIXA_TRACE(("xta_transaction_branch: this transaction "
1441  "(xid=%s) can't be branched because bqual (%s) is "
1442  "related to a non branchable transaction\n",
1443  xid_string, bqual));
1444  LIXA_SYSLOG((LOG_ERR, LIXA_SYSLOG_LXC031E, xid_string, bqual));
1445  THROW(NON_BRANCHABLE_TX);
1446  }
1447  /* generate subordinate XID */
1448  lixa_xid_branch_new(&superior, &subordinate);
1449  /* serialize subordiante XID */
1450  if (!lixa_xid_serialize(&subordinate, lsx)) {
1451  LIXA_TRACE(("xta_transaction_branch: unable to serialize "
1452  "subordinate XID\n"));
1453  THROW(XID_SERIALIZE);
1454  }
1455  /* debug message */
1456  LIXA_TRACE(("xta_transaction_branch: superior XID is '%s', "
1457  "subordinate XID is '%s'\n", xid_string, lsx));
1458  /* create a new xid */
1459  if (NULL == (transact->xid = xta_xid_new_from_XID(&subordinate)))
1460  THROW(NULL_OBJECT2);
1461  /* start the transaction in all the XA Resource Managers as a new
1462  * branch under the scope of an existing global transaction */
1463  ret_cod = lixa_xa_start(transact->local_ccc, transact->client_status,
1464  &txrc,
1465  xta_xid_get_xa_xid(transact->xid), txstate,
1466  next_txstate, &dupid_or_proto, TMXTABRANCH);
1467  switch (ret_cod) {
1468  case LIXA_RC_OK:
1469  break;
1471  /* set the warning condition, but the transaction can go on */
1472  warning = ret_cod;
1473  break;
1474  default:
1475  THROW(LIXA_XA_START_ERROR);
1476  } /* switch (ret_cod) */
1477  /* update the TX state */
1478  client_status_set_txstate(transact->client_status, next_txstate);
1479 
1480  THROW(NONE);
1481  } CATCH {
1482  switch (excp) {
1483  case NULL_OBJECT1:
1484  ret_cod = LIXA_RC_NULL_OBJECT;
1485  break;
1486  case OPEN_INTERNAL_ERROR:
1487  break;
1488  case INVALID_STATUS:
1489  ret_cod = LIXA_RC_INVALID_STATUS;
1490  break;
1491  case XID_DESERIALIZE:
1492  case XID_SERIALIZE:
1493  case GET_BQUAL_ASCII:
1494  ret_cod = LIXA_RC_MALFORMED_XID;
1495  break;
1496  case NON_BRANCHABLE_TX:
1497  ret_cod = LIXA_RC_NON_BRANCHABLE_TX;
1498  break;
1499  case NULL_OBJECT2:
1500  ret_cod = LIXA_RC_NULL_OBJECT;
1501  break;
1502  case LIXA_XA_START_ERROR:
1503  break;
1504  case NONE:
1505  ret_cod = warning;
1506  break;
1507  default:
1508  ret_cod = LIXA_RC_INTERNAL_ERROR;
1509  } /* switch (excp) */
1510  } /* TRY-CATCH */
1511  /* memory recovery */
1512  if (NULL != bqual) {
1513  free(bqual);
1514  bqual = NULL;
1515  }
1516  LIXA_TRACE(("xta_transaction_branch/excp=%d/"
1517  "ret_cod=%d/errno=%d\n", excp, ret_cod, errno));
1518  return ret_cod;
1519 }
1520 
1521 
1522 
1524 {
1525  enum Exception { NULL_OBJECT
1526  , NONE } excp;
1527  int ret_cod = LIXA_RC_INTERNAL_ERROR;
1528  xta_xid_t *xid = NULL;
1529 
1530  LIXA_TRACE(("xta_transaction_get_xid\n"));
1531  TRY {
1532  if (NULL == transact)
1533  THROW(NULL_OBJECT);
1534  xid = transact->xid;
1535 
1536  THROW(NONE);
1537  } CATCH {
1538  switch (excp) {
1539  case NULL_OBJECT:
1540  ret_cod = LIXA_RC_NULL_OBJECT;
1541  break;
1542  case NONE:
1543  ret_cod = LIXA_RC_OK;
1544  break;
1545  default:
1546  ret_cod = LIXA_RC_INTERNAL_ERROR;
1547  } /* switch (excp) */
1548  } /* TRY-CATCH */
1549  LIXA_TRACE(("xta_transaction_get_xid/excp=%d/"
1550  "ret_cod=%d/errno=%d\n", excp, ret_cod, errno));
1551  return xid;
1552 }
1553 
1554 
1555 
1557  const xta_transaction_t *transact)
1558 {
1559  enum Exception { NULL_OBJECT
1560  , NONE } excp;
1561  int ret_cod = LIXA_RC_INTERNAL_ERROR;
1562  int result = FALSE;
1563 
1564  LIXA_TRACE(("xta_transaction_get_multiple_branches\n"));
1565  TRY {
1566  if (NULL == transact)
1567  THROW(NULL_OBJECT);
1568  result = transact->multiple_branches;
1569 
1570  THROW(NONE);
1571  } CATCH {
1572  switch (excp) {
1573  case NULL_OBJECT:
1574  ret_cod = LIXA_RC_NULL_OBJECT;
1575  break;
1576  case NONE:
1577  ret_cod = LIXA_RC_OK;
1578  break;
1579  default:
1580  ret_cod = LIXA_RC_INTERNAL_ERROR;
1581  } /* switch (excp) */
1582  } /* TRY-CATCH */
1583  LIXA_TRACE(("xta_transaction_get_multiple_branches/excp=%d/"
1584  "ret_cod=%d/errno=%d\n", excp, ret_cod, errno));
1585  return result;
1586 }
1587 
void xta_xid_delete(xta_xid_t *xid)
Definition: xta_xid.c:432
int xta_transaction_open_internal(xta_transaction_t *transact)
int xta_transaction_branch(xta_transaction_t *transact, const char *xid_string)
#define LIXA_RC_TX_MIXED
Definition: lixa_errors.h:586
#define LIXA_RC_NULL_OBJECT
Definition: lixa_errors.h:139
#define LIXA_RC_TX_HAZARD
Definition: lixa_errors.h:591
#define LIXA_RC_INTERNAL_ERROR
Definition: lixa_errors.h:122
#define TMXTABRANCH
Definition: xa.h:215
void xta_config_t
Definition: xta_config.h:30
int xta_transaction_open(xta_transaction_t *transact)
int xta_xid_branch_qualifier_is_multibranch(const char *branch_qualifier)
Definition: xta_xid.c:110
#define LIXA_RC_OK
Definition: lixa_errors.h:115
static const char * lixa_job_get_raw(const lixa_job_t *job)
Definition: lixa_config.h:311
xta_xid_t * xta_xid_new_from_XID(const XID *xid)
Definition: xta_xid.c:337
xta_config_t * local_ccc
xta_xid_t * xta_xid_new(const char *branch_qualifier, int multiple_branches)
Definition: xta_xid.c:47
#define LIXA_RC_NO_SUPERIOR_BRANCH
Definition: lixa_errors.h:89
#define TMSUCCESS
Definition: xa.h:181
static void lixa_job_set_config_digest(lixa_job_t *job, const char *config_digest)
Definition: lixa_config.h:333
xta_xid_t * xta_xid_new_from_string(const char *xid_string)
Definition: xta_xid.c:291
int xta_transaction_recover(xta_transaction_t *transact)
#define LIXA_RC_WOULD_BLOCK
Definition: lixa_errors.h:103
char md5_digest_hex_t[MD5_DIGEST_LENGTH *2+1]
Definition: lixa_config.h:215
xta_transaction_client_status_t * client_status
const xta_xa_resource_config_t * xta_xa_resource_get_config(const xta_xa_resource_t *xa_resource)
const XID * xta_xid_get_xa_xid(const xta_xid_t *xid)
Definition: xta_xid.c:458
int xta_transaction_commit(xta_transaction_t *transact, int non_blocking)
const char * lixa_strerror(int ret_cod)
int xta_transaction_resume(xta_transaction_t *transact, const char *xid_string, long flags)
#define LIXA_RC_G_CHECKSUM_NEW_ERROR
Definition: lixa_errors.h:518
int xta_transaction_safe_delete(const xta_transaction_t *transact)
#define LIXA_RC_NON_BRANCHABLE_TX
Definition: lixa_errors.h:596
int xta_transaction_get_multiple_branches(const xta_transaction_t *transact)
#define LIXA_RC_G_TRY_MALLOC_ERROR
Definition: lixa_errors.h:563
int xta_transaction_redigest(xta_transaction_t *transact, const xta_xa_resource_config_t *xrc)
int lixa_job_set_source_ip(lixa_job_t *job, int fd)
Definition: xa.h:28
xta_config_t * xta_transaction_get_config(xta_transaction_t *transact)
static void lixa_job_reset(lixa_job_t *job)
Definition: lixa_config.h:299
#define LIXA_RC_G_CHECKSUM_GET_STRING_ERROR
Definition: lixa_errors.h:514
struct act_rsrmgr_config_s xta_xa_resource_config_t
int xta_transaction_close_internal(xta_transaction_t *transact)
#define TMMIGRATE
Definition: xa.h:205
#define LIXA_RC_TX_ROLLBACK
Definition: lixa_errors.h:581
static int xta_xa_resource_is_dynamic(const xta_xa_resource_t *xa_resource)
void xta_xid_reset(xta_xid_t *xid)
Definition: xta_xid.c:537
int xta_transaction_start(xta_transaction_t *transact, int multiple_branches)
#define TMJOIN
Definition: xa.h:201
#define LIXA_RC_PROTOCOL_ERROR
Definition: lixa_errors.h:167
int xta_transaction_suspend(xta_transaction_t *transact, long flags)
int xta_transaction_close(xta_transaction_t *transact)
#define MD5_DIGEST_LENGTH
Definition: lixa_config.h:62
int xta_transaction_enlist_resource(xta_transaction_t *transact, xta_xa_resource_t *xa_res)
#define LIXA_RC_INVALID_OPTION
Definition: lixa_errors.h:163
#define LIXA_RC_MALFORMED_XID
Definition: lixa_errors.h:224
#define LIXA_RC_INVALID_STATUS
Definition: lixa_errors.h:172
#define TMSUSPEND
Definition: xa.h:185
const xta_xid_t * xta_transaction_get_xid(const xta_transaction_t *transact)
#define TMRESUME
Definition: xa.h:177
#define LIXA_RC_NON_REUSABLE_TX
Definition: lixa_errors.h:600
int xta_transaction_rollback(xta_transaction_t *transact)
void xta_transaction_delete(xta_transaction_t *transact)
#define TMNOFLAGS
Definition: xa.h:141
xta_transaction_t * xta_transaction_new(void)
#define LIXA_RC_OTHER_BRANCH_ERROR
Definition: lixa_errors.h:108
int xta_xa_resource_enlisted(xta_xa_resource_t *xa_resource, const xta_transaction_t *tx)

Copyright © 2009-2019, Christian Ferrari tiian@users.sourceforge.net http://www.tiian.org/