CUBRID Engine  latest
log_2pc.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /*
20  * log_2pc.c -
21  */
22 
23 #ident "$Id$"
24 
25 #include "log_2pc.h"
26 
27 #include "config.h"
28 #if defined(SERVER_MODE)
29 #include "connection_error.h"
30 #endif /* SERVER_MODE */
31 #include "error_manager.h"
32 #include "lock_manager.h"
33 #include "log_append.hpp"
34 #include "log_comm.h"
35 #include "log_impl.h"
36 #include "log_lsa.hpp"
37 #include "log_manager.h"
38 #include "memory_alloc.h"
39 #include "page_buffer.h"
40 #include "storage_common.h"
41 #include "system_parameter.h"
42 
43 #if !defined(WINDOWS)
44 #include "tcp.h" /* for css_gethostid */
45 #else /* !WINDOWS */
46 #include "wintcp.h"
47 #include "porting.h"
48 #endif /* !WINDOWS */
49 
50 #include <stddef.h>
51 #include <string.h>
52 #include <limits.h>
53 #include <assert.h>
54 
55 /* The following two are for getpid */
56 #include <sys/types.h>
57 
58 #if !defined(SERVER_MODE)
59 #define CSS_ENABLE_INTERRUPTS
60 #endif /* !SERVER_MODE */
61 
62 /* Variables */
64 {
65  int (*get_participants) (int *particp_id_length, void **block_particps_ids);
66  int (*lookup_participant) (void *particp_id, int num_particps, void *block_particps_ids);
67  char *(*sprintf_participant) (void *particp_id);
68  void (*dump_participants) (FILE * fp, int block_length, void *block_particps_id);
69  int (*send_prepare) (int gtrid, int num_particps, void *block_particps_ids);
70  bool (*send_commit) (int gtrid, int num_particps, int *particp_indices, void *block_particps_ids);
71  bool (*send_abort) (int gtrid, int num_particps, int *particp_indices, void *block_particps_ids, int collect);
72 };
74 
75 static int log_2pc_get_num_participants (int *partid_len, void **block_particps_ids);
76 static int log_2pc_make_global_tran_id (TRANID tranid);
77 static bool log_2pc_check_duplicate_global_tran_id (int gtrid);
78 static int log_2pc_commit_first_phase (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_2PC_EXECUTE execute_2pc_type,
79  bool * decision);
80 static TRAN_STATE log_2pc_commit_second_phase (THREAD_ENTRY * thread_p, LOG_TDES * tdes, bool * decision);
81 static void log_2pc_append_start (THREAD_ENTRY * thread_p, LOG_TDES * tdes);
82 static void log_2pc_append_decision (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_RECTYPE decsion);
83 static LOG_TDES *log_2pc_find_tran_descriptor (int gtrid);
84 static int log_2pc_attach_client (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_TDES * client_tdes);
85 static void log_2pc_recovery_prepare (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_LSA * log_lsa,
86  LOG_PAGE * log_page_p);
87 static int log_2pc_recovery_start (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
88  int *ack_list, int *ack_count);
89 static int *log_2pc_expand_ack_list (THREAD_ENTRY * thread_p, int *ack_list, int *ack_count, int *size_ack_list);
90 static void log_2pc_recovery_recv_ack (THREAD_ENTRY * thread_p, LOG_LSA * log_lsa, LOG_PAGE * log_page_p, int *ack_list,
91  int *ack_count);
92 static int log_2pc_recovery_analysis_record (THREAD_ENTRY * thread_p, LOG_RECTYPE record_type, LOG_TDES * tdes,
93  LOG_LSA * log_lsa, LOG_PAGE * log_page_p, int **ack_list, int *ack_count,
94  int *size_ack_list, bool * search_2pc_prepare, bool * search_2pc_start);
96 static void log_2pc_recovery_abort_decision (THREAD_ENTRY * thread_p, LOG_TDES * tdes);
97 static void log_2pc_recovery_commit_decision (THREAD_ENTRY * thread_p, LOG_TDES * tdes);
100 
101 /*
102  * FUNCTIONS RELATED TO COMMUNICATION BETWEEN THIS MODULE AND YOUR
103  * APPLICATION (I.E, BETWEEN COORDINATOR AND PARTICIPANTS OR VICE VERSA)
104  */
105 
106 /*
107  * log_2pc_find_particps - Find all participants
108  *
109  * return: number of participants
110  *
111  * partid_len(in): Length of each participant (Set as a side effect)
112  * block_particps_ids(in): An array of participant ids where each participant id
113  * is of length "partid_len" (Set as a side effect)
114  *
115  * NOTE:Find the participants of the current transaction. If the
116  * the transaction was not distributed one, the number of
117  * participants is set to zero.
118  */
119 static int
120 log_2pc_get_num_participants (int *partid_len, void **block_particps_ids)
121 {
122  void *block;
123  int num_particps;
124 
125  if (log_2pc_Userfun.get_participants == NULL)
126  {
127  partid_len = 0;
128  block_particps_ids = NULL;
129  return 0;
130  }
131 
132  num_particps = (*log_2pc_Userfun.get_participants) (partid_len, &block);
133  if (num_particps > 0)
134  {
135  *block_particps_ids = malloc (num_particps * *partid_len);
136  if (*block_particps_ids == NULL)
137  {
138  /* Failure */
139  return -1;
140  }
141  memcpy (*block_particps_ids, block, num_particps * *partid_len);
142  }
143  else
144  {
145  *block_particps_ids = NULL;
146  }
147 
148  return num_particps;
149 }
150 
151 /*
152  * log_2pc_sprintf_particp - A STRING VERSION OF PARTICIPANT-ID
153  *
154  * return:
155  *
156  * particp_id(in): Desired participant identifier
157  *
158  * NOTE:Return a string version of the given participant that can be
159  * printed using the quilifier %s of printf.
160  */
161 char *
162 log_2pc_sprintf_particp (void *particp_id)
163 {
164  if (log_2pc_Userfun.sprintf_participant == NULL)
165  {
166  return NULL;
167  }
168  return (*log_2pc_Userfun.sprintf_participant) (particp_id);
169 }
170 
171 /*
172  * log_2pc_dump_participants - Dump all participants
173  *
174  * return: nothing..
175  *
176  * block_length(in): Length of each participant.
177  * block_particps_ids(in): An array of particpant ids. The length of each
178  * element should be known by the callee.
179  *
180  * Note:Print all participants in a readable form. The particpant
181  * length is used to find out the number of participants.
182  */
183 void
184 log_2pc_dump_participants (FILE * fp, int block_length, void *block_particps_ids)
185 {
186  if (log_2pc_Userfun.dump_participants == NULL)
187  {
188  return;
189  }
190  (*log_2pc_Userfun.dump_participants) (fp, block_length, block_particps_ids);
191 }
192 
193 /*
194  * log_2pc_send_prepare - SEND A PREPARE MESSAGE TO PARTICIPANTS
195  *
196  * return:
197  *
198  * gtrid(in): Global/distributed transaction identifier
199  * num_particps(in): Number of participants at block_particps_ids
200  * block_particps_ids(in): An array of particpant ids. The length of each
201  * element should be known by the callee.
202  *
203  * NOTE: Send a prepare to commit message to all participants, then
204  * collects the votes and retruns true if all participants are
205  * willing to commit, otherwise, false is returned.
206  *
207  * Currently, our communication subsystem does not provide an
208  * asynchronous capabilities for multicasting. Once this is
209  * provided, the jobs of this function will change. For example,
210  * the collecting of votes will be done through interrupts, and
211  * so on.
212  */
213 bool
214 log_2pc_send_prepare (int gtrid, int num_particps, void *block_particps_ids)
215 {
216  if (log_2pc_Userfun.send_prepare == NULL)
217  {
218  return true;
219  }
220 
221  return (*log_2pc_Userfun.send_prepare) (gtrid, num_particps, block_particps_ids);
222 }
223 
224 /*
225  * log_2pc_send_commit_decision - SEND A COMMIT TO PARTICIPANTS
226  *
227  * return:
228  *
229  * gtrid(in): Global/distributed transaction identifier
230  * num_particps(in): Number of participants at block_particps_ids
231  * particps_indices(in): Participant indices
232  * block_particps_ids(in): An array of particpant ids. The length of each
233  * element should be known by the callee.
234  *
235  * NOTE:Send the commit decision to participants which have not
236  * received the commit decision. This is found by looking to the
237  * particps_indices array. If the ith element of the array is 0,
238  * the ith participant needs to be informed, otherwise, it does
239  * not have to. The particps_indices cannot be NULL. When a
240  * participant acknowledge for receiving the decisions, the
241  * function log_2pc_append_recv_ack must be called indicating the index
242  * number.
243  *
244  * Currently, our communication subsystem does not provide an
245  * asynchronous capabilities for multicasting. Once this is
246  * provided, the jobs of this function will change. For example,
247  * the collecting of votes will be done through interrupts, and
248  * so on.
249  */
250 bool
251 log_2pc_send_commit_decision (int gtrid, int num_particps, int *particps_indices, void *block_particps_ids)
252 {
253  bool result = true;
254 
255  if (log_2pc_Userfun.send_commit != NULL)
256  {
257  result = (*log_2pc_Userfun.send_commit) (gtrid, num_particps, particps_indices, block_particps_ids);
258  }
259 
260  return result;
261 }
262 
263 /*
264  * log_2pc_send_abort_decision - SEND AN ABORT TO PARTICIPANTS
265  *
266  * return:
267  *
268  * gtrid(in): Global/distributed transaction identifier
269  * num_particps(in): Number of participants at block_particps_ids
270  * particps_indices(in): Participant indices
271  * block_particps_ids(in): An array of particpant ids. The length of each
272  * element should be known by the callee.
273  * collect(in): Wheater or not acks should be collected
274  *
275  * NOTE:Send the abort decision to participants which have not received
276  * the abort decision and that they were willing to commit. This
277  * is found by looking to the particps_indices array. If the ith
278  * element of the array is 0, the ith participant needs to be
279  * informed, otherwise, it does not have to. If the
280  * particps_indices is NULL, we must sent to all participants.
281  * If collect ack is used to indicate to participants if an ack
282  * is needed. An acks is not needed if the abort was decided
283  * before entering 2PC. When collect is true and when a
284  * participant acknowledge for receiving the decisonis received,
285  * the function log_2pc_append_recv_ack must be called indicating the
286  * index number.
287  *
288  * Currently, our communication subsystem does not provide an
289  * asynchronous capabilities for multicasting. Once this is
290  * provided, the jobs of this function will change. For example,
291  * the collecting of votes will be done through interrupts, and
292  * so on.
293  */
294 bool
295 log_2pc_send_abort_decision (int gtrid, int num_particps, int *particps_indices, void *block_particps_ids, bool collect)
296 {
297  bool result = true;
298 
299  if (log_2pc_Userfun.send_abort != NULL)
300  {
301  result = (*log_2pc_Userfun.send_abort) (gtrid, num_particps, particps_indices, block_particps_ids, collect);
302  }
303 
304  return result;
305 }
306 
307 /*
308  *
309  * THE REST OF SUPPORTING 2PC FUNCTIONS
310  *
311  */
312 
313 #if defined (ENABLE_UNUSED_FUNCTION)
314 /*
315  * log_get_global_tran_id - FIND CURRENT GLOBAL TRANID
316  *
317  * return: gtrid
318  *
319  * NOTE:Find current gloabl transaction identifier.
320  */
321 int
322 log_get_global_tran_id (THREAD_ENTRY * thread_p)
323 {
324  int tran_index;
325  LOG_TDES *tdes; /* Transaction descriptor */
326  int gtrid = LOG_2PC_NULL_GTRID;
327 
328  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
329 
330  TR_TABLE_CS_ENTER (thread_p);
331 
332  tdes = LOG_FIND_TDES (tran_index);
333  if (tdes != NULL)
334  {
335  if (tdes->gtrid == LOG_2PC_NULL_GTRID && log_2pc_is_tran_distributed (tdes) == true)
336  {
337  tdes->gtrid = log_2pc_make_global_tran_id (tdes->trid);
338  }
339 
340  gtrid = tdes->gtrid;
341  }
342 
343  TR_TABLE_CS_EXIT (thread_p);
344 
345  return gtrid;
346 }
347 #endif
348 
349 /*
350  * log_2pc_make_global_tran_id - Make a global transaction identifier for
351  * 2pc purposes
352  *
353  * return:
354  *
355  * tranid(in): Transaction identifier
356  *
357  * NOTE:Build a global transaction identifier based on the host
358  * identifier, the process identifier and the transaction
359  * identifier.
360  */
361 static int
363 {
364  unsigned char *ptr;
365  unsigned int hash;
366  unsigned int value;
367  unsigned int unsig_gtrid;
368  int gtrid;
369  unsigned int i;
370 
371  unsig_gtrid = 0;
372 
373  /* HASH THE HOST IDENTIFIER INTO ONE BYTE */
374  value = css_gethostid ();
375  hash = 0;
376  ptr = (unsigned char *) &value;
377  for (i = 0; i < sizeof (value); i++)
378  {
379  hash = (hash << 5) - hash + *ptr++;
380  }
381  /* Don't use more than one byte */
382  /* set the MSB to zero */
383  unsig_gtrid = unsig_gtrid + ((hash % UCHAR_MAX) & 0x7F);
384 
385  /* HASH THE PROCESS IDENTIFIER INTO ONE BYTE */
386  value = (unsigned int) getpid ();
387  hash = 0;
388  ptr = (unsigned char *) &value;
389  for (i = 0; i < sizeof (value); i++)
390  {
391  hash = (hash << 5) - hash + *ptr++;
392  }
393  /* Don't use more than one byte */
394  unsig_gtrid = (unsig_gtrid << 8) + (hash % UCHAR_MAX);
395 
396 
397  /* FOLD the TRANSACTION IDENTIFIER INTO TWO */
398  unsigned short ushort_one;
399  unsigned short ushort_two;
400  memcpy (&ushort_one, &tranid, sizeof (unsigned short));
401  memcpy (&ushort_two, (char *) (&tranid) + sizeof (unsigned short), sizeof (unsigned short));
402  hash = ushort_one;
403  hash = (hash << 5) - hash + ushort_two;
404 
405  /* Don't use more than two byte */
406  unsig_gtrid = (unsig_gtrid << 16) + (hash % SHRT_MAX);
407 
408 
409  /*
410  * Make sure that another 2PC transaction does not have this identifier.
411  * If there is one, subtract one and check again. Note that the identifier
412  * may be duplicated in a remote site, we do not have control about this.
413  */
414 
415  gtrid = (int) unsig_gtrid;
416 
417  value = 1;
418  if (gtrid == LOG_2PC_NULL_GTRID)
419  {
420  gtrid--;
421  }
422 
424  {
425  gtrid--;
426 
427  if (gtrid == LOG_2PC_NULL_GTRID)
428  {
429  gtrid--;
430  }
431  }
432 
433  return (int) gtrid;
434 }
435 
436 /*
437  * log_2pc_check_duplicate_global_tran_id
438  *
439  * return:
440  *
441  * gtrid(in): Global transaction identifier
442  *
443  * Note:
444  */
445 static bool
447 {
448  LOG_TDES *tdes; /* Transaction descriptor */
449  int i;
450 
451  for (i = 0; i < log_Gl.trantable.num_total_indices; i++)
452  {
453  if (i != LOG_SYSTEM_TRAN_INDEX)
454  {
455  tdes = LOG_FIND_TDES (i);
456  if (tdes != NULL && tdes->trid != NULL_TRANID && tdes->gtrid != LOG_2PC_NULL_GTRID && gtrid == tdes->gtrid)
457  {
458  return true;
459  }
460  }
461  }
462 
463  return false;
464 }
465 
466 /*
467  * log_2pc_commit_first_phase
468  *
469  * return:
470  *
471  * tdes(in):
472  *
473  * Note:
474  */
475 static int
476 log_2pc_commit_first_phase (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_2PC_EXECUTE execute_2pc_type, bool * decision)
477 {
478  int i;
479 
480  /* Start the first phase of 2PC. Prepare to commit or voting phase */
481  if (tdes->state == TRAN_ACTIVE)
482  {
483  /*
484  * Start prepare to commit at coordinator site
485  * Note: that the transient classnames table entries should have
486  * already been taken care of.
487  */
488 
489  /*
490  * Release share locks types and record that the 2PC has started.
491  * NOTE: that log_2pc_append_start flushes the log and change the state
492  * of the transaction 2PC collecting votes
493  */
494 
495  /*
496  * Start the 2PC for this coordinator
497  */
498  log_2pc_append_start (thread_p, tdes);
499 
500  if (execute_2pc_type == LOG_2PC_EXECUTE_FULL)
501  {
502  /*
503  * This is the coordinatoor root
504  */
506  }
507 
508  /* Initialize the Acknowledgement vector to 0 */
509  i = sizeof (int) * tdes->coord->num_particps;
510 
511  tdes->coord->ack_received = (int *) malloc (i);
512  if (tdes->coord->ack_received == NULL)
513  {
514  /* Out of memory */
515  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_2pc_commit");
517  }
518 
519  for (i = 0; i < tdes->coord->num_particps; i++)
520  {
521  tdes->coord->ack_received[i] = false;
522  }
523 
524  *decision = log_2pc_send_prepare (tdes->gtrid, tdes->coord->num_particps, tdes->coord->block_particps_ids);
525  }
526  else
527  {
528  /*
529  * We are not in the right mode for the prepare to commit phase
530  */
531  *decision = false;
532 
533  return ER_FAILED;
534  }
535 
536  return NO_ERROR;
537 }
538 
539 /*
540  * log_2pc_commit_second_phase
541  *
542  * return:
543  *
544  * tdes(in):
545  *
546  * Note:
547  */
548 static TRAN_STATE
549 log_2pc_commit_second_phase (THREAD_ENTRY * thread_p, LOG_TDES * tdes, bool * decision)
550 {
551  TRAN_STATE state;
552 
553  if (*decision == true)
554  {
555  /*
556  * DECISION is COMMIT
557  * The coordinator and all participants of distributed transaction
558  * have agreed to commit the transaction. The commit decision is
559  * forced to the log to find out the decision in the case of a crash.
560  */
561 
563 
564  /*
565  * The transaction has been declared as 2PC commit. We could execute the
566  * LOCAL COMMIT AND THE REMOTE COMMITS IN PARALLEL, however our
567  * communication subsystem does not support asynchronous communication
568  * types. The commitment of the participants is done after the local
569  * commitment is completed.
570  */
571 
572  /* Save the state.. so it can be reverted to the 2pc state .. */
573  state = tdes->state;
574  /* 2PC protocol does not support RETAIN LOCK */
575  (void) log_commit_local (thread_p, tdes, false, false);
576 
577  tdes->state = state; /* Revert to 2PC state... */
578  /*
579  * If the following function fails, the transaction will be dangling
580  * and we need to retry sending the decision at another point.
581  * We have already decided and log the decision in the log file.
582  */
584  tdes->coord->block_particps_ids);
585  /* Check if all the acknowledgments have been received */
586  state = log_complete_for_2pc (thread_p, tdes, LOG_COMMIT, LOG_NEED_NEWTRID);
587  }
588  else
589  {
590  /*
591  * DECISION is ABORT
592  * The coordinator and/or some of the participants of distributed
593  * transaction could not agree to commit the transaction. The abort
594  * decision is logged. We do not need to forced since the default is
595  * abort. It does not matter whether this is a root coordinator or not
596  * the current site has decide to abort.
597  */
598 
599  /*
600  * If the transaction is active and there are not acknowledgments
601  * needed, the abort for the distributed transaction was decided
602  * without using the 2PC
603  */
604 
605  if (tdes->state != TRAN_ACTIVE || tdes->coord->ack_received != NULL)
606  {
608  }
609 
610  /*
611  * The transaction has been declared as 2PC abort. We could execute the
612  * LOCAL ABORT AND THE REMOTE ABORTS IN PARALLEL, however our
613  * communication subsystem does not support asynchronous communication
614  * types. The abort of the participants is done after the local abort
615  * is completed.
616  */
617 
618  /* Save the state.. so it can be reverted to the 2pc state .. */
619  state = tdes->state;
620  /* 2PC protocol does not support RETAIN LOCK */
621  (void) log_abort_local (thread_p, tdes, false);
622 
623  if (tdes->state == TRAN_UNACTIVE_ABORTED)
624  {
625  tdes->state = state; /* Revert to 2PC state... */
626  }
627  /*
628  * Execute the abort at participants sites at this time.
629  */
630  if (tdes->coord->ack_received)
631  {
632  /*
633  * Current site was also a coordinator site (of course not the root
634  * coordinator). Thus, we need to collect acknowledgments.
635  *
636  * If the following function fails, the transaction will be dangling
637  * and we need to retry sending the decision at another point.
638  * We have already decided and log the decision in the log file.
639  */
641  tdes->coord->block_particps_ids, true);
642  }
643  else
644  {
645  /*
646  * Abort was decided without using the 2PC protocol at this site.
647  * That is, the participants are not prepare to commit). Therefore,
648  * there is no need to collect acknowledgments.
649  *
650  * If the following function fails, the transaction will be dangling
651  * and we need to retry sending the decision at another point.
652  * We have already decided and log the decision in the log file.
653  */
655  tdes->coord->block_particps_ids, false);
656  }
657  /* Check if all the acknowledgments have been received */
658  state = log_complete_for_2pc (thread_p, tdes, LOG_ABORT, LOG_NEED_NEWTRID);
659  }
660 
661  return state;
662 }
663 
664 /*
665  * log_2pc_commit - Follow two phase commit protocol (coordinator's algorithm)
666  *
667  * return: TRAN_STATE
668  *
669  * tdes(in): State structure of transaction of the log record
670  * execute_2pc_type(in): Phase of two phase commit to execute
671  * decision(in/out): Wheater coordinator and its participants agree to
672  * commit or abort the transaction
673  *
674  */
676 log_2pc_commit (THREAD_ENTRY * thread_p, log_tdes * tdes, LOG_2PC_EXECUTE execute_2pc_type, bool * decision)
677 {
678  TRAN_STATE state;
679 
680  if (tdes->gtrid == LOG_2PC_NULL_GTRID)
681  {
682  TR_TABLE_CS_ENTER (thread_p);
683  tdes->gtrid = log_2pc_make_global_tran_id (tdes->trid);
684  TR_TABLE_CS_EXIT (thread_p);
685  }
686 
687  /*
688  * PHASE I of 2PC: Guarantee commitment (i.e., coordinator and participants
689  * are Voting)
690  */
691 
692  /* If the transaction is ready to commit, the first phase of the 2PC has already been completed, so skip it here */
693 
694  if (execute_2pc_type == LOG_2PC_EXECUTE_FULL || execute_2pc_type == LOG_2PC_EXECUTE_PREPARE)
695  {
696  if (log_2pc_commit_first_phase (thread_p, tdes, execute_2pc_type, decision) != NO_ERROR)
697  {
698  return tdes->state;
699  }
700  }
701  else
702  {
703  /*
704  * We are currently not executing the first phase of 2PC. The decsion is
705  * already known
706  */
707  if (execute_2pc_type == LOG_2PC_EXECUTE_COMMIT_DECISION)
708  {
709  *decision = true;
710  }
711  else
712  {
713  *decision = false;
714  }
715  }
716 
717  /*
718  * PHASE II of 2PC: Inform decsion to participants (i.e., either commit or
719  * abort)
720  */
721  if (execute_2pc_type != LOG_2PC_EXECUTE_PREPARE || *decision == false)
722  {
723  state = log_2pc_commit_second_phase (thread_p, tdes, decision);
724  }
725  else
726  {
727  state = tdes->state;
728  }
729 
730  return state;
731 }
732 
733 /*
734  * log_set_global_tran_info - SET GLOBAL TRANSACTION INFORMATION
735  *
736  * return:
737  *
738  * gtrid(in): global transaction identifier
739  * info(in): pointer to the user information to be set
740  * size(in): size of the user information to be set
741  *
742  * NOTE:Set the user information related with the global transaction.
743  * The global transaction identified by the 'gtrid' should exist
744  * and should be the value returned by 'db_2pc_start_transaction'
745  * You can use this function to set the longer format of global
746  * transaction identifier such as XID of XA interface.
747  */
748 int
749 log_2pc_set_global_tran_info (THREAD_ENTRY * thread_p, int gtrid, void *info, int size)
750 {
751  LOG_TDES *tdes;
752  int i;
753 
754  if (gtrid != LOG_2PC_NULL_GTRID)
755  {
756  TR_TABLE_CS_ENTER (thread_p);
757 
758  for (i = 0; i < log_Gl.trantable.num_total_indices; i++)
759  {
760  tdes = LOG_FIND_TDES (i);
761  if (tdes != NULL && tdes->trid != NULL_TRANID && tdes->gtrid == gtrid)
762  {
763  /* The transaction is in the middle of the 2PC protocol, we cannot set. */
764  if (LOG_ISTRAN_2PC (tdes))
765  {
767  log_state_string (tdes->state));
768 
769  TR_TABLE_CS_EXIT (thread_p);
771  }
772 
773  /* Set the global transaction information. If already set, overwrite it. */
774  if (tdes->gtrinfo.info_data != NULL)
775  {
777  }
778  tdes->gtrinfo.info_data = malloc (size);
779  if (tdes->gtrinfo.info_data == NULL)
780  {
781  TR_TABLE_CS_EXIT (thread_p);
783  }
784  tdes->gtrinfo.info_length = size;
785  (void) memcpy (tdes->gtrinfo.info_data, info, size);
786 
787  TR_TABLE_CS_EXIT (thread_p);
788  return NO_ERROR;
789  }
790  }
791 
792  TR_TABLE_CS_EXIT (thread_p);
793  }
794 
797 }
798 
799 /*
800  * log_get_global_tran_info - Get global transaction information
801  *
802  * return: NO_ERROR or error code
803  *
804  * gtrid(in): global transaction identifier
805  * buffer(in): pointer to the buffer into which the user information is stored
806  * size(in): size of the buffer
807  *
808  * NOTE:Get the user information of the global transaction identified
809  * by the 'gtrid'.
810  * You can use this function to get the longer format of global
811  * transaction identifier such as XID of XA interface. This
812  * function is designed to use if you want to get XID after
813  * calling 'db_2pc_prepared_transactions' to support xa_recover()
814  */
815 int
816 log_2pc_get_global_tran_info (THREAD_ENTRY * thread_p, int gtrid, void *buffer, int size)
817 {
818  LOG_TDES *tdes;
819  int i;
820 
821  assert (buffer != NULL);
822  assert (size >= 0);
823 
824  if (gtrid != LOG_2PC_NULL_GTRID)
825  {
826 
827  TR_TABLE_CS_ENTER (thread_p);
828 
829  for (i = 0; i < log_Gl.trantable.num_total_indices; i++)
830  {
831  tdes = LOG_FIND_TDES (i);
832  if (tdes != NULL && tdes->trid != NULL_TRANID && tdes->gtrid == gtrid)
833  {
834  /* If the global transation information is not set, error. */
835  if (tdes->gtrinfo.info_data == NULL)
836  {
838 
839  TR_TABLE_CS_EXIT (thread_p);
841  }
842 
843  /* Copy the global transaction information to the buffer. */
844  if (size > tdes->gtrinfo.info_length)
845  {
846  size = tdes->gtrinfo.info_length;
847  }
848  (void) memcpy (buffer, tdes->gtrinfo.info_data, size);
849 
850  TR_TABLE_CS_EXIT (thread_p);
851  return NO_ERROR;
852  }
853  }
854 
855  TR_TABLE_CS_EXIT (thread_p);
856  }
857 
860 }
861 
862 /*
863  * log_2pc_start - START TRANSACTION AS A PART OF GLOBAL TRANSACTION
864  *
865  * return: return global transaction identifier
866  *
867  * NOTE:Make current transaction as a part of a global transaction by
868  * assigning a global transaction identifier(gtrid).
869  * It is recommended to call this function just after the end of
870  * a transaction(commit or abort) before executing other works.
871  * This function is one way of getting gtrid of the transaction.
872  * The other way is to use 'db_2pc_prepare_to_commit_transaction'
873  * The function 'db_2pc_prepare_transaction' should be used if
874  * this function is called.
875  */
876 int
878 {
879  LOG_TDES *tdes;
880  int tran_index;
881 
882  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
883  tdes = LOG_FIND_TDES (tran_index);
884  if (tdes == NULL)
885  {
887  return LOG_2PC_NULL_GTRID;
888  }
889 
890  if (!LOG_ISTRAN_ACTIVE (tdes))
891  {
893  return LOG_2PC_NULL_GTRID;
894  }
895 
896  if (tdes->gtrid == LOG_2PC_NULL_GTRID)
897  {
898  TR_TABLE_CS_ENTER (thread_p);
899  tdes->gtrid = log_2pc_make_global_tran_id (tdes->trid);
900  TR_TABLE_CS_EXIT (thread_p);
901  }
902 
903  return tdes->gtrid;
904 }
905 
906 /*
907  * log_2pc_prepare - PREPARE TRANSACTION TO COMMIT
908  *
909  * return: TRAN_STATE
910  *
911  * NOTE: Prepare the current transaction for commitment in 2PC. The
912  * transaction should be made as a part of a global transaction
913  * before by 'db_2pc_start_transaction', a pair one of this
914  * function.
915  * The system promises not to unilaterally abort the transaction.
916  * After this function call, the only API functions that should
917  * be executed are 'db_commit_transaction' &
918  * 'db_abort_transaction'.
919  */
922 {
923  LOG_TDES *tdes;
924  int tran_index;
925 
926  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
927  tdes = LOG_FIND_TDES (tran_index);
928  if (tdes == NULL)
929  {
931  return TRAN_UNACTIVE_UNKNOWN;
932  }
933 
934  if (tdes->gtrid == LOG_2PC_NULL_GTRID)
935  {
936  /* Transaction is not started by 'log_2pc_start', cannot be prepared. */
938  return tdes->state;
939  }
940 
941  return log_2pc_prepare_global_tran (thread_p, tdes->gtrid);
942 }
943 
944 /*
945  * log_2pc_recovery_prepared - OBTAIN LIST OF PREPARED TRANSACTIONS
946  *
947  * return: the number of ids copied into 'gtrids[]'
948  *
949  * gtrids(in): array into which global transaction identifiers are copied
950  * size(in): size of 'gtrids[]' array
951  *
952  * NOTE:For restart recovery of global transactions, this function
953  * returns gtrids of transactions in prepared state, which was
954  * a part of a global transaction.
955  * If the return value is less than the 'size', there's no more
956  * transactions to recover.
957  */
958 int
959 log_2pc_recovery_prepared (THREAD_ENTRY * thread_p, int gtrids[], int size)
960 {
961  LOG_TDES *tdes;
962  int i, count = 0;
963 
964  assert (size >= 0);
965 
966  TR_TABLE_CS_ENTER (thread_p);
967 
968  for (i = 0; i < log_Gl.trantable.num_total_indices; i++)
969  {
970  tdes = LOG_FIND_TDES (i);
971  if (tdes != NULL && tdes->trid != NULL_TRANID && tdes->gtrid != LOG_2PC_NULL_GTRID
972  && LOG_ISTRAN_2PC_PREPARE (tdes))
973  {
974  if (size <= count)
975  {
976  break;
977  }
978  gtrids[count++] = tdes->gtrid;
979  }
980  }
981 
982  TR_TABLE_CS_EXIT (thread_p);
983  return count;
984 }
985 
986 /*
987  * log_2pc_find_tran_descriptor -
988  *
989  * return:
990  *
991  * gtrid(in): global transaction identifier
992  *
993  * Note:
994  */
995 static LOG_TDES *
997 {
998  LOG_TDES *tdes;
999  int i;
1000 
1001  /*
1002  * Check if the client_user has a 2PC prepare index. If it does, attach
1003  * this index to the given user.
1004  */
1005  for (i = 0; i < log_Gl.trantable.num_total_indices; i++)
1006  {
1007  tdes = LOG_FIND_TDES (i);
1008  if (tdes != NULL && tdes->trid != NULL_TRANID && tdes->gtrid != LOG_2PC_NULL_GTRID
1009  && LOG_ISTRAN_2PC_PREPARE (tdes) && (tdes->gtrid == gtrid))
1010  {
1011  return tdes;
1012  }
1013  }
1014 
1015  return NULL;
1016 }
1017 
1018 /*
1019  * log_2pc_attach_client -
1020  *
1021  * return:
1022  *
1023  * gtrid(in): global transaction identifier
1024  *
1025  * Note:
1026  */
1027 static int
1028 log_2pc_attach_client (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_TDES * client_tdes)
1029 {
1030  /*
1031  * Abort the current client transaction, then attach to the desired
1032  * transaction.
1033  */
1034  (void) log_abort (thread_p, NULL_TRAN_INDEX);
1035 
1036  /*
1037  * Copy the contents of the 2PC transaction descriptor over the
1038  * client transaction index.
1039  */
1040  tdes->isloose_end = false;
1041  tdes->isolation = client_tdes->isolation;
1042  tdes->wait_msecs = client_tdes->wait_msecs;
1043  /*
1044  * The client identification remains the same. So there is not a need
1045  * to set clientids.
1046  */
1047 
1048  /* Return the table entry that is not going to be used anymore */
1049  logtb_free_tran_index (thread_p, client_tdes->tran_index);
1050  LOG_SET_CURRENT_TRAN_INDEX (thread_p, tdes->tran_index);
1051 
1052  /* Reduce the number of loose end transactions by one */
1054 
1055  return NO_ERROR;
1056 }
1057 
1058 /*
1059  * log_2pc_attach_global_tran - Join coordinator to 2pc transaction
1060  *
1061  * return: New transaction index..
1062  *
1063  * gtrid(in): Global transaction identifier
1064  *
1065  * NOTE:The current client index is freed and the one with the given
1066  * 2PC loose end (i.e., transaction waiting for decision)
1067  * transaction is returned. The old client transaction is aborted
1068  * before the attachement, the old client transaction must not be
1069  * in the middle of a 2PC.
1070  * It is recommended to attach a client to a 2PC loose end
1071  * transaction just after the client restart or after a commit
1072  * or abort.
1073  * The attachment is done by copying some information of the
1074  * current transaction client index over the 2PC loose end index
1075  * and the previous assigned client index is freed.
1076  * The attachment may fail if the current client user is not the
1077  * same that the original user due to recovery client issues.
1078  */
1079 int
1081 {
1082  LOG_TDES *client_tdes; /* The current (client) transaction descriptor */
1083  LOG_TDES *tdes; /* Transaction descriptor */
1084  int tran_index;
1085 
1086  assert (gtrid != LOG_2PC_NULL_GTRID);
1087 
1088  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
1089  client_tdes = LOG_FIND_TDES (tran_index);
1090  if (client_tdes == NULL)
1091  {
1093  return NULL_TRAN_INDEX;
1094  }
1095 
1096  if (LOG_ISTRAN_2PC (client_tdes))
1097  {
1098  /*
1099  * The current transaction is in the middle of the 2PC protocol, we
1100  * cannot attach at this moment
1101  */
1103  return NULL_TRAN_INDEX;
1104  }
1105 
1106  TR_TABLE_CS_ENTER (thread_p);
1107 
1109  {
1110  tdes = log_2pc_find_tran_descriptor (gtrid);
1111  if (tdes == NULL)
1112  {
1113  goto error;
1114  }
1115 
1116  if (log_2pc_attach_client (thread_p, tdes, client_tdes) != NO_ERROR)
1117  {
1119 
1120  TR_TABLE_CS_EXIT (thread_p);
1121  return NULL_TRAN_INDEX;
1122  }
1123 
1124  TR_TABLE_CS_EXIT (thread_p);
1125  return (tdes->tran_index);
1126  }
1127 
1128 error:
1129 
1130  TR_TABLE_CS_EXIT (thread_p);
1131 
1132  /* There is no such transaction to attach to */
1134  return NULL_TRAN_INDEX;
1135 
1136 }
1137 
1138 /*
1139  * log_2pc_prepare_global_tran - Prepare the transaction to commit
1140  *
1141  * return: TRAN_STATE
1142  *
1143  * gtrid(in): Identifier of the global transaction. The coordinator is
1144  * responsible for generating the global transaction identifier.
1145  *
1146  * NOTE:This function prepares the transaction identified by "gtrid"
1147  * for commitment. Any objects and data that the transaction held
1148  * or modified are placed in a state that can be guarantee the
1149  * the commintment of the transaction by coordinator request
1150  * regardless of failures. The shared type locks (IS, S) acquired
1151  * by the transaction are released (SIX is demoted to IX lock)
1152  * and the exclusive type locks (IX, X) acquired by the
1153  * transaction are saved in the log as part of the prepare to
1154  * commit log record. This is needed since, we must guarantee the
1155  * consistency of the updated data until the transaction is
1156  * either committed or aborted by the coordinator regardless of
1157  * failures. If the transaction cannot be committed, it was
1158  * previously aborted, and the coordinator is notified of such
1159  * state.
1160  */
1161 TRAN_STATE
1163 {
1164  LOG_TDES *tdes; /* Transaction descriptor */
1165  LOG_TDES *other_tdes; /* Transaction descriptor */
1166  LOG_REC_2PC_PREPCOMMIT *prepared; /* A prepare to commit log record */
1167  LK_ACQUIRED_LOCKS acq_locks; /* List of acquired locks */
1168  bool decision; /* The decision: success or failure */
1169  TRAN_STATE state; /* The state of the transaction */
1170  int size;
1171  int i;
1172  int tran_index;
1173  LOG_PRIOR_NODE *node;
1174  LOG_LSA start_lsa;
1175 
1176  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
1177  tdes = LOG_FIND_TDES (tran_index);
1178  if (tdes == NULL)
1179  {
1181  return TRAN_UNACTIVE_UNKNOWN;
1182  }
1183 
1184  if (!LOG_ISTRAN_ACTIVE (tdes))
1185  {
1186  /*
1187  * May be a system error since transaction is not active.. cannot be
1188  * prepared to committed
1189  */
1190 #if defined(CUBRID_DEBUG)
1192  "log_2pc_prepare: Transaction %d " "(index = %d) is not active for prepare to commit."
1193  " Its state is %s\n", tdes->trid, tdes->tran_index, log_state_string (tdes->state));
1194 #endif /* CUBRID_DEBUG */
1195  return tdes->state;
1196  }
1197 
1198  if (tdes->topops.last >= 0)
1199  {
1200  /*
1201  * This is likely a system error since the transaction is being prepared
1202  * to commit when there are system permanent operations attached to it.
1203  * We assume that the transaction finished those top actions and that a
1204  * commit is required on them.
1205  */
1206 
1207 #if defined(CUBRID_DEBUG)
1209  "log_2pc_prepare: May be a system error.\n" "Prepare to commit requested on the transaction = %d"
1210  " (index = %d) which has permanent operations attached"
1211  " to it.\n Will attach those system operations to the" " transaction\n", tdes->trid,
1212  tdes->tran_index);
1213 #endif /* CUBRID_DEBUG */
1214  assert (false);
1215  while (tdes->topops.last >= 0)
1216  {
1217  log_sysop_attach_to_outer (thread_p);
1218  }
1219  }
1220 
1221  /* Check if the given global transaction identifier is unique. Perform a linear search on the transaction table and
1222  * make sure that the given identifier is not being used by another transaction. Since the number of entries in the
1223  * transaction table is expected to be reasonably small, there is no need to use a hashing mechanism here. */
1224 
1225  TR_TABLE_CS_ENTER (thread_p);
1226 
1227  for (i = 0; i < log_Gl.trantable.num_total_indices; i++)
1228  {
1229  other_tdes = LOG_FIND_TDES (i);
1230  if (other_tdes == NULL)
1231  {
1233  LOG_FIND_THREAD_TRAN_INDEX (thread_p));
1234  TR_TABLE_CS_EXIT (thread_p);
1235  return TRAN_UNACTIVE_UNKNOWN;
1236  }
1237 
1238  if (other_tdes != tdes && other_tdes->trid != NULL_TRANID && other_tdes->gtrid != LOG_2PC_NULL_GTRID
1239  && other_tdes->gtrid == gtrid)
1240  {
1241  /* This gtrid is not unique; It is already been used */
1243  TR_TABLE_CS_EXIT (thread_p);
1244  return tdes->state;
1245  }
1246  }
1247  TR_TABLE_CS_EXIT (thread_p);
1248 
1249  /*
1250  * Check if the current site is not only a participant but also a
1251  * coordinator for some other participnats. If the current site is a
1252  * coordinator of the transaction,its participants must prepare to commit
1253  * before we can proceed with the prepare to commit. If not all the
1254  * participants are willing to commit, the prepare to commit cannot be
1255  * guaranteed; thus, the transaction is aborted at this site and its
1256  * participants that were willing to commit teh transaction.
1257  */
1258 
1259  tdes->gtrid = gtrid;
1260  if (log_2pc_is_tran_distributed (tdes))
1261  {
1262  /*
1263  * Site is also a coordinator, so we need to execute a nested 2PC
1264  */
1265  state = log_2pc_commit (thread_p, tdes, LOG_2PC_EXECUTE_PREPARE, &decision);
1266  if (decision == false)
1267  {
1268  return state;
1269  }
1270 
1271  /* Now proceed as participant of the distributed transaction */
1272  }
1273 
1274  lock_unlock_all_shared_get_all_exclusive (thread_p, &acq_locks);
1275 
1276  /*
1277  * Indicate that we are willing to commit the transaction
1278  */
1279 
1280  size = 0;
1281  if (acq_locks.obj != NULL)
1282  {
1283  size = acq_locks.nobj_locks * sizeof (LK_ACQOBJ_LOCK);
1284  }
1285 
1286  node =
1288  (char *) tdes->gtrinfo.info_data, size, (char *) acq_locks.obj);
1289  if (node == NULL)
1290  {
1291  if (acq_locks.obj != NULL)
1292  {
1293  free_and_init (acq_locks.obj);
1294  }
1295 
1296  return TRAN_UNACTIVE_UNKNOWN;
1297  }
1298 
1299  prepared = (LOG_REC_2PC_PREPCOMMIT *) node->data_header;
1300 
1301  memcpy (prepared->user_name, tdes->client.get_db_user (), DB_MAX_USER_LENGTH);
1302  prepared->gtrid = gtrid;
1303  prepared->gtrinfo_length = tdes->gtrinfo.info_length;
1304  prepared->num_object_locks = acq_locks.nobj_locks;
1305  /* ignore num_page_locks */
1306  prepared->num_page_locks = 0;
1307 
1308  start_lsa = prior_lsa_next_record (thread_p, node, tdes);
1309 
1310  if (acq_locks.obj != NULL)
1311  {
1312  free_and_init (acq_locks.obj);
1313  }
1314 
1315  /*
1316  * END append. The log need to be flushed since we need to guarantee
1317  * the commitment of the transaction if the coordinator requests commit
1318  */
1319 
1321  logpb_flush_pages (thread_p, &start_lsa);
1322 
1323  return tdes->state;
1324 }
1325 
1326 /*
1327  * log_2pc_read_prepare - READ PREPARE_TO_COMMIT LOG RECORD
1328  *
1329  * return: nothing
1330  *
1331  * acquire_locks(in): specify if list of locks needs to be read from the log
1332  * record and the listed locks needs to be acquired.
1333  * tdes(in): Transaction descriptor
1334  * log_lsa(in): Log address identifier containing the log record
1335  * log_pgptr(in): the buffer containing the log page
1336  *
1337  * NOTE:This function is used to read the prepared log record from the
1338  * system log at the specified location. If "acquire_locks"
1339  * parameter is off only the global transaction identifier is
1340  * read. If this parameter is on, on the other hand, the list of
1341  * update-type locks that the transaction had acquired at the
1342  * time of crash is also read from the log record, and the listed
1343  * locks aqcuired.
1344  * Note that the parameters specifying the location of the log
1345  * record to be read are updated to point to the end of the
1346  * record.
1347  */
1348 void
1349 log_2pc_read_prepare (THREAD_ENTRY * thread_p, int acquire_locks, log_tdes * tdes, LOG_LSA * log_lsa,
1350  LOG_PAGE * log_page_p)
1351 {
1352  LOG_REC_2PC_PREPCOMMIT *prepared; /* A 2PC prepare to commit log record */
1353  LK_ACQUIRED_LOCKS acq_locks; /* List of acquired locks before the system crash */
1354  int size;
1355 
1356  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*prepared), log_lsa, log_page_p);
1357 
1358  prepared = (LOG_REC_2PC_PREPCOMMIT *) ((char *) log_page_p->area + log_lsa->offset);
1359 
1361 
1362  tdes->gtrid = prepared->gtrid;
1363  tdes->gtrinfo.info_length = prepared->gtrinfo_length;
1364 
1365  LOG_READ_ADD_ALIGN (thread_p, sizeof (*prepared), log_lsa, log_page_p);
1366 
1367  if (tdes->gtrinfo.info_length > 0)
1368  {
1369  tdes->gtrinfo.info_data = malloc (tdes->gtrinfo.info_length);
1370  if (tdes->gtrinfo.info_data == NULL)
1371  {
1372  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_2pc_read_prepare");
1373 
1374  return;
1375  }
1376 
1377  /* Read the global transaction user information data */
1378  LOG_READ_ALIGN (thread_p, log_lsa, log_page_p);
1379 
1380  logpb_copy_from_log (thread_p, (char *) tdes->gtrinfo.info_data, tdes->gtrinfo.info_length, log_lsa, log_page_p);
1381  }
1382 
1383  /* If the update-type locks that the transaction had obtained before the crash needs to be aqcuired, read them from
1384  * the log record and obtain the locks at this time. */
1385 
1386  if (acquire_locks != false)
1387  {
1388  /* Read in the list of locks to acquire */
1389 
1390  LOG_READ_ALIGN (thread_p, log_lsa, log_page_p);
1391 
1392  acq_locks.nobj_locks = prepared->num_object_locks;
1393  acq_locks.obj = NULL;
1394 
1395  if (acq_locks.nobj_locks > 0)
1396  {
1397  /* obtain the list of locks to acquire on objects */
1398  size = acq_locks.nobj_locks * sizeof (LK_ACQOBJ_LOCK);
1399  acq_locks.obj = (LK_ACQOBJ_LOCK *) malloc (size);
1400  if (acq_locks.obj == NULL)
1401  {
1402  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_2pc_read_prepare");
1403  return;
1404  }
1405 
1406  logpb_copy_from_log (thread_p, (char *) acq_locks.obj, size, log_lsa, log_page_p);
1407  LOG_READ_ALIGN (thread_p, log_lsa, log_page_p);
1408  }
1409 
1410  if (acq_locks.nobj_locks > 0)
1411  {
1412  /* Acquire the locks */
1413  if (lock_reacquire_crash_locks (thread_p, &acq_locks, tdes->tran_index) != LK_GRANTED)
1414  {
1415  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_2pc_read_prepare");
1416  return;
1417  }
1418 
1419  free_and_init (acq_locks.obj);
1420  }
1421  }
1422 }
1423 
1424 /*
1425  * log_2pc_dump_gtrinfo - DUMP GLOBAL TRANSACTION USER INFORMATION
1426  *
1427  * return: nothing
1428  *
1429  * length(in): Length to dump in bytes
1430  * data(in): The data being logged
1431  *
1432  * NOTE:Dump global transaction user information
1433  */
1434 void
1435 log_2pc_dump_gtrinfo (FILE * fp, int length, void *data)
1436 {
1437 }
1438 
1439 /*
1440  * log_2pc_dump_acqobj_locks - DUMP THE ACQUIRED OBJECT LOCKS
1441  *
1442  * return: nothing
1443  *
1444  * length(in): Length to dump in bytes
1445  * data(in): The data being logged
1446  *
1447  * NOTE: Dump the acquired object lock structure.
1448  */
1449 void
1450 log_2pc_dump_acqobj_locks (FILE * fp, int length, void *data)
1451 {
1452  LK_ACQUIRED_LOCKS acq_locks;
1453 
1454  acq_locks.nobj_locks = length / sizeof (LK_ACQOBJ_LOCK);
1455  acq_locks.obj = (LK_ACQOBJ_LOCK *) data;
1456  lock_dump_acquired (fp, &acq_locks);
1457 }
1458 
1459 /*
1460  * log_2pc_append_start - APPEND A VOTING LOG RECORD FOR THE 2PC PROTOCOL
1461  *
1462  * return: nothing
1463  *
1464  * tdes(in/out): State structure of transaction
1465  *
1466  * NOTE:A LOG_2PC_START log record is appended to the log to start
1467  * the 2PC protocol (i.e., its atomic commitment). The
1468  * transaction is declared as collecting votes. This function is
1469  * used by the coordinator site of a distributed transaction.
1470  */
1471 static void
1473 {
1474  LOG_REC_2PC_START *start_2pc; /* Start 2PC log record */
1475  LOG_PRIOR_NODE *node;
1476  LOG_LSA start_lsa;
1477 
1478  node =
1480  (tdes->coord->particp_id_length * tdes->coord->num_particps),
1481  (char *) tdes->coord->block_particps_ids, 0, NULL);
1482  if (node == NULL)
1483  {
1484  return;
1485  }
1486 
1487  start_2pc = (LOG_REC_2PC_START *) node->data_header;
1488 
1489  memcpy (start_2pc->user_name, tdes->client.get_db_user (), DB_MAX_USER_LENGTH);
1490  start_2pc->gtrid = tdes->gtrid;
1491  start_2pc->num_particps = tdes->coord->num_particps;
1492  start_2pc->particp_id_length = tdes->coord->particp_id_length;
1493 
1494  start_lsa = prior_lsa_next_record (thread_p, node, tdes);
1495 
1496  /*
1497  * END append
1498  * We need to flush the log so that we can find the participants of the
1499  * 2PC in the event of a crash. This is needed since the participants do
1500  * not know about the coordinator or other participants. Participants will
1501  * always wait for the coordinators. We do not have a full 2PC in which
1502  * participants know about each other and the coordinator.
1503  */
1505  logpb_flush_pages (thread_p, &start_lsa);
1506 }
1507 
1508 /*
1509  * log_2pc_append_decision - THE DECISION FOR THE DISTRIBUTED TRANSACTION HAS
1510  * BEEN TAKEN
1511  *
1512  * return: nothing
1513  *
1514  * tdes(in/out): State structure of transaction
1515  * decision(in): Either LOG_2PC_COMMIT_DECISION or LOG_2PC_ABORT_DECISION
1516  *
1517  * NOTE:A decision was taken to either commit or abort the distributed
1518  * transaction. If a commit decsion was taken all participants
1519  * and the coordinator have agreed to commit the transaction. On
1520  * the other hand, if an abort decsion wasd taken, the
1521  * coordinator and all participants did not reach a agreement to
1522  * commit the transaction. It is likely that the distributed
1523  * transaction was aborted at a remote site for circunstances
1524  * beyond our control. A LOG_2PC_ABORT_DECISION log record is
1525  * appended to the log. The second phase of the 2PC starts after
1526  * the function finishes.
1527  */
1528 static void
1530 {
1531  LOG_PRIOR_NODE *node;
1532  LOG_LSA start_lsa;
1533 
1534  node = prior_lsa_alloc_and_copy_data (thread_p, decision, RV_NOT_DEFINED, NULL, 0, NULL, 0, NULL);
1535  if (node == NULL)
1536  {
1537  return;
1538  }
1539 
1540  start_lsa = prior_lsa_next_record (thread_p, node, tdes);
1541 
1542  if (decision == LOG_2PC_COMMIT_DECISION)
1543  {
1545 
1546  /*
1547  * END append
1548  * We need to flush the log so that we can find the decision if a
1549  * participant needed in the event of a crash. If the decision is not
1550  * found in the log, we will assume abort
1551  */
1552  logpb_flush_pages (thread_p, &start_lsa);
1553  }
1554  else
1555  {
1557 
1558  /*
1559  * END append
1560  * We do not need to flush the log since if the decision is not found in
1561  * the log, abort is assumed.
1562  */
1563  }
1564 
1565 }
1566 
1567 /*
1568  * log_2pc_alloc_coord_info - ALLOCATE COORDINATOR RELATED INFORMATION
1569  *
1570  * return: tdes or NULL
1571  *
1572  * tdes(in): Transaction descriptor
1573  * num_particps(in): Number of participating sites
1574  * particp_id_length(in): Length of particp_ids block
1575  * block_particps_ids(in): A block of information about the participants
1576  *
1577  * NOTE:This function is used to allocate and initialize coordinator
1578  * related information about participants.
1579  */
1580 log_tdes *
1581 log_2pc_alloc_coord_info (log_tdes * tdes, int num_particps, int particp_id_length, void *block_particps_ids)
1582 {
1583  /* Initialize the coordinator information */
1584  tdes->coord = (LOG_2PC_COORDINATOR *) malloc (sizeof (LOG_2PC_COORDINATOR));
1585  if (tdes->coord == NULL)
1586  {
1587  return NULL;
1588  }
1589  else
1590  {
1591  tdes->coord->num_particps = num_particps;
1592  tdes->coord->particp_id_length = particp_id_length;
1593  tdes->coord->block_particps_ids = block_particps_ids;
1594  tdes->coord->ack_received = NULL;
1595  }
1596 
1597  return tdes;
1598 }
1599 
1600 /*
1601  * log_2pc_free_coord_info - FREE COORDINATOR RELATED INFORMATION
1602  *
1603  * return: nothing
1604  *
1605  * tdes(in): Transaction descriptor
1606  *
1607  * NOTE:This function is used to free coordinator related information
1608  * about participants.
1609  */
1610 void
1612 {
1613  if (tdes->coord != NULL)
1614  {
1615  if (tdes->coord->ack_received != NULL)
1616  {
1617  free_and_init (tdes->coord->ack_received);
1618  }
1619 
1620  if (tdes->coord->block_particps_ids != NULL)
1621  {
1623  }
1624 
1625  free_and_init (tdes->coord);
1626  }
1627 }
1628 
1629 /*
1630  * log_2pc_recovery_prepare -
1631  *
1632  * return:
1633  *
1634  * tdes(in/out):
1635  * lsa(in/out):
1636  * log_page_p(in/out):
1637  *
1638  * Note:
1639  */
1640 static void
1641 log_2pc_recovery_prepare (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_LSA * log_lsa, LOG_PAGE * log_page_p)
1642 {
1643  /*
1644  * This is a particpant of the distributed transaction. We
1645  * need to continue looking since this participant may be
1646  * a non root coordinator
1647  */
1648 
1649  /* Get the DATA HEADER */
1650  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), log_lsa, log_page_p);
1651 
1652  /* The transaction was in prepared_to_commit state at the time of crash. So, read the global transaction identifier
1653  * and list of locks from the log record, and acquire all of the locks. */
1654  if (tdes->state == TRAN_UNACTIVE_2PC_PREPARE)
1655  {
1656  log_2pc_read_prepare (thread_p, LOG_2PC_OBTAIN_LOCKS, tdes, log_lsa, log_page_p);
1657  }
1658  else
1659  {
1660  log_2pc_read_prepare (thread_p, LOG_2PC_DONT_OBTAIN_LOCKS, tdes, log_lsa, log_page_p);
1661  }
1662 }
1663 
1664 /*
1665  * log_2pc_recovery_start -
1666  *
1667  * return:
1668  *
1669  * tdes(in/out):
1670  * lsa(in/out):
1671  * log_page_p(in/out):
1672  * ack_list(in/out):
1673  * ack_count(in/out):
1674  *
1675  * Note:
1676  */
1677 static int
1678 log_2pc_recovery_start (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
1679  int *ack_list, int *ack_count)
1680 {
1681  LOG_REC_2PC_START *start_2pc; /* A 2PC start log record */
1682  void *block_particps_ids; /* A block of participant identifiers */
1683  int num_particps;
1684  int particp_id_length;
1685  int i;
1686 
1687  /* Obtain the coordinator information */
1688  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), log_lsa, log_page_p);
1689  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*start_2pc), log_lsa, log_page_p);
1690 
1691  start_2pc = ((LOG_REC_2PC_START *) ((char *) log_page_p->area + log_lsa->offset));
1692  /*
1693  * Obtain the participant information for this coordinator
1694  */
1695  tdes->client.set_system_internal_with_user (start_2pc->user_name);
1696  tdes->gtrid = start_2pc->gtrid;
1697 
1698  num_particps = start_2pc->num_particps;
1699  particp_id_length = start_2pc->particp_id_length;
1700 
1701  block_particps_ids = malloc (particp_id_length * num_particps);
1702  if (block_particps_ids == NULL)
1703  {
1704  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_2pc_recovery_analysis_info");
1705  return ER_OUT_OF_VIRTUAL_MEMORY;
1706  }
1707 
1708  LOG_READ_ADD_ALIGN (thread_p, sizeof (*start_2pc), log_lsa, log_page_p);
1709  LOG_READ_ALIGN (thread_p, log_lsa, log_page_p);
1710 
1711  /* Read in the participants info. block from the log */
1712  logpb_copy_from_log (thread_p, (char *) block_particps_ids, particp_id_length * num_particps, log_lsa, log_page_p);
1713 
1714  /* Initialize the coordinator information */
1715  if (log_2pc_alloc_coord_info (tdes, num_particps, particp_id_length, block_particps_ids) == NULL)
1716  {
1717  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_2pc_recovery_analysis_info");
1718  return ER_FAILED;
1719  }
1720 
1721  /* Initialize the Acknowledgement vector to false since we do not know what acknowledgments have already been
1722  * received. we need to continue reading the log */
1723 
1724  i = sizeof (int) * tdes->coord->num_particps;
1725  tdes->coord->ack_received = (int *) malloc (i);
1726  if (tdes->coord->ack_received == NULL)
1727  {
1728  log_2pc_free_coord_info (tdes);
1729  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_2pc_recovery_analysis_info");
1730  return ER_OUT_OF_VIRTUAL_MEMORY;
1731  }
1732 
1733  for (i = 0; i < tdes->coord->num_particps; i++)
1734  {
1735  tdes->coord->ack_received[i] = false;
1736  }
1737 
1738  if (*ack_count > 0 && ack_list != NULL)
1739  {
1740  /*
1741  * Some participant acknowledgements have already been
1742  * received. Copy this acknowledgement into the transaction
1743  * descriptor.
1744  */
1745  for (i = 0; i < *ack_count; i++)
1746  {
1747  if (ack_list[i] > tdes->coord->num_particps)
1748  {
1749  er_log_debug (ARG_FILE_LINE, "log_2pc_recovery_analysis_info:" " SYSTEM ERROR for log located at %lld|%d",
1750  log_lsa->pageid, log_lsa->offset);
1751  }
1752  else
1753  {
1754  tdes->coord->ack_received[ack_list[i]] = true;
1755  }
1756  }
1757  free_and_init (ack_list);
1758  *ack_count = 0;
1759  }
1760 
1761  return NO_ERROR;
1762 }
1763 
1764 /*
1765  * log_2pc_expand_ack_list -
1766  *
1767  * return:
1768  *
1769  * ack_list(in/out):
1770  * ack_count(in/out):
1771  * size_ack_list(in/out):
1772  *
1773  * Note:
1774  */
1775 static int *
1776 log_2pc_expand_ack_list (THREAD_ENTRY * thread_p, int *ack_list, int *ack_count, int *size_ack_list)
1777 {
1778  int size;
1779 
1780  if ((*ack_count + 1) > (*size_ack_list))
1781  {
1782  /* allocate space */
1783  if (*size_ack_list == 0)
1784  {
1785  /*
1786  * Initialize the temporary area. Assume no more than 10
1787  * participants
1788  */
1789  *ack_count = 0;
1790  *size_ack_list = 10;
1791 
1792  size = (*size_ack_list) * sizeof (int);
1793  ack_list = (int *) malloc (size);
1794  if (ack_list == NULL)
1795  {
1796  /* Out of memory */
1797  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_2pc_recovery_analysis_info");
1798  return NULL;
1799  }
1800  }
1801  else
1802  {
1803  /* expand ack list by 30% */
1804  *size_ack_list = ((int) (((float) (*size_ack_list) * 1.30) + 0.5));
1805  size = (*size_ack_list) * sizeof (int);
1806  ack_list = (int *) realloc (ack_list, size);
1807  if (ack_list == NULL)
1808  {
1809  /* Out of memory */
1810  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_2pc_recovery_analysis_info");
1811  return NULL;
1812  }
1813  }
1814  }
1815 
1816  return ack_list;
1817 }
1818 
1819 /*
1820  * log_2pc_recovery_recv_ack -
1821  *
1822  * return:
1823  *
1824  * lsa(in/out):
1825  * log_page_p(in/out):
1826  * ack_list(in/out):
1827  * ack_count(in/out):
1828  *
1829  * Note:
1830  */
1831 static void
1832 log_2pc_recovery_recv_ack (THREAD_ENTRY * thread_p, LOG_LSA * log_lsa, LOG_PAGE * log_page_p, int *ack_list,
1833  int *ack_count)
1834 {
1835  LOG_REC_2PC_PARTICP_ACK *received_ack; /* A 2PC recv decision ack */
1836 
1837  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), log_lsa, log_page_p);
1838  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*received_ack), log_lsa, log_page_p);
1839  received_ack = ((LOG_REC_2PC_PARTICP_ACK *) ((char *) log_page_p->area + log_lsa->offset));
1840 
1841  ack_list[*ack_count] = received_ack->particp_index;
1842  (*ack_count)++;
1843 }
1844 
1845 /*
1846  * log_2pc_recovery_analysis_record -
1847  *
1848  * return:
1849  *
1850  * record_type(in):
1851  * tdes(in/out):
1852  * lsa(in/out):
1853  * log_page_p(in/out):
1854  * ack_list(in/out):
1855  * ack_count(in/out):
1856  * size_ack_list(in/out):
1857  * search_2pc_prepare(in/out):
1858  * search_2pc_start(in/out):
1859  *
1860  * Note:
1861  */
1862 static int
1863 log_2pc_recovery_analysis_record (THREAD_ENTRY * thread_p, LOG_RECTYPE record_type, LOG_TDES * tdes, LOG_LSA * log_lsa,
1864  LOG_PAGE * log_page_p, int **ack_list, int *ack_count, int *size_ack_list,
1865  bool * search_2pc_prepare, bool * search_2pc_start)
1866 {
1867  switch (record_type)
1868  {
1869  case LOG_2PC_PREPARE:
1870  if (*search_2pc_prepare)
1871  {
1872  log_2pc_recovery_prepare (thread_p, tdes, log_lsa, log_page_p);
1873  *search_2pc_prepare = false;
1874  }
1875  break;
1876 
1877  case LOG_2PC_START:
1878  if (*search_2pc_start)
1879  {
1880  if (log_2pc_recovery_start (thread_p, tdes, log_lsa, log_page_p, *ack_list, ack_count) == NO_ERROR)
1881  {
1882  *search_2pc_start = false;
1883  }
1884  }
1885  break;
1886 
1887  case LOG_2PC_RECV_ACK:
1888  /*
1889  * Coordiantor site: The distributed transaction is in the
1890  * second phase of the 2PC, that is, coordinator has notfied
1891  * the decision to participants and some of them as acknowledge
1892  * the execution of the decsion.
1893  */
1894  if (*search_2pc_start && LOG_ISTRAN_2PC_IN_SECOND_PHASE (tdes))
1895  {
1896  *ack_list = log_2pc_expand_ack_list (thread_p, *ack_list, ack_count, size_ack_list);
1897  log_2pc_recovery_recv_ack (thread_p, log_lsa, log_page_p, *ack_list, ack_count);
1898  }
1899  break;
1900 
1901  case LOG_COMPENSATE:
1902  case LOG_RUN_POSTPONE:
1903  case LOG_WILL_COMMIT:
1909  /* Skip over this log record types */
1910  break;
1911 
1912  case LOG_UNDOREDO_DATA:
1914  case LOG_UNDO_DATA:
1915  case LOG_REDO_DATA:
1918  case LOG_MVCC_UNDO_DATA:
1919  case LOG_MVCC_REDO_DATA:
1922  case LOG_POSTPONE:
1923  case LOG_SAVEPOINT:
1924  case LOG_COMMIT:
1925  case LOG_ABORT:
1927  case LOG_SYSOP_END:
1928  case LOG_START_CHKPT:
1929  case LOG_END_CHKPT:
1931  case LOG_REPLICATION_DATA:
1933  case LOG_END_OF_LOG:
1934  /*
1935  * Either the prepare to commit or start 2PC record should
1936  * have already been found by now. Otherwise, it is likely that the
1937  * transaction is not a distributed transaction that has loose end
1938  * client actions
1939  */
1940  if (*search_2pc_start == false)
1941  {
1942  *search_2pc_prepare = false;
1943  }
1944  else if (*search_2pc_prepare == false)
1945  {
1946  *search_2pc_start = false;
1947  }
1948 
1949  break;
1950 
1953  default:
1954 #if defined(CUBRID_DEBUG)
1955  er_log_debug (ARG_FILE_LINE, "log_2pc_recovery_analysis_info:" " Unknown record type = %d May be a system error",
1956  log_rec->type);
1957 #endif /* CUBRID_DEBUG */
1959  return ER_LOG_PAGE_CORRUPTED;
1960  }
1961 
1962  return NO_ERROR;
1963 }
1964 
1965 /*
1966  * log_2pc_recovery_analysis_info - FIND 2PC information of given transaction
1967  * upto the given lsa address of transaction
1968  *
1969  * return: nothing
1970  *
1971  * tdes(in/out): State structure of transaction of the log record
1972  * upto_chain_lsa(in): Stop at this lsa of the transaction (This lsa MUST
1973  * be of the given transaction
1974  *
1975  * NOTE:Obtain 2PC information of the given transaction up to the
1976  * given lsa address. This function is needed at the end of the
1977  * recovery analysis phase for transaction that were active at
1978  * the time of the crash and at the time of a checkpoint log
1979  * record. The upto_chain_lsa address is the undo_tail address of
1980  * the transaction at the moment of the checkpoint log record.
1981  * We should point out that a checkpoint log record does not
1982  * contain all information related to 2PC due to the big space
1983  * overhead (e.g., locks) and the closenest to the end of the
1984  * transaction. The rest of the 2PC information of this
1985  * transaction is read by the redo phase of the recovery process.
1986  */
1987 void
1988 log_2pc_recovery_analysis_info (THREAD_ENTRY * thread_p, log_tdes * tdes, LOG_LSA * upto_chain_lsa)
1989 {
1990  LOG_RECORD_HEADER *log_rec; /* Pointer to log record */
1991  char log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT], *aligned_log_pgbuf;
1992  LOG_PAGE *log_page_p = NULL; /* Log page pointer where LSA is located */
1993  LOG_LSA lsa;
1994  LOG_LSA prev_tranlsa; /* prev LSA of transaction */
1995  bool search_2pc_prepare = false;
1996  bool search_2pc_start = false;
1997  int ack_count = 0;
1998  int *ack_list = NULL;
1999  int size_ack_list = 0;
2000 
2001  aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
2002 
2003  if (!LOG_ISTRAN_2PC (tdes))
2004  {
2005  return;
2006  }
2007 
2008  /* For a transaction that was prepared to commit at the time of the crash, make sure that its global transaction
2009  * identifier is obtained from the log and that the update_type locks that were acquired before the time of the crash
2010  * are reacquired. */
2011 
2012  if (tdes->gtrid == LOG_2PC_NULL_GTRID)
2013  {
2014  search_2pc_prepare = true;
2015  }
2016 
2017  /* If this is a coordinator transaction performing 2PC and voting record has not been read from the log in the
2018  * recovery redo phase, read the voting record and any acknowledgement records logged for this transaction */
2019 
2020  if (tdes->coord == NULL)
2021  {
2022  search_2pc_start = true;
2023  }
2024 
2025  /*
2026  * Follow the undo tail chain starting at upto_chain_tail finding all
2027  * 2PC related information
2028  */
2029  log_page_p = (LOG_PAGE *) aligned_log_pgbuf;
2030 
2031  LSA_COPY (&prev_tranlsa, upto_chain_lsa);
2032  while (!LSA_ISNULL (&prev_tranlsa) && (search_2pc_prepare || search_2pc_start))
2033  {
2034  LSA_COPY (&lsa, &prev_tranlsa);
2035  if ((logpb_fetch_page (thread_p, &lsa, LOG_CS_FORCE_USE, log_page_p)) != NO_ERROR)
2036  {
2037  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_2pc_recovery_analysis_info");
2038  break;
2039  }
2040 
2041  while (prev_tranlsa.pageid == lsa.pageid && (search_2pc_prepare || search_2pc_start))
2042  {
2043  lsa.offset = prev_tranlsa.offset;
2044 
2045  log_rec = LOG_GET_LOG_RECORD_HEADER (log_page_p, &lsa);
2046  LSA_COPY (&prev_tranlsa, &log_rec->prev_tranlsa);
2047 
2049  (thread_p, log_rec->type, tdes, &lsa, log_page_p, &ack_list, &ack_count, &size_ack_list,
2050  &search_2pc_prepare, &search_2pc_start) != NO_ERROR)
2051  {
2052  LSA_SET_NULL (&prev_tranlsa);
2053  }
2054  free_and_init (ack_list);
2055  } /* while */
2056  } /* while */
2057 
2058  /* Check for error conditions */
2059  if (tdes->state == TRAN_UNACTIVE_2PC_PREPARE && tdes->gtrid == LOG_2PC_NULL_GTRID)
2060  {
2061 #if defined(CUBRID_DEBUG)
2063  "log_2pc_recovery_analysis_info:" " SYSTEM ERROR... Either the LOG_2PC_PREPARE/LOG_2PC_START\n"
2064  " log record was not found for participant of distributed" " trid = %d with state = %s", tdes->trid,
2065  log_state_string (tdes->state));
2066 #endif /* CUBRID_DEBUG */
2067  }
2068 
2069  /*
2070  * Now the client should attach to this prepared transaction and
2071  * provide the decision (commit/abort). Until then this thread
2072  * is suspended.
2073  */
2074 
2075  if (search_2pc_start)
2076  {
2077  /*
2078  * A 2PC start log record was not found for the coordinator
2079  */
2080  if (tdes->state != TRAN_UNACTIVE_2PC_PREPARE)
2081  {
2082 #if defined(CUBRID_DEBUG)
2084  "log_2pc_recovery_analysis_info:" " SYSTEM ERROR... The LOG_2PC_START log record was"
2085  " not found for coordinator of distributed trid = %d" " with state = %s", tdes->trid,
2086  log_state_string (tdes->state));
2087 #endif /* CUBRID_DEBUG */
2088  }
2089  }
2090 }
2091 
2092 /*
2093  * log_2pc_recovery_collecting_participant_votes -
2094  *
2095  * return: nothing
2096  *
2097  * tdes(in/out): State structure of transaction of the log record
2098  *
2099  * Note:
2100  */
2101 static void
2103 {
2104  /*
2105  * This is a participant which has not decided the fate of the
2106  * distributed transaction. Abort the transaction
2107  */
2109 
2110  /* Let it fall thru the TRAN_UNACTIVE_2PC_ABORT_DECISION case */
2111  log_2pc_recovery_abort_decision (thread_p, tdes);
2112 }
2113 
2114 /*
2115  * log_2pc_recovery_abort_decision -
2116  *
2117  * return: nothing
2118  *
2119  * tdes(in/out): State structure of transaction of the log record
2120  *
2121  * Note:
2122  */
2123 static void
2125 {
2126  TRAN_STATE state;
2127 
2128  /*
2129  * An abort decision has already been taken and the system crash
2130  * during the local abort. Retry it
2131  */
2132 
2133  /*
2134  * The transaction has been declared as 2PC abort. We can execute
2135  * the LOCAL ABORT AND THE REMOTE ABORTS IN PARALLEL, however our
2136  * communication subsystem does not support asynchronous communication
2137  * types. The abort of the participants is done after the local
2138  * abort is completed.
2139  */
2140 
2141  /* Save the state.. so it can be reverted to the 2pc state .. */
2142  state = tdes->state;
2143 
2144  /* 2PC protocol does not support RETAIN LOCK */
2145  (void) log_abort_local (thread_p, tdes, false);
2146 
2147  if (tdes->state == TRAN_UNACTIVE_ABORTED)
2148  {
2149  tdes->state = state; /* Revert to 2PC state... */
2150  }
2151 
2152  /* Try to reconnect to participants that have not sent ACK. yet */
2153 
2154  /*
2155  * If the following function fails, the transaction will be dangling and we
2156  * need to retry sending the decision at another point.
2157  * We have already decided and log the decision in the log file.
2158  */
2159  (void) log_2pc_send_abort_decision (tdes->gtrid, tdes->coord->num_particps, tdes->coord->ack_received,
2160  tdes->coord->block_particps_ids, true);
2161  /* Check if all the acknowledgements have been received */
2162  (void) log_complete_for_2pc (thread_p, tdes, LOG_ABORT, LOG_DONT_NEED_NEWTRID);
2163 }
2164 
2165 /*
2166  * log_2pc_recovery_commit_decision -
2167  *
2168  * return: nothing
2169  *
2170  * tdes(in/out): State structure of transaction of the log record
2171  *
2172  * Note:
2173  */
2174 static void
2176 {
2177  TRAN_STATE state;
2178 
2179 
2180  /* Save the state.. so it can be reverted to the 2pc state .. */
2181  state = tdes->state;
2182 
2183  /* First perform local commit; 2PC protocol does not support RETAIN LOCK */
2184  (void) log_commit_local (thread_p, tdes, false, false);
2185  tdes->state = state; /* Revert to 2PC state... */
2186 
2187  /*
2188  * If the following function fails, the transaction will be dangling and we
2189  * need to retry sending the decision at another point.
2190  * We have already decided and log the decision in the log file.
2191  */
2192 
2194  tdes->coord->block_particps_ids);
2195  /* Check if all the acknowledgments have been received */
2196  (void) log_complete_for_2pc (thread_p, tdes, LOG_COMMIT, LOG_DONT_NEED_NEWTRID);
2197 }
2198 
2199 /*
2200  * log_2pc_recovery_committed_informing_participants -
2201  *
2202  * return: nothing
2203  *
2204  * tdes(in/out): State structure of transaction of the log record
2205  *
2206  * Note:
2207  */
2208 static void
2210 {
2211  /*
2212  * Broadcast the commit to the participants that has not sent an
2213  * acknowledgement yet.
2214  *
2215  * If the following function fails, the transaction will be
2216  * dangling and we need to retry sending the decision at another
2217  * point.
2218  * We have already decided and log the decision in the log file.
2219  */
2221  tdes->coord->block_particps_ids);
2222  (void) log_complete_for_2pc (thread_p, tdes, LOG_COMMIT, LOG_DONT_NEED_NEWTRID);
2223 }
2224 
2225 /*
2226  * log_2pc_recovery_aborted_informing_participants -
2227  *
2228  * return: nothing
2229  *
2230  * tdes(in/out): State structure of transaction of the log record
2231  *
2232  * Note:
2233  */
2234 static void
2236 {
2237  /*
2238  * Broadcast the abort to the participants that has not sent an
2239  * acknowledgement yet.
2240  *
2241  * If the following function fails, the transaction will be
2242  * dangling and we need to retry sending the decision at another
2243  * point.
2244  * We have already decided and log the decision in the log file.
2245  */
2246 
2247  (void) log_2pc_send_abort_decision (tdes->gtrid, tdes->coord->num_particps, tdes->coord->ack_received,
2248  tdes->coord->block_particps_ids, true);
2249  (void) log_complete_for_2pc (thread_p, tdes, LOG_ABORT, LOG_DONT_NEED_NEWTRID);
2250 }
2251 
2252 /*
2253  * log_2pc_recovery - TRY TO FINISH TRANSACTIONS THAT WERE IN THE 2PC PROTOCOL
2254  * AT THE TIME OF CRASH
2255  *
2256  * return: nothing
2257  *
2258  * NOTE:This function tries to finish up the transactions that were
2259  * in the two phase commit protocol at the time of the crash.
2260  */
2261 void
2263 {
2264  LOG_TDES *tdes; /* Transaction descriptor */
2265  int i;
2266 
2267  /*
2268  * Try to finish distributed transaction that are in the uncertain phase
2269  * of the two phase commit
2270  */
2271 
2272  for (i = 0; i < log_Gl.trantable.num_total_indices; i++)
2273  {
2274  tdes = LOG_FIND_TDES (i);
2275 
2276  if (tdes == NULL || tdes->trid == NULL_TRANID || !LOG_ISTRAN_2PC (tdes))
2277  {
2278  continue;
2279  }
2280 
2281  LOG_SET_CURRENT_TRAN_INDEX (thread_p, i);
2282 
2283  switch (tdes->state)
2284  {
2287  break;
2288 
2290  log_2pc_recovery_abort_decision (thread_p, tdes);
2291  break;
2292 
2294  log_2pc_recovery_commit_decision (thread_p, tdes);
2295  break;
2296 
2299  /*
2300  * All the local postpone actions had been completed; there are
2301  * not any client postpone actions. Thus, we can inform the
2302  * participants at this time.
2303  */
2304 
2306  /*
2307  * Let it fall thru the
2308  * TRAN_UNACTIVE_COMMITTED_INFORMING_PARTICIPANTS case
2309  */
2310 
2311  /* FALLTHRU */
2312 
2315  break;
2316 
2319  break;
2320 
2321  case TRAN_RECOVERY:
2322  case TRAN_ACTIVE:
2325  case TRAN_UNACTIVE_ABORTED:
2328  case TRAN_UNACTIVE_UNKNOWN:
2329  break;
2330  }
2331  }
2332 }
2333 
2334 #if defined (ENABLE_UNUSED_FUNCTION)
2335 /*
2336  * log_is_tran_in_2pc - IS TRANSACTION IN THE MIDDLE OF 2PC ?
2337  *
2338  * return:
2339  *
2340  * NOTE: This function finds if the transaction indicated by tran_index
2341  * is in prepare to commit state (i.e., it is waiting for either
2342  * commit or abort from its coordiantor).
2343  */
2344 bool
2345 log_is_tran_in_2pc (THREAD_ENTRY * thread_p)
2346 {
2347  LOG_TDES *tdes; /* Transaction descriptor */
2348  int tran_index;
2349 
2350  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
2351  tdes = LOG_FIND_TDES (tran_index);
2352  if (tdes == NULL)
2353  {
2355  return false;
2356  }
2357 
2358  return (LOG_ISTRAN_2PC (tdes));
2359 }
2360 #endif
2361 
2362 /*
2363  * log_2pc_is_tran_distributed - IS THIS A COORDINATOR OF A DISTRIBUTED TRANSACTION
2364  *
2365  * return:
2366  *
2367  * tdes(in): Transaction descriptor
2368  *
2369  * NOTE:Is this the coordinator of a distributed transaction ? If it
2370  * is, coordinator information is initialized by this function.
2371  */
2372 bool
2374 {
2375  int num_particps = 0; /* Number of participating sites */
2376  int particp_id_length; /* Length of a particp_id */
2377  void *block_particps_ids; /* A block of participant identifiers */
2378 
2379  if (tdes->coord != NULL)
2380  {
2381  return true;
2382  }
2383 
2384  num_particps = log_2pc_get_num_participants (&particp_id_length, &block_particps_ids);
2385  if (num_particps > 0)
2386  {
2387  /* This is a distributed transaction and our site is the coordinator */
2388 
2389  /* If the coordinator info has not been recorded in the tdes, do it now */
2390  (void) log_2pc_alloc_coord_info (tdes, num_particps, particp_id_length, block_particps_ids);
2391  }
2392 
2393  return (tdes->coord != NULL);
2394 }
2395 
2396 /*
2397  * log_2pc_clear_and_is_tran_distributed - FIND IF TRANSACTION IS DISTRIBUTED AFTER
2398  * CLEARING OLD COORDINATOR INFORMATION.
2399  *
2400  * return:
2401  *
2402  * tdes(in): Transaction descriptor
2403  *
2404  * NOTE: Clear coordinator information about participants. Then, check
2405  * if the transaction is distributed..and cache any related
2406  * information.
2407  * This function is used during commit/abort time to make sure
2408  * we have all participants. This is needed since CUBRID does
2409  * not inform me of new participants.
2410  */
2411 bool
2413 {
2414  log_2pc_free_coord_info (tdes);
2415  return log_2pc_is_tran_distributed (tdes);
2416 }
#define LOG_READ_ADD_ALIGN(thread_p, add, lsa, log_pgptr)
Definition: log_impl.h:141
unsigned int num_object_locks
Definition: log_record.hpp:381
void log_2pc_recovery_analysis_info(THREAD_ENTRY *thread_p, log_tdes *tdes, LOG_LSA *upto_chain_lsa)
Definition: log_2pc.c:1988
int tran_index
Definition: log_impl.h:465
bool(* send_commit)(int gtrid, int num_particps, int *particp_indices, void *block_particps_ids)
Definition: log_2pc.c:70
#define NO_ERROR
Definition: error_code.h:46
TRAN_STATE log_commit_local(THREAD_ENTRY *thread_p, LOG_TDES *tdes, bool retain_lock, bool is_local_tran)
Definition: log_manager.c:4883
TRANTABLE trantable
Definition: log_impl.h:650
void log_2pc_dump_acqobj_locks(FILE *fp, int length, void *data)
Definition: log_2pc.c:1450
int num_total_indices
Definition: log_impl.h:581
TRAN_STATE log_abort(THREAD_ENTRY *thread_p, int tran_index)
Definition: log_manager.c:5185
char user_name[DB_MAX_USER_LENGTH+1]
Definition: log_record.hpp:390
void logpb_fatal_error(THREAD_ENTRY *thread_p, bool logexit, const char *file_name, const int lineno, const char *fmt,...)
int TRANID
int info_length
Definition: log_2pc.h:59
void(* dump_participants)(FILE *fp, int block_length, void *block_particps_id)
Definition: log_2pc.c:68
static LOG_TDES * log_2pc_find_tran_descriptor(int gtrid)
Definition: log_2pc.c:996
void LSA_COPY(log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:139
void set_system_internal_with_user(const char *db_user)
#define ER_LOG_PAGE_CORRUPTED
Definition: error_code.h:140
#define LOG_ISTRAN_2PC_IN_SECOND_PHASE(tdes)
Definition: log_impl.h:204
LOG_2PC_COORDINATOR * coord
Definition: log_impl.h:489
int logpb_fetch_page(THREAD_ENTRY *thread_p, const LOG_LSA *req_lsa, LOG_CS_ACCESS_MODE access_mode, LOG_PAGE *log_pgptr)
#define ER_FAILED
Definition: error_code.h:47
#define ER_LOG_CANNOT_SET_GTRINFO
Definition: error_code.h:1078
const int LOG_SYSTEM_TRAN_INDEX
LOG_GLOBAL log_Gl
TRAN_STATE log_2pc_prepare(THREAD_ENTRY *thread_p)
Definition: log_2pc.c:921
#define ER_LOG_2PC_UNKNOWN_GTID
Definition: error_code.h:166
#define NULL_TRANID
int lock_reacquire_crash_locks(THREAD_ENTRY *thread_p, LK_ACQUIRED_LOCKS *acqlocks, int tran_index)
#define LOG_GET_LOG_RECORD_HEADER(log_page_p, lsa)
Definition: log_record.hpp:406
LOG_LSA prev_tranlsa
Definition: log_record.hpp:144
int(* send_prepare)(int gtrid, int num_particps, void *block_particps_ids)
Definition: log_2pc.c:69
static void log_2pc_recovery_prepare(THREAD_ENTRY *thread_p, LOG_TDES *tdes, LOG_LSA *log_lsa, LOG_PAGE *log_page_p)
Definition: log_2pc.c:1641
char user_name[DB_MAX_USER_LENGTH+1]
Definition: log_record.hpp:378
#define ER_LOG_2PC_CANNOT_START
Definition: error_code.h:1076
const int LOG_2PC_NULL_GTRID
Definition: log_2pc.h:40
void lock_dump_acquired(FILE *fp, LK_ACQUIRED_LOCKS *acqlocks)
LOG_TDES * LOG_FIND_TDES(int tran_index)
Definition: log_impl.h:1095
static void log_2pc_recovery_abort_decision(THREAD_ENTRY *thread_p, LOG_TDES *tdes)
Definition: log_2pc.c:2124
#define ER_LOG_2PC_CANNOT_ATTACH
Definition: error_code.h:167
bool log_2pc_clear_and_is_tran_distributed(log_tdes *tdes)
Definition: log_2pc.c:2412
int(* lookup_participant)(void *particp_id, int num_particps, void *block_particps_ids)
Definition: log_2pc.c:66
LOG_PRIOR_NODE * prior_lsa_alloc_and_copy_data(THREAD_ENTRY *thread_p, LOG_RECTYPE rec_type, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, int ulength, const char *udata, int rlength, const char *rdata)
Definition: log_append.cpp:273
bool log_2pc_send_prepare(int gtrid, int num_particps, void *block_particps_ids)
Definition: log_2pc.c:214
void log_2pc_dump_gtrinfo(FILE *fp, int length, void *data)
Definition: log_2pc.c:1435
const char * log_state_string(TRAN_STATE state)
Definition: log_comm.c:125
#define bool
Definition: dbi_compat.h:31
#define PTR_ALIGN(addr, boundary)
Definition: memory_alloc.h:77
void * block_particps_ids
Definition: log_2pc.h:68
int log_2pc_attach_global_tran(THREAD_ENTRY *thread_p, int gtrid)
Definition: log_2pc.c:1080
#define er_log_debug(...)
static void log_2pc_append_start(THREAD_ENTRY *thread_p, LOG_TDES *tdes)
Definition: log_2pc.c:1472
struct lk_acqobj_lock LK_ACQOBJ_LOCK
Definition: lock_manager.h:103
#define MAX_ALIGNMENT
Definition: memory_alloc.h:70
static bool log_2pc_check_duplicate_global_tran_id(int gtrid)
Definition: log_2pc.c:446
static int * log_2pc_expand_ack_list(THREAD_ENTRY *thread_p, int *ack_list, int *ack_count, int *size_ack_list)
Definition: log_2pc.c:1776
const bool LOG_2PC_OBTAIN_LOCKS
Definition: log_2pc.h:41
void THREAD_ENTRY
#define TR_TABLE_CS_ENTER(thread_p)
Definition: log_impl.h:88
static int log_2pc_commit_first_phase(THREAD_ENTRY *thread_p, LOG_TDES *tdes, LOG_2PC_EXECUTE execute_2pc_type, bool *decision)
Definition: log_2pc.c:476
void log_2pc_free_coord_info(log_tdes *tdes)
Definition: log_2pc.c:1611
LOG_RECTYPE type
Definition: log_record.hpp:148
LOG_LSA prior_lsa_next_record(THREAD_ENTRY *thread_p, LOG_PRIOR_NODE *node, log_tdes *tdes)
int log_2pc_set_global_tran_info(THREAD_ENTRY *thread_p, int gtrid, void *info, int size)
Definition: log_2pc.c:749
char * data_header
Definition: log_append.hpp:99
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
char * log_2pc_sprintf_particp(void *particp_id)
Definition: log_2pc.c:162
TRAN_STATE log_2pc_commit(THREAD_ENTRY *thread_p, log_tdes *tdes, LOG_2PC_EXECUTE execute_2pc_type, bool *decision)
Definition: log_2pc.c:676
#define ER_LOG_2PC_NON_UNIQUE_GTID
Definition: error_code.h:165
#define ER_LOG_2PC_NOT_STARTED
Definition: error_code.h:1077
int gtrid
Definition: log_impl.h:482
TRAN_STATE log_complete_for_2pc(THREAD_ENTRY *thread_p, LOG_TDES *tdes, LOG_RECTYPE iscommitted, LOG_GETNEWTRID get_newtrid)
Definition: log_manager.c:5474
#define assert(x)
#define LOG_ISTRAN_ACTIVE(tdes)
Definition: log_impl.h:182
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
static TRAN_STATE log_2pc_commit_second_phase(THREAD_ENTRY *thread_p, LOG_TDES *tdes, bool *decision)
Definition: log_2pc.c:549
char area[1]
Definition: log_storage.hpp:85
enum log_rectype LOG_RECTYPE
Definition: log_record.hpp:138
bool(* send_abort)(int gtrid, int num_particps, int *particp_indices, void *block_particps_ids, int collect)
Definition: log_2pc.c:71
void log_2pc_read_prepare(THREAD_ENTRY *thread_p, int acquire_locks, log_tdes *tdes, LOG_LSA *log_lsa, LOG_PAGE *log_page_p)
Definition: log_2pc.c:1349
int log_2pc_start(THREAD_ENTRY *thread_p)
Definition: log_2pc.c:877
int num_prepared_loose_end_indices
Definition: log_impl.h:586
std::int64_t pageid
Definition: log_lsa.hpp:36
static void log_2pc_recovery_recv_ack(THREAD_ENTRY *thread_p, LOG_LSA *log_lsa, LOG_PAGE *log_page_p, int *ack_list, int *ack_count)
Definition: log_2pc.c:1832
#define NULL
Definition: freelistheap.h:34
bool log_2pc_send_commit_decision(int gtrid, int num_particps, int *particps_indices, void *block_particps_ids)
Definition: log_2pc.c:251
bool LSA_ISNULL(const log_lsa *lsa_ptr)
Definition: log_lsa.hpp:153
void log_2pc_dump_participants(FILE *fp, int block_length, void *block_particps_ids)
Definition: log_2pc.c:184
static int log_2pc_make_global_tran_id(TRANID tranid)
Definition: log_2pc.c:362
int * ack_received
Definition: log_2pc.h:69
bool log_2pc_send_abort_decision(int gtrid, int num_particps, int *particps_indices, void *block_particps_ids, bool collect)
Definition: log_2pc.c:295
static void log_2pc_recovery_aborted_informing_participants(THREAD_ENTRY *thread_p, LOG_TDES *tdes)
Definition: log_2pc.c:2235
CLIENTIDS client
Definition: log_impl.h:484
#define LOG_SET_CURRENT_TRAN_INDEX(thrd, index)
Definition: log_impl.h:178
int count(int &result, const cub_regex_object &reg, const std::string &src, const int position, const INTL_CODESET codeset)
#define ER_LOG_UNKNOWN_TRANINDEX
Definition: error_code.h:913
log_tdes * log_2pc_alloc_coord_info(log_tdes *tdes, int num_particps, int particp_id_length, void *block_particps_ids)
Definition: log_2pc.c:1581
LK_ACQOBJ_LOCK * obj
Definition: lock_manager.h:114
void log_2pc_recovery(THREAD_ENTRY *thread_p)
Definition: log_2pc.c:2262
int(* get_participants)(int *particp_id_length, void **block_particps_ids)
Definition: log_2pc.c:65
void * info_data
Definition: log_2pc.h:60
#define LOG_ISTRAN_2PC_PREPARE(tdes)
Definition: log_impl.h:217
#define NULL_TRAN_INDEX
unsigned int css_gethostid(void)
Definition: tcp.c:1209
static void error(const char *msg)
Definition: gencat.c:331
void logtb_free_tran_index(THREAD_ENTRY *thread_p, int tran_index)
#define LOG_FIND_THREAD_TRAN_INDEX(thrd)
Definition: perf_monitor.h:158
#define LOG_READ_ALIGN(thread_p, lsa, log_pgptr)
Definition: log_impl.h:122
#define ARG_FILE_LINE
Definition: error_manager.h:44
LOG_TOPOPS_STACK topops
Definition: log_impl.h:486
int wait_msecs
Definition: log_impl.h:471
static void log_2pc_recovery_collecting_participant_votes(THREAD_ENTRY *thread_p, LOG_TDES *tdes)
Definition: log_2pc.c:2102
const char * get_db_user() const
bool isloose_end
Definition: log_impl.h:468
#define free_and_init(ptr)
Definition: memory_alloc.h:147
void LSA_SET_NULL(log_lsa *lsa_ptr)
Definition: log_lsa.hpp:146
TRANID trid
Definition: log_impl.h:466
void logpb_flush_pages(THREAD_ENTRY *thread_p, LOG_LSA *flush_lsa)
void logpb_copy_from_log(THREAD_ENTRY *thread_p, char *area, int length, LOG_LSA *log_lsa, LOG_PAGE *log_pgptr)
enum log_2pc_execute LOG_2PC_EXECUTE
Definition: log_2pc.h:54
char *(* sprintf_participant)(void *particp_id)
Definition: log_2pc.c:67
static void log_2pc_recovery_committed_informing_participants(THREAD_ENTRY *thread_p, LOG_TDES *tdes)
Definition: log_2pc.c:2209
unsigned int nobj_locks
Definition: lock_manager.h:115
int log_2pc_recovery_prepared(THREAD_ENTRY *thread_p, int gtrids[], int size)
Definition: log_2pc.c:959
void log_sysop_attach_to_outer(THREAD_ENTRY *thread_p)
Definition: log_manager.c:4076
static void log_2pc_recovery_commit_decision(THREAD_ENTRY *thread_p, LOG_TDES *tdes)
Definition: log_2pc.c:2175
static int log_2pc_recovery_start(THREAD_ENTRY *thread_p, LOG_TDES *tdes, LOG_LSA *log_lsa, LOG_PAGE *log_page_p, int *ack_list, int *ack_count)
Definition: log_2pc.c:1678
TRAN_STATE log_abort_local(THREAD_ENTRY *thread_p, LOG_TDES *tdes, bool is_local_tran)
Definition: log_manager.c:5001
LOG_2PC_GTRINFO gtrinfo
Definition: log_impl.h:488
int i
Definition: dynamic_load.c:954
#define LOG_ISTRAN_2PC(tdes)
Definition: log_impl.h:212
TRAN_ISOLATION isolation
Definition: log_impl.h:470
TRAN_STATE state
Definition: log_impl.h:469
TRAN_STATE
Definition: log_comm.h:36
#define IO_MAX_PAGE_SIZE
static int log_2pc_get_num_participants(int *partid_len, void **block_particps_ids)
Definition: log_2pc.c:120
static int log_2pc_recovery_analysis_record(THREAD_ENTRY *thread_p, LOG_RECTYPE record_type, LOG_TDES *tdes, LOG_LSA *log_lsa, LOG_PAGE *log_page_p, int **ack_list, int *ack_count, int *size_ack_list, bool *search_2pc_prepare, bool *search_2pc_start)
Definition: log_2pc.c:1863
TRAN_STATE log_2pc_prepare_global_tran(THREAD_ENTRY *thread_p, int gtrid)
Definition: log_2pc.c:1162
unsigned int num_page_locks
Definition: log_record.hpp:383
bool log_2pc_is_tran_distributed(log_tdes *tdes)
Definition: log_2pc.c:2373
#define TR_TABLE_CS_EXIT(thread_p)
Definition: log_impl.h:90
#define DB_MAX_USER_LENGTH
Definition: dbtype_def.h:498
static void log_2pc_append_decision(THREAD_ENTRY *thread_p, LOG_TDES *tdes, LOG_RECTYPE decsion)
Definition: log_2pc.c:1529
const bool LOG_2PC_DONT_OBTAIN_LOCKS
Definition: log_2pc.h:42
std::int64_t offset
Definition: log_lsa.hpp:37
void lock_unlock_all_shared_get_all_exclusive(THREAD_ENTRY *thread_p, LK_ACQUIRED_LOCKS *acqlocks)
int log_2pc_get_global_tran_info(THREAD_ENTRY *thread_p, int gtrid, void *buffer, int size)
Definition: log_2pc.c:816
static int log_2pc_attach_client(THREAD_ENTRY *thread_p, LOG_TDES *tdes, LOG_TDES *client_tdes)
Definition: log_2pc.c:1028
#define LOG_READ_ADVANCE_WHEN_DOESNT_FIT(thread_p, length, lsa, log_pgptr)
Definition: log_impl.h:149
struct log_2pc_global_data log_2pc_Userfun
Definition: log_2pc.c:73