CUBRID Engine  latest
log_manager.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_manager.c -
21  */
22 
23 #ident "$Id$"
24 
25 #include "config.h"
26 
27 #include <stdio.h>
28 #include <string.h>
29 #include <stddef.h>
30 #include <stdlib.h>
31 #include <time.h>
32 #if defined(SOLARIS)
33 #include <netdb.h>
34 #endif /* SOLARIS */
35 #include <sys/stat.h>
36 #include <assert.h>
37 #if defined(WINDOWS)
38 #include <io.h>
39 #endif /* WINDOWS */
40 
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 
45 #include <cstdint>
46 
47 #include "log_manager.h"
48 
49 #include "btree.h"
50 #include "elo.h"
51 #include "recovery.h"
52 #include "replication.h"
53 #include "xserver_interface.h"
54 #include "page_buffer.h"
55 #include "porting_inline.hpp"
56 #include "query_manager.h"
57 #include "message_catalog.h"
58 #include "msgcat_set_log.hpp"
59 #include "environment_variable.h"
60 #if defined(SERVER_MODE)
61 #include "server_support.h"
62 #endif /* SERVER_MODE */
63 #include "log_append.hpp"
64 #include "log_archives.hpp"
65 #include "log_compress.h"
66 #include "log_record.hpp"
67 #include "log_system_tran.hpp"
68 #include "log_volids.hpp"
69 #include "log_writer.h"
70 #include "partition_sr.h"
71 #include "filter_pred_cache.h"
72 #include "heap_file.h"
73 #include "slotted_page.h"
74 #include "object_primitive.h"
75 #include "object_representation.h"
76 #include "tz_support.h"
77 #include "db_date.h"
78 #include "fault_injection.h"
79 #if defined (SA_MODE)
80 #include "connection_support.h"
81 #endif /* defined (SA_MODE) */
82 #include "db_value_printer.hpp"
83 #include "mem_block.hpp"
84 #include "string_buffer.hpp"
85 #include "boot_sr.h"
86 #include "thread_daemon.hpp"
87 #include "thread_entry.hpp"
88 #include "thread_entry_task.hpp"
89 #include "thread_manager.hpp"
91 #include "vacuum.h"
92 #include "xasl_cache.h"
93 
94 #include "dbtype.h"
95 
96 #if !defined(SERVER_MODE)
97 
98 #define pthread_mutex_init(a, b)
99 #define pthread_mutex_destroy(a)
100 #define pthread_mutex_lock(a) 0
101 #define pthread_mutex_unlock(a)
102 static int rv;
103 #endif /* !SERVER_MODE */
104 
105 /*
106  *
107  * IS TIME TO EXECUTE A CHECKPOINT ?
108  *
109  */
110 
111 /* A checkpoint is taken after a set of log pages has been used */
112 
113 #define LOG_ISCHECKPOINT_TIME() \
114  (log_Gl.rcv_phase == LOG_RESTARTED \
115  && log_Gl.run_nxchkpt_atpageid != NULL_PAGEID \
116  && log_Gl.hdr.append_lsa.pageid >= log_Gl.run_nxchkpt_atpageid)
117 
118 #if defined(SERVER_MODE)
119 #define LOG_FLUSH_LOGGING_HAS_BEEN_SKIPPED(thread_p) \
120  do { \
121  if (log_Gl.hdr.has_logging_been_skipped != true) { \
122  /* Write in the log header that logging has been skipped */ \
123  LOG_CS_ENTER((thread_p)); \
124  if (log_Gl.hdr.has_logging_been_skipped != true) { \
125  log_Gl.hdr.has_logging_been_skipped = true; \
126  logpb_flush_header((thread_p)); \
127  } \
128  LOG_CS_EXIT(thread_p); \
129  } \
130  } while (0)
131 #else /* SERVER_MODE */
132 #define LOG_FLUSH_LOGGING_HAS_BEEN_SKIPPED(thread_p) \
133  do { \
134  if (log_Gl.hdr.has_logging_been_skipped != true) { \
135  /* Write in the log header that logging has been skipped */ \
136  log_Gl.hdr.has_logging_been_skipped = true; \
137  logpb_flush_header((thread_p)); \
138  } \
139  } while (0)
140 #endif /* SERVER_MODE */
141 
142  /*
143  * Some log record rcvindex types should never be skipped.
144  * In the case of LINK_PERM_VOLEXT, the link of a permanent temp
145  * volume must be logged to support media failures.
146  * See also canskip_undo. If there are others, add them here.
147  */
148 #define LOG_ISUNSAFE_TO_SKIP_RCVINDEX(RCVI) \
149  ((RCVI) == RVDK_LINK_PERM_VOLEXT)
150 
151 #define LOG_NEED_TO_SET_LSA(RCVI, PGPTR) \
152  (((RCVI) != RVBT_MVCC_INCREMENTS_UPD) \
153  && ((RCVI) != RVBT_LOG_GLOBAL_UNIQUE_STATS_COMMIT) \
154  && ((RCVI) != RVBT_REMOVE_UNIQUE_STATS) \
155  && ((RCVI) != RVLOC_CLASSNAME_DUMMY) \
156  && ((RCVI) != RVDK_LINK_PERM_VOLEXT || !pgbuf_is_lsa_temporary(PGPTR)))
157 
158 
159 /* struct for active log header scan */
162 {
164 };
165 
166 /* struct for archive log header scan */
169 {
171 };
172 
173 /*
174  * The maximum number of times to try to undo a log record.
175  * It is only used by the log_undo_rec_restartable() function.
176  */
177 static const int LOG_REC_UNDO_MAX_ATTEMPTS = 3;
178 
179 /* true: Skip logging, false: Don't skip logging */
180 static bool log_No_logging = false;
181 
182 #define LOG_TDES_LAST_SYSOP(tdes) (&(tdes)->topops.stack[(tdes)->topops.last])
183 #define LOG_TDES_LAST_SYSOP_PARENT_LSA(tdes) (&LOG_TDES_LAST_SYSOP(tdes)->lastparent_lsa)
184 #define LOG_TDES_LAST_SYSOP_POSP_LSA(tdes) (&LOG_TDES_LAST_SYSOP(tdes)->posp_lsa)
185 
186 #if defined (SERVER_MODE)
187 /* Current time in milliseconds */
188 // *INDENT-OFF*
189 std::atomic<std::int64_t> log_Clock_msec = {0};
190 // *INDENT-ON*
191 #endif /* SERVER_MODE */
192 
193 static bool log_verify_dbcreation (THREAD_ENTRY * thread_p, VOLID volid, const INT64 * log_dbcreation);
194 static int log_create_internal (THREAD_ENTRY * thread_p, const char *db_fullname, const char *logpath,
195  const char *prefix_logname, DKNPAGES npages, INT64 * db_creation);
196 static int log_initialize_internal (THREAD_ENTRY * thread_p, const char *db_fullname, const char *logpath,
197  const char *prefix_logname, bool ismedia_crash, BO_RESTART_ARG * r_args,
198  bool init_emergency);
199 #if defined(SERVER_MODE)
200 static int log_abort_by_tdes (THREAD_ENTRY * thread_p, LOG_TDES * tdes);
201 #endif /* SERVER_MODE */
202 static LOG_LSA *log_get_savepoint_lsa (THREAD_ENTRY * thread_p, const char *savept_name, LOG_TDES * tdes,
203  LOG_LSA * savept_lsa);
204 static bool log_can_skip_undo_logging (THREAD_ENTRY * thread_p, LOG_RCVINDEX rcvindex, const LOG_TDES * tdes,
205  LOG_DATA_ADDR * addr);
206 static bool log_can_skip_redo_logging (LOG_RCVINDEX rcvindex, const LOG_TDES * ignore_tdes, LOG_DATA_ADDR * addr);
207 static void log_append_commit_postpone (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_LSA * start_postpone_lsa);
208 static void log_append_sysop_start_postpone (THREAD_ENTRY * thread_p, LOG_TDES * tdes,
209  LOG_REC_SYSOP_START_POSTPONE * sysop_start_postpone, int data_size,
210  const char *data);
211 static void log_append_sysop_end (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_REC_SYSOP_END * sysop_end,
212  int data_size, const char *data);
213 static void log_append_repl_info_internal (THREAD_ENTRY * thread_p, LOG_TDES * tdes, bool is_commit, int with_lock);
214 static void log_append_repl_info_with_lock (THREAD_ENTRY * thread_p, LOG_TDES * tdes, bool is_commit);
215 static void log_append_repl_info_and_commit_log (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_LSA * commit_lsa);
216 static void log_append_donetime_internal (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_LSA * eot_lsa,
217  LOG_RECTYPE iscommitted, enum LOG_PRIOR_LSA_LOCK with_lock);
218 static void log_change_tran_as_completed (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_RECTYPE iscommitted,
219  LOG_LSA * lsa);
220 static void log_append_commit_log (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_LSA * commit_lsa);
221 static void log_append_commit_log_with_lock (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_LSA * commit_lsa);
222 static void log_append_abort_log (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_LSA * abort_lsa);
223 
224 static void log_dump_record_header_to_string (LOG_RECORD_HEADER * log, char *buf, size_t len);
225 static void log_ascii_dump (FILE * out_fp, int length, void *data);
226 static void log_hexa_dump (FILE * out_fp, int length, void *data);
227 static void log_dump_data (THREAD_ENTRY * thread_p, FILE * out_fp, int length, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
228  void (*dumpfun) (FILE * fp, int, void *), LOG_ZIP * log_dump_ptr);
229 static void log_dump_header (FILE * out_fp, LOG_HEADER * log_header_p);
230 static LOG_PAGE *log_dump_record_undoredo (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * lsa_p,
231  LOG_PAGE * log_page_p, LOG_ZIP * log_zip_p);
232 static LOG_PAGE *log_dump_record_undo (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * lsa_p, LOG_PAGE * log_page_p,
233  LOG_ZIP * log_zip_p);
234 static LOG_PAGE *log_dump_record_redo (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * lsa_p, LOG_PAGE * log_page_p,
235  LOG_ZIP * log_zip_p);
236 static LOG_PAGE *log_dump_record_mvcc_undoredo (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * lsa_p,
237  LOG_PAGE * log_page_p, LOG_ZIP * log_zip_p);
238 static LOG_PAGE *log_dump_record_mvcc_undo (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * lsa_p,
239  LOG_PAGE * log_page_p, LOG_ZIP * log_zip_p);
240 static LOG_PAGE *log_dump_record_mvcc_redo (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * lsa_p,
241  LOG_PAGE * log_page_p, LOG_ZIP * log_zip_p);
242 static LOG_PAGE *log_dump_record_postpone (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * lsa_p,
243  LOG_PAGE * log_page_p);
244 static LOG_PAGE *log_dump_record_dbout_redo (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * lsa_p,
245  LOG_PAGE * log_page_p);
246 static LOG_PAGE *log_dump_record_compensate (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * lsa_p,
247  LOG_PAGE * log_page_p);
248 static LOG_PAGE *log_dump_record_commit_postpone (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * lsa_p,
249  LOG_PAGE * log_page_p);
250 static LOG_PAGE *log_dump_record_transaction_finish (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * lsa_p,
251  LOG_PAGE * log_page_p);
252 static LOG_PAGE *log_dump_record_replication (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * lsa_p,
253  LOG_PAGE * log_page_p);
254 static LOG_PAGE *log_dump_record_sysop_start_postpone (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * lsa_p,
255  LOG_PAGE * log_page_p, LOG_ZIP * log_zip_p);
256 static LOG_PAGE *log_dump_record_sysop_end (THREAD_ENTRY * thread_p, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
257  LOG_ZIP * log_zip_p, FILE * out_fp);
259  LOG_LSA * log_lsa, LOG_PAGE * log_page_p, LOG_ZIP * log_zip_p,
260  FILE * out_fp);
261 static LOG_PAGE *log_dump_record_checkpoint (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * lsa_p,
262  LOG_PAGE * log_page_p);
263 static void log_dump_checkpoint_topops (FILE * out_fp, int length, void *data);
264 static LOG_PAGE *log_dump_record_save_point (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * lsa_p,
265  LOG_PAGE * log_page_p);
266 static LOG_PAGE *log_dump_record_2pc_prepare_commit (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * lsa_p,
267  LOG_PAGE * log_page_p);
268 static LOG_PAGE *log_dump_record_2pc_start (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * lsa_p,
269  LOG_PAGE * log_page_p);
270 static LOG_PAGE *log_dump_record_2pc_acknowledgement (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * lsa_p,
271  LOG_PAGE * log_page_p);
272 static LOG_PAGE *log_dump_record_ha_server_state (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * log_lsa,
273  LOG_PAGE * log_page_p);
274 static LOG_PAGE *log_dump_record (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_RECTYPE record_type, LOG_LSA * lsa_p,
275  LOG_PAGE * log_page_p, LOG_ZIP * log_zip_p);
276 static void log_rollback_record (THREAD_ENTRY * thread_p, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
277  LOG_RCVINDEX rcvindex, VPID * rcv_vpid, LOG_RCV * rcv, LOG_TDES * tdes,
278  LOG_ZIP * log_unzip_ptr);
279 static int log_undo_rec_restartable (THREAD_ENTRY * thread_p, LOG_RCVINDEX rcvindex, LOG_RCV * rcv);
280 static void log_rollback (THREAD_ENTRY * thread_p, LOG_TDES * tdes, const LOG_LSA * upto_lsa_ptr);
281 static int log_run_postpone_op (THREAD_ENTRY * thread_p, LOG_LSA * log_lsa, LOG_PAGE * log_pgptr);
282 static void log_find_end_log (THREAD_ENTRY * thread_p, LOG_LSA * end_lsa);
283 
284 static void log_cleanup_modified_class (const tx_transient_class_entry & t, bool & stop);
285 static void log_cleanup_modified_class_list (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_LSA * savept_lsa,
286  bool release, bool decache_classrepr);
287 
288 static void log_append_compensate_internal (THREAD_ENTRY * thread_p, LOG_RCVINDEX rcvindex, const VPID * vpid,
289  PGLENGTH offset, PAGE_PTR pgptr, int length, const void *data,
290  LOG_TDES * tdes, const LOG_LSA * undo_nxlsa);
291 
293 STATIC_INLINE void log_sysop_end_begin (THREAD_ENTRY * thread_p, int *tran_index_out, LOG_TDES ** tdes_out)
297 static void log_sysop_commit_internal (THREAD_ENTRY * thread_p, LOG_REC_SYSOP_END * log_record, int data_size,
298  const char *data, bool is_rv_finish_postpone);
299 STATIC_INLINE void log_sysop_get_tran_index_and_tdes (THREAD_ENTRY * thread_p, int *tran_index_out,
300  LOG_TDES ** tdes_out) __attribute__ ((ALWAYS_INLINE));
302 
303 static void log_tran_do_postpone (THREAD_ENTRY * thread_p, LOG_TDES * tdes);
304 static void log_sysop_do_postpone (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_REC_SYSOP_END * sysop_end,
305  int data_size, const char *data);
306 
307 static int logtb_tran_update_stats_online_index_rb (THREAD_ENTRY * thread_p, void *data, void *args);
308 
309 #if defined(SERVER_MODE)
310 // *INDENT-OFF*
311 static void log_abort_task_execute (cubthread::entry &thread_ref, LOG_TDES &tdes);
312 // *INDENT-ON*
313 #endif // SERVER_MODE
314 
315 #if defined(SERVER_MODE)
316 // *INDENT-OFF*
317 static cubthread::daemon *log_Clock_daemon = NULL;
318 static cubthread::daemon *log_Checkpoint_daemon = NULL;
319 static cubthread::daemon *log_Remove_log_archive_daemon = NULL;
320 static cubthread::daemon *log_Check_ha_delay_info_daemon = NULL;
321 
322 static cubthread::daemon *log_Flush_daemon = NULL;
323 static std::atomic_bool log_Flush_has_been_requested = {false};
324 // *INDENT-ON*
325 
326 static void log_daemons_init ();
327 static void log_daemons_destroy ();
328 
329 // used by log_Check_ha_delay_info_daemon
330 extern int catcls_get_apply_info_log_record_time (THREAD_ENTRY * thread_p, time_t * log_record_time);
331 #endif /* SERVER_MODE */
332 
333 /*
334  * log_rectype_string - RETURN TYPE OF LOG RECORD IN STRING FORMAT
335  *
336  * return:
337  *
338  * type(in): Type of log record
339  *
340  * NOTE: Return the type of the log record in string format
341  */
342 const char *
344 {
345  switch (type)
346  {
347  case LOG_UNDOREDO_DATA:
348  return "LOG_UNDOREDO_DATA";
349 
350  case LOG_DIFF_UNDOREDO_DATA: /* LOG DIFF undo and redo data */
351  return "LOG_DIFF_UNDOREDO_DATA";
352 
353  case LOG_UNDO_DATA:
354  return "LOG_UNDO_DATA";
355 
356  case LOG_REDO_DATA:
357  return "LOG_REDO_DATA";
358 
360  return "LOG_MVCC_UNDOREDO_DATA";
361 
363  return "LOG_MVCC_DIFF_UNDOREDO_DATA";
364 
365  case LOG_MVCC_UNDO_DATA:
366  return "LOG_MVCC_UNDO_DATA";
367 
368  case LOG_MVCC_REDO_DATA:
369  return "LOG_MVCC_REDO_DATA";
370 
372  return "LOG_DBEXTERN_REDO_DATA";
373 
375  return "LOG_DUMMY_HEAD_POSTPONE";
376 
377  case LOG_POSTPONE:
378  return "LOG_POSTPONE";
379 
380  case LOG_RUN_POSTPONE:
381  return "LOG_RUN_POSTPONE";
382 
383  case LOG_COMPENSATE:
384  return "LOG_COMPENSATE";
385 
386  case LOG_WILL_COMMIT:
387  return "LOG_WILL_COMMIT";
388 
390  return "LOG_COMMIT_WITH_POSTPONE";
391 
392  case LOG_COMMIT:
393  return "LOG_COMMIT";
394 
396  return "LOG_SYSOP_START_POSTPONE";
397 
398  case LOG_SYSOP_END:
399  return "LOG_SYSOP_END";
400 
401  case LOG_ABORT:
402  return "LOG_ABORT";
403 
404  case LOG_START_CHKPT:
405  return "LOG_START_CHKPT";
406 
407  case LOG_END_CHKPT:
408  return "LOG_END_CHKPT";
409 
410  case LOG_SAVEPOINT:
411  return "LOG_SAVEPOINT";
412 
413  case LOG_2PC_PREPARE:
414  return "LOG_2PC_PREPARE";
415 
416  case LOG_2PC_START:
417  return "LOG_2PC_START";
418 
420  return "LOG_2PC_COMMIT_DECISION";
421 
423  return "LOG_2PC_ABORT_DECISION";
424 
426  return "LOG_2PC_COMMIT_INFORM_PARTICPS";
427 
429  return "LOG_2PC_ABORT_INFORM_PARTICPS";
430 
431  case LOG_2PC_RECV_ACK:
432  return "LOG_2PC_RECV_ACK";
433 
435  return "LOG_DUMMY_CRASH_RECOVERY";
436 
437  case LOG_END_OF_LOG:
438  return "LOG_END_OF_LOG";
439 
441  return "LOG_REPLICATION_DATA";
443  return "LOG_REPLICATION_STATEMENT";
444 
446  return "LOG_SYSOP_ATOMIC_START";
447 
449  return "LOG_DUMMY_HA_SERVER_STATE";
451  return "LOG_DUMMY_OVF_RECORD";
452  case LOG_DUMMY_GENERIC:
453  return "LOG_DUMMY_GENERIC";
454 
457  break;
458 
459  default:
460  assert (false);
461  break;
462  }
463 
464  return "UNKNOWN_LOG_REC_TYPE";
465 
466 }
467 
468 /*
469  * log_is_in_crash_recovery - are we in crash recovery ?
470  *
471  * return:
472  *
473  * NOTE: Are we in crash recovery time ?
474  */
475 bool
477 {
478  if (LOG_ISRESTARTED ())
479  {
480  return false;
481  }
482  else
483  {
484  return true;
485  }
486 }
487 
488 /*
489  * log_is_in_crash_recovery_and_not_year_complets_redo - completes redo recovery?
490  *
491  * return:
492  *
493  */
494 bool
496 {
498  {
499  return true;
500  }
501  else
502  {
503  return false;
504  }
505 }
506 
507 /*
508  * log_get_restart_lsa - FIND RESTART LOG SEQUENCE ADDRESS
509  *
510  * return:
511  *
512  * NOTE: Find the restart log sequence address.
513  */
514 LOG_LSA *
516 {
517  if (LOG_ISRESTARTED ())
518  {
519  return &log_Gl.rcv_phase_lsa;
520  }
521  else
522  {
523  return &log_Gl.hdr.chkpt_lsa;
524  }
525 }
526 
527 /*
528  * log_get_crash_point_lsa - get last lsa address of the log before a crash
529  *
530  * return:
531  *
532  * NOTE: Find the log sequence address at the time of a crash. This
533  * function can only be called during the recovery phases after analysis
534  * and prior to RESTART.
535  */
536 LOG_LSA *
538 {
539 #if defined(CUBRID_DEBUG)
541  {
542  /* i.e. cannot be RESTARTED or ANALYSIS */
544  "log_find_crash_point_lsa: Warning, only expected to be called during recovery phases.");
545  }
546 #endif /* CUBRID_DEBUG */
547 
548  return (&log_Gl.rcv_phase_lsa);
549 }
550 
551 /*
552  * log_find_find_lsa -
553  *
554  * return:
555  *
556  * NOTE:
557  */
558 LOG_LSA *
560 {
561  return (&log_Gl.hdr.append_lsa);
562 }
563 
564 /*
565  * log_get_eof_lsa -
566  *
567  * return:
568  *
569  * NOTE:
570  */
571 LOG_LSA *
573 {
574  return (&log_Gl.hdr.eof_lsa);
575 }
576 
577 /*
578  * log_is_logged_since_restart - is log sequence address made after restart ?
579  *
580  * return:
581  *
582  * lsa_ptr(in): Log sequence address attached to page
583  *
584  * NOTE: Find if the log sequence address has been made after restart.
585  * This function is useful to detect bugs. For example, when a
586  * data page (actually a buffer)is freed, and the page is dirty,
587  * there should be a log record for some data of the page,
588  * otherwise, a potential error exists. It is clear that this
589  * function will not detect all kinds of errors, but it will help
590  * some.
591  */
592 bool
594 {
595  return (!LOG_ISRESTARTED () || LSA_LE (&log_Gl.rcv_phase_lsa, lsa_ptr));
596 }
597 
598 #if defined(SA_MODE)
599 /*
600  * log_get_final_restored_lsa -
601  *
602  * return:
603  *
604  * NOTE:
605  */
606 LOG_LSA *
608 {
609  return (&log_Gl.final_restored_lsa);
610 }
611 #endif /* SA_MODE */
612 
613 /*
614  * FUNCTION RELATED TO INITIALIZATION AND TERMINATION OF LOG MANAGER
615  */
616 
617 /*
618  * log_verify_dbcreation - verify database creation time
619  *
620  * return:
621  *
622  * volid(in): Volume identifier
623  * log_dbcreation(in): Database creation time according to the log.
624  *
625  * NOTE:Verify if database creation time according to the log matches
626  * the one according to the database volume. If they do not, it
627  * is likely that the log and data volume does not correspond to
628  * the same database.
629  */
630 static bool
631 log_verify_dbcreation (THREAD_ENTRY * thread_p, VOLID volid, const INT64 * log_dbcreation)
632 {
633  INT64 vol_dbcreation; /* Database creation time in volume */
634 
635  if (disk_get_creation_time (thread_p, volid, &vol_dbcreation) != NO_ERROR)
636  {
637  return false;
638  }
639 
640  if (difftime ((time_t) vol_dbcreation, (time_t) (*log_dbcreation)) == 0)
641  {
642  return true;
643  }
644  else
645  {
646  return false;
647  }
648 }
649 
650 /*
651  * log_get_db_start_parameters - Get start parameters
652  *
653  * return: nothing
654  *
655  * db_creation(out): Database creation time
656  * chkpt_lsa(out): Last checkpoint address
657  *
658  * NOTE: Get the start parameters: database creation time and the last
659  * checkpoint process.
660  * For safety reasons, the database creation time is included, in
661  * all database volumes and the log. This value allows verifying
662  * if a log and a data volume correspond to the same database.
663  * This function is used to obtain the database creation time and
664  * the last checkpoint address, so that they can be included in
665  * new defined volumes.
666  */
667 int
668 log_get_db_start_parameters (INT64 * db_creation, LOG_LSA * chkpt_lsa)
669 {
670 #if defined(SERVER_MODE)
671  int rv;
672 #endif /* SERVER_MODE */
673 
674  memcpy (db_creation, &log_Gl.hdr.db_creation, sizeof (*db_creation));
675  rv = pthread_mutex_lock (&log_Gl.chkpt_lsa_lock);
676  memcpy (chkpt_lsa, &log_Gl.hdr.chkpt_lsa, sizeof (*chkpt_lsa));
677  pthread_mutex_unlock (&log_Gl.chkpt_lsa_lock);
678 
679  return NO_ERROR;
680 }
681 
682 /*
683  * log_get_num_pages_for_creation - find default number of pages for the log
684  *
685  * return: number of pages
686  *
687  * db_npages(in): Estimated number of pages for database (for first volume of
688  * database) or -1
689  *
690  * NOTE: Find the default number of pages to use during the creation of
691  * the log.
692  * If a negative value is given, the database should have been
693  * already created. That is, we are recreating the log
694  */
695 int
697 {
698  int log_npages;
699  int vdes;
700 
701  log_npages = db_npages;
702  if (log_npages < 0)
703  {
704  /*
705  * Use the default that is the size of the database
706  * Don't use DK since the database may not be restarted at all.
707  */
709  if (vdes != NULL_VOLDES)
710  {
711  log_npages = fileio_get_number_of_volume_pages (vdes, IO_PAGESIZE);
712  }
713  }
714 
715  if (log_npages < 10)
716  {
717  log_npages = 10;
718  }
719 
720  return log_npages;
721 }
722 
723 /*
724  * log_create - create the active portion of the log
725  *
726  * return:
727  *
728  * db_fullname(in): Full name of the database
729  * logpath(in): Directory where the log volumes reside
730  * prefix_logname(in): Name of the log volumes. It is usually set the same as
731  * database name. For example, if the value is equal to
732  * "db", the names of the log volumes created are as
733  * follow:
734  * Active_log = db_logactive
735  * Archive_logs = db_logarchive.0
736  * db_logarchive.1
737  * .
738  * .
739  * .
740  * db_logarchive.n
741  * Log_information = db_loginfo
742  * Database Backup = db_backup
743  * npages(in): Size of active log in pages
744  *
745  * NOTE: Format/create the active log volume. The header of the volume
746  * is initialized.
747  */
748 int
749 log_create (THREAD_ENTRY * thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname,
750  DKNPAGES npages)
751 {
752  int error_code = NO_ERROR;
753  INT64 db_creation;
754 
755  db_creation = time (NULL);
756  if (db_creation == -1)
757  {
758  error_code = ER_FAILED;
759  return error_code;
760  }
761 
762  error_code = log_create_internal (thread_p, db_fullname, logpath, prefix_logname, npages, &db_creation);
763  if (error_code != NO_ERROR)
764  {
765  return error_code;
766  }
767 
768  return NO_ERROR;
769 }
770 
771 /*
772  * log_create_internal -
773  *
774  * return:
775  *
776  * db_fullname(in):
777  * logpath(in):
778  * prefix_logname(in):
779  * npages(in):
780  * db_creation(in):
781  *
782  * NOTE:
783  */
784 static int
785 log_create_internal (THREAD_ENTRY * thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname,
786  DKNPAGES npages, INT64 * db_creation)
787 {
788  LOG_PAGE *loghdr_pgptr; /* Pointer to log header */
789  const char *catmsg;
790  int error_code = NO_ERROR;
791  VOLID volid1, volid2;
792 
793  LOG_CS_ENTER (thread_p);
794 
795  /* Make sure that we are starting from a clean state */
796  if (log_Gl.trantable.area != NULL)
797  {
798  log_final (thread_p);
799  }
800 
801  /*
802  * Turn off creation bits for group and others
803  */
804 
805  (void) umask (S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
806 
807  /* Initialize the log buffer pool and the log names */
808  error_code = logpb_initialize_pool (thread_p);
809  if (error_code != NO_ERROR)
810  {
811  goto error;
812  }
813  error_code = logpb_initialize_log_names (thread_p, db_fullname, logpath, prefix_logname);
814  if (error_code != NO_ERROR)
815  {
816  goto error;
817  }
818 
819  logpb_decache_archive_info (thread_p);
820 
822 
823  /* Initialize the log header */
824  error_code = logpb_initialize_header (thread_p, &log_Gl.hdr, prefix_logname, npages, db_creation);
825  if (error_code != NO_ERROR)
826  {
827  goto error;
828  }
829 
830  loghdr_pgptr = logpb_create_header_page (thread_p);
831 
832  /*
833  * Format the volume and fetch the header page and the first append page
834  */
835  log_Gl.append.vdes =
836  fileio_format (thread_p, db_fullname, log_Name_active, LOG_DBLOG_ACTIVE_VOLID, npages,
837  prm_get_bool_value (PRM_ID_LOG_SWEEP_CLEAN), true, false, LOG_PAGESIZE, 0, false);
838  if (log_Gl.append.vdes == NULL_VOLDES || logpb_fetch_start_append_page (thread_p) != NO_ERROR || loghdr_pgptr == NULL)
839  {
840  goto error;
841  }
842 
844  /* copy log_Gl.append.prev_lsa to log_Gl.prior_info.prev_lsa */
846 
847  /*
848  * Flush the append page, so that the end of the log mark is written.
849  * Then, free the page, same for the header page.
850  */
852  logpb_flush_pages_direct (thread_p);
853 
855 
856  /* Flush the log header */
857 
858  memcpy (loghdr_pgptr->area, &log_Gl.hdr, sizeof (log_Gl.hdr));
859  logpb_set_dirty (thread_p, loghdr_pgptr);
860 
861 #if defined(CUBRID_DEBUG)
862  {
863  char temp_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT], *aligned_temp_pgbuf;
864  LOG_PAGE *temp_pgptr;
865 
866  aligned_temp_pgbuf = PTR_ALIGN (temp_pgbuf, MAX_ALIGNMENT);
867 
868  temp_pgptr = (LOG_PAGE *) aligned_temp_pgbuf;
869  memset (temp_pgptr, 0, LOG_PAGESIZE);
871  assert (memcmp ((LOG_HEADER *) temp_pgptr->area, &log_Gl.hdr, sizeof (log_Gl.hdr)) != 0);
872  }
873 #endif /* CUBRID_DEBUG */
874 
875  error_code = logpb_flush_page (thread_p, loghdr_pgptr);
876  if (error_code != NO_ERROR)
877  {
878  goto error;
879  }
880 #if defined(CUBRID_DEBUG)
881  {
882  char temp_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT], *aligned_temp_pgbuf;
883  LOG_PAGE *temp_pgptr;
884 
885  aligned_temp_pgbuf = PTR_ALIGN (temp_pgbuf, MAX_ALIGNMENT);
886 
887  temp_pgptr = (LOG_PAGE *) aligned_temp_pgbuf;
888  memset (temp_pgptr, 0, LOG_PAGESIZE);
890  assert (memcmp ((LOG_HEADER *) temp_pgptr->area, &log_Gl.hdr, sizeof (log_Gl.hdr)) == 0);
891  }
892 #endif /* CUBRID_DEBUG */
893 
894  /* logpb_flush_header(); */
895 
896  /*
897  * Free the append and header page and dismount the lg active volume
898  */
900 
901  fileio_dismount (thread_p, log_Gl.append.vdes);
902 
903  error_code = logpb_create_volume_info (NULL);
904  if (error_code != NO_ERROR)
905  {
906  goto error;
907  }
908 
909  /* Create the information file to append log info stuff to the DBA */
911 
913  if (catmsg == NULL)
914  {
915  catmsg = "ACTIVE: %s %d pages\n";
916  }
917  error_code = log_dump_log_info (log_Name_info, false, catmsg, log_Name_active, npages);
918  if (error_code == NO_ERROR || error_code == ER_LOG_MOUNT_FAIL)
919  {
921  if (volid1 == LOG_DBLOG_BKUPINFO_VOLID)
922  {
924  }
925 
926  if (volid1 != LOG_DBLOG_BKUPINFO_VOLID || volid2 != LOG_DBLOG_ACTIVE_VOLID)
927  {
928  goto error;
929  }
930  }
931 
932  logpb_finalize_pool (thread_p);
933  LOG_CS_EXIT (thread_p);
934 
935  return NO_ERROR;
936 
937 error:
938  logpb_finalize_pool (thread_p);
939  LOG_CS_EXIT (thread_p);
940 
941  return (error_code == NO_ERROR) ? ER_FAILED : error_code;
942 }
943 
944 /*
945  * log_set_no_logging - Force the system to do no logging.
946  *
947  * return: NO_ERROR or error code
948  *
949  */
950 int
952 {
953  int error_code = NO_ERROR;
954 
955 #if defined(SA_MODE)
956 
958  {
961  }
962  else
963  {
964  log_No_logging = true;
965  error_code = NO_ERROR;
966 #if !defined(NDEBUG)
968  {
969  fprintf (stdout, "**Running without logging**\n");
970  fflush (stdout);
971  }
972 #endif /* NDEBUG */
973  }
974 
975 #else /* SA_MODE */
977  error_code = ER_ONLY_IN_STANDALONE;
978 #endif /* SA_MODE */
979 
980  return error_code;
981 }
982 
983 /*
984  * log_initialize - Initialize the log manager
985  *
986  * return: nothing
987  *
988  * db_fullname(in): Full name of the database
989  * logpath(in): Directory where the log volumes reside
990  * prefix_logname(in): Name of the log volumes. It must be the same as the
991  * one given during the creation of the database.
992  * ismedia_crash(in): Are we recovering from media crash ?.
993  * stopat(in): If we are recovering from a media crash, we can stop
994  * the recovery process at a given time.
995  *
996  * NOTE:Initialize the log manager. If the database system crashed,
997  * before the system was shutdown, the recovery process is
998  * executed as part of the initialization. The recovery process
999  * consists of redoing any changes that were previously committed
1000  * and currently missing from the database disk, and undoing any
1001  * changes that were not committed but that are stored in the
1002  * database disk.
1003  */
1004 void
1005 log_initialize (THREAD_ENTRY * thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname,
1006  int ismedia_crash, BO_RESTART_ARG * r_args)
1007 {
1008  er_log_debug (ARG_FILE_LINE, "LOG INITIALIZE\n" "\tdb_fullname = %s \n" "\tlogpath = %s \n"
1009  "\tprefix_logname = %s \n" "\tismedia_crash = %d \n",
1010  db_fullname != NULL ? db_fullname : "(UNKNOWN)",
1011  logpath != NULL ? logpath : "(UNKNOWN)",
1012  prefix_logname != NULL ? prefix_logname : "(UNKNOWN)", ismedia_crash);
1013 
1014  (void) log_initialize_internal (thread_p, db_fullname, logpath, prefix_logname, ismedia_crash, r_args, false);
1015 
1016 #if defined(SERVER_MODE)
1017  log_daemons_init ();
1018 #endif // SERVER_MODE
1019 
1021 #if !defined(NDEBUG)
1023  {
1024  fprintf (stdout, "**Running without logging**\n");
1025  fflush (stdout);
1026  }
1027 #endif /* !NDEBUG */
1028 }
1029 
1030 /*
1031  * log_initialize_internal -
1032  *
1033  * return:
1034  *
1035  * db_fullname(in): Full name of the database
1036  * logpath(in): Directory where the log volumes reside
1037  * prefix_logname(in): Name of the log volumes. It must be the same as the
1038  * one given during the creation of the database.
1039  * ismedia_crash(in): Are we recovering from media crash ?.
1040  * stopat(in): If we are recovering from a media crash, we can stop
1041  * the recovery process at a given time.
1042  *
1043  * NOTE:
1044  */
1045 static int
1046 log_initialize_internal (THREAD_ENTRY * thread_p, const char *db_fullname, const char *logpath,
1047  const char *prefix_logname, bool ismedia_crash, BO_RESTART_ARG * r_args, bool init_emergency)
1048 {
1049  LOG_RECORD_HEADER *eof; /* End of log record */
1050  REL_FIXUP_FUNCTION *disk_compatibility_functions = NULL;
1051  REL_COMPATIBILITY compat;
1052  int i;
1053  int error_code = NO_ERROR;
1054  time_t *stopat = (r_args) ? &r_args->stopat : NULL;
1055 
1056 #if !defined (NDEBUG)
1057  /* Make sure that the recovery function array is synchronized.. */
1058  rv_check_rvfuns ();
1059 #endif /* !NDEBUG */
1060 
1061  (void) umask (S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
1062 
1063  /* Make sure that the log is a valid one */
1065 
1066  LOG_CS_ENTER (thread_p);
1067 
1068  if (log_Gl.trantable.area != NULL)
1069  {
1070  log_final (thread_p);
1071  }
1072 
1073  /* Initialize log name for log volumes */
1074  error_code = logpb_initialize_log_names (thread_p, db_fullname, logpath, prefix_logname);
1075  if (error_code != NO_ERROR)
1076  {
1077  logpb_fatal_error (thread_p, !init_emergency, ARG_FILE_LINE, "log_xinit");
1078  goto error;
1079  }
1080  logpb_decache_archive_info (thread_p);
1081  log_Gl.run_nxchkpt_atpageid = NULL_PAGEID; /* Don't run the checkpoint */
1083 
1084  log_Gl.loghdr_pgptr = (LOG_PAGE *) malloc (LOG_PAGESIZE);
1085  if (log_Gl.loghdr_pgptr == NULL)
1086  {
1088  logpb_fatal_error (thread_p, !init_emergency, ARG_FILE_LINE, "log_xinit");
1089  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
1090  goto error;
1091  }
1092  error_code = logpb_initialize_pool (thread_p);
1093  if (error_code != NO_ERROR)
1094  {
1095  goto error;
1096  }
1097 
1098  /* Mount the active log and read the log header */
1099  log_Gl.append.vdes = fileio_mount (thread_p, db_fullname, log_Name_active, LOG_DBLOG_ACTIVE_VOLID, true, false);
1100  if (log_Gl.append.vdes == NULL_VOLDES)
1101  {
1102  if (ismedia_crash != false)
1103  {
1104  /*
1105  * Set an approximate log header to continue the recovery process
1106  */
1107  INT64 db_creation = -1; /* Database creation time in volume */
1108  int log_npages;
1109 
1110  log_npages = log_get_num_pages_for_creation (-1);
1111 
1112  error_code = logpb_initialize_header (thread_p, &log_Gl.hdr, prefix_logname, log_npages, &db_creation);
1113  if (error_code != NO_ERROR)
1114  {
1115  goto error;
1116  }
1120 
1121  /* sync append_lsa to prior_lsa */
1123 
1128  }
1129  else
1130  {
1131  /* Unable to mount the active log */
1132  error_code = ER_IO_MOUNT_FAIL;
1133  goto error;
1134  }
1135  }
1136  else
1137  {
1138  logpb_fetch_header (thread_p, &log_Gl.hdr);
1139  }
1140 
1141  if (ismedia_crash != false && (r_args) && r_args->restore_slave)
1142  {
1143  r_args->db_creation = log_Gl.hdr.db_creation;
1145  }
1146 
1148 
1149  /* Make sure that this is the desired log */
1150  if (strcmp (log_Gl.hdr.prefix_name, prefix_logname) != 0)
1151  {
1152  /*
1153  * This looks like the log or the log was renamed. Incompatible
1154  * prefix name with the prefix stored on disk
1155  */
1158  /* Continue anyhow */
1159  }
1160 
1161  /*
1162  * Make sure that we are running with the same page size. If we are not,
1163  * restart again since page and log buffers may reflect an incorrect
1164  * pagesize
1165  */
1166 
1168  {
1169  /*
1170  * Pagesize is incorrect. We need to undefine anything that has been
1171  * created with old pagesize and start again
1172  */
1174  {
1175  /* Pagesize is incompatible */
1176  error_code = ER_FAILED;
1177  goto error;
1178  }
1179  /*
1180  * Call the function again... since we have a different setting for the
1181  * page size
1182  */
1183  logpb_finalize_pool (thread_p);
1184  fileio_dismount (thread_p, log_Gl.append.vdes);
1186 
1188  LOG_CS_EXIT (thread_p);
1189 
1191  if (error_code != NO_ERROR)
1192  {
1193  return error_code;
1194  }
1195  error_code = log_initialize_internal (thread_p, db_fullname, logpath, prefix_logname, ismedia_crash,
1196  r_args, init_emergency);
1197 
1198  return error_code;
1199  }
1200 
1201  /* Make sure that the database is compatible with the CUBRID version. This will compare the given level against the
1202  * value returned by rel_disk_compatible(). */
1203  compat = rel_get_disk_compatible (log_Gl.hdr.db_compatibility, &disk_compatibility_functions);
1204 
1205  /* If we're not completely compatible, signal an error. There had been no compatibility rules on R2.1 or earlier
1206  * version. However, a compatibility rule between R2.2 and R2.1 (or earlier) was added to provide restoration from
1207  * R2.1 to R2.2. */
1208  if (compat != REL_FULLY_COMPATIBLE)
1209  {
1210  /* Database is incompatible with current release */
1212  rel_release_string ());
1213  error_code = ER_LOG_INCOMPATIBLE_DATABASE;
1214  goto error;
1215  }
1216 
1218  {
1219  /*
1220  * First time this database is restarted using the current version of
1221  * CUBRID. Recovery should be done using the old version of the
1222  * system
1223  */
1224  if (log_Gl.hdr.is_shutdown == false)
1225  {
1226  const char *env_value;
1227  bool unsafe;
1228  /*
1229  * Check environment variable to see if caller want to force to continue
1230  * the recovery using current version.
1231  */
1232  env_value = envvar_get ("LOG_UNSAFE_RECOVER_NEW_RELEASE");
1233  if (env_value != NULL)
1234  {
1235  if (atoi (env_value) != 0)
1236  {
1237  unsafe = true;
1238  }
1239  else
1240  {
1241  unsafe = false;
1242  }
1243  }
1244  else
1245  {
1246  unsafe = false;
1247  }
1248 
1249  if (unsafe == false)
1250  {
1253  error_code = ER_LOG_RECOVER_ON_OLD_RELEASE;
1254  goto error;
1255  }
1256  }
1257 
1258  /*
1259  * It seems safe to move to new version of the system
1260  */
1261 
1263  {
1266  error_code = ER_LOG_COMPILATION_RELEASE;
1267  goto error;
1268  }
1270  }
1271 
1272  /*
1273  * Create the transaction table and make sure that data volumes and log
1274  * volumes belong to the same database
1275  */
1276 #if 1
1277  /*
1278  * for XA support: there is prepared transaction after recovery.
1279  * so, can not recreate transaction description
1280  * table after recovery.
1281  * NEED MORE CONSIDERATION
1282  *
1283  * Total number of transaction descriptor is set to the value of
1284  * max_clients+1
1285  */
1286  error_code = logtb_define_trantable_log_latch (thread_p, -1);
1287  if (error_code != NO_ERROR)
1288  {
1289  goto error;
1290  }
1291 #else
1293  if (error_code != NO_ERROR)
1294  {
1295  goto error;
1296  }
1297 #endif
1298 
1299  if (log_Gl.append.vdes != NULL_VOLDES)
1300  {
1301  if (fileio_map_mounted (thread_p, (bool (*)(THREAD_ENTRY *, VOLID, void *)) log_verify_dbcreation,
1302  &log_Gl.hdr.db_creation) != true)
1303  {
1304  /* The log does not belong to the given database */
1305  logtb_undefine_trantable (thread_p);
1308  goto error;
1309  }
1310  }
1311 
1313 
1315  {
1316  init_emergency = true;
1317  }
1318 
1319  /*
1320  * Was the database system shut down or was it involved in a crash ?
1321  */
1322  if (init_emergency == false && (log_Gl.hdr.is_shutdown == false || ismedia_crash == true))
1323  {
1324  /*
1325  * System was involved in a crash.
1326  * Execute the recovery process
1327  */
1328  log_recovery (thread_p, ismedia_crash, stopat);
1329  }
1330  else
1331  {
1332  if (init_emergency == true && log_Gl.hdr.is_shutdown == false)
1333  {
1335  {
1336  /* We cannot believe in append_lsa for this case. It points to an unflushed log page. Since we are
1337  * going to skip recovery for emergency startup, just replace it with eof_lsa. */
1339  }
1340  }
1341 
1342  /*
1343  * The system was shut down. There is nothing to recover.
1344  * Find the append page and start execution
1345  */
1346  if (logpb_fetch_start_append_page (thread_p) != NO_ERROR)
1347  {
1348  error_code = ER_FAILED;
1349  goto error;
1350  }
1351 
1352  /* Read the End of file record to find out the previous address */
1354  {
1355  eof = (LOG_RECORD_HEADER *) LOG_APPEND_PTR ();
1356  LOG_RESET_PREV_LSA (&eof->back_lsa);
1357  }
1358 
1359 #if defined(SERVER_MODE)
1360  /* fix flushed_lsa_lower_bound become NULL_LSA */
1361  LSA_COPY (&log_Gl.flushed_lsa_lower_bound, &log_Gl.append.prev_lsa);
1362 #endif /* SERVER_MODE */
1363 
1364  /*
1365  * Indicate that database system is UP,... flush the header so that we
1366  * we know that the system was running in the even of crashes
1367  */
1368  log_Gl.hdr.is_shutdown = false;
1369  logpb_flush_header (thread_p);
1370  }
1372 
1375 
1377  {
1378  assert (0);
1379  /* defense code */
1381  }
1383  {
1384  assert (0);
1385  /* defense code */
1387  }
1388 
1389  /*
1390  *
1391  * Don't checkpoint to sizes smaller than the number of log buffers
1392  */
1394  {
1396  }
1397 
1398  /* Next checkpoint should be run at ... */
1400 
1402 
1403  /* run the compatibility functions if we have any */
1404  if (disk_compatibility_functions != NULL)
1405  {
1406  for (i = 0; disk_compatibility_functions[i] != NULL; i++)
1407  {
1408  (*(disk_compatibility_functions[i])) ();
1409  }
1410  }
1411 
1414 
1416  {
1417  BACKGROUND_ARCHIVING_INFO *bg_arv_info;
1418 
1419  bg_arv_info = &log_Gl.bg_archive_info;
1420  bg_arv_info->start_page_id = NULL_PAGEID;
1421  bg_arv_info->current_page_id = NULL_PAGEID;
1422  bg_arv_info->last_sync_pageid = NULL_PAGEID;
1423 
1424  bg_arv_info->vdes =
1426  log_Gl.hdr.npages + 1, false, false, false, LOG_PAGESIZE, 0, false);
1427  if (bg_arv_info->vdes != NULL_VOLDES)
1428  {
1429  bg_arv_info->start_page_id = log_Gl.hdr.nxarv_pageid;
1430  bg_arv_info->current_page_id = log_Gl.hdr.nxarv_pageid;
1431  bg_arv_info->last_sync_pageid = log_Gl.hdr.nxarv_pageid;
1432  }
1433  else
1434  {
1435  er_log_debug (ARG_FILE_LINE, "Unable to create temporary archive log %s\n", log_Name_bg_archive);
1436  }
1437 
1438  if (bg_arv_info->vdes != NULL_VOLDES)
1439  {
1440  (void) logpb_background_archiving (thread_p);
1441  }
1442  }
1443 
1444  LOG_CS_EXIT (thread_p);
1445 
1446  er_log_debug (ARG_FILE_LINE, "log_initialize_internal: end of log initializaton, append_lsa = (%lld|%d) \n",
1447  (long long int) log_Gl.hdr.append_lsa.pageid, log_Gl.hdr.append_lsa.offset);
1448 
1449  return error_code;
1450 
1451 error:
1452  /* ***** */
1453 
1454  if (log_Gl.append.vdes != NULL_VOLDES)
1455  {
1456  fileio_dismount (thread_p, log_Gl.append.vdes);
1457  }
1458 
1460 
1461  if (log_Gl.loghdr_pgptr != NULL)
1462  {
1464  }
1465 
1466  LOG_CS_EXIT (thread_p);
1467 
1468  logpb_fatal_error (thread_p, !init_emergency, ARG_FILE_LINE, "log_init");
1469 
1470  return error_code;
1471 
1472 }
1473 
1474 #if defined (ENABLE_UNUSED_FUNCTION)
1475 /*
1476  * log_update_compatibility_and_release -
1477  *
1478  * return: NO_ERROR
1479  *
1480  * compatibility(in):
1481  * release(in):
1482  *
1483  * NOTE:
1484  */
1485 int
1486 log_update_compatibility_and_release (THREAD_ENTRY * thread_p, float compatibility, char release[])
1487 {
1488  LOG_CS_ENTER (thread_p);
1489 
1490  log_Gl.hdr.db_compatibility = compatibility;
1491  strncpy (log_Gl.hdr.db_release, release, REL_MAX_RELEASE_LENGTH);
1492 
1493  logpb_flush_header (thread_p);
1494 
1495  LOG_CS_EXIT (thread_p);
1496 
1497  return NO_ERROR;
1498 }
1499 #endif /* ENABLE_UNUSED_FUNCTION */
1500 
1501 #if defined(SERVER_MODE) || defined(SA_MODE)
1502 /*
1503  * log_get_db_compatibility -
1504  *
1505  * return:
1506  *
1507  * NOTE:
1508  */
1509 float
1511 {
1512  return log_Gl.hdr.db_compatibility;
1513 }
1514 #endif /* SERVER_MODE || SA_MODE */
1515 
1516 #if defined(SERVER_MODE)
1517 /*
1518  * log_abort_by_tdes - Abort a transaction
1519  *
1520  * return: NO_ERROR
1521  *
1522  * arg(in): Transaction descriptor
1523  *
1524  * NOTE:
1525  */
1526 static int
1527 log_abort_by_tdes (THREAD_ENTRY * thread_p, LOG_TDES * tdes)
1528 {
1529  if (thread_p == NULL)
1530  {
1531  thread_p = thread_get_thread_entry_info ();
1532  }
1533 
1534  thread_p->tran_index = tdes->tran_index;
1535  pthread_mutex_unlock (&thread_p->tran_index_lock);
1536 
1537  (void) log_abort (thread_p, tdes->tran_index);
1538 
1539  return NO_ERROR;
1540 }
1541 #endif /* SERVER_MODE */
1542 
1543 /*
1544  * TODO : STL
1545  * log_abort_all_active_transaction -
1546  *
1547  * return:
1548  *
1549  * NOTE:
1550  */
1551 void
1553 {
1554  int i;
1555  LOG_TDES *tdes; /* Transaction descriptor */
1556 #if defined(SERVER_MODE)
1557  int repeat_loop;
1558  int *abort_thread_running;
1559  static int already_called = 0;
1560 
1561  if (already_called)
1562  {
1563  return;
1564  }
1565  already_called = 1;
1566 
1567  if (log_Gl.trantable.area == NULL)
1568  {
1569  return;
1570  }
1571 
1572  abort_thread_running = (int *) malloc (sizeof (int) * log_Gl.trantable.num_total_indices);
1573  if (abort_thread_running == NULL)
1574  {
1576  sizeof (int) * log_Gl.trantable.num_total_indices);
1577  return;
1578  }
1579  memset (abort_thread_running, 0, sizeof (int) * log_Gl.trantable.num_total_indices);
1580 
1581  /* Abort all active transactions */
1582 loop:
1583  repeat_loop = false;
1584 
1585  for (i = 0; i < log_Gl.trantable.num_total_indices; i++)
1586  {
1587  if (i != LOG_SYSTEM_TRAN_INDEX && (tdes = LOG_FIND_TDES (i)) != NULL && tdes->trid != NULL_TRANID)
1588  {
1589  if (css_count_transaction_worker_threads (thread_p, i, tdes->client_id) > 0)
1590  {
1591  repeat_loop = true;
1592  }
1593  else if (LOG_ISTRAN_ACTIVE (tdes) && abort_thread_running[i] == 0)
1594  {
1595  // *INDENT-OFF*
1597  std::bind (log_abort_task_execute, std::placeholders::_1, std::ref (*tdes));
1599  // *INDENT-ON*
1600  abort_thread_running[i] = 1;
1601  repeat_loop = true;
1602  }
1603  }
1604  }
1605 
1606  if (repeat_loop)
1607  {
1608  thread_sleep (50); /* sleep 0.05 sec */
1610  {
1611  if (abort_thread_running != NULL)
1612  {
1613  free_and_init (abort_thread_running);
1614  }
1615  /* exit process after some tries */
1616  er_log_debug (ARG_FILE_LINE, "log_abort_all_active_transaction: _exit(0)\n");
1617  _exit (0);
1618  }
1619  goto loop;
1620  }
1621 
1622  if (abort_thread_running != NULL)
1623  {
1624  free_and_init (abort_thread_running);
1625  }
1626 
1627 #else /* SERVER_MODE */
1628  int save_tran_index = log_Tran_index; /* Return to this index */
1629 
1630  if (log_Gl.trantable.area == NULL)
1631  {
1632  return;
1633  }
1634 
1635  /* Abort all active transactions */
1636  for (i = 0; i < log_Gl.trantable.num_total_indices; i++)
1637  {
1638  tdes = LOG_FIND_TDES (i);
1639  if (i != LOG_SYSTEM_TRAN_INDEX && tdes != NULL && tdes->trid != NULL_TRANID)
1640  {
1641  if (LOG_ISTRAN_ACTIVE (tdes))
1642  {
1643  log_Tran_index = i;
1644  (void) log_abort (thread_p, log_Tran_index);
1645  }
1646  }
1647  }
1648  log_Tran_index = save_tran_index;
1649 #endif /* SERVER_MODE */
1650 }
1651 
1652 /*
1653  * TODO : STL
1654  * log_final - Terminate the log manager
1655  *
1656  * return: nothing
1657  *
1658  * NOTE: Terminate the log correctly, so that no recovery will be
1659  * needed when the database system is restarted again. If there
1660  * are any active transactions, they are all aborted. The log is
1661  * flushed and all dirty data pages are also flushed to disk.
1662  */
1663 void
1665 {
1666  int i;
1667  LOG_TDES *tdes; /* Transaction descriptor */
1668  int save_tran_index;
1669  bool anyloose_ends = false;
1670  int error_code = NO_ERROR;
1671 
1672 #if defined(SERVER_MODE)
1673  log_daemons_destroy ();
1674 #endif /* SERVER_MODE */
1675  // *INDENT-OFF*
1677  // *INDENT-ON*
1678 
1679  LOG_CS_ENTER (thread_p);
1680 
1681  /* reset log_Gl.rcv_phase */
1683 
1684  if (log_Gl.trantable.area == NULL)
1685  {
1686  LOG_CS_EXIT (thread_p);
1687  return;
1688  }
1689 
1690  save_tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
1691 
1692  if (!logpb_is_pool_initialized ())
1693  {
1694  logtb_undefine_trantable (thread_p);
1695  LOG_CS_EXIT (thread_p);
1696  return;
1697  }
1698 
1699  if (log_Gl.append.vdes == NULL_VOLDES)
1700  {
1701  logpb_finalize_pool (thread_p);
1702  logtb_undefine_trantable (thread_p);
1703  LOG_CS_EXIT (thread_p);
1704  return;
1705  }
1706 
1707  /*
1708  * Cannot use the critical section here since we are assigning the
1709  * transaction index and the critical sections are base on the transaction
1710  * index. Acquire the critical section and the get out immediately.. by
1711  * this time the scheduler will not preempt you.
1712  */
1713 
1714  /* Abort all active transactions */
1715  for (i = 0; i < log_Gl.trantable.num_total_indices; i++)
1716  {
1717  tdes = LOG_FIND_TDES (i);
1718  if (i != LOG_SYSTEM_TRAN_INDEX && tdes != NULL && tdes->trid != NULL_TRANID)
1719  {
1720  if (LOG_ISTRAN_ACTIVE (tdes))
1721  {
1722  LOG_SET_CURRENT_TRAN_INDEX (thread_p, i);
1723  (void) log_abort (thread_p, i);
1724  }
1725  else
1726  {
1727  anyloose_ends = true;
1728  }
1729  }
1730  }
1731 
1732  LOG_SET_CURRENT_TRAN_INDEX (thread_p, save_tran_index);
1733 
1734  /*
1735  * Flush all log append dirty pages and all data dirty pages
1736  */
1737  logpb_flush_pages_direct (thread_p);
1738 
1739  error_code = pgbuf_flush_all (thread_p, NULL_VOLID);
1740  if (error_code == NO_ERROR)
1741  {
1742  error_code = fileio_synchronize_all (thread_p, false);
1743  }
1744 
1745  logpb_decache_archive_info (thread_p);
1746 
1747  /*
1748  * Flush the header of the log with information to restart the system
1749  * easily. For example, without a recovery process
1750  */
1751 
1753  if (anyloose_ends == false && error_code == NO_ERROR)
1754  {
1755  log_Gl.hdr.is_shutdown = true;
1758  }
1759  else
1760  {
1761  (void) logpb_checkpoint (thread_p);
1762  }
1763 
1764  logpb_flush_header (thread_p);
1765 
1766  /* Undefine page buffer pool and transaction table */
1767  logpb_finalize_pool (thread_p);
1768 
1769  logtb_undefine_trantable (thread_p);
1770 
1772  {
1774  {
1777  }
1778  }
1779 
1780  /* Dismount the active log volume */
1781  fileio_dismount (thread_p, log_Gl.append.vdes);
1783 
1785 
1786  LOG_CS_EXIT (thread_p);
1787 }
1788 
1789 void
1791 {
1792 #if defined (SERVER_MODE)
1793  cubthread::get_manager ()->destroy_daemon (log_Check_ha_delay_info_daemon);
1794 #endif // SERVER_MODE
1795 }
1796 
1797 /*
1798  * log_restart_emergency - Emergency restart of log manager
1799  *
1800  * return: nothing
1801  *
1802  * db_fullname(in): Full name of the database
1803  * logpath(in): Directory where the log volumes reside
1804  * prefix_logname(in): Name of the log volumes. It must be the same as the
1805  * one given during the creation of the database.
1806  *
1807  * NOTE: Initialize the log manager in emergency fashion. That is,
1808  * restart recovery is ignored.
1809  */
1810 void
1811 log_restart_emergency (THREAD_ENTRY * thread_p, const char *db_fullname, const char *logpath,
1812  const char *prefix_logname)
1813 {
1814  (void) log_initialize_internal (thread_p, db_fullname, logpath, prefix_logname, false, NULL, true);
1815 }
1816 
1817 /*
1818  *
1819  * INTERFACE FUNCTION FOR LOGGING DATA
1820  *
1821  */
1822 
1823 /*
1824  * log_append_undoredo_data - LOG UNDO (BEFORE) + REDO (AFTER) DATA
1825  *
1826  * return: nothing
1827  *
1828  * rcvindex(in): Index to recovery function
1829  * addr(in): Address (Volume, page, and offset) of data
1830  * undo_length(in): Length of undo(before) data
1831  * redo_length(in): Length of redo(after) data
1832  * undo_data(in): Undo (before) data
1833  * redo_data(in): Redo (after) data
1834  *
1835  */
1836 void
1837 log_append_undoredo_data (THREAD_ENTRY * thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR * addr, int undo_length,
1838  int redo_length, const void *undo_data, const void *redo_data)
1839 {
1840  LOG_CRUMB undo_crumb;
1841  LOG_CRUMB redo_crumb;
1842 
1843  /* Set undo length/data to crumb */
1844  assert (0 <= undo_length);
1845  assert (0 == undo_length || undo_data != NULL);
1846 
1847  undo_crumb.data = undo_data;
1848  undo_crumb.length = undo_length;
1849 
1850  /* Set redo length/data to crumb */
1851  assert (0 <= redo_length);
1852  assert (0 == redo_length || redo_data != NULL);
1853 
1854  redo_crumb.data = redo_data;
1855  redo_crumb.length = redo_length;
1856 
1857  log_append_undoredo_crumbs (thread_p, rcvindex, addr, 1, 1, &undo_crumb, &redo_crumb);
1858 }
1859 
1860 void
1862  PGLENGTH offset, int undo_length, int redo_length, const void *undo_data,
1863  const void *redo_data)
1864 {
1865  LOG_DATA_ADDR addr;
1866  LOG_CRUMB undo_crumb;
1867  LOG_CRUMB redo_crumb;
1868 
1869  /* Set data address */
1870  addr.vfid = vfid;
1871  addr.pgptr = pgptr;
1872  addr.offset = offset;
1873 
1874  /* Set undo length/data to crumb */
1875  assert (0 <= undo_length);
1876  assert (0 == undo_length || undo_data != NULL);
1877 
1878  undo_crumb.data = undo_data;
1879  undo_crumb.length = undo_length;
1880 
1881  /* Set redo length/data to crumb */
1882  assert (0 <= redo_length);
1883  assert (0 == redo_length || redo_data != NULL);
1884 
1885  redo_crumb.data = redo_data;
1886  redo_crumb.length = redo_length;
1887 
1888  log_append_undoredo_crumbs (thread_p, rcvindex, &addr, 1, 1, &undo_crumb, &redo_crumb);
1889 }
1890 
1891 /*
1892  * log_append_undo_data - LOG UNDO (BEFORE) DATA
1893  *
1894  * return: nothing
1895  *
1896  * rcvindex(in): Index to recovery function
1897  * addr(in): Address (Volume, page, and offset) of data
1898  * length(in): Length of undo(before) data
1899  * data(in): Undo (before) data
1900  *
1901  * NOTE: Log undo(before) data. A log record is constructed to recover
1902  * data by undoing data during abort and during recovery.
1903  *
1904  * In the case of a rollback, the undo function described by
1905  * rcvindex is called with a recovery structure which contains
1906  * the page pointer and offset of the data to recover along with
1907  * the undo data. It is up to this function to determine how to
1908  * undo the data.
1909  *
1910  * 1) This function accepts either page operation logging (with a
1911  * valid address) or logical log (with a null address).
1912  * 2) Very IMPORTANT: If an update is associated with two individual
1913  * log records, the undo record must be logged before the redo
1914  * record.
1915  */
1916 void
1917 log_append_undo_data (THREAD_ENTRY * thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR * addr, int length,
1918  const void *data)
1919 {
1920  LOG_CRUMB undo_crumb;
1921 
1922  /* Set length/data to crumb */
1923  assert (0 <= length);
1924  assert (0 == length || data != NULL);
1925 
1926  undo_crumb.data = data;
1927  undo_crumb.length = length;
1928 
1929  log_append_undo_crumbs (thread_p, rcvindex, addr, 1, &undo_crumb);
1930 }
1931 
1932 void
1933 log_append_undo_data2 (THREAD_ENTRY * thread_p, LOG_RCVINDEX rcvindex, const VFID * vfid, PAGE_PTR pgptr,
1934  PGLENGTH offset, int length, const void *data)
1935 {
1936  LOG_DATA_ADDR addr;
1937  LOG_CRUMB undo_crumb;
1938 
1939  /* Set data address */
1940  addr.vfid = vfid;
1941  addr.pgptr = pgptr;
1942  addr.offset = offset;
1943 
1944  /* Set length/data to crumb */
1945  assert (0 <= length);
1946  assert (0 == length || data != NULL);
1947 
1948  undo_crumb.data = data;
1949  undo_crumb.length = length;
1950 
1951  log_append_undo_crumbs (thread_p, rcvindex, &addr, 1, &undo_crumb);
1952 }
1953 
1954 /*
1955  * log_append_redo_data - LOG REDO (AFTER) DATA
1956  *
1957  * return: nothing
1958  *
1959  * rcvindex(in): Index to recovery function
1960  * addr(in): Address (Volume, page, and offset) of data
1961  * length(in): Length of redo(after) data
1962  * data(in): Redo (after) data
1963  *
1964  * NOTE: Log redo(after) data. A log record is constructed to recover
1965  * data by redoing data during recovery.
1966  *
1967  * During recovery(e.g., system crash recovery), the redo
1968  * function described by rcvindex is called with a recovery
1969  * structure which contains the page pointer and offset of the
1970  * data to recover along with the redo data. It is up to this
1971  * function to determine how to redo the data.
1972  *
1973  * 1) The only type of logging accepted by this function is page
1974  * operation level logging, thus, an address must must be given.
1975  * 2) During the redo phase of crash recovery, any redo logging is
1976  * ignored.
1977  */
1978 void
1979 log_append_redo_data (THREAD_ENTRY * thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR * addr, int length,
1980  const void *data)
1981 {
1982  LOG_CRUMB redo_crumb;
1983 
1984  /* Set length/data to crumb */
1985  assert (0 <= length);
1986  assert (0 == length || data != NULL);
1987 
1988  redo_crumb.data = data;
1989  redo_crumb.length = length;
1990 
1991  log_append_redo_crumbs (thread_p, rcvindex, addr, 1, &redo_crumb);
1992 }
1993 
1994 void
1995 log_append_redo_data2 (THREAD_ENTRY * thread_p, LOG_RCVINDEX rcvindex, const VFID * vfid, PAGE_PTR pgptr,
1996  PGLENGTH offset, int length, const void *data)
1997 {
1998  LOG_DATA_ADDR addr;
1999  LOG_CRUMB redo_crumb;
2000 
2001  /* Set data address */
2002  addr.vfid = vfid;
2003  addr.pgptr = pgptr;
2004  addr.offset = offset;
2005 
2006  /* Set length/data to crumb */
2007  assert (0 <= length);
2008  assert (0 == length || data != NULL);
2009 
2010  redo_crumb.data = data;
2011  redo_crumb.length = length;
2012 
2013  log_append_redo_crumbs (thread_p, rcvindex, &addr, 1, &redo_crumb);
2014 }
2015 
2016 /*
2017  * log_append_undoredo_crumbs - LOG UNDO (BEFORE) + REDO (AFTER) CRUMBS OF DATA
2018  *
2019  * return: nothing
2020  *
2021  * rcvindex(in): Index to recovery function
2022  * addr(in): Address (Volume, page, and offset) of data
2023  * num_undo_crumbs(in): Number of undo crumbs
2024  * num_redo_crumbs(in): Number of redo crumbs
2025  * undo_crumbs(in): The undo crumbs
2026  * redo_crumbs(in): The redo crumbs
2027  *
2028  */
2029 void
2030 log_append_undoredo_crumbs (THREAD_ENTRY * thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR * addr, int num_undo_crumbs,
2031  int num_redo_crumbs, const LOG_CRUMB * undo_crumbs, const LOG_CRUMB * redo_crumbs)
2032 {
2033  LOG_TDES *tdes; /* Transaction descriptor */
2034  int tran_index;
2035  int error_code = NO_ERROR;
2036  LOG_PRIOR_NODE *node;
2037  LOG_LSA start_lsa;
2039 
2040 #if defined(CUBRID_DEBUG)
2041  if (addr->pgptr == NULL)
2042  {
2043  /*
2044  * Redo is always an operation page level logging. Thus, a data page
2045  * pointer must have been given as part of the address
2046  */
2048  error_code = ER_LOG_REDO_INTERFACE;
2049  return;
2050  }
2051  if (RV_fun[rcvindex].undofun == NULL || RV_fun[rcvindex].redofun == NULL)
2052  {
2053  assert (false);
2054  return;
2055  }
2056 #endif /* CUBRID_DEBUG */
2057 
2058 #if !defined(SERVER_MODE)
2059  assert_release (!LOG_IS_MVCC_OPERATION (rcvindex));
2060 #endif /* SERVER_MODE */
2061 
2062  if (log_No_logging)
2063  {
2064  /* We are not logging */
2066  log_skip_logging (thread_p, addr);
2067  return;
2068  }
2069 
2070  /* Find transaction descriptor for current logging transaction */
2071  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
2072  tdes = LOG_FIND_TDES (tran_index);
2073  if (tdes == NULL)
2074  {
2076  error_code = ER_LOG_UNKNOWN_TRANINDEX;
2077  return;
2078  }
2079 
2080  /*
2081  * If we are not in a top system operation, the transaction is unactive, and
2082  * the transaction is not in the process of been aborted, we do nothing.
2083  */
2084  if (tdes->topops.last < 0 && !LOG_ISTRAN_ACTIVE (tdes) && !LOG_ISTRAN_ABORTED (tdes))
2085  {
2086  /*
2087  * We do not log anything when the transaction is unactive and it is not
2088  * in the process of aborting.
2089  */
2090  return;
2091  }
2092 
2093  /*
2094  * is undo logging needed ?
2095  */
2096 
2097  if (log_can_skip_undo_logging (thread_p, rcvindex, tdes, addr) == true)
2098  {
2099  /* undo logging is ignored at this point */
2100  log_append_redo_crumbs (thread_p, rcvindex, addr, num_redo_crumbs, redo_crumbs);
2101  return;
2102  }
2103 
2104  /*
2105  * Now do the UNDO & REDO portion
2106  */
2107 
2108  node = prior_lsa_alloc_and_copy_crumbs (thread_p, rectype, rcvindex, addr, num_undo_crumbs, undo_crumbs,
2109  num_redo_crumbs, redo_crumbs);
2110  if (node == NULL)
2111  {
2112  return;
2113  }
2114 
2115  if (LOG_MAY_CONTAIN_USER_DATA (rcvindex))
2116  {
2118  {
2119  if (prior_set_tde_encrypted (node, rcvindex) != NO_ERROR)
2120  {
2121  assert (false);
2122  return;
2123  }
2124  }
2125  }
2126 
2127  start_lsa = prior_lsa_next_record (thread_p, node, tdes);
2128 
2129  if (LOG_NEED_TO_SET_LSA (rcvindex, addr->pgptr))
2130  {
2131  if (pgbuf_set_lsa (thread_p, addr->pgptr, &start_lsa) == NULL)
2132  {
2133  assert (false);
2134  return;
2135  }
2136  }
2137  if (addr->pgptr != NULL && LOG_IS_MVCC_OPERATION (rcvindex))
2138  {
2139  pgbuf_notify_vacuum_follows (thread_p, addr->pgptr);
2140  }
2141 
2142  if (!LOG_CHECK_LOG_APPLIER (thread_p) && log_does_allow_replication () == true)
2143  {
2144  if (rcvindex == RVHF_UPDATE || rcvindex == RVOVF_CHANGE_LINK || rcvindex == RVHF_UPDATE_NOTIFY_VACUUM
2145  || rcvindex == RVHF_INSERT_NEWHOME)
2146  {
2147  LSA_COPY (&tdes->repl_update_lsa, &tdes->tail_lsa);
2148  assert (tdes->is_active_worker_transaction ());
2149  }
2150  else if (rcvindex == RVHF_INSERT || rcvindex == RVHF_MVCC_INSERT)
2151  {
2152  LSA_COPY (&tdes->repl_insert_lsa, &tdes->tail_lsa);
2153  assert (tdes->is_active_worker_transaction ());
2154  }
2155  }
2156 }
2157 
2158 /*
2159  * log_append_undo_crumbs - LOG UNDO (BEFORE) CRUMBS OF DATA
2160  *
2161  * return: nothing
2162  *
2163  * rcvindex(in): Index to recovery function
2164  * addr(in): Address (Volume, page, and offset) of data
2165  * num_crumbs(in): Number of undo crumbs
2166  * crumbs(in): The undo crumbs
2167  *
2168  */
2169 void
2170 log_append_undo_crumbs (THREAD_ENTRY * thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR * addr, int num_crumbs,
2171  const LOG_CRUMB * crumbs)
2172 {
2173  LOG_TDES *tdes; /* Transaction descriptor */
2174  int tran_index;
2175  int error_code = NO_ERROR;
2176  LOG_PRIOR_NODE *node;
2177  LOG_LSA start_lsa;
2179 
2180 #if defined(CUBRID_DEBUG)
2181  if (RV_fun[rcvindex].undofun == NULL)
2182  {
2183  assert (false);
2184  return;
2185  }
2186 #endif /* CUBRID_DEBUG */
2187 
2188  if (log_No_logging)
2189  {
2190  /* We are not logging */
2192  if (addr->pgptr != NULL)
2193  {
2194  log_skip_logging (thread_p, addr);
2195  }
2196  return;
2197  }
2198 
2199  /* Find transaction descriptor for current logging transaction */
2200  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
2201  tdes = LOG_FIND_TDES (tran_index);
2202  if (tdes == NULL)
2203  {
2205  error_code = ER_LOG_UNKNOWN_TRANINDEX;
2206  return;
2207  }
2208 
2209  /*
2210  * If we are not in a top system operation, the transaction is unactive, and
2211  * the transaction is not in the process of been aborted, we do nothing.
2212  */
2213  if (tdes->topops.last < 0 && !LOG_ISTRAN_ACTIVE (tdes) && !LOG_ISTRAN_ABORTED (tdes))
2214  {
2215  /*
2216  * We do not log anything when the transaction is unactive and it is not
2217  * in the process of aborting.
2218  */
2219  return;
2220  }
2221 
2222  /*
2223  * is undo logging needed ?
2224  */
2225  if (log_can_skip_undo_logging (thread_p, rcvindex, tdes, addr) == true)
2226  {
2227  /* undo logging is ignored at this point */
2228  ; /* NO-OP */
2229  return;
2230  }
2231 
2232  /*
2233  * NOW do the UNDO ...
2234  */
2235 
2236  node = prior_lsa_alloc_and_copy_crumbs (thread_p, rectype, rcvindex, addr, num_crumbs, crumbs, 0, NULL);
2237  if (node == NULL)
2238  {
2239  assert (false);
2240  return;
2241  }
2242 
2243  /*
2244  * if pgptr is NULL, the user data can be spilled as un-encrypted.
2245  * Now it seems that there is no case, but can be in the future.
2246  */
2247  if (addr->pgptr != NULL && LOG_MAY_CONTAIN_USER_DATA (rcvindex))
2248  {
2250  {
2251  if (prior_set_tde_encrypted (node, rcvindex) != NO_ERROR)
2252  {
2253  assert (false);
2254  return;
2255  }
2256  }
2257  }
2258 
2259  start_lsa = prior_lsa_next_record (thread_p, node, tdes);
2260 
2261  if (addr->pgptr != NULL && LOG_NEED_TO_SET_LSA (rcvindex, addr->pgptr))
2262  {
2263  if (pgbuf_set_lsa (thread_p, addr->pgptr, &start_lsa) == NULL)
2264  {
2265  assert (false);
2266  return;
2267  }
2268  }
2269  if (addr->pgptr != NULL && LOG_IS_MVCC_OPERATION (rcvindex))
2270  {
2271  pgbuf_notify_vacuum_follows (thread_p, addr->pgptr);
2272  }
2273 }
2274 
2275 /*
2276  * log_append_redo_crumbs - LOG REDO (AFTER) CRUMBS OF DATA
2277  *
2278  * return: nothing
2279  *
2280  * rcvindex(in): Index to recovery function
2281  * addr(in): Address (Volume, page, and offset) of data
2282  * num_crumbs(in): Number of undo crumbs
2283  * crumbs(in): The undo crumbs
2284  *
2285  * NOTE: Log redo(after) crumbs of data. A log record is constructed to
2286  * recover data by redoing data during recovery.
2287  * The log manager does not really store crumbs of data, instead
2288  * the log manager glues them together as a stream of data, and
2289  * thus, it looses the knowledge that the data was from crumbs.
2290  * This is done to avoid extra storage overhead. It is the
2291  * responsibility of the recovery functions to build the crumbs
2292  * when needed from the glued data.
2293  *
2294  * During recovery(e.g., system crash recovery), the redo
2295  * function described by rcvindex is called with a recovery
2296  * structure which contains the page pointer and offset of the
2297  * data to recover along with the redo glued data. The redo
2298  * function must construct the crumbs when needed. It is up to
2299  * this function, how to undo the data.
2300  *
2301  * 1) Same notes as log_append_redo_data (see this function)
2302  * 2) The only purpose of this function is to avoid extra data
2303  * copying (the glue into one contiguous area) by the caller,
2304  * otherwise, the same as log_append_redo_data.
2305  */
2306 void
2307 log_append_redo_crumbs (THREAD_ENTRY * thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR * addr, int num_crumbs,
2308  const LOG_CRUMB * crumbs)
2309 {
2310  LOG_TDES *tdes; /* Transaction descriptor */
2311  int tran_index;
2312  int error_code = NO_ERROR;
2313  LOG_PRIOR_NODE *node;
2314  LOG_LSA start_lsa;
2316 
2317 #if defined(CUBRID_DEBUG)
2318  if (addr->pgptr == NULL)
2319  {
2320  /*
2321  * Redo is always an operation page level logging. Thus, a data page
2322  * pointer must have been given as part of the address
2323  */
2325  error_code = ER_LOG_REDO_INTERFACE;
2326  return;
2327  }
2328  if (RV_fun[rcvindex].redofun == NULL)
2329  {
2330  assert (false);
2331  return;
2332  }
2333 #endif /* CUBRID_DEBUG */
2334 
2335  if (log_No_logging)
2336  {
2337  /* We are not logging */
2339  log_skip_logging (thread_p, addr);
2340  return;
2341  }
2342 
2343  /* Find transaction descriptor for current logging transaction */
2344  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
2345  tdes = LOG_FIND_TDES (tran_index);
2346  if (tdes == NULL)
2347  {
2349  error_code = ER_LOG_UNKNOWN_TRANINDEX;
2350  return;
2351  }
2352 
2353  /*
2354  * If we are not in a top system operation, the transaction is unactive, and
2355  * the transaction is not in the process of been aborted, we do nothing.
2356  */
2357  if (tdes->topops.last < 0 && !LOG_ISTRAN_ACTIVE (tdes) && !LOG_ISTRAN_ABORTED (tdes))
2358  {
2359  /*
2360  * We do not log anything when the transaction is unactive and it is not
2361  * in the process of aborting.
2362  */
2363  return;
2364  }
2365 
2366  if (log_can_skip_redo_logging (rcvindex, tdes, addr) == true)
2367  {
2368  return;
2369  }
2370 
2371  node = prior_lsa_alloc_and_copy_crumbs (thread_p, rectype, rcvindex, addr, 0, NULL, num_crumbs, crumbs);
2372  if (node == NULL)
2373  {
2374  return;
2375  }
2376 
2377  if (LOG_MAY_CONTAIN_USER_DATA (rcvindex))
2378  {
2380  {
2381  if (prior_set_tde_encrypted (node, rcvindex) != NO_ERROR)
2382  {
2383  assert (false);
2384  return;
2385  }
2386  }
2387  }
2388 
2389  start_lsa = prior_lsa_next_record (thread_p, node, tdes);
2390 
2391  /*
2392  * Set the LSA on the data page of the corresponding log record for page
2393  * operation logging.
2394  *
2395  * Make sure that I should log. Page operational logging is not done for
2396  * temporary data of temporary files and volumes
2397  */
2398  if (LOG_NEED_TO_SET_LSA (rcvindex, addr->pgptr))
2399  {
2400  if (pgbuf_set_lsa (thread_p, addr->pgptr, &start_lsa) == NULL)
2401  {
2402  assert (false);
2403  return;
2404  }
2405  }
2406 
2407  if (!LOG_CHECK_LOG_APPLIER (thread_p) && log_does_allow_replication () == true)
2408  {
2409  if (rcvindex == RVHF_UPDATE || rcvindex == RVOVF_CHANGE_LINK || rcvindex == RVHF_UPDATE_NOTIFY_VACUUM)
2410  {
2411  LSA_COPY (&tdes->repl_update_lsa, &tdes->tail_lsa);
2412  assert (tdes->is_active_worker_transaction ());
2413  }
2414  else if (rcvindex == RVHF_INSERT || rcvindex == RVHF_MVCC_INSERT)
2415  {
2416  LSA_COPY (&tdes->repl_insert_lsa, &tdes->tail_lsa);
2417  assert (tdes->is_active_worker_transaction ());
2418  }
2419  }
2420 }
2421 
2422 /*
2423  * log_append_undoredo_recdes - LOG UNDO (BEFORE) + REDO (AFTER) RECORD DESCRIPTOR
2424  *
2425  * return: nothing
2426  *
2427  * rcvindex(in): Index to recovery function
2428  * addr(in): Address (Volume, page, and offset) of data
2429  * undo_recdes(in): Undo(before) record descriptor
2430  * redo_recdes(in): Redo(after) record descriptor
2431  *
2432  */
2433 void
2435  const RECDES * undo_recdes, const RECDES * redo_recdes)
2436 {
2437  log_append_undoredo_recdes2 (thread_p, rcvindex, addr->vfid, addr->pgptr, addr->offset, undo_recdes, redo_recdes);
2438 }
2439 
2440 void
2442  PGLENGTH offset, const RECDES * undo_recdes, const RECDES * redo_recdes)
2443 {
2444  LOG_CRUMB crumbs[4];
2445  LOG_CRUMB *undo_crumbs = &crumbs[0];
2446  LOG_CRUMB *redo_crumbs = &crumbs[2];
2447  int num_undo_crumbs;
2448  int num_redo_crumbs;
2449  LOG_DATA_ADDR addr;
2450 
2451  addr.vfid = vfid;
2452  addr.pgptr = pgptr;
2453  addr.offset = offset;
2454 
2455 #if 0
2456  if (rcvindex == RVHF_UPDATE)
2457  {
2458  LOG_TDES *tdes = LOG_FIND_CURRENT_TDES (thread_p);
2459  if (tdes && tdes->null_log.is_set && undo_recdes && redo_recdes)
2460  {
2461  tdes->null_log.recdes = malloc (sizeof (RECDES));
2462  if (tdes == NULL)
2463  {
2464  return; /* error */
2465  }
2466  *(tdes->null_log.recdes) = *undo_recdes;
2467  tdes->null_log.recdes->data = malloc (undo_recdes->length);
2468  if (tdes->null_log.recdes->data == NULL)
2469  {
2470  free_and_init (tdes->null_log.recdes);
2471  return; /* error */
2472  }
2473  (void) memcpy (tdes->null_log.recdes->data, undo_recdes->data, undo_recdes->length);
2474  }
2475  undo_crumbs[0].length = sizeof (undo_recdes->type);
2476  undo_crumbs[0].data = (char *) &undo_recdes->type;
2477  undo_crumbs[1].length = 0;
2478  undo_crumbs[1].data = NULL;
2479  num_undo_crumbs = 2;
2480  redo_crumbs[0].length = sizeof (redo_recdes->type);
2481  redo_crumbs[0].data = (char *) &redo_recdes->type;
2482  redo_crumbs[1].length = 0;
2483  redo_crumbs[1].data = NULL;
2484  num_redo_crumbs = 2;
2485  log_append_undoredo_crumbs (rcvindex, addr, num_undo_crumbs, num_redo_crumbs, undo_crumbs, redo_crumbs);
2486  return;
2487  }
2488 #endif
2489 
2490  if (undo_recdes != NULL)
2491  {
2492  undo_crumbs[0].length = sizeof (undo_recdes->type);
2493  undo_crumbs[0].data = (char *) &undo_recdes->type;
2494  undo_crumbs[1].length = undo_recdes->length;
2495  undo_crumbs[1].data = undo_recdes->data;
2496  num_undo_crumbs = 2;
2497  }
2498  else
2499  {
2500  undo_crumbs = NULL;
2501  num_undo_crumbs = 0;
2502  }
2503 
2504  if (redo_recdes != NULL)
2505  {
2506  redo_crumbs[0].length = sizeof (redo_recdes->type);
2507  redo_crumbs[0].data = (char *) &redo_recdes->type;
2508  redo_crumbs[1].length = redo_recdes->length;
2509  redo_crumbs[1].data = redo_recdes->data;
2510  num_redo_crumbs = 2;
2511  }
2512  else
2513  {
2514  redo_crumbs = NULL;
2515  num_redo_crumbs = 0;
2516  }
2517 
2518  log_append_undoredo_crumbs (thread_p, rcvindex, &addr, num_undo_crumbs, num_redo_crumbs, undo_crumbs, redo_crumbs);
2519 }
2520 
2521 /*
2522  * log_append_undo_recdes - LOG UNDO (BEFORE) RECORD DESCRIPTOR
2523  *
2524  * return: nothing
2525  *
2526  * rcvindex(in): Index to recovery function
2527  * addr(in): Address (Volume, page, and offset) of data
2528  * recdes(in): Undo(before) record descriptor
2529  *
2530  */
2531 void
2533 {
2534  log_append_undo_recdes2 (thread_p, rcvindex, addr->vfid, addr->pgptr, addr->offset, recdes);
2535 }
2536 
2537 void
2538 log_append_undo_recdes2 (THREAD_ENTRY * thread_p, LOG_RCVINDEX rcvindex, const VFID * vfid, PAGE_PTR pgptr,
2539  PGLENGTH offset, const RECDES * recdes)
2540 {
2541  LOG_CRUMB crumbs[2];
2542  LOG_DATA_ADDR addr;
2543 
2544  addr.vfid = vfid;
2545  addr.pgptr = pgptr;
2546  addr.offset = offset;
2547 
2548  if (recdes != NULL)
2549  {
2550  crumbs[0].length = sizeof (recdes->type);
2551  crumbs[0].data = (char *) &recdes->type;
2552  crumbs[1].length = recdes->length;
2553  crumbs[1].data = recdes->data;
2554  log_append_undo_crumbs (thread_p, rcvindex, &addr, 2, crumbs);
2555  }
2556  else
2557  {
2558  log_append_undo_crumbs (thread_p, rcvindex, &addr, 0, NULL);
2559  }
2560 }
2561 
2562 /*
2563  * log_append_redo_recdes - LOG REDO (AFTER) RECORD DESCRIPTOR
2564  *
2565  * return: nothing
2566  *
2567  * rcvindex(in): Index to recovery function
2568  * addr(in): Address (Volume, page, and offset) of data
2569  * recdes(in): Redo(after) record descriptor
2570  *
2571  */
2572 void
2574 {
2575  log_append_redo_recdes2 (thread_p, rcvindex, addr->vfid, addr->pgptr, addr->offset, recdes);
2576 }
2577 
2578 void
2579 log_append_redo_recdes2 (THREAD_ENTRY * thread_p, LOG_RCVINDEX rcvindex, const VFID * vfid, PAGE_PTR pgptr,
2580  PGLENGTH offset, const RECDES * recdes)
2581 {
2582  LOG_CRUMB crumbs[2];
2583  LOG_DATA_ADDR addr;
2584 
2585  addr.vfid = vfid;
2586  addr.pgptr = pgptr;
2587  addr.offset = offset;
2588 
2589  if (recdes != NULL)
2590  {
2591  crumbs[0].length = sizeof (recdes->type);
2592  crumbs[0].data = (char *) &recdes->type;
2593  crumbs[1].length = recdes->length;
2594  crumbs[1].data = recdes->data;
2595  log_append_redo_crumbs (thread_p, rcvindex, &addr, 2, crumbs);
2596  }
2597  else
2598  {
2599  log_append_redo_crumbs (thread_p, rcvindex, &addr, 0, NULL);
2600  }
2601 }
2602 
2603 /*
2604  * log_append_dboutside_redo - Log redo (after) data for operations outside the db
2605  *
2606  * return: nothing
2607  *
2608  * rcvindex(in): Index to recovery function
2609  * length(in): Length of redo(after) data
2610  * data(in): Redo (after) data
2611  *
2612  * NOTE: A log record is constructed to recover external (outside of
2613  * database) data by always redoing data during recovery.
2614  *
2615  * During recovery(e.g., system crash recovery), the redo
2616  * function described by rcvindex is called with a recovery
2617  * structure which contains the page pointer and offset of the
2618  * data to recover along with the redo data. It is up to this
2619  * function to determine how to redo the data.
2620  *
2621  * 1) The logging of this function is logical since it is for
2622  * external data.
2623  * 2) Both during the redo and undo phase, dboutside redo is
2624  * ignored.
2625  */
2626 void
2627 log_append_dboutside_redo (THREAD_ENTRY * thread_p, LOG_RCVINDEX rcvindex, int length, const void *data)
2628 {
2629  LOG_TDES *tdes; /* Transaction descriptor */
2630  int tran_index;
2631  int error_code = NO_ERROR;
2632  LOG_PRIOR_NODE *node;
2633 
2634 #if defined(CUBRID_DEBUG)
2635  if (RV_fun[rcvindex].redofun == NULL)
2636  {
2637  assert (false);
2638  return;
2639  }
2640 #endif /* CUBRID_DEBUG */
2641 
2642  if (log_No_logging)
2643  {
2644  /* We are not logging */
2646  return;
2647  }
2648 
2649  /* Find transaction descriptor for current logging transaction */
2650  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
2651  tdes = LOG_FIND_TDES (tran_index);
2652  if (tdes == NULL)
2653  {
2655  error_code = ER_LOG_UNKNOWN_TRANINDEX;
2656  return;
2657  }
2658 
2659  /*
2660  * If we are not in a top system operation, the transaction is unactive, and
2661  * the transaction is not in the process of been aborted, we do nothing.
2662  */
2663  if (tdes->topops.last < 0 && !LOG_ISTRAN_ACTIVE (tdes) && !LOG_ISTRAN_ABORTED (tdes))
2664  {
2665  /*
2666  * We do not log anything when the transaction is unactive and it is not
2667  * in the process of aborting.
2668  */
2669  return;
2670  }
2671 
2672  node =
2673  prior_lsa_alloc_and_copy_data (thread_p, LOG_DBEXTERN_REDO_DATA, rcvindex, NULL, 0, NULL, length, (char *) data);
2674  if (node == NULL)
2675  {
2676  return;
2677  }
2678 
2679  (void) prior_lsa_next_record (thread_p, node, tdes);
2680 }
2681 
2682 /*
2683  * log_append_postpone - Log postpone after data, for redo
2684  *
2685  * return: nothing
2686  *
2687  * rcvindex(in): Index to recovery function
2688  * addr(in): Index to recovery function
2689  * length(in): Length of postpone redo(after) data
2690  * data(in): Postpone redo (after) data
2691  *
2692  * NOTE: A postpone data operation is postponed after the transaction
2693  * commits. Once it is executed, it becomes a log_redo operation.
2694  * This distinction is needed due to log sequence number in the
2695  * log and the data pages which are used to avoid redos.
2696  */
2697 void
2698 log_append_postpone (THREAD_ENTRY * thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR * addr, int length, const void *data)
2699 {
2700  LOG_TDES *tdes; /* Transaction descriptor */
2701  LOG_RCV rcv; /* Recovery structure for execution */
2702  bool skipredo;
2703  LOG_LSA *crash_lsa;
2704  int tran_index;
2705  int error_code = NO_ERROR;
2706  LOG_PRIOR_NODE *node;
2707 
2708 #if defined(CUBRID_DEBUG)
2709  if (addr->pgptr == NULL)
2710  {
2711  /*
2712  * Postpone is always an operation page level logging. Thus, a data page
2713  * pointer must have been given as part of the address
2714  */
2716  error_code = ER_LOG_POSTPONE_INTERFACE;
2717  return;
2718  }
2719  if (RV_fun[rcvindex].redofun == NULL)
2720  {
2721  assert (false);
2722  return;
2723  }
2724 #endif /* CUBRID_DEBUG */
2725 
2726  if (log_No_logging)
2727  {
2728  /*
2729  * We are not logging. Execute the postpone operation immediately since
2730  * we cannot undo
2731  */
2732  rcv.length = length;
2733  rcv.offset = addr->offset;
2734  rcv.pgptr = addr->pgptr;
2735  rcv.data = (char *) data;
2736 
2737  assert (RV_fun[rcvindex].redofun != NULL);
2738  (void) (*RV_fun[rcvindex].redofun) (thread_p, &rcv);
2739 
2741  log_skip_logging (thread_p, addr);
2742  return;
2743  }
2744 
2745  /* Find transaction descriptor for current logging transaction */
2746  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
2747  tdes = LOG_FIND_TDES (tran_index);
2748  if (tdes == NULL)
2749  {
2751  error_code = ER_LOG_UNKNOWN_TRANINDEX;
2752  return;
2753  }
2754 
2755  skipredo = log_can_skip_redo_logging (rcvindex, tdes, addr);
2756  if (skipredo == true || (tdes->topops.last < 0 && !LOG_ISTRAN_ACTIVE (tdes) && !LOG_ISTRAN_ABORTED (tdes)))
2757  {
2758  /*
2759  * Warning postpone logging is ignored during REDO recovery, normal
2760  * rollbacks, and for temporary data pages
2761  */
2762  rcv.length = length;
2763  rcv.offset = addr->offset;
2764  rcv.pgptr = addr->pgptr;
2765  rcv.data = (char *) data;
2766 
2767  assert (RV_fun[rcvindex].redofun != NULL);
2768  (void) (*RV_fun[rcvindex].redofun) (thread_p, &rcv);
2769  if (skipredo == false)
2770  {
2771  log_append_redo_data (thread_p, rcvindex, addr, length, data);
2772  }
2773 
2774  return;
2775  }
2776 
2777  /*
2778  * If the transaction has not logged any record, add a dummy record to
2779  * start the postpone purposes during the commit.
2780  */
2781 
2782  if (LSA_ISNULL (&tdes->tail_lsa)
2784  && (crash_lsa = log_get_crash_point_lsa ()) != NULL && LSA_LE (&tdes->tail_lsa, crash_lsa)))
2785  {
2787  }
2788 
2789  node = prior_lsa_alloc_and_copy_data (thread_p, LOG_POSTPONE, rcvindex, addr, 0, NULL, length, (char *) data);
2790  if (node == NULL)
2791  {
2792  return;
2793  }
2794 
2795  if (LOG_MAY_CONTAIN_USER_DATA (rcvindex))
2796  {
2798  {
2799  if (prior_set_tde_encrypted (node, rcvindex) != NO_ERROR)
2800  {
2801  assert (false);
2802  return;
2803  }
2804  }
2805  }
2806 
2807  // redo data must be saved before calling prior_lsa_next_record, which may free this prior node
2808  tdes->m_log_postpone_cache.add_redo_data (*node);
2809 
2810  // an entry for this postpone log record was already created and we also need to save its LSA
2811  LOG_LSA start_lsa = prior_lsa_next_record (thread_p, node, tdes);
2812  tdes->m_log_postpone_cache.add_lsa (start_lsa);
2813 
2814  /* Set address early in case there is a crash, because of skip_head */
2815  if (tdes->topops.last >= 0)
2816  {
2817  if (LSA_ISNULL (&tdes->topops.stack[tdes->topops.last].posp_lsa))
2818  {
2819  LSA_COPY (&tdes->topops.stack[tdes->topops.last].posp_lsa, &tdes->tail_lsa);
2820  }
2821  }
2822  else if (LSA_ISNULL (&tdes->posp_nxlsa))
2823  {
2824  LSA_COPY (&tdes->posp_nxlsa, &tdes->tail_lsa);
2825  }
2826 
2827  /*
2828  * Note: The lsa of the page is not set for postpone log records since
2829  * the change has not been done (has been postpone) to the page.
2830  */
2831 }
2832 
2833 /*
2834  * log_run_postpone - Log run redo (after) postpone data
2835  *
2836  * return: nothing
2837  *
2838  * rcvindex(in): Index to recovery function
2839  * addr(in): Address (Volume, page, and offset) of data
2840  * rcv_vpid(in):
2841  * length(in): Length of redo(after) data
2842  * data(in): Redo (after) data
2843  * ref_lsa(in): Log sequence address of original postpone record
2844  *
2845  * NOTE: Log run_redo(after) postpone data. This function is only used
2846  * when the transaction has been declared as a committed with
2847  * postpone actions. A system log record is constructed to
2848  * recover data by redoing data during recovery.
2849  *
2850  * During recovery(e.g., system crash recovery), the redo
2851  * function described by rcvindex is called with a recovery
2852  * structure which contains the page pointer and offset of the
2853  * data to recover along with the redo data. It is up to this
2854  * function how to redo the data.
2855  *
2856  * 1) The only type of logging accepted by this function is page
2857  * operation level logging, thus, an address must be given.
2858  */
2859 void
2860 log_append_run_postpone (THREAD_ENTRY * thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR * addr, const VPID * rcv_vpid,
2861  int length, const void *data, const LOG_LSA * ref_lsa)
2862 {
2863  LOG_REC_RUN_POSTPONE *run_posp; /* A run postpone record */
2864  LOG_TDES *tdes; /* Transaction descriptor */
2865  int tran_index;
2866  int error_code = NO_ERROR;
2867  LOG_PRIOR_NODE *node;
2868  LOG_LSA start_lsa;
2869 
2870  /* Find transaction descriptor for current logging transaction */
2871  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
2872  tdes = LOG_FIND_TDES (tran_index);
2873  if (tdes == NULL)
2874  {
2876  error_code = ER_LOG_UNKNOWN_TRANINDEX;
2877  return;
2878  }
2879 
2882  {
2883  /* Warning run postpone is ignored when transaction is not committed */
2884 #if defined(CUBRID_DEBUG)
2886  "log_run_postpone: Warning run postpone logging is ignored when transaction is not committed\n");
2887 #endif /* CUBRID_DEBUG */
2888  assert (false);
2889  }
2890  else
2891  {
2892  node = prior_lsa_alloc_and_copy_data (thread_p, LOG_RUN_POSTPONE, RV_NOT_DEFINED, NULL, length, (char *) data,
2893  0, NULL);
2894  if (node == NULL)
2895  {
2896  return;
2897  }
2898 
2899  /*
2900  * By the comment above for this function, all the potpone log is page-oriented,
2901  * and have to contain page address. However, code below check if addr->pgptr is NULL.
2902  * So, we also check it just in case.
2903  */
2904  if (addr->pgptr != NULL && LOG_MAY_CONTAIN_USER_DATA (rcvindex))
2905  {
2907  {
2908  if (prior_set_tde_encrypted (node, rcvindex) != NO_ERROR)
2909  {
2910  assert (false);
2911  return;
2912  }
2913  }
2914  }
2915 
2916  run_posp = (LOG_REC_RUN_POSTPONE *) node->data_header;
2917  run_posp->data.rcvindex = rcvindex;
2918  run_posp->data.pageid = rcv_vpid->pageid;
2919  run_posp->data.volid = rcv_vpid->volid;
2920  run_posp->data.offset = addr->offset;
2921  LSA_COPY (&run_posp->ref_lsa, ref_lsa);
2922  run_posp->length = length;
2923 
2924  start_lsa = prior_lsa_next_record (thread_p, node, tdes);
2925 
2926  /*
2927  * Set the LSA on the data page of the corresponding log record for page operation logging.
2928  * Make sure that I should log. Page operational logging is not done for temporary data of temporary files/volumes
2929  */
2930  if (addr->pgptr != NULL && LOG_NEED_TO_SET_LSA (rcvindex, addr->pgptr))
2931  {
2932  if (pgbuf_set_lsa (thread_p, addr->pgptr, &start_lsa) == NULL)
2933  {
2934  assert (false);
2935  return;
2936  }
2937  }
2938  }
2939 }
2940 
2941 /*
2942  * log_append_compensate - LOG COMPENSATE DATA
2943  *
2944  * return: nothing
2945  *
2946  * rcvindex(in): Index to recovery function
2947  * vpid(in): Volume-page address of compensate data
2948  * offset(in): Offset of compensate data
2949  * pgptr(in): Page pointer where compensating data resides. It may be
2950  * NULL when the page is not available during recovery.
2951  * length(in): Length of compensating data (kind of redo(after) data)
2952  * data(in): Compensating data (kind of redo(after) data)
2953  * tdes(in/out): State structure of transaction of the log record
2954  *
2955  * NOTE: Log a compensating log record. An undo performed during a
2956  * rollback or recovery is logged using what is called a
2957  * compensation log record. A compensation log record undoes the
2958  * redo of an aborted transaction during the redo phase of the
2959  * recovery process. Compensating log records are quite useful to
2960  * make system and media crash recovery faster. Compensating log
2961  * records are redo log records and thus, they are never undone.
2962  */
2963 void
2964 log_append_compensate (THREAD_ENTRY * thread_p, LOG_RCVINDEX rcvindex, const VPID * vpid, PGLENGTH offset,
2965  PAGE_PTR pgptr, int length, const void *data, LOG_TDES * tdes)
2966 {
2967  log_append_compensate_internal (thread_p, rcvindex, vpid, offset, pgptr, length, data, tdes, NULL);
2968 }
2969 
2970 /*
2971  * log_append_compensate_with_undo_nxlsa () - Append compensate log record
2972  * and overwrite its undo_nxlsa.
2973  *
2974  * return : Void.
2975  * thread_p (in) : Thread entry.
2976  * rcvindex (in) : Index to recovery function.
2977  * vpid (in) : Volume-page address of compensate data
2978  * offset(in) : Offset of compensate data
2979  * pgptr(in) : Page pointer where compensating data resides. It may be
2980  * NULL when the page is not available during recovery.
2981  * length (in) : Length of compensating data (kind of redo(after) data)
2982  * data (in) : Compensating data (kind of redo(after) data)
2983  * tdes (in/out) : State structure of transaction of the log record
2984  * undo_nxlsa (in) : Use a different undo_nxlsa than tdes->undo_nxlsa.
2985  * Necessary for cases when log records may be added before
2986  * compensation (one example being index merge/split before
2987  * undoing b-tree operation).
2988  */
2989 void
2991  PGLENGTH offset, PAGE_PTR pgptr, int length, const void *data, LOG_TDES * tdes,
2992  const LOG_LSA * undo_nxlsa)
2993 {
2994  assert (undo_nxlsa != NULL);
2995 
2996  log_append_compensate_internal (thread_p, rcvindex, vpid, offset, pgptr, length, data, tdes, undo_nxlsa);
2997 }
2998 
2999 /*
3000  * log_append_compensate - LOG COMPENSATE DATA
3001  *
3002  * return: nothing
3003  *
3004  * rcvindex(in): Index to recovery function
3005  * vpid(in): Volume-page address of compensate data
3006  * offset(in): Offset of compensate data
3007  * pgptr(in): Page pointer where compensating data resides. It may be
3008  * NULL when the page is not available during recovery.
3009  * length(in): Length of compensating data (kind of redo(after) data)
3010  * data(in): Compensating data (kind of redo(after) data)
3011  * tdes(in/out): State structure of transaction of the log record
3012  * undo_nxlsa(in): Use a different undo_nxlsa than tdes->undo_nxlsa.
3013  * Necessary for cases when log records may be added before
3014  * compensation (one example being index merge/split before
3015  * undoing b-tree operation).
3016  *
3017  * NOTE: Log a compensating log record. An undo performed during a
3018  * rollback or recovery is logged using what is called a
3019  * compensation log record. A compensation log record undoes the
3020  * redo of an aborted transaction during the redo phase of the
3021  * recovery process. Compensating log records are quite useful to
3022  * make system and media crash recovery faster. Compensating log
3023  * records are redo log records and thus, they are never undone.
3024  */
3025 static void
3026 log_append_compensate_internal (THREAD_ENTRY * thread_p, LOG_RCVINDEX rcvindex, const VPID * vpid, PGLENGTH offset,
3027  PAGE_PTR pgptr, int length, const void *data, LOG_TDES * tdes,
3028  const LOG_LSA * undo_nxlsa)
3029 {
3030  LOG_REC_COMPENSATE *compensate; /* Compensate log record */
3031  LOG_LSA prev_lsa; /* LSA of next record to undo */
3032  LOG_PRIOR_NODE *node;
3033  LOG_LSA start_lsa;
3034 
3035 #if defined(CUBRID_DEBUG)
3036  int error_code = NO_ERROR;
3037 
3038  if (vpid->volid == NULL_VOLID || vpid->pageid == NULL_PAGEID)
3039  {
3040  /*
3041  * Compensate is always an operation page level logging. Thus, a data page
3042  * pointer must have been given as part of the address
3043  */
3045  error_code = ER_LOG_COMPENSATE_INTERFACE;
3046  return;
3047  }
3048 #endif /* CUBRID_DEBUG */
3049 
3050  node =
3051  prior_lsa_alloc_and_copy_data (thread_p, LOG_COMPENSATE, rcvindex, NULL, length, (char *) data, 0, (char *) NULL);
3052  if (node == NULL)
3053  {
3054  return;
3055  }
3056 
3057  LSA_COPY (&prev_lsa, &tdes->undo_nxlsa);
3058 
3059  compensate = (LOG_REC_COMPENSATE *) node->data_header;
3060 
3061  compensate->data.rcvindex = rcvindex;
3062  compensate->data.pageid = vpid->pageid;
3063  compensate->data.offset = offset;
3064  compensate->data.volid = vpid->volid;
3065  if (undo_nxlsa != NULL)
3066  {
3067  LSA_COPY (&compensate->undo_nxlsa, undo_nxlsa);
3068  }
3069  else
3070  {
3071  LSA_COPY (&compensate->undo_nxlsa, &prev_lsa);
3072  }
3073  compensate->length = length;
3074 
3075  /*
3076  * Although compensation log is page-oriented, pgptr can be NULL
3077  * when fails to fix the page because of an error.
3078  * In this case, we don't encrypt the log and it can contain user data un-encrypted.
3079  * After all, it is very rare and exceptional case.
3080  */
3081  if (pgptr != NULL && LOG_MAY_CONTAIN_USER_DATA (rcvindex))
3082  {
3084  {
3085  if (prior_set_tde_encrypted (node, rcvindex) != NO_ERROR)
3086  {
3087  assert (false);
3088  return;
3089  }
3090  }
3091  }
3092 
3093  start_lsa = prior_lsa_next_record (thread_p, node, tdes);
3094 
3095  /*
3096  * Set the LSA on the data page of the corresponding log record for page
3097  * operation logging.
3098  * Make sure that I should log. Page operational logging is not done for
3099  * temporary data of temporary files and volumes
3100  */
3101  if (pgptr != NULL && pgbuf_set_lsa (thread_p, pgptr, &start_lsa) == NULL)
3102  {
3103  assert (false);
3104  return;
3105  }
3106 
3107  /* Go back to our undo link */
3108  LSA_COPY (&tdes->undo_nxlsa, &prev_lsa);
3109 }
3110 
3111 /*
3112  * log_append_empty_record -
3113  *
3114  * return: nothing
3115  */
3116 void
3118 {
3119  int tran_index;
3120  bool skip = false;
3121  LOG_TDES *tdes;
3122  LOG_PRIOR_NODE *node;
3123 
3124  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
3125  tdes = LOG_FIND_TDES (tran_index);
3126  if (tdes == NULL)
3127  {
3128  assert (false);
3129  return;
3130  }
3131 
3132  if (addr != NULL)
3133  {
3134  skip = log_can_skip_redo_logging (RV_NOT_DEFINED, tdes, addr);
3135  if (skip == true)
3136  {
3137  return;
3138  }
3139  }
3140 
3141  node = prior_lsa_alloc_and_copy_data (thread_p, logrec_type, RV_NOT_DEFINED, NULL, 0, NULL, 0, NULL);
3142  if (node == NULL)
3143  {
3144  return;
3145  }
3146 
3147  (void) prior_lsa_next_record (thread_p, node, tdes);
3148 }
3149 
3150 /*
3151  * log_append_ha_server_state -
3152  *
3153  * return: nothing
3154  */
3155 void
3157 {
3158  int tran_index;
3159  LOG_TDES *tdes;
3161  LOG_PRIOR_NODE *node;
3162  LOG_LSA start_lsa;
3163 
3164  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
3165  tdes = LOG_FIND_TDES (tran_index);
3166  if (tdes == NULL)
3167  {
3168  return;
3169  }
3170  assert (tdes->is_active_worker_transaction () || tdes->is_system_main_transaction ());
3171 
3173  if (node == NULL)
3174  {
3175  return;
3176  }
3177 
3178  ha_server_state = (LOG_REC_HA_SERVER_STATE *) node->data_header;
3179  memset (ha_server_state, 0, sizeof (LOG_REC_HA_SERVER_STATE));
3180 
3181  ha_server_state->state = state;
3182  ha_server_state->at_time = time (NULL);
3183 
3184  start_lsa = prior_lsa_next_record (thread_p, node, tdes);
3185 
3186  logpb_flush_pages (thread_p, &start_lsa);
3187 }
3188 
3189 /*
3190  * log_skip_logging_set_lsa - A log entry was not recorded intentionally
3191  * by the caller. set page LSA
3192  *
3193  * return: nothing
3194 *
3195  * addr(in): Address (Volume, page, and offset) of data
3196  *
3197  * NOTE: A log entry was not recorded intentionally by the caller. For
3198  * example, if the data is not accurate, the logging could be
3199  * avoided since it will be brought up to date later by the
3200  * normal execution of the database.
3201  * This function is used to avoid warning of unlogged pages.
3202  */
3203 void
3205 {
3206  assert (addr && addr->pgptr != NULL);
3207 
3208 #if defined(CUBRID_DEBUG)
3209  if (addr->pgptr == NULL)
3210  {
3212  "log_skip_logging_set_lsa: A data page pointer must"
3213  " be given as part of the address... ignored\n");
3214  return;
3215  }
3216 #endif /* CUBRID_DEBUG */
3217 
3218  /* Don't need to log */
3219 
3221 
3222  (void) pgbuf_set_lsa (thread_p, addr->pgptr, &log_Gl.prior_info.prior_lsa);
3223 
3224  log_Gl.prior_info.prior_lsa_mutex.unlock ();
3225 
3226  return;
3227 }
3228 
3229 /*
3230  * log_skip_logging - A log entry was not recorded intentionally by the
3231  * caller
3232  *
3233  * return: nothing
3234  *
3235  * addr(in): Address (Volume, page, and offset) of data
3236  *
3237  * NOTE: A log entry was not recorded intentionally by the caller. For
3238  * example, if the data is not accurate, the logging could be
3239  * avoided since it will be brought up to date later by the
3240  * normal execution of the database.
3241  * This function is used to avoid warning of unlogged pages.
3242  */
3243 void
3245 {
3246 #if 0
3247  LOG_TDES *tdes; /* Transaction descriptor */
3248  LOG_LSA *page_lsa;
3249 #if defined(SERVER_MODE)
3250  int rv;
3251 #endif /* SERVER_MODE */
3252  int tran_index;
3253  int error_code = NO_ERROR;
3254 #endif
3255 
3256 #if defined(CUBRID_DEBUG)
3257  if (addr->pgptr == NULL)
3258  {
3260  "log_skip_logging: A data page pointer must be given as part of the address... ignored\n");
3261  return;
3262  }
3263 #endif /* CUBRID_DEBUG */
3264 
3265  return;
3266 
3267 #if 0
3268  if (!pgbuf_is_lsa_temporary (addr->pgptr))
3269  {
3270  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
3271  tdes = LOG_FIND_TDES (tran_index);
3272  if (tdes == NULL)
3273  {
3275  error_code = ER_LOG_UNKNOWN_TRANINDEX;
3276  return;
3277  }
3278 
3279  /*
3280  * If the page LSA has not been changed since the lsa checkpoint record,
3281  * change it to either the checkpoint record or the restart LSA.
3282  */
3283 
3284  page_lsa = pgbuf_get_lsa (addr->pgptr);
3285 
3287  {
3288  if (LSA_GE (&log_Gl.rcv_phase_lsa, page_lsa))
3289  {
3290  LOG_LSA chkpt_lsa;
3291 
3292  rv = pthread_mutex_lock (&log_Gl.chkpt_lsa_lock);
3293  LSA_COPY (&chkpt_lsa, &log_Gl.hdr.chkpt_lsa);
3294  pthread_mutex_unlock (&log_Gl.chkpt_lsa_lock);
3295 
3296  if (LSA_GT (&chkpt_lsa, &log_Gl.rcv_phase_lsa))
3297  {
3298  (void) pgbuf_set_lsa (thread_p, addr->pgptr, &chkpt_lsa);
3299  }
3300  else
3301  {
3302  (void) pgbuf_set_lsa (thread_p, addr->pgptr, &log_Gl.rcv_phase_lsa);
3303  }
3304  }
3305  }
3306  else
3307  {
3308  /*
3309  * Likely the system is not restarted
3310  */
3311  if (LSA_GT (&tdes->tail_lsa, page_lsa))
3312  {
3313  (void) pgbuf_set_lsa (thread_p, addr->pgptr, &tdes->tail_lsa);
3314  }
3315  }
3316  }
3317 #endif
3318 }
3319 
3320 /*
3321  * log_append_savepoint - DECLARE A USER SAVEPOINT
3322  *
3323  * return: LSA
3324  *
3325  * savept_name(in): Name of the savepoint
3326  *
3327  * NOTE: A savepoint is established for the current transaction, so
3328  * that future transaction actions can be rolled back to this
3329  * established savepoint. We call this operation a partial abort
3330  * (rollback). That is, all database actions affected by the
3331  * transaction after the savepoint are undone, and all effects
3332  * of the transaction preceding the savepoint remain. The
3333  * transaction can then continue executing other database
3334  * statements. It is permissible to abort to the same savepoint
3335  * repeatedly within the same transaction.
3336  * If the same savepoint name is used in multiple savepoint
3337  * declarations within the same transaction, then only the latest
3338  * savepoint with that name is available for aborts and the
3339  * others are forgotten.
3340  * There are no limits on the number of savepoints that a
3341  * transaction can have.
3342  */
3343 LOG_LSA *
3344 log_append_savepoint (THREAD_ENTRY * thread_p, const char *savept_name)
3345 {
3346  LOG_REC_SAVEPT *savept; /* A savept log record */
3347  LOG_TDES *tdes; /* Transaction descriptor */
3348  int length; /* Length of the name of the save point */
3349  int tran_index;
3350  int error_code;
3351  LOG_PRIOR_NODE *node;
3352 
3353  /* Find transaction descriptor for current logging transaction */
3354 
3355  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
3356  tdes = LOG_FIND_TDES (tran_index);
3357  if (tdes == NULL)
3358  {
3360  error_code = ER_LOG_UNKNOWN_TRANINDEX;
3361  return NULL;
3362  }
3363  assert (tdes->is_active_worker_transaction ());
3364 
3365  if (!LOG_ISTRAN_ACTIVE (tdes))
3366  {
3367  /*
3368  * Error, a user savepoint cannot be added when the transaction is not
3369  * active
3370  */
3372  error_code = ER_LOG_CANNOT_ADD_SAVEPOINT;
3373  return NULL;
3374  }
3375 
3376  if (savept_name == NULL)
3377  {
3379  error_code = ER_LOG_NONAME_SAVEPOINT;
3380  return NULL;
3381  }
3382 
3383  length = (int) strlen (savept_name) + 1;
3384 
3385  node =
3386  prior_lsa_alloc_and_copy_data (thread_p, LOG_SAVEPOINT, RV_NOT_DEFINED, NULL, length, (char *) savept_name, 0,
3387  (char *) NULL);
3388  if (node == NULL)
3389  {
3390  return NULL;
3391  }
3392 
3393  savept = (LOG_REC_SAVEPT *) node->data_header;
3394  savept->length = length;
3395  LSA_COPY (&savept->prv_savept, &tdes->savept_lsa);
3396 
3397  (void) prior_lsa_next_record (thread_p, node, tdes);
3398 
3399  LSA_COPY (&tdes->savept_lsa, &tdes->tail_lsa);
3400 
3402 
3403  return &tdes->savept_lsa;
3404 }
3405 
3406 /*
3407  * log_find_savept_lsa - FIND LSA ADDRESS OF GIVEN SAVEPOINT
3408  *
3409  * return: savept_lsa or NULL
3410  *
3411  * savept_name(in): Name of the savept
3412  * tdes(in): State structure of transaction of the log record or NULL
3413  * when unknown
3414  * savept_lsa(in/out): Address of the savept_name
3415  *
3416  * NOTE:The LSA address of the given savept_name is found.
3417  */
3418 static LOG_LSA *
3419 log_get_savepoint_lsa (THREAD_ENTRY * thread_p, const char *savept_name, LOG_TDES * tdes, LOG_LSA * savept_lsa)
3420 {
3421  char *ptr; /* Pointer to savepoint name */
3422  char log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT], *aligned_log_pgbuf;
3423  LOG_PAGE *log_pgptr = NULL; /* Log page pointer where a savepoint log record is located */
3424  LOG_RECORD_HEADER *log_rec; /* Pointer to log record */
3425  LOG_REC_SAVEPT *savept; /* A savepoint log record */
3426  LOG_LSA prev_lsa; /* Previous savepoint */
3427  LOG_LSA log_lsa;
3428  int length; /* Length of savepoint name */
3429  bool found = false;
3430 
3431  aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
3432 
3433  /* Find the savepoint LSA, for the given savepoint name */
3434  LSA_COPY (&prev_lsa, &tdes->savept_lsa);
3435 
3436  log_pgptr = (LOG_PAGE *) aligned_log_pgbuf;
3437 
3438  while (!LSA_ISNULL (&prev_lsa) && found == false)
3439  {
3440  if (logpb_fetch_page (thread_p, &prev_lsa, LOG_CS_FORCE_USE, log_pgptr) != NO_ERROR)
3441  {
3442  break;
3443  }
3444 
3445  savept_lsa->pageid = log_lsa.pageid = prev_lsa.pageid;
3446 
3447  while (found == false && prev_lsa.pageid == log_lsa.pageid)
3448  {
3449  /* Find the savepoint record */
3450  savept_lsa->offset = log_lsa.offset = prev_lsa.offset;
3451  log_rec = LOG_GET_LOG_RECORD_HEADER (log_pgptr, &log_lsa);
3452  if (log_rec->type != LOG_SAVEPOINT && log_rec->trid != tdes->trid)
3453  {
3454  /* System error... */
3455  er_log_debug (ARG_FILE_LINE, "log_find_savept_lsa: Corrupted log rec");
3456  LSA_SET_NULL (&prev_lsa);
3457  break;
3458  }
3459 
3460  /* Advance the pointer to read the savepoint log record */
3461 
3462  LOG_READ_ADD_ALIGN (thread_p, sizeof (*log_rec), &log_lsa, log_pgptr);
3463  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*savept), &log_lsa, log_pgptr);
3464 
3465  savept = (LOG_REC_SAVEPT *) ((char *) log_pgptr->area + log_lsa.offset);
3466  LSA_COPY (&prev_lsa, &savept->prv_savept);
3467  length = savept->length;
3468 
3469  LOG_READ_ADD_ALIGN (thread_p, sizeof (*savept), &log_lsa, log_pgptr);
3470  /*
3471  * Is the name contained in only one buffer, or in several buffers
3472  */
3473 
3474  if (log_lsa.offset + length < (int) LOGAREA_SIZE)
3475  {
3476  /* Savepoint name is in one buffer */
3477  ptr = (char *) log_pgptr->area + log_lsa.offset;
3478  if (strcmp (savept_name, ptr) == 0)
3479  {
3480  found = true;
3481  }
3482  }
3483  else
3484  {
3485  /* Need to copy the data into a contiguous area */
3486  int area_offset; /* The area offset */
3487  int remains_length; /* Length of data that remains to be copied */
3488  unsigned int copy_length; /* Length to copy into area */
3489 
3490  ptr = (char *) db_private_alloc (thread_p, length);
3491  if (ptr == NULL)
3492  {
3493  LSA_SET_NULL (&prev_lsa);
3494  break;
3495  }
3496  /* Copy the name */
3497  remains_length = length;
3498  area_offset = 0;
3499  while (remains_length > 0)
3500  {
3501  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, 0, &log_lsa, log_pgptr);
3502  if (log_lsa.offset + remains_length < (int) LOGAREA_SIZE)
3503  {
3504  copy_length = remains_length;
3505  }
3506  else
3507  {
3508  copy_length = LOGAREA_SIZE - (int) (log_lsa.offset);
3509  }
3510 
3511  memcpy (ptr + area_offset, (char *) log_pgptr->area + log_lsa.offset, copy_length);
3512  remains_length -= copy_length;
3513  area_offset += copy_length;
3514  log_lsa.offset += copy_length;
3515  }
3516  if (strcmp (savept_name, ptr) == 0)
3517  {
3518  found = true;
3519  }
3520  db_private_free_and_init (thread_p, ptr);
3521  }
3522  }
3523  }
3524 
3525  if (found)
3526  {
3527  return savept_lsa;
3528  }
3529  else
3530  {
3531  LSA_SET_NULL (savept_lsa);
3532  return NULL;
3533  }
3534 }
3535 
3536 /*
3537  *
3538  * FUNCTIONS RELATED TO TERMINATION OF TRANSACTIONS AND OPERATIONS
3539  *
3540  */
3541 
3542 /*
3543  * log_sysop_end_type_string () - string for log sys op end type
3544  *
3545  * return : string for log sys op end type
3546  * end_type (in) : log sys op end type
3547  */
3548 const char *
3550 {
3551  switch (end_type)
3552  {
3553  case LOG_SYSOP_END_COMMIT:
3554  return "LOG_SYSOP_END_COMMIT";
3555  case LOG_SYSOP_END_ABORT:
3556  return "LOG_SYSOP_END_ABORT";
3558  return "LOG_SYSOP_END_LOGICAL_UNDO";
3560  return "LOG_SYSOP_END_LOGICAL_MVCC_UNDO";
3562  return "LOG_SYSOP_END_LOGICAL_COMPENSATE";
3564  return "LOG_SYSOP_END_LOGICAL_RUN_POSTPONE";
3565  default:
3566  assert (false);
3567  return "UNKNOWN LOG_SYSOP_END_TYPE";
3568  }
3569 }
3570 
3571 /*
3572  * log_sysop_start () - Start a new system operation. This can also be nested in another system operation.
3573  *
3574  * return : Error code.
3575  * thread_p (in) : Thread entry.
3576  */
3577 void
3579 {
3580  LOG_TDES *tdes = NULL;
3581  int tran_index;
3582 
3583  if (thread_p == NULL)
3584  {
3585  thread_p = thread_get_thread_entry_info ();
3586  }
3587 
3588  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
3589  tdes = LOG_FIND_TDES (tran_index);
3590  if (tdes == NULL)
3591  {
3593  return;
3594  }
3595 
3596  assert (tdes->is_allowed_sysop ());
3597 
3598  tdes->lock_topop ();
3599 
3600  /* Can current tdes.topops stack handle another system operation? */
3601  if (tdes->topops.max == 0 || (tdes->topops.last + 1) >= tdes->topops.max)
3602  {
3603  if (logtb_realloc_topops_stack (tdes, 1) == NULL)
3604  {
3605  /* Out of memory */
3606  assert (false);
3607  tdes->unlock_topop ();
3608  return;
3609  }
3610  }
3611 
3612  if (VACUUM_IS_THREAD_VACUUM (thread_p))
3613  {
3614  /* should not be in process log */
3616 
3618  "Start system operation. Current worker tdes: tdes->trid=%d, tdes->topops.last=%d, "
3619  "tdes->tail_lsa=(%lld, %d). Worker state=%d.", tdes->trid, tdes->topops.last,
3620  (long long int) tdes->tail_lsa.pageid, (int) tdes->tail_lsa.offset,
3621  vacuum_get_worker_state (thread_p));
3622  }
3623 
3624  tdes->on_sysop_start ();
3625 
3626  /* NOTE if tdes->topops.last >= 0, there is an already defined top system operation. */
3627  tdes->topops.last++;
3628  LSA_COPY (&tdes->topops.stack[tdes->topops.last].lastparent_lsa, &tdes->tail_lsa);
3629  LSA_COPY (&tdes->topop_lsa, &tdes->tail_lsa);
3630 
3631  LSA_SET_NULL (&tdes->topops.stack[tdes->topops.last].posp_lsa);
3632 
3634 }
3635 
3636 /*
3637  * log_sysop_start_atomic () - start a system operation that required to be atomic. it is aborted during recovery before
3638  * all postpones are finished.
3639  *
3640  * return : void
3641  * thread_p (in) : thread entry
3642  */
3643 void
3645 {
3646  LOG_TDES *tdes = NULL;
3647  int tran_index;
3648 
3649  log_sysop_start (thread_p);
3650  log_sysop_get_tran_index_and_tdes (thread_p, &tran_index, &tdes);
3651  if (tdes == NULL || tdes->topops.last < 0)
3652  {
3653  /* not a good context. must be in a system operation */
3654  assert_release (false);
3655  return;
3656  }
3657  if (LSA_ISNULL (&tdes->rcv.atomic_sysop_start_lsa))
3658  {
3659  LOG_PRIOR_NODE *node =
3661  if (node == NULL)
3662  {
3663  return;
3664  }
3665 
3666  (void) prior_lsa_next_record (thread_p, node, tdes);
3667  }
3668  else
3669  {
3670  /* this must be a nested atomic system operation. If parent is atomic, we'll be atomic too. */
3671  assert (tdes->topops.last > 0);
3672 
3673  /* oh, and please tell me this is not a nested system operation during postpone of system operation nested to
3674  * another atomic system operation... */
3676  }
3677 }
3678 
3679 /*
3680  * log_sysop_end_random_exit () - Random exit from system operation end functions. Used to simulate crashes.
3681  *
3682  * return : Void.
3683  * thread_p (in) : Thread entry.
3684  */
3685 STATIC_INLINE void
3687 {
3688  int mod_factor = 5000; /* 0.02% */
3689 
3691 }
3692 
3693 /*
3694  * log_sysop_end_begin () - Used at the beginning of system operation end functions. Verifies valid context and outputs
3695  * transaction index and descriptor.
3696  *
3697  * return : Void.
3698  * thread_p (in) : Thread entry.
3699  * tran_index_out (out) : Transaction index.
3700  * tdes_out (out) : Transaction descriptor.
3701  */
3702 STATIC_INLINE void
3703 log_sysop_end_begin (THREAD_ENTRY * thread_p, int *tran_index_out, LOG_TDES ** tdes_out)
3704 {
3705  log_sysop_end_random_exit (thread_p);
3706 
3707  log_sysop_get_tran_index_and_tdes (thread_p, tran_index_out, tdes_out);
3708  if ((*tdes_out) != NULL && (*tdes_out)->topops.last < 0)
3709  {
3710  assert (false);
3712  *tdes_out = NULL;
3713  return;
3714  }
3715 }
3716 
3717 /*
3718  * log_sysop_end_unstack () - Used for ending system operations, removes last sysop from transaction descriptor's stack.
3719  *
3720  * return : Void.
3721  * thread_p (in) : Thread entry.
3722  * tdes (in/out) : Transaction descriptor.
3723  */
3724 STATIC_INLINE void
3726 {
3727  tdes->topops.last--;
3728  if (tdes->topops.last >= 0)
3729  {
3730  LSA_COPY (&tdes->topop_lsa, &LOG_TDES_LAST_SYSOP (tdes)->lastparent_lsa);
3731  }
3732  else
3733  {
3734  LSA_SET_NULL (&tdes->topop_lsa);
3735  }
3736 }
3737 
3738 /*
3739  * log_sysop_end_final () - Used to complete a system operation at the end of system operation end functions.
3740  *
3741  * return : Void.
3742  * thread_p (in) : Thread entry.
3743  * tdes (in/out) : Transaction descriptor.
3744  */
3745 STATIC_INLINE void
3747 {
3748  int r = NO_ERROR;
3749 
3750  log_sysop_end_unstack (thread_p, tdes);
3751 
3752  tdes->unlock_topop ();
3753 
3755 
3756  if (VACUUM_IS_THREAD_VACUUM (thread_p) && tdes->topops.last < 0)
3757  {
3760  "Ended all top operations. Tdes: tdes->trid=%d tdes->head_lsa=(%lld, %d), "
3761  "tdes->tail_lsa=(%lld, %d), tdes->undo_nxlsa=(%lld, %d), "
3762  "tdes->tail_topresult_lsa=(%lld, %d). Worker state=%d.", tdes->trid,
3763  (long long int) tdes->head_lsa.pageid, (int) tdes->head_lsa.offset,
3764  (long long int) tdes->tail_lsa.pageid, (int) tdes->tail_lsa.offset,
3765  (long long int) tdes->undo_nxlsa.pageid, (int) tdes->undo_nxlsa.offset,
3766  (long long int) tdes->tail_topresult_lsa.pageid, (int) tdes->tail_topresult_lsa.offset,
3767  vacuum_get_worker_state (thread_p));
3768  }
3769  tdes->on_sysop_end ();
3770 
3771  log_sysop_end_random_exit (thread_p);
3772 
3773  if (LOG_ISCHECKPOINT_TIME ())
3774  {
3775 #if defined(SERVER_MODE)
3777 #else /* SERVER_MODE */
3778  if (!tdes->is_under_sysop ())
3779  {
3780  (void) logpb_checkpoint (thread_p);
3781  }
3782  else
3783  {
3784  // not safe to do a checkpoint in the middle of a system operations; for instance, tdes is cleared after
3785  // checkpoint
3786  }
3787 #endif /* SERVER_MODE */
3788  }
3789 }
3790 
3791 /*
3792  * log_sysop_commit_internal () - Commit system operation. This can be used just to guarantee atomicity or permanence of
3793  * all changes in system operation. Or it can be extended to also act as an undo,
3794  * compensate or run postpone log record. The type is decided using log_record argument.
3795  *
3796  * return : Void.
3797  * thread_p (in) : Thread entry.
3798  * log_record (in) : All information that are required to build the log record for commit system operation.
3799  * data_size (in) : recovery data size
3800  * data (in) : recovery data
3801  * is_rv_finish_postpone (in) : true if this is called during recovery to finish a system op postpone
3802  */
3803 void
3804 log_sysop_commit_internal (THREAD_ENTRY * thread_p, LOG_REC_SYSOP_END * log_record, int data_size, const char *data,
3805  bool is_rv_finish_postpone)
3806 {
3807  int tran_index;
3808  LOG_TDES *tdes = NULL;
3809 
3810  assert (log_record != NULL);
3811  assert (log_record->type != LOG_SYSOP_END_ABORT);
3812 
3813  log_sysop_end_begin (thread_p, &tran_index, &tdes);
3814  if (tdes == NULL)
3815  {
3816  assert_release (false);
3817  return;
3818  }
3819 
3820  if ((LSA_ISNULL (&tdes->tail_lsa) || LSA_LE (&tdes->tail_lsa, LOG_TDES_LAST_SYSOP_PARENT_LSA (tdes)))
3821  && log_record->type == LOG_SYSOP_END_COMMIT)
3822  {
3823  /* No change. */
3824  assert (LSA_ISNULL (&LOG_TDES_LAST_SYSOP (tdes)->posp_lsa));
3825  }
3826  else
3827  {
3828  /* we are here because either system operation is not empty, or this is the end of a logical system operation.
3829  * we don't actually allow empty logical system operation because it might hide a logic flaw. however, there are
3830  * unusual cases when a logical operation does not really require logging (see RVPGBUF_FLUSH_PAGE). if you create
3831  * such a case, you should add a dummy log record to trick this assert. */
3832  assert (!LSA_ISNULL (&tdes->tail_lsa) && LSA_GT (&tdes->tail_lsa, LOG_TDES_LAST_SYSOP_PARENT_LSA (tdes)));
3833 
3834  /* now that we have access to tdes, we can do some updates on log record and sanity checks */
3835  if (log_record->type == LOG_SYSOP_END_LOGICAL_RUN_POSTPONE)
3836  {
3837  /* only allowed for postpones */
3840 
3841  /* this is relevant for proper recovery */
3842  log_record->run_postpone.is_sysop_postpone =
3843  (tdes->state == TRAN_UNACTIVE_TOPOPE_COMMITTED_WITH_POSTPONE && !is_rv_finish_postpone);
3844  }
3845  else if (log_record->type == LOG_SYSOP_END_LOGICAL_COMPENSATE)
3846  {
3847  /* we should be doing rollback or undo recovery */
3849  || (is_rv_finish_postpone && (tdes->state == TRAN_UNACTIVE_TOPOPE_COMMITTED_WITH_POSTPONE
3851  }
3852  else if (log_record->type == LOG_SYSOP_END_LOGICAL_UNDO || log_record->type == LOG_SYSOP_END_LOGICAL_MVCC_UNDO)
3853  {
3854  /* ... no restrictions I can think of */
3855  }
3856  else
3857  {
3858  assert (log_record->type == LOG_SYSOP_END_COMMIT);
3860  && (tdes->state != TRAN_UNACTIVE_TOPOPE_COMMITTED_WITH_POSTPONE || is_rv_finish_postpone));
3861  }
3862 
3863  if (!LOG_CHECK_LOG_APPLIER (thread_p) && tdes->is_active_worker_transaction ()
3864  && log_does_allow_replication () == true)
3865  {
3866  /* for the replication agent guarantee the order of transaction */
3867  /* for CC(Click Counter) : at here */
3868  log_append_repl_info (thread_p, tdes, false);
3869  }
3870 
3871  log_record->lastparent_lsa = *LOG_TDES_LAST_SYSOP_PARENT_LSA (tdes);
3872  log_record->prv_topresult_lsa = tdes->tail_topresult_lsa;
3873 
3874  /* do postpone */
3875  log_sysop_do_postpone (thread_p, tdes, log_record, data_size, data);
3876 
3877  /* log system operation end */
3878  log_append_sysop_end (thread_p, tdes, log_record, data_size, data);
3879 
3880  /* Remember last partial result */
3881  LSA_COPY (&tdes->tail_topresult_lsa, &tdes->tail_lsa);
3882  }
3883 
3884  log_sysop_end_final (thread_p, tdes);
3885 }
3886 
3887 /*
3888  * log_sysop_commit () - Commit system operation. This is the default type to end a system operation successfully and
3889  * to guarantee atomicity/permanency of all its operations.
3890  *
3891  * return : Void.
3892  * thread_p (in) : Thread entry.
3893  */
3894 void
3896 {
3897  LOG_REC_SYSOP_END log_record;
3898 
3899  log_record.type = LOG_SYSOP_END_COMMIT;
3900 
3901  log_sysop_commit_internal (thread_p, &log_record, 0, NULL, false);
3902 }
3903 
3904 /*
3905  * log_sysop_end_logical_undo () - Commit system operation and add an undo log record. This is a logical undo for complex
3906  * operations that cannot be easily located when rollback or recovery undo is executed.
3907  *
3908  * return : Void.
3909  * thread_p (in) : Thread entry.
3910  * rcvindex (in) : Recovery index for undo operation.
3911  * vfid (in) : NULL or file identifier. Must be not NULL for mvcc operations.
3912  * undo_size (in) : Undo data size.
3913  * undo_data (in) : Undo data.
3914  *
3915  * note: sys ops used for logical undo have a limitation: they cannot use postpone log records. this limitation can
3916  * be changed if needed by extending sys op start postpone log record to support undo data. so far, the extension
3917  * was not necessary.
3918  */
3919 void
3920 log_sysop_end_logical_undo (THREAD_ENTRY * thread_p, LOG_RCVINDEX rcvindex, const VFID * vfid, int undo_size,
3921  const char *undo_data)
3922 {
3923  LOG_REC_SYSOP_END log_record;
3924 
3925  assert (rcvindex != RV_NOT_DEFINED);
3926 
3927  if (LOG_IS_MVCC_OPERATION (rcvindex))
3928  {
3930  log_record.mvcc_undo.undo.data.offset = NULL_OFFSET;
3931  log_record.mvcc_undo.undo.data.volid = NULL_VOLID;
3932  log_record.mvcc_undo.undo.data.pageid = NULL_PAGEID;
3933  log_record.mvcc_undo.undo.data.rcvindex = rcvindex;
3934  log_record.mvcc_undo.undo.length = undo_size;
3935  log_record.mvcc_undo.mvccid = logtb_get_current_mvccid (thread_p);
3936  log_record.mvcc_undo.vacuum_info.vfid = *vfid;
3938  }
3939  else
3940  {
3941  log_record.type = LOG_SYSOP_END_LOGICAL_UNDO;
3942  log_record.undo.data.offset = NULL_OFFSET;
3943  log_record.undo.data.volid = NULL_VOLID;
3944  log_record.undo.data.pageid = NULL_PAGEID;
3945  log_record.undo.data.rcvindex = rcvindex;
3946  log_record.undo.length = undo_size;
3947  }
3948  assert (LOG_MAY_CONTAIN_USER_DATA (rcvindex) ? vfid != NULL : true);
3949  log_record.vfid = vfid;
3950 
3951  log_sysop_commit_internal (thread_p, &log_record, undo_size, undo_data, false);
3952 }
3953 
3954 /*
3955  * log_sysop_commit_and_compensate () - Commit system operation and add a compensate log record. This is a logical
3956  * compensation that is too complex to be included in a single log record.
3957  *
3958  * return : Void.
3959  * thread_p (in) : Thread entry.
3960  * undo_nxlsa (in) : LSA of next undo LSA (equivalent to compensated undo record previous LSA).
3961  */
3962 void
3964 {
3965  LOG_REC_SYSOP_END log_record;
3966 
3968  log_record.compensate_lsa = *undo_nxlsa;
3969 
3970  log_sysop_commit_internal (thread_p, &log_record, 0, NULL, false);
3971 }
3972 
3973 /*
3974  * log_sysop_end_logical_run_postpone () - Commit system operation and add a run postpone log record. This is a logical
3975  * run postpone that is too complex to be included in a single log record.
3976  *
3977  * return : Void.
3978  * thread_p (in) : Thread entry.
3979  * posp_lsa (in) : The LSA of postpone record which was executed by this run postpone.
3980  */
3981 void
3983 {
3984  LOG_REC_SYSOP_END log_record;
3985 
3987  log_record.run_postpone.postpone_lsa = *posp_lsa;
3988  /* is_sysop_postpone will be set in log_sysop_commit_internal */
3989 
3990  log_sysop_commit_internal (thread_p, &log_record, 0, NULL, false);
3991 }
3992 
3993 /*
3994  * log_sysop_end_recovery_postpone () - called during recovery to finish the postpone phase of system op
3995  *
3996  * return : void
3997  * thread_p (in) : thread entry
3998  * log_record (in) : end system op log record as it was read from start postpone log record
3999  * data_size (in) : undo data size
4000  * data (in) : undo data
4001  */
4002 void
4003 log_sysop_end_recovery_postpone (THREAD_ENTRY * thread_p, LOG_REC_SYSOP_END * log_record, int data_size,
4004  const char *data)
4005 {
4006  log_sysop_commit_internal (thread_p, log_record, data_size, data, true);
4007 }
4008 
4009 /*
4010  * log_sysop_abort () - Abort sytem operations (usually due to errors). All changes in this system operation are
4011  * rollbacked.
4012  *
4013  * return : Void.
4014  * thread_p (in) : Thread entry.
4015  */
4016 void
4018 {
4019  int tran_index;
4020  LOG_TDES *tdes = NULL;
4021  LOG_REC_SYSOP_END sysop_end;
4022 
4023  log_sysop_end_begin (thread_p, &tran_index, &tdes);
4024  if (tdes == NULL)
4025  {
4026  assert_release (false);
4027  return;
4028  }
4029 
4030  if (LSA_ISNULL (&tdes->tail_lsa) || LSA_LE (&tdes->tail_lsa, &LOG_TDES_LAST_SYSOP (tdes)->lastparent_lsa))
4031  {
4032  /* No change. */
4033  }
4034  else
4035  {
4036  TRAN_STATE save_state;
4037 
4038  if (!LOG_CHECK_LOG_APPLIER (thread_p) && tdes->is_active_worker_transaction ()
4039  && log_does_allow_replication () == true)
4040  {
4041  repl_log_abort_after_lsa (tdes, LOG_TDES_LAST_SYSOP_PARENT_LSA (tdes));
4042  }
4043 
4044  /* Abort changes in system op. */
4045  save_state = tdes->state;
4046  tdes->state = TRAN_UNACTIVE_ABORTED;
4047 
4048  /* Rollback changes. */
4049  log_rollback (thread_p, tdes, LOG_TDES_LAST_SYSOP_PARENT_LSA (tdes));
4051 
4052  /* Log abort system operation. */
4053  sysop_end.type = LOG_SYSOP_END_ABORT;
4054  sysop_end.lastparent_lsa = *LOG_TDES_LAST_SYSOP_PARENT_LSA (tdes);
4055  sysop_end.prv_topresult_lsa = tdes->tail_topresult_lsa;
4056  log_append_sysop_end (thread_p, tdes, &sysop_end, 0, NULL);
4057 
4058  /* Remember last partial result */
4059  LSA_COPY (&tdes->tail_topresult_lsa, &tdes->tail_lsa);
4060 
4061  /* Restore transaction state. */
4062  tdes->state = save_state;
4063  }
4064 
4065  log_sysop_end_final (thread_p, tdes);
4066 }
4067 
4068 /*
4069  * log_sysop_attach_to_outer () - Attach system operation to its immediate parent (another system operation or, if this
4070  * is top system operation, to transaction descriptor).
4071  *
4072  * return : Void.
4073  * thread_p (in) : Thread entry.
4074  */
4075 void
4077 {
4078  int tran_index;
4079  LOG_TDES *tdes = NULL;
4080 
4081  log_sysop_end_begin (thread_p, &tran_index, &tdes);
4082  if (tdes == NULL)
4083  {
4084  assert_release (false);
4085  return;
4086  }
4087 
4088  /* Is attach to outer allowed? */
4089  if (tdes->topops.last == 0 && (!LOG_ISTRAN_ACTIVE (tdes) || tdes->is_system_transaction ()))
4090  {
4091  /* Nothing to attach to. Be conservative and commit the transaction. */
4092  assert_release (false);
4093  log_sysop_commit (thread_p);
4094  return;
4095  }
4096 
4097  /* Attach to outer: transfer postpone LSA. Not much to do really :) */
4098  if (tdes->topops.last - 1 >= 0)
4099  {
4100  if (LSA_ISNULL (&tdes->topops.stack[tdes->topops.last - 1].posp_lsa))
4101  {
4102  LSA_COPY (&tdes->topops.stack[tdes->topops.last - 1].posp_lsa,
4103  &tdes->topops.stack[tdes->topops.last].posp_lsa);
4104  }
4105  }
4106  else
4107  {
4108  if (LSA_ISNULL (&tdes->posp_nxlsa))
4109  {
4110  LSA_COPY (&tdes->posp_nxlsa, &tdes->topops.stack[tdes->topops.last].posp_lsa);
4111  }
4112  }
4113 
4114  log_sysop_end_final (thread_p, tdes);
4115 }
4116 
4117 /*
4118  * log_sysop_get_level () - Get current system operation level. If no system operation is started, it returns -1.
4119  *
4120  * return : System op level
4121  * thread_p (in) : Thread entry
4122  */
4123 STATIC_INLINE int
4125 {
4126  int tran_index;
4127  LOG_TDES *tdes = NULL;
4128 
4129  log_sysop_get_tran_index_and_tdes (thread_p, &tran_index, &tdes);
4130  if (tdes == NULL)
4131  {
4132  assert_release (false);
4133  return -1;
4134  }
4135  return tdes->topops.last;
4136 }
4137 
4138 /*
4139  * log_sysop_get_tran_index_and_tdes () - Get transaction descriptor for system operations (in case of VACUUM, it will
4140  * return the thread special tdes instead of system tdes).
4141  *
4142  * return : Void
4143  * thread_p (in) : Thread entry
4144  * tran_index_out (out) : Transaction index
4145  * tdes_out (out) : Transaction descriptor
4146  */
4147 STATIC_INLINE void
4148 log_sysop_get_tran_index_and_tdes (THREAD_ENTRY * thread_p, int *tran_index_out, LOG_TDES ** tdes_out)
4149 {
4150  *tran_index_out = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
4151  *tdes_out = LOG_FIND_TDES (*tran_index_out);
4152  if (*tdes_out == NULL)
4153  {
4154  assert_release (false);
4155  return;
4156  }
4157 }
4158 
4159 /*
4160  * log_check_system_op_is_started () - Check system op is started.
4161  *
4162  * return : Error code.
4163  * thread_p (in) : Thread entry.
4164  */
4165 bool
4167 {
4168  LOG_TDES *tdes; /* Transaction descriptor */
4169  int tran_index;
4170 
4171  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
4172  tdes = LOG_FIND_TDES (tran_index);
4173  if (tdes == NULL)
4174  {
4175  assert_release (false);
4176  return false;
4177  }
4178 
4179  if (!LOG_IS_SYSTEM_OP_STARTED (tdes))
4180  {
4181  assert_release (false);
4182  return false;
4183  }
4184 
4185  return true;
4186 }
4187 
4188 /*
4189  * log_get_parent_lsa_system_op - Get parent lsa of top operation
4190  *
4191  * return: lsa of parent or NULL
4192  *
4193  * parent_lsa(in/out): The topop LSA for current top operation
4194  *
4195  * NOTE: Find the address of the parent of top operation.
4196  */
4197 LOG_LSA *
4199 {
4200  LOG_TDES *tdes; /* Transaction descriptor */
4201  int tran_index;
4202  int error_code = NO_ERROR;
4203 
4204  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
4205  tdes = LOG_FIND_TDES (tran_index);
4206  if (tdes == NULL)
4207  {
4209  error_code = ER_LOG_UNKNOWN_TRANINDEX;
4210  return NULL;
4211  }
4212 
4213  if (tdes->topops.last < 0)
4214  {
4215  LSA_SET_NULL (parent_lsa);
4216  return NULL;
4217  }
4218 
4219  LSA_COPY (parent_lsa, &tdes->topops.stack[tdes->topops.last].lastparent_lsa);
4220 
4221  return parent_lsa;
4222 }
4223 
4224 /*
4225  * log_is_tran_in_system_op - Find if current transaction is doing a top nested
4226  * system operation
4227  *
4228  * return:
4229  *
4230  * NOTE: Find if the current transaction is doing a top nested system
4231  * operation.
4232  */
4233 bool
4235 {
4236  LOG_TDES *tdes; /* Transaction descriptor */
4237  int tran_index;
4238  int error_code = NO_ERROR;
4239 
4240  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
4241  tdes = LOG_FIND_TDES (tran_index);
4242  if (tdes == NULL)
4243  {
4245  error_code = ER_LOG_UNKNOWN_TRANINDEX;
4246  return false;
4247  }
4248 
4249  if (tdes->topops.last < 0 && LSA_ISNULL (&tdes->savept_lsa))
4250  {
4251  return false;
4252  }
4253  else
4254  {
4255  return true;
4256  }
4257 }
4258 
4259 /*
4260  * log_can_skip_undo_logging - Is it safe to skip undo logging for given file ?
4261  *
4262  * return:
4263  *
4264  * rcvindex(in): Index to recovery function
4265  * tdes(in):
4266  * addr(in):
4267  *
4268  * NOTE: Find if it is safe to skip undo logging for data related to given file.
4269  * Some rcvindex values should never be skipped.
4270  */
4271 static bool
4272 log_can_skip_undo_logging (THREAD_ENTRY * thread_p, LOG_RCVINDEX rcvindex, const LOG_TDES * tdes, LOG_DATA_ADDR * addr)
4273 {
4274  /*
4275  * Some log record types (rcvindex) should never be skipped.
4276  * In the case of LINK_PERM_VOLEXT, the link of a permanent temp volume must be logged to support media failures.
4277  * See also log_can_skip_redo_logging.
4278  */
4279  if (LOG_ISUNSAFE_TO_SKIP_RCVINDEX (rcvindex))
4280  {
4281  return false;
4282  }
4283 
4284  if (tdes->is_system_worker_transaction () && !tdes->is_under_sysop ())
4285  {
4286  /* If vacuum worker has not started a system operation, it can skip using undo logging. */
4287  // note - maybe it is better to add an assert (false)?
4288  return true;
4289  }
4290 
4291  /*
4292  * Operation level undo can be skipped on temporary pages. For example, those of temporary files.
4293  * No-operational level undo (i.e., logical logging) can be skipped for temporary files.
4294  */
4295  if (addr->pgptr != NULL && pgbuf_is_lsa_temporary (addr->pgptr) == true)
4296  {
4297  /* why do we log temporary files */
4298  assert (false);
4299  return true;
4300  }
4301 
4302  if (addr->vfid == NULL || VFID_ISNULL (addr->vfid))
4303  {
4304  return false;
4305  }
4306 
4307  return false;
4308 }
4309 
4310 /*
4311  * log_can_skip_redo_logging - Is it safe to skip redo logging for given file ?
4312  *
4313  * return:
4314  *
4315  * rcvindex(in): Index to recovery function
4316  * ignore_tdes(in):
4317  * addr(in): Address (Volume, page, and offset) of data
4318  *
4319  * NOTE: Find if it is safe to skip redo logging for data related to given file.
4320  * Redo logging can be skip on any temporary page. For example, pages of temporary files on any volume.
4321  * Some rcvindex values should never be skipped.
4322  */
4323 static bool
4324 log_can_skip_redo_logging (LOG_RCVINDEX rcvindex, const LOG_TDES * ignore_tdes, LOG_DATA_ADDR * addr)
4325 {
4326  /*
4327  * Some log record types (rcvindex) should never be skipped.
4328  * In the case of LINK_PERM_VOLEXT, the link of a permanent temp volume must be logged to support media failures.
4329  * See also log_can_skip_undo_logging.
4330  */
4331  if (LOG_ISUNSAFE_TO_SKIP_RCVINDEX (rcvindex))
4332  {
4333  return false;
4334  }
4335 
4336  /*
4337  * Operation level redo can be skipped on temporary pages. For example, those of temporary files
4338  */
4339  if (addr->pgptr != NULL && pgbuf_is_lsa_temporary (addr->pgptr) == true)
4340  {
4341  return true;
4342  }
4343  else
4344  {
4345  return false;
4346  }
4347 }
4348 
4349 /*
4350  * log_append_commit_postpone - APPEND COMMIT WITH POSTPONE
4351  *
4352  * return: nothing
4353  *
4354  * tdes(in/out): State structure of transaction being committed
4355  * start_posplsa(in): Address where the first postpone log record start
4356  *
4357  * NOTE: The transaction is declared as committed with postpone actions.
4358  * The transaction is not fully committed until all postpone actions are executed.
4359  *
4360  * The postpone operations are not invoked by this function.
4361  */
4362 static void
4363 log_append_commit_postpone (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_LSA * start_postpone_lsa)
4364 {
4365  LOG_REC_START_POSTPONE *start_posp; /* Start postpone actions */
4366  LOG_PRIOR_NODE *node;
4367  LOG_LSA start_lsa;
4368 
4370  if (node == NULL)
4371  {
4372  return;
4373  }
4374 
4375  start_posp = (LOG_REC_START_POSTPONE *) node->data_header;
4376  LSA_COPY (&start_posp->posp_lsa, start_postpone_lsa);
4377 
4378  start_lsa = prior_lsa_next_record (thread_p, node, tdes);
4379 
4381 
4382  logpb_flush_pages (thread_p, &start_lsa);
4383 }
4384 
4385 /*
4386  * log_append_sysop_start_postpone () - append a log record when system op starts postpone.
4387  *
4388  * return : void
4389  * thread_p (in) : thread entry
4390  * tdes (in) : transaction descriptor
4391  * sysop_start_postpone (in) : start postpone log record
4392  * data_size (in) : undo data size
4393  * data (in) : undo data
4394  */
4395 static void
4397  LOG_REC_SYSOP_START_POSTPONE * sysop_start_postpone, int data_size, const char *data)
4398 {
4399  LOG_PRIOR_NODE *node;
4400 
4401  node =
4402  prior_lsa_alloc_and_copy_data (thread_p, LOG_SYSOP_START_POSTPONE, RV_NOT_DEFINED, NULL, data_size, (char *) data,
4403  0, NULL);
4404  if (node == NULL)
4405  {
4406  return;
4407  }
4408 
4409  *(LOG_REC_SYSOP_START_POSTPONE *) node->data_header = *sysop_start_postpone;
4410  (void) prior_lsa_next_record (thread_p, node, tdes);
4411 }
4412 
4413 /*
4414  * log_append_sysop_end () - append sys op end log record
4415  *
4416  * return : void
4417  * thread_p (in) : thread entry
4418  * tdes (in) : transaction descriptor
4419  * sysop_end (in) : sys op end log record
4420  * data_size (in) : data size
4421  * data (in) : recovery data
4422  */
4423 static void
4424 log_append_sysop_end (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_REC_SYSOP_END * sysop_end, int data_size,
4425  const char *data)
4426 {
4427  LOG_PRIOR_NODE *node = NULL;
4428 
4429  assert (tdes != NULL);
4430  assert (sysop_end != NULL);
4431  assert (data_size == 0 || data != NULL);
4432 
4433  node = prior_lsa_alloc_and_copy_data (thread_p, LOG_SYSOP_END, RV_NOT_DEFINED, NULL, data_size, data, 0, NULL);
4434  if (node == NULL)
4435  {
4436  /* Is this possible? */
4437  assert (false);
4438  }
4439  else
4440  {
4441  LOG_RCVINDEX rcvindex = RV_NOT_DEFINED;
4442  /* Save data head. */
4443  /* First save lastparent_lsa and prv_topresult_lsa. */
4444  LOG_LSA start_lsa = LSA_INITIALIZER;
4445 
4446  memcpy (node->data_header, sysop_end, node->data_header_length);
4447 
4448  if (sysop_end->type == LOG_SYSOP_END_LOGICAL_UNDO)
4449  {
4450  rcvindex = sysop_end->undo.data.rcvindex;
4451  }
4452  else if (sysop_end->type == LOG_SYSOP_END_LOGICAL_MVCC_UNDO)
4453  {
4454  rcvindex = sysop_end->mvcc_undo.undo.data.rcvindex;
4455  }
4456 
4457  if (LOG_MAY_CONTAIN_USER_DATA (rcvindex))
4458  {
4459  /* Some cases of logical undo */
4460  TDE_ALGORITHM tde_algo = TDE_ALGORITHM_NONE;
4461 
4462  assert (sysop_end->vfid != NULL);
4463  if (file_get_tde_algorithm (thread_p, sysop_end->vfid, PGBUF_CONDITIONAL_LATCH, &tde_algo) != NO_ERROR)
4464  {
4465  tde_algo = TDE_ALGORITHM_NONE;
4466  /* skip to encrypt in release */
4467  }
4468  if (tde_algo != TDE_ALGORITHM_NONE)
4469  {
4470  if (prior_set_tde_encrypted (node, rcvindex) != NO_ERROR)
4471  {
4472  assert (false);
4473  return;
4474  }
4475  }
4476  }
4477 
4478  start_lsa = prior_lsa_next_record (thread_p, node, tdes);
4479  assert (!LSA_ISNULL (&start_lsa));
4480  }
4481 }
4482 
4483 /*
4484  * log_append_repl_info_internal - APPEND REPLICATION LOG RECORD
4485  *
4486  * return: nothing
4487  *
4488  * thread_p(in):
4489  * tdes(in): State structure of transaction being committed/aborted.
4490  * is_commit(in):
4491  * with_lock(in):
4492  *
4493  * NOTE:critical section is set by its caller function.
4494  */
4495 static void
4496 log_append_repl_info_internal (THREAD_ENTRY * thread_p, LOG_TDES * tdes, bool is_commit, int with_lock)
4497 {
4498  LOG_REPL_RECORD *repl_rec;
4499  LOG_REC_REPLICATION *log;
4500  LOG_PRIOR_NODE *node;
4501 
4502  if (tdes->append_repl_recidx == -1 /* the first time */
4503  || is_commit)
4504  {
4505  tdes->append_repl_recidx = 0;
4506  }
4507 
4508  /* there is any replication info */
4509  while (tdes->append_repl_recidx < tdes->cur_repl_record)
4510  {
4511  repl_rec = (LOG_REPL_RECORD *) (&(tdes->repl_records[tdes->append_repl_recidx]));
4512 
4513  if ((repl_rec->repl_type == LOG_REPLICATION_DATA || repl_rec->repl_type == LOG_REPLICATION_STATEMENT)
4514  && ((is_commit && repl_rec->must_flush != LOG_REPL_DONT_NEED_FLUSH)
4515  || repl_rec->must_flush == LOG_REPL_NEED_FLUSH))
4516  {
4517  node =
4518  prior_lsa_alloc_and_copy_data (thread_p, repl_rec->repl_type, RV_NOT_DEFINED, NULL, repl_rec->length,
4519  repl_rec->repl_data, 0, NULL);
4520  if (node == NULL)
4521  {
4522  assert (false);
4523  continue;
4524  }
4525 
4526  if (repl_rec->tde_encrypted)
4527  {
4528  if (prior_set_tde_encrypted (node, repl_rec->rcvindex) != NO_ERROR)
4529  {
4530  assert (false);
4531  continue;
4532  }
4533  }
4534 
4535  log = (LOG_REC_REPLICATION *) node->data_header;
4536  if (repl_rec->rcvindex == RVREPL_DATA_DELETE || repl_rec->rcvindex == RVREPL_STATEMENT)
4537  {
4538  LSA_SET_NULL (&log->lsa);
4539  }
4540  else
4541  {
4542  LSA_COPY (&log->lsa, &repl_rec->lsa);
4543  }
4544  log->length = repl_rec->length;
4545  log->rcvindex = repl_rec->rcvindex;
4546 
4547  if (with_lock == LOG_PRIOR_LSA_WITH_LOCK)
4548  {
4549  (void) prior_lsa_next_record_with_lock (thread_p, node, tdes);
4550  }
4551  else
4552  {
4553  (void) prior_lsa_next_record (thread_p, node, tdes);
4554  }
4555 
4556  repl_rec->must_flush = LOG_REPL_DONT_NEED_FLUSH;
4557  }
4558 
4559  tdes->append_repl_recidx++;
4560  }
4561 }
4562 
4563 void
4564 log_append_repl_info (THREAD_ENTRY * thread_p, LOG_TDES * tdes, bool is_commit)
4565 {
4566  log_append_repl_info_internal (thread_p, tdes, is_commit, LOG_PRIOR_LSA_WITHOUT_LOCK);
4567 }
4568 
4569 static void
4570 log_append_repl_info_with_lock (THREAD_ENTRY * thread_p, LOG_TDES * tdes, bool is_commit)
4571 {
4572  log_append_repl_info_internal (thread_p, tdes, is_commit, LOG_PRIOR_LSA_WITH_LOCK);
4573 }
4574 
4575 /*
4576  * log_append_repl_info_and_commit_log - append repl log along with commit log.
4577  *
4578  * return: none
4579  *
4580  * tdes(in):
4581  * commit_lsa(out): LSA of commit log
4582  *
4583  * NOTE: Atomic write of replication log and commit log is crucial for replication consistencies.
4584  * When a commit log of others is written in the middle of one's replication and commit log,
4585  * a restart of replication will break consistencies of slaves/replicas.
4586  */
4587 static void
4589 {
4591 
4592  log_append_repl_info_with_lock (thread_p, tdes, true);
4593  log_append_commit_log_with_lock (thread_p, tdes, commit_lsa);
4594 
4595  log_Gl.prior_info.prior_lsa_mutex.unlock ();
4596 }
4597 
4598 /*
4599  * log_append_donetime_internal - APPEND COMMIT/ABORT LOG RECORD ALONG WITH TIME OF TERMINATION.
4600  *
4601  * return: none
4602  *
4603  * tdes(in):
4604  * eot_lsa(out): LSA of COMMIT/ABORT log
4605  * iscommitted(in): Is transaction been finished as committed?
4606  * with_lock(in): whether it has mutex or not.
4607  *
4608  * NOTE: a commit or abort record is recorded along with the current time as the termination time of the transaction.
4609  */
4610 static void
4611 log_append_donetime_internal (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_LSA * eot_lsa, LOG_RECTYPE iscommitted,
4612  enum LOG_PRIOR_LSA_LOCK with_lock)
4613 {
4614  LOG_REC_DONETIME *donetime;
4615  LOG_PRIOR_NODE *node;
4616  LOG_LSA lsa;
4617 
4618  eot_lsa->pageid = NULL_PAGEID;
4619  eot_lsa->offset = NULL_OFFSET;
4620 
4621  node = prior_lsa_alloc_and_copy_data (thread_p, iscommitted, RV_NOT_DEFINED, NULL, 0, NULL, 0, NULL);
4622  if (node == NULL)
4623  {
4624  /* FIXME */
4625  return;
4626  }
4627 
4628  donetime = (LOG_REC_DONETIME *) node->data_header;
4629  donetime->at_time = time (NULL);
4630 
4631  if (with_lock == LOG_PRIOR_LSA_WITH_LOCK)
4632  {
4633  lsa = prior_lsa_next_record_with_lock (thread_p, node, tdes);
4634  }
4635  else
4636  {
4637  lsa = prior_lsa_next_record (thread_p, node, tdes);
4638  }
4639 
4640  LSA_COPY (eot_lsa, &lsa);
4641 }
4642 
4643 /*
4644  * log_change_tran_as_completed - change the state of a transaction as committed/aborted
4645  *
4646  * return: nothing
4647  *
4648  * tdes(in/out): State structure of transaction being committed/aborted.
4649  * iscommitted(in): Is transaction been finished as committed ?
4650  * lsa(in): commit lsa to flush logs
4651  *
4652  */
4653 static void
4655 {
4656  if (iscommitted == LOG_COMMIT)
4657  {
4659 
4661 
4662  logpb_flush_pages (thread_p, lsa);
4663  }
4664  else
4665  {
4666  tdes->state = TRAN_UNACTIVE_ABORTED;
4667 
4668 #if defined(SERVER_MODE)
4669  // [TODO] Here is an argument: committers are waiting for flush. Then, why not aborters?
4670  // The current fix minimizes potential impacts but it may miss some other cases.
4671  // I think it might be better to remove the condition and let aborters also wait for flush.
4672  // Maybe in the next milestone.
4674  {
4675  /* Flush the log in case that checkpoint is started. Otherwise, the current transaction
4676  * may finish, but its LOG_ABORT not flushed yet. The checkpoint can advance with smallest
4677  * LSA. Also, VACUUM can finalize cleaning. So, the archive may be removed. If the server crashes,
4678  * at recovery, the current transaction must be aborted. But, some of its log records are in
4679  * the archive that was previously removed => crash. Fixed, by forcing log flush before ending.
4680  */
4681  logpb_flush_pages (thread_p, lsa);
4682  }
4683 #endif
4684  }
4685 
4686 #if !defined (NDEBUG)
4688  {
4689  char time_val[CTIME_MAX];
4690  time_t xxtime = time (NULL);
4691 
4692  (void) ctime_r (&xxtime, time_val);
4693  fprintf (stdout,
4696  tdes->tran_index, tdes->trid, log_Gl.hdr.append_lsa.pageid, log_Gl.hdr.append_lsa.offset, time_val);
4697  fflush (stdout);
4698  }
4699 #endif /* !NDEBUG */
4700 }
4701 
4702 /*
4703  * log_append_commit_log - append commit log record along with time of termination.
4704  *
4705  * return: nothing
4706  *
4707  * tdes(in/out): State structure of transaction being committed.
4708  * commit_lsa(out): LSA of commit log.
4709  */
4710 static void
4711 log_append_commit_log (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_LSA * commit_lsa)
4712 {
4714 }
4715 
4716 /*
4717  * log_append_commit_log_with_lock - append commit log record along with time of termination with prior lsa mutex.
4718  *
4719  * return: none
4720  *
4721  * tdes(in/out): State structure of transaction being committed.
4722  * commit_lsa(out): LSA of commit log.
4723  */
4724 static void
4726 {
4727  log_append_donetime_internal (thread_p, tdes, commit_lsa, LOG_COMMIT, LOG_PRIOR_LSA_WITH_LOCK);
4728 }
4729 
4730 /*
4731  * log_append_abort_log - append abort log record along with time of termination
4732  *
4733  * return: nothing
4734  *
4735  * tdes(in/out): State structure of transaction being aborted.
4736  * abort_lsa(out): LSA of abort log.
4737  */
4738 static void
4739 log_append_abort_log (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_LSA * abort_lsa)
4740 {
4742 }
4743 
4744 /*
4745  * log_add_to_modified_class_list -
4746  *
4747  * return:
4748  *
4749  * classname(in):
4750  * class_oid(in):
4751  *
4752  * NOTE: Function for LOG_TDES.modified_class_list
4753  * This list keeps the following information:
4754  * {name, OID} of modified class and LSA for the last modification
4755  */
4756 int
4757 log_add_to_modified_class_list (THREAD_ENTRY * thread_p, const char *classname, const OID * class_oid)
4758 {
4759  LOG_TDES *tdes;
4760  int tran_index;
4761 
4762  assert (classname != NULL);
4763  assert (class_oid != NULL);
4764  assert (!OID_ISNULL (class_oid));
4765  assert (class_oid->volid >= 0); /* is not temp_oid */
4766 
4767  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
4768  tdes = LOG_FIND_TDES (tran_index);
4769  if (tdes == NULL)
4770  {
4771  return ER_FAILED;
4772  }
4773 
4774  tdes->m_modified_classes.add (classname, *class_oid, tdes->tail_lsa);
4775  return NO_ERROR;
4776 }
4777 
4778 /*
4779  * log_is_class_being_modified () - check if a class is being modified by the transaction which is executed by the
4780  * thread parameter
4781  * return : true if the class is being modified, false otherwise
4782  * thread_p (in) : thread entry
4783  * class_oid (in) : class identifier
4784  */
4785 bool
4786 log_is_class_being_modified (THREAD_ENTRY * thread_p, const OID * class_oid)
4787 {
4788  LOG_TDES *tdes;
4789  int tran_index;
4790 
4791  assert (class_oid != NULL);
4792  assert (!OID_ISNULL (class_oid));
4793  assert (class_oid->volid >= 0); /* is not temp_oid */
4794 
4795  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
4796  tdes = LOG_FIND_TDES (tran_index);
4797 
4798  if (tdes == NULL)
4799  {
4800  /* this is an error but this is not the place for handling it */
4801  return false;
4802  }
4803 
4804  return tdes->m_modified_classes.has_class (*class_oid);
4805 }
4806 
4807 /*
4808  * log_cleanup_modified_class -
4809  *
4810  * return:
4811  *
4812  * t(in):
4813  * arg(in):
4814  *
4815  * NOTE: Function for LOG_TDES.modified_class_list
4816  * This will be used to decache the class representations and XASLs when a transaction is finished.
4817  */
4818 static void
4820 {
4822 
4823  /* decache this class from the partitions cache also */
4824  (void) partition_decache_class (thread_p, &t.m_class_oid);
4825 
4826  /* remove XASL cache entries which are relevant with this class */
4827  xcache_remove_by_oid (thread_p, &t.m_class_oid);
4828  /* remove filter predicate cache entries which are relevant with this class */
4829  fpcache_remove_by_class (thread_p, &t.m_class_oid);
4830 }
4831 
4832 extern int locator_drop_transient_class_name_entries (THREAD_ENTRY * thread_p, LOG_LSA * savep_lsa);
4833 
4834 /*
4835  * log_cleanup_modified_class_list -
4836  *
4837  * return:
4838  *
4839  * tdes(in):
4840  * savept_lsa(in): savepoint lsa to rollback
4841  * bool(in): release the memory or not
4842  * decache_classrepr(in): decache the class representation or not
4843  *
4844  * NOTE: Function for LOG_TDES.modified_class_list
4845  */
4846 static void
4847 log_cleanup_modified_class_list (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_LSA * savept_lsa, bool release,
4848  bool decache_classrepr)
4849 {
4850  if (decache_classrepr)
4851  {
4852  // decache heap representations
4853  tdes->m_modified_classes.decache_heap_repr (savept_lsa != NULL ? *savept_lsa : NULL_LSA);
4854  }
4856 
4857  /* always execute for defense */
4858  (void) locator_drop_transient_class_name_entries (thread_p, savept_lsa);
4859 
4860  if (release)
4861  {
4862  tdes->m_modified_classes.clear ();
4863  }
4864 }
4865 
4866 /*
4867  * log_commit_local - Perform the local commit operations of a transaction
4868  *
4869  * return: state of commit operation
4870  *
4871  * tdes(in/out): State structure of transaction of the log record
4872  * retain_lock(in): false = release locks (default)
4873  * true = retain locks
4874  * is_local_tran(in): Is a local transaction?
4875  *
4876  * NOTE: Commit the current transaction locally. If there are postpone actions, the transaction is declared
4877  * committed_with_postpone_actions by logging a log record indicating this state. Then, the postpone actions
4878  * are executed. When the transaction is declared as fully committed, the locks acquired by the transaction
4879  * are released. A committed transaction is not subject to deadlock when postpone operations are executed.
4880  * The function returns the state of the transaction(i.e. whether it is completely committed or not).
4881  */
4882 TRAN_STATE
4883 log_commit_local (THREAD_ENTRY * thread_p, LOG_TDES * tdes, bool retain_lock, bool is_local_tran)
4884 {
4885  qmgr_clear_trans_wakeup (thread_p, tdes->tran_index, false, false);
4886 
4887  /* tx_lob_locator_clear and logtb_complete_mvcc operations must be done before entering unactive state because
4888  * they do some logging. We must NOT log (or do other regular changes to the database) after the transaction enters
4889  * the unactive state because of the following scenario: 1. enter TRAN_UNACTIVE_WILL_COMMIT state 2. a checkpoint
4890  * occurs and finishes. All active transactions are saved in log including their state. Our transaction will be saved
4891  * with TRAN_UNACTIVE_WILL_COMMIT state. 3. a crash occurs before our logging. Here, for example in case of unique
4892  * statistics, we will lost logging of unique statistics. 4. A recovery will occur. Because our transaction was saved
4893  * at checkpoint with TRAN_UNACTIVE_WILL_COMMIT state, it will be committed. Because we didn't logged the changes
4894  * made by the transaction we will not reflect the changes. They will be definitely lost. */
4895  tx_lob_locator_clear (thread_p, tdes, true, NULL);
4896 
4897  /* clear mvccid before releasing the locks. This operation must be done before do_postpone because it stores unique
4898  * statistics for all B-trees and if an error occurs those operations and all operations of current transaction must
4899  * be rolled back. */
4900  logtb_complete_mvcc (thread_p, tdes, true);
4901 
4903  /* undo_nxlsa is no longer required here and must be reset, in case checkpoint takes a snapshot of this transaction
4904  * during TRAN_UNACTIVE_WILL_COMMIT phase.
4905  */
4906  LSA_SET_NULL (&tdes->undo_nxlsa);
4907 
4908  /* destroy all transaction's remaining temporary files */
4910 
4911  if (!LSA_ISNULL (&tdes->tail_lsa))
4912  {
4913  /*
4914  * Transaction updated data.
4915  */
4916 
4917  log_tran_do_postpone (thread_p, tdes);
4918 
4919  /* The files created by this transaction are not new files any longer. Close any query cursors at this moment
4920  * too. */
4921  if (tdes->first_save_entry != NULL)
4922  {
4923  spage_free_saved_spaces (thread_p, tdes->first_save_entry);
4924  tdes->first_save_entry = NULL;
4925  }
4926 
4927  log_cleanup_modified_class_list (thread_p, tdes, NULL, true, false);
4928 
4929  if (is_local_tran)
4930  {
4931  LOG_LSA commit_lsa;
4932 
4933  /* To write unlock log before releasing locks for transactional consistencies. When a transaction(T2) which
4934  * is resumed by this committing transaction(T1) commits and a crash happens before T1 completes, transaction
4935  * consistencies will be broken because T1 will be aborted during restart recovery and T2 was already
4936  * committed. */
4937  if (!LOG_CHECK_LOG_APPLIER (thread_p) && tdes->is_active_worker_transaction ()
4938  && log_does_allow_replication () == true)
4939  {
4940  /* for the replication agent guarantee the order of transaction */
4941  log_append_repl_info_and_commit_log (thread_p, tdes, &commit_lsa);
4942  }
4943  else
4944  {
4945  log_append_commit_log (thread_p, tdes, &commit_lsa);
4946  }
4947 
4948  if (retain_lock != true)
4949  {
4950  lock_unlock_all (thread_p);
4951  }
4952 
4953  /* Flush commit log and change the transaction state. */
4954  log_change_tran_as_completed (thread_p, tdes, LOG_COMMIT, &commit_lsa);
4955  }
4956  else
4957  {
4958  /* Postpone appending replication and commit log and releasing locks to log_complete_for_2pc. */
4959  }
4960  }
4961  else
4962  {
4963  /*
4964  * Transaction did not update anything or we are not logging
4965  */
4966 
4967  /*
4968  * We are not logging, and changes were done
4969  */
4970  if (tdes->first_save_entry != NULL)
4971  {
4972  spage_free_saved_spaces (thread_p, tdes->first_save_entry);
4973  tdes->first_save_entry = NULL;
4974  }
4975 
4976  if (retain_lock != true)
4977  {
4978  lock_unlock_all (thread_p);
4979  }
4980 
4982  }
4983 
4984  return tdes->state;
4985 }
4986 
4987 /*
4988  * log_abort_local - Perform the local abort operations of a transaction
4989  *
4990  * return: state of abort operation
4991  *
4992  * tdes(in/out): State structure of transaction of the log record
4993  * is_local_tran(in): Is a local transaction? (It is not used at this point)
4994  *
4995  * NOTE: Abort the current transaction locally.
4996  * When the transaction is declared as fully aborted, the locks acquired by the transaction are released and
4997  * query cursors are closed.
4998  * This function is used for both local and coordinator transactions.
4999  */
5000 TRAN_STATE
5001 log_abort_local (THREAD_ENTRY * thread_p, LOG_TDES * tdes, bool is_local_tran)
5002 {
5003  qmgr_clear_trans_wakeup (thread_p, tdes->tran_index, false, true);
5004 
5005  tdes->state = TRAN_UNACTIVE_ABORTED;
5006 
5007  /* destroy transaction's temporary files */
5009 
5010  if (!LSA_ISNULL (&tdes->tail_lsa))
5011  {
5012  /*
5013  * Transaction updated data.
5014  */
5015 
5016  log_rollback (thread_p, tdes, NULL);
5017 
5019 
5020  log_cleanup_modified_class_list (thread_p, tdes, NULL, true, true);
5021 
5022  if (tdes->first_save_entry != NULL)
5023  {
5024  spage_free_saved_spaces (thread_p, tdes->first_save_entry);
5025  tdes->first_save_entry = NULL;
5026  }
5027 
5028  /* clear mvccid before releasing the locks */
5029  logtb_complete_mvcc (thread_p, tdes, false);
5030 
5031  /* It is safe to release locks here, since we already completed abort. */
5032  lock_unlock_all (thread_p);
5033  }
5034  else
5035  {
5036  /*
5037  * Transaction did not update anything or we are not logging
5038  */
5039 
5040  if (tdes->first_save_entry != NULL)
5041  {
5042  spage_free_saved_spaces (thread_p, tdes->first_save_entry);
5043  tdes->first_save_entry = NULL;
5044  }
5045 
5046  /* clear mvccid before releasing the locks */
5047  logtb_complete_mvcc (thread_p, tdes, false);
5048 
5049  lock_unlock_all (thread_p);
5050 
5051  /* There is no need to create a new transaction identifier */
5052  }
5053 
5054  tx_lob_locator_clear (thread_p, tdes, false, NULL);
5055 
5056  return tdes->state;
5057 }
5058 
5059 /*
5060  * log_commit - COMMIT A TRANSACTION
5061  *
5062  * return: state of commit operation
5063  *
5064  * tran_index(in): tran_index
5065  * retain_lock(in): false = release locks (default)
5066  * true = retain locks
5067  *
5068  * NOTE: Commit the current transaction. The function returns the
5069  * state of the transaction (i.e., notify if the transaction
5070  * is completely commited or not). If the transaction was
5071  * coordinating a global transaction then the Two Phase Commit
5072  * protocol is followed by this function. Otherwise, only the
5073  * local commit actions are performed.
5074  */
5075 TRAN_STATE
5076 log_commit (THREAD_ENTRY * thread_p, int tran_index, bool retain_lock)
5077 {
5078  TRAN_STATE state; /* State of committed transaction */
5079  LOG_TDES *tdes; /* Transaction descriptor */
5080  bool decision;
5081  LOG_2PC_EXECUTE execute_2pc_type;
5082  int error_code = NO_ERROR;
5083 
5084  if (tran_index == NULL_TRAN_INDEX)
5085  {
5086  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
5087  }
5088 
5089  tdes = LOG_FIND_TDES (tran_index);
5090  if (tdes == NULL)
5091  {
5093  error_code = ER_LOG_UNKNOWN_TRANINDEX;
5094  return TRAN_UNACTIVE_UNKNOWN;
5095  }
5096  assert (!tdes->is_system_worker_transaction ());
5097 
5098  if (!LOG_ISTRAN_ACTIVE (tdes) && !LOG_ISTRAN_2PC_PREPARE (tdes) && LOG_ISRESTARTED ())
5099  {
5100  /* May be a system error since transaction is not active.. cannot be committed */
5101 #if defined(CUBRID_DEBUG)
5103  "log_commit: Transaction %d (index = %d) is"
5104  " not active and cannot be committed. Its state is %s\n", tdes->trid, tdes->tran_index,
5105  log_state_string (tdes->state));
5106 #endif /* CUBRID_DEBUG */
5107  return tdes->state;
5108  }
5109 
5110  if (tdes->topops.last >= 0)
5111  {
5112  /* This is likely a system error since the transaction is being committed when there are system permanent
5113  * operations attached to it. Commit those operations too */
5115  tdes->tran_index);
5116  assert (false);
5117  while (tdes->topops.last >= 0)
5118  {
5119  log_sysop_attach_to_outer (thread_p);
5120  }
5121  }
5122 
5123  tdes->m_multiupd_stats.clear ();
5124 
5126  {
5127  /* This is the coordinator of a distributed transaction If we are in prepare to commit mode. I cannot be the
5128  * root coordinator, so the decision has been taken at this moment by the root coordinator */
5129  if (LOG_ISTRAN_2PC_PREPARE (tdes))
5130  {
5131  execute_2pc_type = LOG_2PC_EXECUTE_COMMIT_DECISION;
5132  }
5133  else
5134  {
5135  execute_2pc_type = LOG_2PC_EXECUTE_FULL;
5136  }
5137 
5138  state = log_2pc_commit (thread_p, tdes, execute_2pc_type, &decision);
5139  }
5140  else
5141  {
5142  /*
5143  * This is a local transaction or is a participant of a distributed transaction
5144  */
5145  state = log_commit_local (thread_p, tdes, retain_lock, true);
5147  }
5148 
5149  if (log_No_logging)
5150  {
5151  LOG_CS_ENTER (thread_p);
5152  /* We are not logging */
5153  logpb_flush_pages_direct (thread_p);
5154  (void) pgbuf_flush_all_unfixed (thread_p, NULL_VOLID);
5156  {
5157  /*
5158  * Indicate that logging has not been ignored for next transaction
5159  */
5161  logpb_flush_header (thread_p);
5162  }
5163  LOG_CS_EXIT (thread_p);
5164  }
5165 
5167 
5168  return state;
5169 }
5170 
5171 /*
5172  * log_abort - ABORT A TRANSACTION
5173  *
5174  * return: TRAN_STATE
5175  *
5176  * tran_index(in): tran_index
5177  *
5178  * NOTE: Abort the current transaction. If the transaction is the
5179  * coordinator of a global transaction, the participants are also
5180  * informed about the abort, and if necessary their
5181  * acknowledgements are collected before finishing the
5182  * transaction.
5183  */
5184 TRAN_STATE
5185 log_abort (THREAD_ENTRY * thread_p, int tran_index)
5186 {
5187  TRAN_STATE state; /* State of aborted transaction */
5188  LOG_TDES *tdes; /* Transaction descriptor */
5189  bool decision;
5190  int error_code = NO_ERROR;
5191 
5192  if (tran_index == NULL_TRAN_INDEX)
5193  {
5194  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
5195  }
5196 
5197  tdes = LOG_FIND_TDES (tran_index);
5198  if (tdes == NULL)
5199  {
5201  error_code = ER_LOG_UNKNOWN_TRANINDEX;
5202  return TRAN_UNACTIVE_UNKNOWN;
5203  }
5204  assert (!tdes->is_system_worker_transaction ());
5205 
5207  {
5209  error_code = ER_LOG_CORRUPTED_DB_DUE_NOLOGGING;
5210  return tdes->state;
5211  }
5212 
5213  if (!LOG_ISTRAN_ACTIVE (tdes) && !LOG_ISTRAN_2PC_PREPARE (tdes))
5214  {
5215  /*
5216  * May be a system error: Transaction is not in an active state nor
5217  * prepare to commit state
5218  */
5219  return tdes->state;
5220  }
5221 
5222  if (tdes->topops.last >= 0)
5223  {
5224  /*
5225  * This is likely a system error since the transaction is being aborted
5226  * when there are system permananet operations attached to it. Abort those
5227  * operations too.
5228  */
5230  tdes->tran_index);
5231  assert (false);
5232  while (tdes->topops.last >= 0)
5233  {
5234  log_sysop_attach_to_outer (thread_p);
5235  }
5236  }
5237 
5238  tdes->m_multiupd_stats.clear ();
5239 
5240  /*
5241  * If we are in prepare to commit mode. I cannot be the root coodinator,
5242  * so the decision has already been taken at this moment by the root
5243  * coordinator. If a distributed transaction is not in 2PC, the decision
5244  * has been taken without using the 2PC.
5245  */
5246 
5248  {
5249  /* This is the coordinator of a distributed transaction */
5250  state = log_2pc_commit (thread_p, tdes, LOG_2PC_EXECUTE_ABORT_DECISION, &decision);
5251  }
5252  else
5253  {
5254  /*
5255  * This is a local transaction or is a participant of a distributed transaction.
5256  * Perform the server rollback first.
5257  */
5258  state = log_abort_local (thread_p, tdes, true);
5260  }
5261 
5263 
5264  return state;
5265 }
5266 
5267 /*
5268  * log_abort_partial - ABORT ACTIONS OF A TRANSACTION TO A SAVEPOINT
5269  *
5270  * return: state of partial aborted operation.
5271  *
5272  * savepoint_name(in): Name of the savepoint
5273  * savept_lsa(in):
5274  *
5275  * NOTE: All the effects done by the current transaction after the
5276  * given savepoint are undone and all effects of the transaction
5277  * preceding the given savepoint remain. After the partial abort
5278  * the transaction can continue its normal execution as if
5279  * the statements that were undone were never executed.
5280  */
5281 TRAN_STATE
5282 log_abort_partial (THREAD_ENTRY * thread_p, const char *savepoint_name, LOG_LSA * savept_lsa)
5283 {
5284  LOG_TDES *tdes; /* Transaction descriptor */
5285  int tran_index;
5286 
5287  /* Find current transaction descriptor */
5288  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
5289  tdes = LOG_FIND_TDES (tran_index);
5290  if (tdes == NULL)
5291  {
5293  return TRAN_UNACTIVE_UNKNOWN;
5294  }
5295 
5297  {
5299  return tdes->state;
5300  }
5301 
5302  if (!LOG_ISTRAN_ACTIVE (tdes))
5303  {
5304  /*
5305  * May be a system error: Transaction is not in an active state
5306  */
5307  return tdes->state;
5308  }
5309 
5310  if (savepoint_name == NULL || log_get_savepoint_lsa (thread_p, savepoint_name, tdes, savept_lsa) == NULL)
5311  {
5313  return TRAN_UNACTIVE_UNKNOWN;
5314  }
5315 
5316  if (tdes->topops.last >= 0)
5317  {
5318  /*
5319  * This is likely a system error since the transaction is being partially
5320  * aborted when there are nested top system permanent operations
5321  * attached to it. Abort those operations too.
5322  */
5324  tdes->tran_index);
5325  assert (false);
5326  while (tdes->topops.last >= 0)
5327  {
5328  log_sysop_attach_to_outer (thread_p);
5329  }
5330  }
5331 
5332  log_sysop_start (thread_p);
5333 
5334  LSA_COPY (&tdes->topops.stack[tdes->topops.last].lastparent_lsa, savept_lsa);
5335 
5336  if (!LSA_ISNULL (&tdes->posp_nxlsa))
5337  {
5338  if (LSA_LT (savept_lsa, &tdes->posp_nxlsa))
5339  {
5340  LSA_COPY (&tdes->topops.stack[tdes->topops.last].posp_lsa, &tdes->posp_nxlsa);
5341  LSA_SET_NULL (&tdes->posp_nxlsa);
5342  }
5343  else
5344  {
5345  LSA_COPY (&tdes->topops.stack[tdes->topops.last].posp_lsa, savept_lsa);
5346  }
5347  }
5348 
5349  log_sysop_abort (thread_p);
5350 
5351  log_cleanup_modified_class_list (thread_p, tdes, savept_lsa, false, true);
5352 
5353  tx_lob_locator_clear (thread_p, tdes, false, savept_lsa);
5354 
5355  /*
5356  * The following is done so that if we go over several savepoints, they
5357  * get undefined and cannot get call by the user any longer.
5358  */
5359  LSA_COPY (&tdes->savept_lsa, savept_lsa);
5360  return TRAN_UNACTIVE_ABORTED;
5361 }
5362 
5363 /*
5364  * log_complete - Complete in commit/abort mode the transaction whenever
5365  * is possible otherwise trasfer it to another tran index
5366  *
5367  * return: state of transaction
5368  *
5369  * tdes(in/out): State structure of transaction of the log record
5370  * iscommitted(in): Is transaction been finished as committed ?
5371  * get_newtrid(in):
5372  *
5373  * NOTE: This function does not consider 2PC.
5374  * Find the existing function as log_complete_for_2pc
5375  */
5376 TRAN_STATE
5377 log_complete (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_RECTYPE iscommitted, LOG_GETNEWTRID get_newtrid,
5378  LOG_WRITE_EOT_LOG wrote_eot_log)
5379 {
5380  TRAN_STATE state; /* State of transaction */
5381 
5382  assert (iscommitted == LOG_COMMIT || iscommitted == LOG_ABORT);
5383  assert (!tdes->is_system_worker_transaction ());
5384 
5385  state = tdes->state;
5386 
5387  /*
5388  * DECLARE THE TRANSACTION AS COMPLETED
5389  */
5390 
5391  if (LSA_ISNULL (&tdes->tail_lsa))
5392  {
5393  /* Transaction did not update any data, thus we do not need to log a commit/abort log record. */
5394  if (iscommitted == LOG_COMMIT)
5395  {
5396  state = TRAN_UNACTIVE_COMMITTED;
5397  }
5398  else
5399  {
5400  state = TRAN_UNACTIVE_ABORTED;
5401  }
5402 
5403  logtb_clear_tdes (thread_p, tdes);
5404  }
5405  else
5406  {
5407  /*
5408  * Transaction updated data
5409  */
5410  if (wrote_eot_log == LOG_NEED_TO_WRITE_EOT_LOG)
5411  {
5412  if (iscommitted == LOG_COMMIT)
5413  {
5414  LOG_LSA commit_lsa;
5415 
5416  log_append_commit_log (thread_p, tdes, &commit_lsa);
5417  log_change_tran_as_completed (thread_p, tdes, LOG_COMMIT, &commit_lsa);
5418  }
5419  else
5420  {
5421  LOG_LSA abort_lsa;
5422 
5423  log_append_abort_log (thread_p, tdes, &abort_lsa);
5424  log_change_tran_as_completed (thread_p, tdes, LOG_ABORT, &abort_lsa);
5425  }
5426 
5427  state = tdes->state;
5428  }
5429  else
5430  {
5431  assert (iscommitted == LOG_COMMIT && state == TRAN_UNACTIVE_COMMITTED);
5432  }
5433 
5434  /* Unblock global oldest active update. */
5435  tdes->unlock_global_oldest_visible_mvccid ();
5436 
5437  if (iscommitted == LOG_COMMIT)
5438  {
5440  }
5441 
5442  if (get_newtrid == LOG_NEED_NEWTRID)
5443  {
5444  (void) logtb_get_new_tran_id (thread_p, tdes);
5445  }
5446 
5447  /* Finish the append operation and flush the log */
5448  }
5449 
5450  if (LOG_ISCHECKPOINT_TIME ())
5451  {
5452 #if defined(SERVER_MODE)
5454 #else /* SERVER_MODE */
5455  (void) logpb_checkpoint (thread_p);
5456 #endif /* SERVER_MODE */
5457  }
5458 
5459  return state;
5460 }
5461 
5462 /*
5463  * log_complete_for_2pc - Complete in commit/abort mode the transaction whenever
5464  * is possible otherwise trasfer it to another tran index
5465  *
5466  * return: state of transaction
5467  *
5468  * tdes(in/out): State structure of transaction of the log record
5469  * iscommitted(in): Is transaction been finished as committed ?
5470  * get_newtrid(in):
5471  *
5472  */
5473 TRAN_STATE
5474 log_complete_for_2pc (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_RECTYPE iscommitted, LOG_GETNEWTRID get_newtrid)
5475 {
5476  TRAN_STATE state; /* State of transaction */
5477  int new_tran_index;
5478  LOG_TDES *new_tdes; /* New transaction descriptor when the transaction is transfered since the 2PC cannot
5479  * be fully completed at this moment */
5480  int return_2pc_loose_tranindex; /* Whether or not to return the current index */
5481  bool all_acks = true;
5482  int i;
5483  LOG_PRIOR_NODE *node;
5484  LOG_LSA start_lsa;
5485  int wait_msecs;
5486 
5487  assert (iscommitted == LOG_COMMIT || iscommitted == LOG_ABORT);
5488  assert (!tdes->is_system_worker_transaction ());
5489 
5490  state = tdes->state;
5491 
5492  if (tdes->coord != NULL && tdes->coord->ack_received != NULL)
5493  {
5494  /*
5495  * Make sure that all acknowledgments from participants have been received
5496  * before declaring the transaction as finished.
5497  */
5498  for (i = 0; i < tdes->coord->num_particps; i++)
5499  {
5500  if (tdes->coord->ack_received[i] == false)
5501  {
5502  all_acks = false;
5503  /*
5504  * There are missing acknowledgments. The transaction cannot be
5505  * completed at this moment. If we are not in the restart recovery
5506  * process, the transaction is transfered to another transaction
5507  * index which is declared as a distributed loose end and a new
5508  * transaction is assigned to the client transaction index. The
5509  * transaction will be declared as fully completed once all
5510  * acknowledgment are received.
5511  */
5512  if (iscommitted != LOG_ABORT)
5513  {
5514  /* Committed */
5516  {
5517  node =
5519  0, NULL, 0, NULL);
5520  if (node == NULL)
5521  {
5522  assert (false);
5523  return state;
5524  }
5525 
5527  state = tdes->state;
5528 
5529  start_lsa = prior_lsa_next_record (thread_p, node, tdes);
5530 
5531  logpb_flush_pages (thread_p, &start_lsa);
5532  }
5533  }
5534  else
5535  {
5536  /* aborted */
5538  {
5539  node =
5541  NULL, 0, NULL);
5542  if (node == NULL)
5543  {
5544  assert (false);
5545  return state;
5546  }
5547 
5549  state = tdes->state;
5550 
5551  start_lsa = prior_lsa_next_record (thread_p, node, tdes);
5552 
5553  logpb_flush_pages (thread_p, &start_lsa);
5554  }
5555  }
5556  /*
5557  * If this is not a loose end transaction and the system is not
5558  * in restart recovery, transfer the transaction to another
5559  * transaction index
5560  */
5561  if (LOG_ISRESTARTED () && tdes->isloose_end == false)
5562  {
5564 
5565  if (wait_msecs > 0)
5566  {
5567  wait_msecs = wait_msecs * 1000;
5568  }
5569  new_tran_index =
5570  logtb_assign_tran_index (thread_p, NULL_TRANID, TRAN_RECOVERY, NULL, NULL, wait_msecs,
5572  new_tdes = LOG_FIND_TDES (new_tran_index);
5573  if (new_tran_index == NULL_TRAN_INDEX || new_tdes == NULL)
5574  {
5575  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_fully_completed");
5576  return state;
5577  }
5578 
5579  /*
5580  * Copy of tdes structures, and then reset memory allocated fields
5581  * for only one the new or the old one.
5582  */
5583 
5584  // todo - this is completely unsafe.
5585  memcpy (new_tdes, tdes, sizeof (*tdes));
5586  new_tdes->tran_index = new_tran_index;
5587  new_tdes->isloose_end = true;
5588  /* new_tdes does not inherit topops fields */
5589  new_tdes->topops.stack = NULL;
5590  new_tdes->topops.last = -1;
5591  new_tdes->topops.max = 0;
5592 
5593  /* The old one keep the coordinator/participant information */
5594  tdes->coord = NULL;
5595 
5596  TR_TABLE_CS_ENTER (thread_p);
5598  TR_TABLE_CS_EXIT (thread_p);
5599  /*
5600  * Start a new transaction for our original transaction index.
5601  * Set the coordinator stuff to NULL, in our original index since
5602  * it has been transfer to another index. That is, distributed
5603  * information should be freed using the new transaction index.
5604  */
5605 
5606  /*
5607  * Go back to the old index
5608  */
5609 
5610  LOG_SET_CURRENT_TRAN_INDEX (thread_p, tdes->tran_index);
5611 
5612  (void) logtb_get_new_tran_id (thread_p, tdes);
5613  }
5614 
5615  if (LOG_ISCHECKPOINT_TIME ())
5616  {
5617 #if defined(SERVER_MODE)
5619 #else /* SERVER_MODE */
5620  (void) logpb_checkpoint (thread_p);
5621 #endif /* SERVER_MODE */
5622  }
5623 
5624  return state;
5625  }
5626  }
5627 
5628  /*
5629  * All acknowledgments of participants have been received, declare the
5630  * the transaction as completed
5631  */
5632  }
5633 
5634  /*
5635  * DECLARE THE TRANSACTION AS COMPLETED
5636  */
5637 
5638  /*
5639  * Check if this index needs to be returned after finishing the transaction
5640  */
5641 
5642  if (tdes->isloose_end == true && all_acks == true)
5643  {
5644  return_2pc_loose_tranindex = true;
5645  }
5646  else
5647  {
5648  return_2pc_loose_tranindex = false;
5649  }
5650 
5651  if (LSA_ISNULL (&tdes->tail_lsa))
5652  {
5653  /*
5654  * Transaction did not update any data, thus we do not need to log a
5655  * commit/abort log record
5656  */
5657  if (iscommitted != LOG_ABORT)
5658  {
5659  state = TRAN_UNACTIVE_COMMITTED;
5660  }
5661  else
5662  {
5663  state = TRAN_UNACTIVE_ABORTED;
5664  }
5665 #if !defined(NDEBUG)
5667  {
5668  char time_val[CTIME_MAX];
5669  time_t xxtime = time (NULL);
5670 
5671  (void) ctime_r (&xxtime, time_val);
5672  fprintf (stdout,
5675  tdes->tran_index, tdes->trid, log_Gl.hdr.append_lsa.pageid, log_Gl.hdr.append_lsa.offset, time_val);
5676  fflush (stdout);
5677  }
5678 #endif /* !NDEBUG */
5679  logtb_clear_tdes (thread_p, tdes);
5680  }
5681  else
5682  {
5683  /*
5684  * Transaction updated data or this is a coordinator
5685  */
5686  if (iscommitted == LOG_COMMIT)
5687  {
5688  LOG_LSA commit_lsa;
5689 
5690  /* To write unlock log before releasing locks for transactional consistencies. When a transaction(T2) which
5691  * is resumed by this committing transaction(T1) commits and a crash happens before T1 completes, transaction
5692  * * consistencies will be broken because T1 will be aborted during restart recovery and T2 was already
5693  * committed. */
5694  if (!LOG_CHECK_LOG_APPLIER (thread_p) && log_does_allow_replication () == true)
5695  {
5696  log_append_repl_info_and_commit_log (thread_p, tdes, &commit_lsa);
5697  }
5698  else
5699  {
5700  log_append_commit_log (thread_p, tdes, &commit_lsa);
5701  }
5702 
5703  log_change_tran_as_completed (thread_p, tdes, LOG_COMMIT, &commit_lsa);
5704  }
5705  else
5706  {
5707  LOG_LSA abort_lsa;
5708 
5709  log_append_abort_log (thread_p, tdes, &abort_lsa);
5710  log_change_tran_as_completed (thread_p, tdes, LOG_ABORT, &abort_lsa);
5711  }
5712 
5713  state = tdes->state;
5714 
5715  /* now releases locks */
5716  lock_unlock_all (thread_p);
5717 
5718  /* Unblock global oldest active update. */
5719  tdes->unlock_global_oldest_visible_mvccid ();
5720 
5721  if (iscommitted == LOG_COMMIT)
5722  {
5724  }
5725 
5726  /* If recovery restart operation, or, if this is a coordinator loose end transaction return this index and
5727  * decrement coordinator loose end transactions counter. */
5728  if (return_2pc_loose_tranindex == false)
5729  {
5730  if (get_newtrid == LOG_NEED_NEWTRID)
5731  {
5732  (void) logtb_get_new_tran_id (thread_p, tdes);
5733  }
5734  }
5735  else
5736  {
5737  /* Free the index */
5738  if (tdes->isloose_end == true)
5739  {
5740  TR_TABLE_CS_ENTER (thread_p);
5742  TR_TABLE_CS_EXIT (thread_p);
5743  }
5744  logtb_free_tran_index (thread_p, tdes->tran_index);
5745  }
5746 
5747  /* Finish the append operation and flush the log */
5748  }
5749 
5750  if (LOG_ISCHECKPOINT_TIME ())
5751  {
5752 #if defined(SERVER_MODE)
5754 #else /* SERVER_MODE */
5755  (void) logpb_checkpoint (thread_p);
5756 #endif /* SERVER_MODE */
5757  }
5758 
5759  return state;
5760 }
5761 
5762 /*
5763  *
5764  * FUNCTIONS RELATED TO DUMPING THE LOG AND ITS DATA
5765  *
5766  */
5767 
5768 /*
5769  * log_ascii_dump - PRINT DATA IN ASCII FORMAT
5770  *
5771  * return: nothing
5772  *
5773  * length(in): Length of Recovery Data
5774  * data(in): The data being logged
5775  *
5776  * NOTE: Dump recovery information in ascii format.
5777  * It is used when a dump function is not provided.
5778  */
5779 static void
5780 log_ascii_dump (FILE * out_fp, int length, void *data)
5781 {
5782  char *ptr; /* Pointer to data */
5783  int i;
5784 
5785  for (i = 0, ptr = (char *) data; i < length; i++)
5786  {
5787  (void) fputc (*ptr++, out_fp);
5788  }
5789 }
5790 
5791 /*
5792  * log_hexa_dump () - Point recovery data as hexadecimals.
5793  *
5794  * return : Void.
5795  * out_fp (in) : Print output.
5796  * length (in) : Recovery data length.
5797  * data (in) : Recovery data.
5798  */
5799 void
5800 log_hexa_dump (FILE * out_fp, int length, void *data)
5801 {
5802  char *ptr; /* Pointer to data */
5803  int i;
5804 
5805  fprintf (out_fp, " 00000: ");
5806  for (i = 0, ptr = (char *) data; i < length; i++)
5807  {
5808  fprintf (out_fp, "%02X ", (unsigned char) (*ptr++));
5809  if (i % 16 == 15 && i != length)
5810  {
5811  fprintf (out_fp, "\n %05d: ", i + 1);
5812  }
5813  }
5814  fprintf (out_fp, "\n");
5815 }
5816 
5817 static void
5818 log_repl_data_dump (FILE * out_fp, int length, void *data)
5819 {
5820  char *ptr = (char *) data;
5821  char *class_name;
5822  DB_VALUE value;
5823 
5824  ptr = or_unpack_string_nocopy (ptr, &class_name);
5825  ptr = or_unpack_mem_value (ptr, &value);
5826 
5827  string_buffer sb;
5828  db_value_printer printer (sb);
5829 
5830  printer.describe_value (&value);
5831  fprintf (out_fp, "C[%s] K[%s]\n", class_name, sb.get_buffer ());
5832  pr_clear_value (&value);
5833 }
5834 
5835 static void
5836 log_repl_schema_dump (FILE * out_fp, int length, void *data)
5837 {
5838  char *ptr;
5839  int statement_type;
5840  char *class_name;
5841  char *sql;
5842 
5843  ptr = (char *) data;
5844  ptr = or_unpack_int (ptr, &statement_type);
5845  ptr = or_unpack_string_nocopy (ptr, &class_name);
5846  ptr = or_unpack_string_nocopy (ptr, &sql);
5847 
5848  fprintf (out_fp, "C[%s] S[%s]\n", class_name, sql);
5849 }
5850 
5851 /*
5852  * log_dump_data - DUMP DATA STORED IN LOG
5853  *
5854  * return: nothing
5855  *
5856  * length(in): Length of the data
5857  * log_lsa(in/out):Log address identifier containing the log record
5858  * log_pgptr(in/out): Pointer to page where data starts (Set as a side
5859  * effect to the page where data ends)
5860  * dumpfun(in): Function to invoke to dump the data
5861  * log_dump_ptr(in):
5862  *
5863  * NOTE:Dump the data stored at given log location.
5864  * This function is used for debugging purposes.
5865  */
5866 static void
5867 log_dump_data (THREAD_ENTRY * thread_p, FILE * out_fp, int length, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
5868  void (*dumpfun) (FILE *, int, void *), LOG_ZIP * log_dump_ptr)
5869 {
5870  char *ptr; /* Pointer to data to be printed */
5871  bool is_zipped = false;
5872  bool is_unzipped = false;
5873  /* Call the dumper function */
5874 
5875  /*
5876  * If data is contained in only one buffer, pass pointer directly.
5877  * Otherwise, allocate a contiguous area, copy the data and pass this
5878  * area. At the end deallocate the area
5879  */
5880 
5881  if (dumpfun == NULL)
5882  {
5883  /* Set default to log_hexa_dump */
5884  dumpfun = log_hexa_dump;
5885  }
5886 
5887  if (ZIP_CHECK (length))
5888  {
5889  length = (int) GET_ZIP_LEN (length);
5890  is_zipped = true;
5891  }
5892 
5893  if (log_lsa->offset + length < (int) LOGAREA_SIZE)
5894  {
5895  /* Data is contained in one buffer */
5896 
5897  ptr = (char *) log_page_p->area + log_lsa->offset;
5898 
5899  if (length != 0 && is_zipped)
5900  {
5901  is_unzipped = log_unzip (log_dump_ptr, length, ptr);
5902  }
5903 
5904  if (is_zipped && is_unzipped)
5905  {
5906  (*dumpfun) (out_fp, (int) log_dump_ptr->data_length, log_dump_ptr->log_data);
5907  log_lsa->offset += length;
5908  }
5909  else
5910  {
5911  (*dumpfun) (out_fp, length, ptr);
5912  log_lsa->offset += length;
5913  }
5914  }
5915  else
5916  {
5917  /* Need to copy the data into a contiguous area */
5918  ptr = (char *) malloc (length);
5919  if (ptr == NULL)
5920  {
5922  return;
5923  }
5924  /* Copy the data */
5925  logpb_copy_from_log (thread_p, ptr, length, log_lsa, log_page_p);
5926 
5927  if (is_zipped)
5928  {
5929  is_unzipped = log_unzip (log_dump_ptr, length, ptr);
5930  }
5931 
5932  if (is_zipped && is_unzipped)
5933  {
5934  (*dumpfun) (out_fp, (int) log_dump_ptr->data_length, log_dump_ptr->log_data);
5935  }
5936  else
5937  {
5938  (*dumpfun) (out_fp, length, ptr);
5939  }
5940  free_and_init (ptr);
5941  }
5942  LOG_READ_ALIGN (thread_p, log_lsa, log_page_p);
5943 
5944 }
5945 
5946 static void
5947 log_dump_header (FILE * out_fp, LOG_HEADER * log_header_p)
5948 {
5949  time_t tmp_time;
5950  char time_val[CTIME_MAX];
5951 
5952  fprintf (out_fp, "\n ** DUMP LOG HEADER **\n");
5953 
5954  tmp_time = (time_t) log_header_p->db_creation;
5955  (void) ctime_r (&tmp_time, time_val);
5956  fprintf (out_fp,
5957  "HDR: Magic Symbol = %s at disk location = %lld\n Creation_time = %s"
5958  " Release = %s, Compatibility_disk_version = %g,\n"
5959  " Db_pagesize = %d, log_pagesize= %d, Shutdown = %d,\n"
5960  " Next_trid = %d, Next_mvcc_id = %llu, Num_avg_trans = %d, Num_avg_locks = %d,\n"
5961  " Num_active_log_pages = %d, First_active_log_page = %lld,\n"
5962  " Current_append = %lld|%d, Checkpoint = %lld|%d,\n", log_header_p->magic,
5963  (long long) offsetof (LOG_PAGE, area), time_val, log_header_p->db_release, log_header_p->db_compatibility,
5964  log_header_p->db_iopagesize, log_header_p->db_logpagesize, log_header_p->is_shutdown,
5965  log_header_p->next_trid, (long long int) log_header_p->mvcc_next_id, log_header_p->avg_ntrans,
5966  log_header_p->avg_nlocks, log_header_p->npages, (long long) log_header_p->fpageid,
5967  LSA_AS_ARGS (&log_header_p->append_lsa), LSA_AS_ARGS (&log_header_p->chkpt_lsa));
5968 
5969  fprintf (out_fp,
5970  " Next_archive_pageid = %lld at active_phy_pageid = %d,\n"
5971  " Next_archive_num = %d, Last_archiv_num_for_syscrashes = %d,\n"
5972  " Last_deleted_arv_num = %d, has_logging_been_skipped = %d,\n"
5973  " bkup_lsa: level0 = %lld|%d, level1 = %lld|%d, level2 = %lld|%d,\n Log_prefix = %s\n",
5974  (long long int) log_header_p->nxarv_pageid, log_header_p->nxarv_phy_pageid, log_header_p->nxarv_num,
5975  log_header_p->last_arv_num_for_syscrashes, log_header_p->last_deleted_arv_num,
5976  log_header_p->has_logging_been_skipped, LSA_AS_ARGS (&log_header_p->bkup_level0_lsa),
5977  LSA_AS_ARGS (&log_header_p->bkup_level1_lsa), LSA_AS_ARGS (&log_header_p->bkup_level2_lsa),
5978  log_header_p->prefix_name);
5979 }
5980 
5981 static LOG_PAGE *
5982 log_dump_record_undoredo (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
5983  LOG_ZIP * log_zip_p)
5984 {
5985  LOG_REC_UNDOREDO *undoredo;
5986  int undo_length;
5987  int redo_length;
5988  LOG_RCVINDEX rcvindex;
5989 
5990  /* Read the DATA HEADER */
5991  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*undoredo), log_lsa, log_page_p);
5992  undoredo = (LOG_REC_UNDOREDO *) ((char *) log_page_p->area + log_lsa->offset);
5993  fprintf (out_fp, ", Recv_index = %s, \n", rv_rcvindex_string (undoredo->data.rcvindex));
5994  fprintf (out_fp,
5995  " Volid = %d Pageid = %d Offset = %d,\n Undo(Before) length = %d, Redo(After) length = %d,\n",
5996  undoredo->data.volid, undoredo->data.pageid, undoredo->data.offset, (int) GET_ZIP_LEN (undoredo->ulength),
5997  (int) GET_ZIP_LEN (undoredo->rlength));
5998 
5999  undo_length = undoredo->ulength;
6000  redo_length = undoredo->rlength;
6001  rcvindex = undoredo->data.rcvindex;
6002 
6003  LOG_READ_ADD_ALIGN (thread_p, sizeof (*undoredo), log_lsa, log_page_p);
6004  /* Print UNDO(BEFORE) DATA */
6005  fprintf (out_fp, "-->> Undo (Before) Data:\n");
6006  log_dump_data (thread_p, out_fp, undo_length, log_lsa, log_page_p, RV_fun[rcvindex].dump_undofun, log_zip_p);
6007  /* Print REDO (AFTER) DATA */
6008  fprintf (out_fp, "-->> Redo (After) Data:\n");
6009  log_dump_data (thread_p, out_fp, redo_length, log_lsa, log_page_p, RV_fun[rcvindex].dump_redofun, log_zip_p);
6010 
6011  return log_page_p;
6012 }
6013 
6014 static LOG_PAGE *
6015 log_dump_record_undo (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
6016  LOG_ZIP * log_zip_p)
6017 {
6018  LOG_REC_UNDO *undo;
6019  int undo_length;
6020  LOG_RCVINDEX rcvindex;
6021 
6022  /* Read the DATA HEADER */
6023  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*undo), log_lsa, log_page_p);
6024  undo = (LOG_REC_UNDO *) ((char *) log_page_p->area + log_lsa->offset);
6025 
6026  fprintf (out_fp, ", Recv_index = %s,\n", rv_rcvindex_string (undo->data.rcvindex));
6027  fprintf (out_fp, " Volid = %d Pageid = %d Offset = %d,\n Undo (Before) length = %d,\n", undo->data.volid,
6028  undo->data.pageid, undo->data.offset, (int) GET_ZIP_LEN (undo->length));
6029 
6030  undo_length = undo->length;
6031  rcvindex = undo->data.rcvindex;
6032  LOG_READ_ADD_ALIGN (thread_p, sizeof (*undo), log_lsa, log_page_p);
6033 
6034  /* Print UNDO(BEFORE) DATA */
6035  fprintf (out_fp, "-->> Undo (Before) Data:\n");
6036  log_dump_data (thread_p, out_fp, undo_length, log_lsa, log_page_p, RV_fun[rcvindex].dump_undofun, log_zip_p);
6037 
6038  return log_page_p;
6039 }
6040 
6041 static LOG_PAGE *
6042 log_dump_record_redo (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
6043  LOG_ZIP * log_zip_p)
6044 {
6045  LOG_REC_REDO *redo;
6046  int redo_length;
6047  LOG_RCVINDEX rcvindex;
6048 
6049  /* Read the DATA HEADER */
6050  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*redo), log_lsa, log_page_p);
6051  redo = (LOG_REC_REDO *) ((char *) log_page_p->area + log_lsa->offset);
6052 
6053  fprintf (out_fp, ", Recv_index = %s,\n", rv_rcvindex_string (redo->data.rcvindex));
6054  fprintf (out_fp, " Volid = %d Pageid = %d Offset = %d,\n Redo (After) length = %d,\n", redo->data.volid,
6055  redo->data.pageid, redo->data.offset, (int) GET_ZIP_LEN (redo->length));
6056 
6057  redo_length = redo->length;
6058  rcvindex = redo->data.rcvindex;
6059  LOG_READ_ADD_ALIGN (thread_p, sizeof (*redo), log_lsa, log_page_p);
6060 
6061  /* Print REDO(AFTER) DATA */
6062  fprintf (out_fp, "-->> Redo (After) Data:\n");
6063  log_dump_data (thread_p, out_fp, redo_length, log_lsa, log_page_p, RV_fun[rcvindex].dump_redofun, log_zip_p);
6064 
6065  return log_page_p;
6066 }
6067 
6068 static LOG_PAGE *
6069 log_dump_record_mvcc_undoredo (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
6070  LOG_ZIP * log_zip_p)
6071 {
6072  LOG_REC_MVCC_UNDOREDO *mvcc_undoredo;
6073  int undo_length;
6074  int redo_length;
6075  LOG_RCVINDEX rcvindex;
6076 
6077  /* Read the DATA HEADER */
6078  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*mvcc_undoredo), log_lsa, log_page_p);
6079  mvcc_undoredo = (LOG_REC_MVCC_UNDOREDO *) ((char *) log_page_p->area + log_lsa->offset);
6080  fprintf (out_fp, ", Recv_index = %s, \n", rv_rcvindex_string (mvcc_undoredo->undoredo.data.rcvindex));
6081  fprintf (out_fp,
6082  " Volid = %d Pageid = %d Offset = %d,\n Undo(Before) length = %d, Redo(After) length = %d,\n",
6083  mvcc_undoredo->undoredo.data.volid, mvcc_undoredo->undoredo.data.pageid, mvcc_undoredo->undoredo.data.offset,
6084  (int) GET_ZIP_LEN (mvcc_undoredo->undoredo.ulength), (int) GET_ZIP_LEN (mvcc_undoredo->undoredo.rlength));
6085  fprintf (out_fp, " MVCCID = %llu, \n Prev_mvcc_op_log_lsa = %lld|%d, \n VFID = (%d, %d)",
6086  (long long int) mvcc_undoredo->mvccid,
6087  (long long int) mvcc_undoredo->vacuum_info.prev_mvcc_op_log_lsa.pageid,
6088  (int) mvcc_undoredo->vacuum_info.prev_mvcc_op_log_lsa.offset, mvcc_undoredo->vacuum_info.vfid.volid,
6089  mvcc_undoredo->vacuum_info.vfid.fileid);
6090 
6091  undo_length = mvcc_undoredo->undoredo.ulength;
6092  redo_length = mvcc_undoredo->undoredo.rlength;
6093  rcvindex = mvcc_undoredo->undoredo.data.rcvindex;
6094 
6095  LOG_READ_ADD_ALIGN (thread_p, sizeof (*mvcc_undoredo), log_lsa, log_page_p);
6096  /* Print UNDO(BEFORE) DATA */
6097  fprintf (out_fp, "-->> Undo (Before) Data:\n");
6098  log_dump_data (thread_p, out_fp, undo_length, log_lsa, log_page_p, RV_fun[rcvindex].dump_undofun, log_zip_p);
6099  /* Print REDO (AFTER) DATA */
6100  fprintf (out_fp, "-->> Redo (After) Data:\n");
6101  log_dump_data (thread_p, out_fp, redo_length, log_lsa, log_page_p, RV_fun[rcvindex].dump_redofun, log_zip_p);
6102 
6103  return log_page_p;
6104 }
6105 
6106 static LOG_PAGE *
6107 log_dump_record_mvcc_undo (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
6108  LOG_ZIP * log_zip_p)
6109 {
6110  LOG_REC_MVCC_UNDO *mvcc_undo;
6111  int undo_length;
6112  LOG_RCVINDEX rcvindex;
6113 
6114  /* Read the DATA HEADER */
6115  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*mvcc_undo), log_lsa, log_page_p);
6116  mvcc_undo = (LOG_REC_MVCC_UNDO *) ((char *) log_page_p->area + log_lsa->offset);
6117 
6118  fprintf (out_fp, ", Recv_index = %s,\n", rv_rcvindex_string (mvcc_undo->undo.data.rcvindex));
6119  fprintf (out_fp, " Volid = %d Pageid = %d Offset = %d,\n Undo (Before) length = %d,\n",
6120  mvcc_undo->undo.data.volid, mvcc_undo->undo.data.pageid, mvcc_undo->undo.data.offset,
6121  (int) GET_ZIP_LEN (mvcc_undo->undo.length));
6122  fprintf (out_fp, " MVCCID = %llu, \n Prev_mvcc_op_log_lsa = %lld|%d, \n VFID = (%d, %d)",
6123  (long long int) mvcc_undo->mvccid, (long long int) mvcc_undo->vacuum_info.prev_mvcc_op_log_lsa.pageid,
6124  (int) mvcc_undo->vacuum_info.prev_mvcc_op_log_lsa.offset, mvcc_undo->vacuum_info.vfid.volid,
6125  mvcc_undo->vacuum_info.vfid.fileid);
6126 
6127  undo_length = mvcc_undo->undo.length;
6128  rcvindex = mvcc_undo->undo.data.rcvindex;
6129  LOG_READ_ADD_ALIGN (thread_p, sizeof (*mvcc_undo), log_lsa, log_page_p);
6130 
6131  /* Print UNDO(BEFORE) DATA */
6132  fprintf (out_fp, "-->> Undo (Before) Data:\n");
6133  log_dump_data (thread_p, out_fp, undo_length, log_lsa, log_page_p, RV_fun[rcvindex].dump_undofun, log_zip_p);
6134 
6135  return log_page_p;
6136 }
6137 
6138 static LOG_PAGE *
6139 log_dump_record_mvcc_redo (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
6140  LOG_ZIP * log_zip_p)
6141 {
6142  LOG_REC_MVCC_REDO *mvcc_redo;
6143  int redo_length;
6144  LOG_RCVINDEX rcvindex;
6145 
6146  /* Read the DATA HEADER */
6147  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*mvcc_redo), log_lsa, log_page_p);
6148  mvcc_redo = (LOG_REC_MVCC_REDO *) ((char *) log_page_p->area + log_lsa->offset);
6149 
6150  fprintf (out_fp, ", Recv_index = %s,\n", rv_rcvindex_string (mvcc_redo->redo.data.rcvindex));
6151  fprintf (out_fp, " Volid = %d Pageid = %d Offset = %d,\n Redo (After) length = %d,\n",
6152  mvcc_redo->redo.data.volid, mvcc_redo->redo.data.pageid, mvcc_redo->redo.data.offset,
6153  (int) GET_ZIP_LEN (mvcc_redo->redo.length));
6154  fprintf (out_fp, " MVCCID = %llu, \n", (long long int) mvcc_redo->mvccid);
6155 
6156  redo_length = mvcc_redo->redo.length;
6157  rcvindex = mvcc_redo->redo.data.rcvindex;
6158  LOG_READ_ADD_ALIGN (thread_p, sizeof (*mvcc_redo), log_lsa, log_page_p);
6159 
6160  /* Print REDO(AFTER) DATA */
6161  fprintf (out_fp, "-->> Redo (After) Data:\n");
6162  log_dump_data (thread_p, out_fp, redo_length, log_lsa, log_page_p, RV_fun[rcvindex].dump_redofun, log_zip_p);
6163 
6164  return log_page_p;
6165 }
6166 
6167 static LOG_PAGE *
6168 log_dump_record_postpone (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * log_lsa, LOG_PAGE * log_page_p)
6169 {
6170  LOG_REC_RUN_POSTPONE *run_posp;
6171  int redo_length;
6172  LOG_RCVINDEX rcvindex;
6173 
6174  /* Read the DATA HEADER */
6175  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*run_posp), log_lsa, log_page_p);
6176  run_posp = (LOG_REC_RUN_POSTPONE *) ((char *) log_page_p->area + log_lsa->offset);
6177  fprintf (out_fp, ", Recv_index = %s,\n", rv_rcvindex_string (run_posp->data.rcvindex));
6178  fprintf (out_fp,
6179  " Volid = %d Pageid = %d Offset = %d,\n Run postpone (Redo/After) length = %d, corresponding"
6180  " to\n Postpone record with LSA = %lld|%d\n", run_posp->data.volid, run_posp->data.pageid,
6181  run_posp->data.offset, run_posp->length, LSA_AS_ARGS (&run_posp->ref_lsa));
6182 
6183  redo_length = run_posp->length;
6184  rcvindex = run_posp->data.rcvindex;
6185  LOG_READ_ADD_ALIGN (thread_p, sizeof (*run_posp), log_lsa, log_page_p);
6186 
6187  /* Print RUN POSTPONE (REDO/AFTER) DATA */
6188  fprintf (out_fp, "-->> Run Postpone (Redo/After) Data:\n");
6189  log_dump_data (thread_p, out_fp, redo_length, log_lsa, log_page_p, RV_fun[rcvindex].dump_redofun, NULL);
6190 
6191  return log_page_p;
6192 }
6193 
6194 static LOG_PAGE *
6195 log_dump_record_dbout_redo (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * log_lsa, LOG_PAGE * log_page_p)
6196 {
6197  LOG_REC_DBOUT_REDO *dbout_redo;
6198  int redo_length;
6199  LOG_RCVINDEX rcvindex;
6200 
6201  /* Read the data header */
6202  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*dbout_redo), log_lsa, log_page_p);
6203  dbout_redo = ((LOG_REC_DBOUT_REDO *) ((char *) log_page_p->area + log_lsa->offset));
6204 
6205  redo_length = dbout_redo->length;
6206  rcvindex = dbout_redo->rcvindex;
6207 
6208  fprintf (out_fp, ", Recv_index = %s, Length = %d,\n", rv_rcvindex_string (rcvindex), redo_length);
6209 
6210  LOG_READ_ADD_ALIGN (thread_p, sizeof (*dbout_redo), log_lsa, log_page_p);
6211 
6212  /* Print Database External DATA */
6213  fprintf (out_fp, "-->> Database external Data:\n");
6214  log_dump_data (thread_p, out_fp, redo_length, log_lsa, log_page_p, RV_fun[rcvindex].dump_redofun, NULL);
6215 
6216  return log_page_p;
6217 }
6218 
6219 static LOG_PAGE *
6220 log_dump_record_compensate (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * log_lsa, LOG_PAGE * log_page_p)
6221 {
6222  LOG_REC_COMPENSATE *compensate;
6223  int length_compensate;
6224  LOG_RCVINDEX rcvindex;
6225 
6226  /* Read the DATA HEADER */
6227  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*compensate), log_lsa, log_page_p);
6228  compensate = (LOG_REC_COMPENSATE *) ((char *) log_page_p->area + log_lsa->offset);
6229 
6230  fprintf (out_fp, ", Recv_index = %s,\n", rv_rcvindex_string (compensate->data.rcvindex));
6231  fprintf (out_fp, " Volid = %d Pageid = %d Offset = %d,\n Compensate length = %d, Next_to_UNDO = %lld|%d\n",
6232  compensate->data.volid, compensate->data.pageid, compensate->data.offset, compensate->length,
6233  LSA_AS_ARGS (&compensate->undo_nxlsa));
6234 
6235  length_compensate = compensate->length;
6236  rcvindex = compensate->data.rcvindex;
6237  LOG_READ_ADD_ALIGN (thread_p, sizeof (*compensate), log_lsa, log_page_p);
6238 
6239  /* Print COMPENSATE DATA */
6240  fprintf (out_fp, "-->> Compensate Data:\n");
6241  log_dump_data (thread_p, out_fp, length_compensate, log_lsa, log_page_p, RV_fun[rcvindex].dump_undofun, NULL);
6242 
6243  return log_page_p;
6244 }
6245 
6246 static LOG_PAGE *
6247 log_dump_record_commit_postpone (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * log_lsa, LOG_PAGE * log_page_p)
6248 {
6249  LOG_REC_START_POSTPONE *start_posp;
6250 
6251  /* Read the DATA HEADER */
6252  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*start_posp), log_lsa, log_page_p);
6253  start_posp = (LOG_REC_START_POSTPONE *) ((char *) log_page_p->area + log_lsa->offset);
6254  fprintf (out_fp, ", First postpone record at before or after Page = %lld and offset = %d\n",
6255  LSA_AS_ARGS (&start_posp->posp_lsa));
6256 
6257  return log_page_p;
6258 }
6259 
6260 static LOG_PAGE *
6261 log_dump_record_transaction_finish (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * log_lsa, LOG_PAGE * log_page_p)
6262 {
6263  LOG_REC_DONETIME *donetime;
6264  time_t tmp_time;
6265  char time_val[CTIME_MAX];
6266 
6267  /* Read the DATA HEADER */
6268  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*donetime), log_lsa, log_page_p);
6269  donetime = (LOG_REC_DONETIME *) ((char *) log_page_p->area + log_lsa->offset);
6270  tmp_time = (time_t) donetime->at_time;
6271  (void) ctime_r (&tmp_time, time_val);
6272  fprintf (out_fp, ",\n Transaction finish time at = %s\n", time_val);
6273 
6274  return log_page_p;
6275 }
6276 
6277 static LOG_PAGE *
6278 log_dump_record_replication (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * log_lsa, LOG_PAGE * log_page_p)
6279 {
6280  LOG_REC_REPLICATION *repl_log;
6281  int length;
6282  const char *type;
6283  void (*dump_function) (FILE *, int, void *);
6284 
6285  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*repl_log), log_lsa, log_page_p);
6286  repl_log = (LOG_REC_REPLICATION *) ((char *) log_page_p->area + log_lsa->offset);
6287  fprintf (out_fp, ", Target log lsa = %lld|%d\n", LSA_AS_ARGS (&repl_log->lsa));
6288  length = repl_log->length;
6289 
6290  LOG_READ_ADD_ALIGN (thread_p, sizeof (*repl_log), log_lsa, log_page_p);
6291 
6292  switch (repl_log->rcvindex)
6293  {
6294  case RVREPL_DATA_INSERT:
6295  type = "RVREPL_DATA_INSERT";
6296  dump_function = log_repl_data_dump;
6297  break;
6299  type = "RVREPL_DATA_UPDATE_START";
6300  dump_function = log_repl_data_dump;
6301  break;
6302  case RVREPL_DATA_UPDATE:
6303  type = "RVREPL_DATA_UPDATE";
6304  dump_function = log_repl_data_dump;
6305  break;
6307  type = "RVREPL_DATA_UPDATE_END";
6308  dump_function = log_repl_data_dump;
6309  break;
6310  case RVREPL_DATA_DELETE:
6311  type = "RVREPL_DATA_DELETE";
6312  dump_function = log_repl_data_dump;
6313  break;
6314  default:
6315  type = "RVREPL_SCHEMA";
6316  dump_function = log_repl_schema_dump;
6317  break;
6318  }
6319  fprintf (out_fp, "T[%s] ", type);
6320 
6321  log_dump_data (thread_p, out_fp, length, log_lsa, log_page_p, dump_function, NULL);
6322  return log_page_p;
6323 }
6324 
6325 /*
6326  * log_dump_record_sysop_start_postpone () - dump system op start postpone log record
6327  *
6328  * return : log page
6329  * thread_p (in) : thread entry
6330  * out_fp (in/out) : dump output
6331  * log_lsa (in/out) : log lsa
6332  * log_page_p (in/out) : log page
6333  * log_zip_p (in/out) : log unzip
6334  */
6335 static LOG_PAGE *
6336 log_dump_record_sysop_start_postpone (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
6337  LOG_ZIP * log_zip_p)
6338 {
6339  LOG_REC_SYSOP_START_POSTPONE sysop_start_postpone;
6340 
6341  /* Read the DATA HEADER */
6342  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (sysop_start_postpone), log_lsa, log_page_p);
6343  sysop_start_postpone = *((LOG_REC_SYSOP_START_POSTPONE *) ((char *) log_page_p->area + log_lsa->offset));
6344 
6345  (void) log_dump_record_sysop_end_internal (thread_p, &sysop_start_postpone.sysop_end, log_lsa, log_page_p, log_zip_p,
6346  out_fp);
6347  fprintf (out_fp, " postpone_lsa = %lld|%d \n", LSA_AS_ARGS (&sysop_start_postpone.posp_lsa));
6348 
6349  return log_page_p;
6350 }
6351 
6352 /*
6353  * log_dump_record_sysop_end_internal () - dump sysop end log record types
6354  *
6355  * return : log page
6356  * thread_p (in) : thread entry
6357  * sysop_end (in) : system op end log record
6358  * log_lsa (in/out) : LSA of undo data (logical undo only)
6359  * log_page_p (in/out) : page of undo data (logical undo only)
6360  * log_zip_p (in/out) : log unzip
6361  * out_fp (in/out) : dump output
6362  */
6363 static LOG_PAGE *
6365  LOG_PAGE * log_page_p, LOG_ZIP * log_zip_p, FILE * out_fp)
6366 {
6367  int undo_length;
6368  LOG_RCVINDEX rcvindex;
6369 
6370  fprintf (out_fp, ",\n Prev parent LSA = %lld|%d, Prev_topresult_lsa = %lld|%d, %s \n",
6371  LSA_AS_ARGS (&sysop_end->lastparent_lsa), LSA_AS_ARGS (&sysop_end->prv_topresult_lsa),
6372  log_sysop_end_type_string (sysop_end->type));
6373  switch (sysop_end->type)
6374  {
6375  case LOG_SYSOP_END_ABORT:
6376  case LOG_SYSOP_END_COMMIT:
6377  /* nothing else to print */
6378  break;
6380  fprintf (out_fp, " compansate_lsa = %lld|%d \n", LSA_AS_ARGS (&sysop_end->compensate_lsa));
6381  break;
6383  fprintf (out_fp, " run_postpone_lsa = %lld|%d, postpone = %s \n",
6384  LSA_AS_ARGS (&sysop_end->run_postpone.postpone_lsa),
6385  sysop_end->run_postpone.is_sysop_postpone ? "sysop" : "transaction");
6386  break;
6388  assert (log_lsa != NULL && log_page_p != NULL && log_zip_p != NULL);
6389 
6390  fprintf (out_fp, ", Recv_index = %s,\n", rv_rcvindex_string (sysop_end->undo.data.rcvindex));
6391  fprintf (out_fp, " Volid = %d Pageid = %d Offset = %d,\n Undo (Before) length = %d,\n",
6392  sysop_end->undo.data.volid, sysop_end->undo.data.pageid, sysop_end->undo.data.offset,
6393  (int) GET_ZIP_LEN (sysop_end->undo.length));
6394 
6395  undo_length = sysop_end->undo.length;
6396  rcvindex = sysop_end->undo.data.rcvindex;
6397  LOG_READ_ADD_ALIGN (thread_p, sizeof (*sysop_end), log_lsa, log_page_p);
6398  log_dump_data (thread_p, out_fp, undo_length, log_lsa, log_page_p, RV_fun[rcvindex].dump_undofun, log_zip_p);
6399  break;
6401  assert (log_lsa != NULL && log_page_p != NULL && log_zip_p != NULL);
6402 
6403  fprintf (out_fp, ", Recv_index = %s,\n", rv_rcvindex_string (sysop_end->mvcc_undo.undo.data.rcvindex));
6404  fprintf (out_fp, " Volid = %d Pageid = %d Offset = %d,\n Undo (Before) length = %d,\n",
6405  sysop_end->mvcc_undo.undo.data.volid, sysop_end->mvcc_undo.undo.data.pageid,
6406  sysop_end->mvcc_undo.undo.data.offset, (int) GET_ZIP_LEN (sysop_end->mvcc_undo.undo.length));
6407  fprintf (out_fp, " MVCCID = %llu, \n Prev_mvcc_op_log_lsa = %lld|%d, \n VFID = (%d, %d)",
6408  (unsigned long long int) sysop_end->mvcc_undo.mvccid,
6410  VFID_AS_ARGS (&sysop_end->mvcc_undo.vacuum_info.vfid));
6411 
6412  undo_length = sysop_end->mvcc_undo.undo.length;
6413  rcvindex = sysop_end->mvcc_undo.undo.data.rcvindex;
6414  LOG_READ_ADD_ALIGN (thread_p, sizeof (*sysop_end), log_lsa, log_page_p);
6415  log_dump_data (thread_p, out_fp, undo_length, log_lsa, log_page_p, RV_fun[rcvindex].dump_undofun, log_zip_p);
6416  break;
6417  default:
6418  assert (false);
6419  break;
6420  }
6421  return log_page_p;
6422 }
6423 
6424 /*
6425  * log_dump_record_sysop_end () - Dump sysop end log record types. Side-effect: log_lsa and log_page_p will be
6426  * positioned after the log record.
6427  *
6428  * return : NULL if something bad happens, pointer to log page otherwise.
6429  * thread_p (in) : Thread entry.
6430  * log_lsa (in/out) : in - LSA of log record, out - LSA after log record.
6431  * log_page_p (in/out) : in - page of log record, out - page after log record.
6432  * log_zip_p (in) : Unzip context.
6433  * out_fp (in/out) : Dump output.
6434  */
6435 static LOG_PAGE *
6436 log_dump_record_sysop_end (THREAD_ENTRY * thread_p, LOG_LSA * log_lsa, LOG_PAGE * log_page_p, LOG_ZIP * log_zip_p,
6437  FILE * out_fp)
6438 {
6439  LOG_REC_SYSOP_END *sysop_end;
6440 
6441  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*sysop_end), log_lsa, log_page_p);
6442  sysop_end = (LOG_REC_SYSOP_END *) ((char *) log_page_p->area + log_lsa->offset);
6443 
6444  log_dump_record_sysop_end_internal (thread_p, sysop_end, log_lsa, log_page_p, log_zip_p, out_fp);
6445 
6446  return log_page_p;
6447 }
6448 
6449 /*
6450  * log_dump_checkpoint_topops - DUMP CHECKPOINT OF TOP SYSTEM OPERATIONS
6451  *
6452  * return: nothing
6453  *
6454  * length(in): Length to dump in bytes
6455  * data(in): The data being logged
6456  *
6457  * NOTE: Dump the checkpoint top system operation structure.
6458  */
6459 static void
6460 log_dump_checkpoint_topops (FILE * out_fp, int length, void *data)
6461 {
6462  int ntops, i;
6463  LOG_INFO_CHKPT_SYSOP *chkpt_topops; /* Checkpoint top system operations that are in commit postpone
6464  * mode */
6465  LOG_INFO_CHKPT_SYSOP *chkpt_topone; /* One top system ope */
6466 
6467  chkpt_topops = (LOG_INFO_CHKPT_SYSOP *) data;
6468  ntops = length / sizeof (*chkpt_topops);
6469 
6470  /* Start dumping each checkpoint top system operation */
6471 
6472  for (i = 0; i < ntops; i++)
6473  {
6474  chkpt_topone = &chkpt_topops[i];
6475  fprintf (out_fp, " Trid = %d \n", chkpt_topone->trid);
6476  fprintf (out_fp, " Sysop start postpone LSA = %lld|%d \n",
6477  LSA_AS_ARGS (&chkpt_topone->sysop_start_postpone_lsa));
6478  }
6479  (void) fprintf (out_fp, "\n");
6480 }
6481 
6482 static LOG_PAGE *
6483 log_dump_record_checkpoint (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * log_lsa, LOG_PAGE * log_page_p)
6484 {
6485  LOG_REC_CHKPT *chkpt; /* check point log record */
6486  int length_active_tran;
6487  int length_topope;
6488 
6489  /* Read the DATA HEADER */
6490  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*chkpt), log_lsa, log_page_p);
6491 
6492  chkpt = (LOG_REC_CHKPT *) ((char *) log_page_p->area + log_lsa->offset);
6493  fprintf (out_fp, ", Num_trans = %d,\n", chkpt->ntrans);
6494  fprintf (out_fp, " Redo_LSA = %lld|%d\n", LSA_AS_ARGS (&chkpt->redo_lsa));
6495 
6496  length_active_tran = sizeof (LOG_INFO_CHKPT_TRANS) * chkpt->ntrans;
6497  length_topope = (sizeof (LOG_INFO_CHKPT_SYSOP) * chkpt->ntops);
6498  LOG_READ_ADD_ALIGN (thread_p, sizeof (*chkpt), log_lsa, log_page_p);
6499  log_dump_data (thread_p, out_fp, length_active_tran, log_lsa, log_page_p, logpb_dump_checkpoint_trans, NULL);
6500  if (length_topope > 0)
6501  {
6502  log_dump_data (thread_p, out_fp, length_active_tran, log_lsa, log_page_p, log_dump_checkpoint_topops, NULL);
6503  }
6504 
6505  return log_page_p;
6506 }
6507 
6508 static LOG_PAGE *
6509 log_dump_record_save_point (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * log_lsa, LOG_PAGE * log_page_p)
6510 {
6511  LOG_REC_SAVEPT *savept;
6512  int length_save_point;
6513 
6514  /* Read the DATA HEADER */
6515  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*savept), log_lsa, log_page_p);
6516  savept = (LOG_REC_SAVEPT *) ((char *) log_page_p->area + log_lsa->offset);
6517 
6518  fprintf (out_fp, ", Prev_savept_Lsa = %lld|%d, length = %d,\n", LSA_AS_ARGS (&savept->prv_savept), savept->length);
6519 
6520  length_save_point = savept->length;
6521  LOG_READ_ADD_ALIGN (thread_p, sizeof (*savept), log_lsa, log_page_p);
6522 
6523  /* Print savept name */
6524  fprintf (out_fp, " Savept Name =");
6525  log_dump_data (thread_p, out_fp, length_save_point, log_lsa, log_page_p, log_hexa_dump, NULL);
6526 
6527  return log_page_p;
6528 }
6529 
6530 static LOG_PAGE *
6531 log_dump_record_2pc_prepare_commit (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * log_lsa, LOG_PAGE * log_page_p)
6532 {
6533  LOG_REC_2PC_PREPCOMMIT *prepared;
6534  unsigned int nobj_locks;
6535  int size;
6536 
6537  /* Get the DATA HEADER */
6538  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*prepared), log_lsa, log_page_p);
6539  prepared = (LOG_REC_2PC_PREPCOMMIT *) ((char *) log_page_p->area + log_lsa->offset);
6540 
6541  fprintf (out_fp, ", Client_name = %s, Gtrid = %d, Num objlocks = %u\n", prepared->user_name, prepared->gtrid,
6542  prepared->num_object_locks);
6543 
6544  nobj_locks = prepared->num_object_locks;
6545 
6546  LOG_READ_ADD_ALIGN (thread_p, sizeof (*prepared), log_lsa, log_page_p);
6547 
6548  /* Dump global transaction user information */
6549  if (prepared->gtrinfo_length > 0)
6550  {
6551  log_dump_data (thread_p, out_fp, prepared->gtrinfo_length, log_lsa, log_page_p, log_2pc_dump_gtrinfo, NULL);
6552  }
6553 
6554  /* Dump object locks */
6555  if (nobj_locks > 0)
6556  {
6557  size = nobj_locks * sizeof (LK_ACQOBJ_LOCK);
6558  log_dump_data (thread_p, out_fp, size, log_lsa, log_page_p, log_2pc_dump_acqobj_locks, NULL);
6559  }
6560 
6561  return log_page_p;
6562 }
6563 
6564 static LOG_PAGE *
6565 log_dump_record_2pc_start (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * log_lsa, LOG_PAGE * log_page_p)
6566 {
6567  LOG_REC_2PC_START *start_2pc; /* Start log record of 2PC protocol */
6568 
6569  /* Get the DATA HEADER */
6570  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*start_2pc), log_lsa, log_page_p);
6571  start_2pc = (LOG_REC_2PC_START *) ((char *) log_page_p->area + log_lsa->offset);
6572 
6573  /* Initilize the coordinator information */
6574  fprintf (out_fp, " Client_name = %s, Gtrid = %d, Num_participants = %d", start_2pc->user_name, start_2pc->gtrid,
6575  start_2pc->num_particps);
6576 
6577  LOG_READ_ADD_ALIGN (thread_p, sizeof (*start_2pc), log_lsa, log_page_p);
6578  /* Read in the participants info. block from the log */
6579  log_dump_data (thread_p, out_fp, (start_2pc->particp_id_length * start_2pc->num_particps), log_lsa, log_page_p,
6581 
6582  return log_page_p;
6583 }
6584 
6585 static LOG_PAGE *
6586 log_dump_record_2pc_acknowledgement (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * log_lsa, LOG_PAGE * log_page_p)
6587 {
6588  LOG_REC_2PC_PARTICP_ACK *received_ack; /* ack log record of 2pc protocol */
6589 
6590  /* Get the DATA HEADER */
6591  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*received_ack), log_lsa, log_page_p);
6592  received_ack = ((LOG_REC_2PC_PARTICP_ACK *) ((char *) log_page_p->area + log_lsa->offset));
6593  fprintf (out_fp, " Participant index = %d\n", received_ack->particp_index);
6594 
6595  return log_page_p;
6596 }
6597 
6598 static LOG_PAGE *
6599 log_dump_record_ha_server_state (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_LSA * log_lsa, LOG_PAGE * log_page_p)
6600 {
6602 
6603  /* Get the DATA HEADER */
6604  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*ha_server_state), log_lsa, log_page_p);
6605  ha_server_state = ((LOG_REC_HA_SERVER_STATE *) ((char *) log_page_p->area + log_lsa->offset));
6606  fprintf (out_fp, " HA server state = %d\n", ha_server_state->state);
6607 
6608  return log_page_p;
6609 }
6610 
6611 static LOG_PAGE *
6612 log_dump_record (THREAD_ENTRY * thread_p, FILE * out_fp, LOG_RECTYPE record_type, LOG_LSA * log_lsa,
6613  LOG_PAGE * log_page_p, LOG_ZIP * log_zip_p)
6614 {
6615  switch (record_type)
6616  {
6617  case LOG_UNDOREDO_DATA:
6619  log_page_p = log_dump_record_undoredo (thread_p, out_fp, log_lsa, log_page_p, log_zip_p);
6620  break;
6621 
6622  case LOG_UNDO_DATA:
6623  log_page_p = log_dump_record_undo (thread_p, out_fp, log_lsa, log_page_p, log_zip_p);
6624  break;
6625 
6626  case LOG_REDO_DATA:
6627  case LOG_POSTPONE:
6628  log_page_p = log_dump_record_redo (thread_p, out_fp, log_lsa, log_page_p, log_zip_p);
6629  break;
6630 
6633  log_page_p = log_dump_record_mvcc_undoredo (thread_p, out_fp, log_lsa, log_page_p, log_zip_p);
6634  break;
6635 
6636  case LOG_MVCC_UNDO_DATA:
6637  log_page_p = log_dump_record_mvcc_undo (thread_p, out_fp, log_lsa, log_page_p, log_zip_p);
6638  break;
6639 
6640  case LOG_MVCC_REDO_DATA:
6641  log_page_p = log_dump_record_mvcc_redo (thread_p, out_fp, log_lsa, log_page_p, log_zip_p);
6642  break;
6643 
6644  case LOG_RUN_POSTPONE:
6645  log_page_p = log_dump_record_postpone (thread_p, out_fp, log_lsa, log_page_p);
6646  break;
6647 
6649  log_page_p = log_dump_record_dbout_redo (thread_p, out_fp, log_lsa, log_page_p);
6650  break;
6651 
6652  case LOG_COMPENSATE:
6653  log_page_p = log_dump_record_compensate (thread_p, out_fp, log_lsa, log_page_p);
6654  break;
6655 
6657  log_page_p = log_dump_record_commit_postpone (thread_p, out_fp, log_lsa, log_page_p);
6658  break;
6659 
6660  case LOG_WILL_COMMIT:
6661  fprintf (out_fp, "\n");
6662  break;
6663 
6664  case LOG_COMMIT:
6665  case LOG_ABORT:
6666  log_page_p = log_dump_record_transaction_finish (thread_p, out_fp, log_lsa, log_page_p);
6667  break;
6668 
6669  case LOG_REPLICATION_DATA:
6671  log_page_p = log_dump_record_replication (thread_p, out_fp, log_lsa, log_page_p);
6672  break;
6673 
6675  log_page_p = log_dump_record_sysop_start_postpone (thread_p, out_fp, log_lsa, log_page_p, log_zip_p);
6676  break;
6677 
6678  case LOG_SYSOP_END:
6679  log_page_p = log_dump_record_sysop_end (thread_p, log_lsa, log_page_p, log_zip_p, out_fp);
6680  break;
6681 
6682  case LOG_END_CHKPT:
6683  log_page_p = log_dump_record_checkpoint (thread_p, out_fp, log_lsa, log_page_p);
6684  break;
6685 
6686  case LOG_SAVEPOINT:
6687  log_page_p = log_dump_record_save_point (thread_p, out_fp, log_lsa, log_page_p);
6688  break;
6689 
6690  case LOG_2PC_PREPARE:
6691  log_page_p = log_dump_record_2pc_prepare_commit (thread_p, out_fp, log_lsa, log_page_p);
6692  break;
6693 
6694  case LOG_2PC_START:
6695  log_page_p = log_dump_record_2pc_start (thread_p, out_fp, log_lsa, log_page_p);
6696  break;
6697 
6698  case LOG_2PC_RECV_ACK:
6699  log_page_p = log_dump_record_2pc_acknowledgement (thread_p, out_fp, log_lsa, log_page_p);
6700  break;
6701 
6703  log_page_p = log_dump_record_ha_server_state (thread_p, out_fp, log_lsa, log_page_p);
6704  break;
6705 
6706  case LOG_START_CHKPT:
6714  case LOG_DUMMY_OVF_RECORD:
6715  case LOG_DUMMY_GENERIC:
6716  fprintf (out_fp, "\n");
6717  /* That is all for this kind of log record */
6718  break;
6719 
6720  case LOG_END_OF_LOG:
6721  if (!logpb_is_page_in_archive (log_lsa->pageid))
6722  {
6723  fprintf (out_fp, "\n... xxx END OF LOG xxx ...\n");
6724  }
6725  break;
6726 
6729  default:
6730  fprintf (out_fp, "log_dump: Unknown record type = %d (%s).\n", record_type, log_to_string (record_type));
6731  LSA_SET_NULL (log_lsa);
6732  break;
6733  }
6734 
6735  return log_page_p;
6736 }
6737 
6738 /*
6739  * xlog_dump - DUMP THE LOG
6740  *
6741  * return: nothing
6742  *
6743  * isforward(in): Dump the log forward ?
6744  * start_logpageid(in): Start dumping the log at this location
6745  * dump_npages(in): Number of pages to dump
6746  * desired_tranid(in): Dump entries of only this transaction. If NULL_TRANID,
6747  * dump all.
6748  *
6749  * NOTE: Dump a set of log records stored in "dump_npages" starting at
6750  * page "start_logpageid" forward (or backward) according to the
6751  * value of "isforward". When the value of start_logpageid is
6752  * negative, we start either at the beginning or at end of the
6753  * log according to the direction of the dump. If the value of
6754  * dump_npages is a negative value, dump as many pages as
6755  * possible.
6756  * This function is used for debugging purposes.
6757  */
6758 void
6759 xlog_dump (THREAD_ENTRY * thread_p, FILE * out_fp, int isforward, LOG_PAGEID start_logpageid, DKNPAGES dump_npages,
6760  TRANID desired_tranid)
6761 {
6762  LOG_LSA lsa; /* LSA of log record to dump */
6763  char log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT], *aligned_log_pgbuf;
6764  LOG_PAGE *log_pgptr = NULL; /* Log page pointer where LSA is located */
6765  LOG_LSA log_lsa;
6766  LOG_RECTYPE type; /* Log record type */
6767  LOG_RECORD_HEADER *log_rec; /* Pointer to log record */
6768 
6769  LOG_ZIP *log_dump_ptr = NULL;
6770 
6771  aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
6772 
6773  if (out_fp == NULL)
6774  {
6775  out_fp = stdout;
6776  }
6777 
6778  fprintf (out_fp, "**************** DUMP LOGGING INFORMATION ************\n");
6779  /* Dump the transaction table and the log buffers */
6780 
6781  /* Flush any dirty log page */
6782  LOG_CS_ENTER (thread_p);
6783 
6784  xlogtb_dump_trantable (thread_p, out_fp);
6785  logpb_flush_pages_direct (thread_p);
6786  logpb_flush_header (thread_p);
6787 
6788  /* Now start dumping the log */
6789  log_dump_header (out_fp, &log_Gl.hdr);
6790 
6791  lsa.pageid = start_logpageid;
6792  lsa.offset = NULL_OFFSET;
6793 
6794  if (isforward != false)
6795  {
6796  /* Forward */
6797  if (lsa.pageid < 0)
6798  {
6799  lsa.pageid = 0;
6800  }
6801  else if (lsa.pageid > log_Gl.hdr.append_lsa.pageid && LOG_ISRESTARTED ())
6802  {
6804  }
6805  }
6806  else
6807  {
6808  /* Backward */
6809  if (lsa.pageid < 0 || lsa.pageid > log_Gl.hdr.append_lsa.pageid)
6810  {
6811  log_find_end_log (thread_p, &lsa);
6812  }
6813  }
6814 
6815  if (dump_npages > log_Gl.hdr.npages || dump_npages < 0)
6816  {
6817  dump_npages = log_Gl.hdr.npages;
6818  }
6819 
6820  fprintf (out_fp,
6821  "\n START DUMPING LOG_RECORDS: %s, start_logpageid = %lld,\n"
6822  " Num_pages_to_dump = %d, desired_tranid = %d\n", (isforward ? "Forward" : "Backaward"),
6823  (long long int) start_logpageid, dump_npages, desired_tranid);
6824 
6825  LOG_CS_EXIT (thread_p);
6826 
6827  log_pgptr = (LOG_PAGE *) aligned_log_pgbuf;
6828 
6829  if (log_dump_ptr == NULL)
6830  {
6831  log_dump_ptr = log_zip_alloc (IO_PAGESIZE);
6832  if (log_dump_ptr == NULL)
6833  {
6834  fprintf (out_fp, " Error memory alloc... Quit\n");
6835  return;
6836  }
6837  }
6838 
6839  /* Start dumping all log records following the given direction */
6840  while (!LSA_ISNULL (&lsa) && dump_npages-- > 0)
6841  {
6842  if ((logpb_fetch_page (thread_p, &lsa, LOG_CS_SAFE_READER, log_pgptr)) != NO_ERROR)
6843  {
6844  fprintf (out_fp, " Error reading page %lld... Quit\n", (long long int) lsa.pageid);
6845  if (log_dump_ptr != NULL)
6846  {
6847  log_zip_free (log_dump_ptr);
6848  }
6849  return;
6850  }
6851  /*
6852  * If offset is missing, it is because we archive an incomplete
6853  * log record or we start dumping the log not from its first page. We
6854  * have to find the offset by searching for the next log_record in the page
6855  */
6856  if (lsa.offset == NULL_OFFSET && (lsa.offset = log_pgptr->hdr.offset) == NULL_OFFSET)
6857  {
6858  /* Nothing in this page.. */
6859  if (lsa.pageid >= log_Gl.hdr.append_lsa.pageid || lsa.pageid <= 0)
6860  {
6861  LSA_SET_NULL (&lsa);
6862  }
6863  else
6864  {
6865  /* We need to dump one more page */
6866  lsa.pageid--;
6867  dump_npages++;
6868  }
6869  continue;
6870  }
6871 
6872  /* Dump all the log records stored in current log page */
6873  log_lsa.pageid = lsa.pageid;
6874 
6875  while (lsa.pageid == log_lsa.pageid)
6876  {
6877  log_lsa.offset = lsa.offset;
6878  log_rec = LOG_GET_LOG_RECORD_HEADER (log_pgptr, &log_lsa);
6879  type = log_rec->type;
6880 
6881  {
6882  /*
6883  * The following is just for debugging next address calculations
6884  */
6885  LOG_LSA next_lsa;
6886 
6887  LSA_COPY (&next_lsa, &lsa);
6888  if (log_startof_nxrec (thread_p, &next_lsa, false) == NULL
6889  || (!LSA_EQ (&next_lsa, &log_rec->forw_lsa) && !LSA_ISNULL (&log_rec->forw_lsa)))
6890  {
6891  fprintf (out_fp, "\n\n>>>>>****\n");
6892  fprintf (out_fp, "Guess next address = %lld|%d for LSA = %lld|%d\n",
6893  LSA_AS_ARGS (&next_lsa), LSA_AS_ARGS (&lsa));
6894  fprintf (out_fp, "<<<<<****\n");
6895  }
6896  }
6897 
6898  /* Find the next log record to dump .. after current one is dumped */
6899  if (isforward != false)
6900  {
6901  if (LSA_ISNULL (&log_rec->forw_lsa) && type != LOG_END_OF_LOG)
6902  {
6903  if (log_startof_nxrec (thread_p, &lsa, false) == NULL)
6904  {
6905  fprintf (out_fp, "\n****\n");
6906  fprintf (out_fp, "log_dump: Problems finding next record. BYE\n");
6907  fprintf (out_fp, "\n****\n");
6908  break;
6909  }
6910  }
6911  else
6912  {
6913  LSA_COPY (&lsa, &log_rec->forw_lsa);
6914  }
6915  /*
6916  * If the next page is NULL_PAGEID and the current page is an archive
6917  * page, this is not the end, this situation happens when an incomplete
6918  * log record was archived.
6919  * Note that we have to set lsa.pageid here since the log_lsa.pageid value
6920  * can be changed (e.g., the log record is stored in an archive page
6921  * and in an active page. Later, we try to modify it whenever is
6922  * possible.
6923  */
6924  if (LSA_ISNULL (&lsa) && logpb_is_page_in_archive (log_lsa.pageid))
6925  {
6926  lsa.pageid = log_lsa.pageid + 1;
6927  }
6928  }
6929  else
6930  {
6931  LSA_COPY (&lsa, &log_rec->back_lsa);
6932  }
6933 
6934  if (desired_tranid != NULL_TRANID && desired_tranid != log_rec->trid && log_rec->type != LOG_END_OF_LOG)
6935  {
6936  /* Don't dump this log record... */
6937  continue;
6938  }
6939 
6940  fprintf (out_fp,
6941  "\nLSA = %3lld|%3d, Forw log = %3lld|%3d, Backw log = %3lld|%3d,\n"
6942  " Trid = %3d, Prev tran logrec = %3lld|%3d\n Type = %s", (long long int) log_lsa.pageid,
6943  (int) log_lsa.offset, (long long int) log_rec->forw_lsa.pageid, (int) log_rec->forw_lsa.offset,
6944  (long long int) log_rec->back_lsa.pageid, (int) log_rec->back_lsa.offset, log_rec->trid,
6945  (long long int) log_rec->prev_tranlsa.pageid, (int) log_rec->prev_tranlsa.offset,
6946  log_to_string (type));
6947 
6948  if (LSA_ISNULL (&log_rec->forw_lsa) && type != LOG_END_OF_LOG)
6949  {
6950  /* Incomplete log record... quit */
6951  fprintf (out_fp, "\n****\n");
6952  fprintf (out_fp, "log_dump: Incomplete log_record.. Quit\n");
6953  fprintf (out_fp, "\n****\n");
6954  continue;
6955  }
6956 
6957  /* Advance the pointer to dump the type of log record */
6958 
6959  LOG_READ_ADD_ALIGN (thread_p, sizeof (*log_rec), &log_lsa, log_pgptr);
6960  log_pgptr = log_dump_record (thread_p, out_fp, type, &log_lsa, log_pgptr, log_dump_ptr);
6961  fflush (out_fp);
6962  /*
6963  * We can fix the lsa.pageid in the case of log_records without forward
6964  * address at this moment.
6965  */
6966  if (lsa.offset == NULL_OFFSET && lsa.pageid != NULL_PAGEID && lsa.pageid < log_lsa.pageid)
6967  {
6968  lsa.pageid = log_lsa.pageid;
6969  }
6970  }
6971  }
6972 
6973  if (log_dump_ptr)
6974  {
6975  log_zip_free (log_dump_ptr);
6976  }
6977 
6978  fprintf (out_fp, "\n FINISH DUMPING LOG_RECORDS \n");
6979  fprintf (out_fp, "******************************************************\n");
6980  fflush (out_fp);
6981 
6982  return;
6983 }
6984 
6985 /*
6986  *
6987  * RECOVERY DURING NORMAL PROCESSING
6988  *
6989  */
6990 
6991 /*
6992  * log_rollback_record - EXECUTE AN UNDO DURING NORMAL PROCESSING
6993  *
6994  * return: nothing
6995  *
6996  * log_lsa(in/out):Log address identifier containing the log record
6997  * log_pgptr(in/out): Pointer to page where data starts (Set as a side
6998  * effect to the page where data ends)
6999  * rcvindex(in): Index to recovery functions
7000  * rcv_vpid(in): Address of page to recover
7001  * rcv(in/out): Recovery structure for recovery function
7002  * tdes(in/out): State structure of transaction undoing data
7003  * log_unzip_ptr(in):
7004  *
7005  * NOTE: Execute an undo log record during normal rollbacks (i.e.,
7006  * other than restart recovery). A compensating log record for
7007  * operation page level logging is written by the current
7008  * function. For logical level logging, the undo function is
7009  * responsible to log a redo record, which is converted into a
7010  * compensating record by the log manager.
7011  * This function now attempts to repeat an rv function if it
7012  * fails in certain ways (e.g. due to deadlock). This is to
7013  * maintain data integrity as much as possible. The old way was
7014  * to simply ignore a failure and continue with the next record,
7015  * Obviously, skipping a record during recover could leave the
7016  * database inconsistent. All rv functions should return a
7017  * int and be coded to be called again if the work wasn't
7018  * undone the first time.
7019  */
7020 static void
7021 log_rollback_record (THREAD_ENTRY * thread_p, LOG_LSA * log_lsa, LOG_PAGE * log_page_p, LOG_RCVINDEX rcvindex,
7022  VPID * rcv_vpid, LOG_RCV * rcv, LOG_TDES * tdes, LOG_ZIP * log_unzip_ptr)
7023 {
7024  char *area = NULL;
7025  TRAN_STATE save_state; /* The current state of the transaction. Must be returned to this state */
7026  int rv_err;
7027  bool is_zipped = false;
7028 
7029  /*
7030  * Fetch the page for physical log records. If the page does not exist
7031  * anymore or there are problems fetching the page, continue anyhow, so that
7032  * compensating records are logged.
7033  */
7034 
7035  assert (rcvindex != RV_NOT_DEFINED);
7036  assert (RV_fun[rcvindex].undofun != NULL);
7037 
7038  if (RCV_IS_LOGICAL_LOG (rcv_vpid, rcvindex))
7039  {
7040  rcv->pgptr = NULL;
7041  }
7042  else
7043  {
7044  rcv->pgptr = pgbuf_fix (thread_p, rcv_vpid, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
7045  if (rcv->pgptr == NULL)
7046  {
7047  assert (false);
7048  }
7049  }
7050 
7051  /* GET BEFORE DATA */
7052 
7053  /*
7054  * If data is contained in only one buffer, pass pointer directly.
7055  * Otherwise, allocate a contiguous area, copy the data and pass this area.
7056  * At the end deallocate the area.
7057  */
7058 
7059  if (ZIP_CHECK (rcv->length))
7060  { /* check compress data */
7061  rcv->length = (int) GET_ZIP_LEN (rcv->length); /* MSB set 0 */
7062  is_zipped = true;
7063  }
7064 
7065  if (log_lsa->offset + rcv->length < (int) LOGAREA_SIZE)
7066  {
7067  rcv->data = (char *) log_page_p->area + log_lsa->offset;
7068  log_lsa->offset += rcv->length;
7069  }
7070  else
7071  {
7072  /* Need to copy the data into a contiguous area */
7073  area = (char *) malloc (rcv->length);
7074  if (area == NULL)
7075  {
7076  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rollback_record");
7077  if (rcv->pgptr != NULL)
7078  {
7079  pgbuf_unfix (thread_p, rcv->pgptr);
7080  }
7081  return;
7082  }
7083  /* Copy the data */
7084  logpb_copy_from_log (thread_p, area, rcv->length, log_lsa, log_page_p);
7085  rcv->data = area;
7086  }
7087 
7088  if (is_zipped)
7089  {
7090  /* Data UnZip */
7091  if (log_unzip (log_unzip_ptr, rcv->length, (char *) rcv->data))
7092  {
7093  rcv->length = (int) log_unzip_ptr->data_length;
7094  rcv->data = (char *) log_unzip_ptr->log_data;
7095  }
7096  else
7097  {
7098  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rollback_record");
7099  if (area != NULL)
7100  {
7101  free_and_init (area);
7102  }
7103  if (rcv->pgptr != NULL)
7104  {
7105  pgbuf_unfix (thread_p, rcv->pgptr);
7106  }
7107  return;
7108  }
7109  }
7110 
7111  /* Now call the UNDO recovery function */
7112  if (rcv->pgptr != NULL || RCV_IS_LOGICAL_LOG (rcv_vpid, rcvindex))
7113  {
7114  /*
7115  * Write a compensating log record for operation page level logging.
7116  * For logical level logging, the recovery undo function must log an
7117  * redo/CLR log to describe the undo. This in turn will be translated
7118  * to a compensating record.
7119  */
7120  if (rcvindex == RVBT_MVCC_INCREMENTS_UPD)
7121  {
7122  /* this is a special case. we need to undo changes to transaction local stats. this only has an impact on
7123  * this transaction during runtime, and recovery has no interest, so we don't have to add a compensate log
7124  * record. */
7125  rv_err = (*RV_fun[rcvindex].undofun) (thread_p, rcv);
7126  assert (rv_err == NO_ERROR);
7127  }
7128  else if (rcvindex == RVBT_MVCC_NOTIFY_VACUUM || rcvindex == RVES_NOTIFY_VACUUM)
7129  {
7130  /* do nothing */
7131  }
7132  else if (rcvindex == RVBT_LOG_GLOBAL_UNIQUE_STATS_COMMIT)
7133  {
7134  /* impossible. we cannot rollback anymore. */
7135  assert_release (false);
7136  rv_err = ER_FAILED;
7137  }
7138  else if (RCV_IS_LOGICAL_COMPENSATE_MANUAL (rcvindex))
7139  {
7140  /* B-tree logical logs will add a regular compensate in the modified pages. They do not require a logical
7141  * compensation since the "undone" page can be accessed and logged. Only no-page logical operations require
7142  * logical compensation. */
7143  /* Invoke Undo recovery function */
7144  LSA_COPY (&rcv->reference_lsa, &tdes->undo_nxlsa);
7145  rv_err = log_undo_rec_restartable (thread_p, rcvindex, rcv);
7146  if (rv_err != NO_ERROR)
7147  {
7149  "log_rollback_record: SYSTEM ERROR... Transaction %d, "
7150  "Log record %lld|%d, rcvindex = %s, was not undone due to error (%d)\n",
7151  tdes->tran_index, (long long int) log_lsa->pageid, log_lsa->offset,
7152  rv_rcvindex_string (rcvindex), rv_err);
7154  fileio_get_volume_label (rcv_vpid->volid, PEEK));
7155  assert (false);
7156  }
7158  {
7160  "BTREE_ROLLBACK: Successfully executed undo/compensate for log entry before "
7161  "lsa=%lld|%d, undo_nxlsa=%lld|%d. Transaction=%d, rcvindex=%d.\n",
7162  (long long int) log_lsa->pageid, (int) log_lsa->offset,
7163  (long long int) tdes->undo_nxlsa.pageid, (int) tdes->undo_nxlsa.offset, tdes->tran_index,
7164  rcvindex);
7165  }
7166  }
7167  else if (!RCV_IS_LOGICAL_LOG (rcv_vpid, rcvindex))
7168  {
7169  log_append_compensate (thread_p, rcvindex, rcv_vpid, rcv->offset, rcv->pgptr, rcv->length, rcv->data, tdes);
7170  /* Invoke Undo recovery function */
7171  rv_err = log_undo_rec_restartable (thread_p, rcvindex, rcv);
7172  if (rv_err != NO_ERROR)
7173  {
7175  "log_rollback_record: SYSTEM ERROR... Transaction %d, "
7176  "Log record %lld|%d, rcvindex = %s, was not undone due to error (%d)\n",
7177  tdes->tran_index, (long long int) log_lsa->pageid, log_lsa->offset,
7178  rv_rcvindex_string (rcvindex), rv_err);
7180  fileio_get_volume_label (rcv_vpid->volid, PEEK));
7181  assert (false);
7182  }
7183  }
7184  else
7185  {
7186  /* Logical logging? This is a logical undo. For now, we also use a logical compensation, meaning that we
7187  * open a system operation that is committed & compensate at the same time.
7188  * However, there might be cases when compensation is not necessarily logical. If the compensation can be
7189  * made in a single log record and can be attached to a page, the system operation becomes useless. Take the
7190  * example of some b-tree cases for compensations. There might be other cases too.
7191  */
7192  save_state = tdes->state;
7193 
7194  LSA_COPY (&rcv->reference_lsa, &tdes->undo_nxlsa);
7195 
7196  log_sysop_start (thread_p);
7197 
7198 #if defined(CUBRID_DEBUG)
7199  {
7200  LOG_LSA check_tail_lsa;
7201 
7202  LSA_COPY (&check_tail_lsa, &tdes->tail_lsa);
7203  /*
7204  * Note that tail_lsa is changed by the following function
7205  */
7206  /* Invoke Undo recovery function */
7207  rv_err = log_undo_rec_restartable (rcvindex, rcv);
7208 
7209  /* Make sure that a CLR was logged */
7210  if (LSA_EQ (&check_tail_lsa, &tdes->tail_lsa))
7211  {
7213  rv_rcvindex_string (rcvindex));
7214  }
7215  }
7216 #else /* CUBRID_DEBUG */
7217  /* Invoke Undo recovery function */
7218  /* TODO: Is undo restartable needed? */
7219  rv_err = log_undo_rec_restartable (thread_p, rcvindex, rcv);
7220 #endif /* CUBRID_DEBUG */
7221 
7222  if (rv_err != NO_ERROR)
7223  {
7225  "log_rollback_record: SYSTEM ERROR... Transaction %d, "
7226  "Log record %lld|%d, rcvindex = %s, was not undone due to error (%d)\n",
7227  tdes->tran_index, (long long int) log_lsa->pageid, log_lsa->offset,
7228  rv_rcvindex_string (rcvindex), rv_err);
7230  fileio_get_volume_label (rcv_vpid->volid, PEEK));
7231  assert (false);
7232  }
7233 
7235  tdes->state = save_state;
7236  }
7237  }
7238  else
7239  {
7240  /*
7241  * Unable to fetch page of volume... May need media recovery on such
7242  * page... write a CLR anyhow
7243  */
7244  log_append_compensate (thread_p, rcvindex, rcv_vpid, rcv->offset, NULL, rcv->length, rcv->data, tdes);
7246  fileio_get_volume_label (rcv_vpid->volid, PEEK));
7247  assert (false);
7248  }
7249 
7250  if (area != NULL)
7251  {
7252  free_and_init (area);
7253  }
7254 
7255  if (rcv->pgptr != NULL)
7256  {
7257  pgbuf_unfix (thread_p, rcv->pgptr);
7258  }
7259 }
7260 
7261 /*
7262  * log_undo_rec_restartable - Rollback a single undo record w/ restart
7263  *
7264  * return: nothing
7265  *
7266  * rcvindex(in): Index to recovery functions
7267  * rcv(in/out): Recovery structure for recovery function
7268  *
7269  * NOTE: Perform the undo of a singe log record. Even though it would
7270  * indicate a serious problem in the design, check for deadlock
7271  * and timeout to make sure this log record was truly undone.
7272  * Continue to retry the log undo if possible.
7273  * CAVEAT: This attempt to retry in the case of failure assumes that the
7274  * rcvindex undo function we invoke has no partial side-effects
7275  * for the case where it fails. Otherwise restarting it would not
7276  * be a very smart thing to do.
7277  */
7278 static int
7280 {
7281  int num_retries = 0; /* Avoid infinite loop */
7282  int error_code = NO_ERROR;
7283 
7284  do
7285  {
7286  if (error_code != NO_ERROR)
7287  {
7288 #if defined(CUBRID_DEBUG)
7290  "WARNING: RETRY DURING UNDO WAS NEEDED ... TranIndex: %d, Cnt = %d, Err = %d, Rcvindex = %s\n",
7291  LOG_FIND_THREAD_TRAN_INDEX (thread_p), num_retries, error_code, rv_rcvindex_string (rcvindex));
7292 #endif /* CUBRID_DEBUG */
7293  }
7294  error_code = (*RV_fun[rcvindex].undofun) (thread_p, rcv);
7295  }
7296  while (++num_retries <= LOG_REC_UNDO_MAX_ATTEMPTS
7297  && (error_code == ER_LK_PAGE_TIMEOUT || error_code == ER_LK_UNILATERALLY_ABORTED));
7298 
7299  return error_code;
7300 }
7301 
7302 /*
7303  * log_dump_record_header_to_string - dump log record header to string
7304  *
7305  * return: nothing
7306  *
7307  * log(in): log record header pointer
7308  * buf(out): char buffer pointer
7309  * len(in): max size of the buffer
7310  *
7311  */
7312 static void
7314 {
7315  const char *fmt = "TYPE[%d], TRID[%d], PREV[%lld,%d], BACK[%lld,%d], FORW[%lld,%d]";
7316 
7317  snprintf (buf, len, fmt, log->type, log->trid, (long long int) log->prev_tranlsa.pageid, log->prev_tranlsa.offset,
7318  (long long int) log->back_lsa.pageid, log->back_lsa.offset, (long long int) log->forw_lsa.pageid,
7319  log->forw_lsa.offset);
7320 }
7321 
7322 /*
7323  * log_rollback - Rollback a transaction
7324  *
7325  * return: nothing
7326  *
7327  * tdes(in): Transaction descriptor
7328  * upto_lsa_ptr(in): Rollback up to this log sequence address
7329  *
7330  * NOTE:Rollback the transaction associated with the given tdes
7331  * structure upto the given lsa. If LSA is NULL, the transaction
7332  * is completely rolled back. This function is used for aborts
7333  * related no to database crashes.
7334  */
7335 static void
7336 log_rollback (THREAD_ENTRY * thread_p, LOG_TDES * tdes, const LOG_LSA * upto_lsa_ptr)
7337 {
7338  LOG_LSA prev_tranlsa; /* Previous LSA */
7339  LOG_LSA upto_lsa; /* copy of upto_lsa_ptr contents */
7340  char log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT], *aligned_log_pgbuf;
7341  LOG_PAGE *log_pgptr = NULL; /* Log page pointer of LSA log record */
7342  LOG_LSA log_lsa;
7343  LOG_RECORD_HEADER *log_rec = NULL; /* The log record */
7344  LOG_REC_UNDOREDO *undoredo = NULL; /* An undoredo log record */
7345  LOG_REC_MVCC_UNDOREDO *mvcc_undoredo = NULL; /* A MVCC undoredo log rec */
7346  LOG_REC_UNDO *undo = NULL; /* An undo log record */
7347  LOG_REC_MVCC_UNDO *mvcc_undo = NULL; /* An undo log record */
7348  LOG_REC_COMPENSATE *compensate = NULL; /* A compensating log record */
7349  LOG_REC_SYSOP_END *sysop_end = NULL; /* Partial result from top system operation */
7350  LOG_RCV rcv; /* Recovery structure */
7351  VPID rcv_vpid; /* VPID of data to recover */
7352  LOG_RCVINDEX rcvindex; /* Recovery index */
7353  bool isdone;
7354  int old_wait_msecs = 0; /* Old transaction lock wait */
7355  LOG_ZIP *log_unzip_ptr = NULL;
7356  int data_header_size = 0;
7357  bool is_mvcc_op = false;
7358 
7359  aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
7360 
7361  /*
7362  * Execute every single undo log record upto the given upto_lsa_ptr since it
7363  * is not a system crash
7364  */
7365 
7366  if (LSA_ISNULL (&tdes->tail_lsa))
7367  {
7368  /* Nothing to undo */
7369  return;
7370  }
7371 
7372  /*
7373  * I should not timeout on a page that I need to undo, otherwise, I may
7374  * end up with database corruption problems. That is, no timeouts during
7375  * rollback.
7376  */
7377  old_wait_msecs = xlogtb_reset_wait_msecs (thread_p, TRAN_LOCK_INFINITE_WAIT);
7378 
7379  LSA_COPY (&prev_tranlsa, &tdes->undo_nxlsa);
7380  /*
7381  * In some cases what upto_lsa_ptr points to is volatile, e.g.
7382  * when it is from the topops stack (which can be reallocated by
7383  * operations during this rollback).
7384  */
7385  if (upto_lsa_ptr != NULL)
7386  {
7387  LSA_COPY (&upto_lsa, upto_lsa_ptr);
7388  }
7389  else
7390  {
7391  LSA_SET_NULL (&upto_lsa);
7392  }
7393 
7394  log_pgptr = (LOG_PAGE *) aligned_log_pgbuf;
7395 
7396  isdone = false;
7397 
7398  log_unzip_ptr = log_zip_alloc (IO_PAGESIZE);
7399 
7400  if (log_unzip_ptr == NULL)
7401  {
7402  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rollback");
7403  return;
7404  }
7405 
7406  while (!LSA_ISNULL (&prev_tranlsa) && !isdone)
7407  {
7408  /* Fetch the page where the LSA record to undo is located */
7409  LSA_COPY (&log_lsa, &prev_tranlsa);
7410  log_lsa.offset = LOG_PAGESIZE;
7411 
7412  if ((logpb_fetch_page (thread_p, &log_lsa, LOG_CS_FORCE_USE, log_pgptr)) != NO_ERROR)
7413  {
7414  (void) xlogtb_reset_wait_msecs (thread_p, old_wait_msecs);
7415  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rollback");
7416  if (log_unzip_ptr != NULL)
7417  {
7418  log_zip_free (log_unzip_ptr);
7419  }
7420  return;
7421  }
7422 
7423  while (prev_tranlsa.pageid == log_lsa.pageid)
7424  {
7425  /* Break at upto_lsa for partial rollbacks */
7426  if (upto_lsa_ptr != NULL && LSA_LE (&prev_tranlsa, &upto_lsa))
7427  {
7428  /* Finish at this point */
7429  isdone = true;
7430  break;
7431  }
7432 
7433  /* Find the log record to undo */
7434  log_lsa.offset = prev_tranlsa.offset;
7435  log_rec = LOG_GET_LOG_RECORD_HEADER (log_pgptr, &log_lsa);
7436 
7437  /*
7438  * Next record to undo.. that is previous record in the chain.
7439  * We need to save it in this variable since the undo_nxlsa pointer
7440  * may be set when we log something related to rollback (e.g., case
7441  * of logical operation). Reset the undo_nxlsa back once the
7442  * rollback_rec is done.
7443  */
7444 
7445  LSA_COPY (&prev_tranlsa, &log_rec->prev_tranlsa);
7446  LSA_COPY (&tdes->undo_nxlsa, &prev_tranlsa);
7447 
7448  switch (log_rec->type)
7449  {
7452  case LOG_UNDOREDO_DATA:
7454 
7455  /* Does this record belong to a MVCC op? */
7456  if (log_rec->type == LOG_MVCC_UNDOREDO_DATA || log_rec->type == LOG_MVCC_DIFF_UNDOREDO_DATA)
7457  {
7458  is_mvcc_op = true;
7459  }
7460  else
7461  {
7462  is_mvcc_op = false;
7463  }
7464 
7465  /* Read the DATA HEADER */
7466  LOG_READ_ADD_ALIGN (thread_p, sizeof (*log_rec), &log_lsa, log_pgptr);
7467  if (is_mvcc_op)
7468  {
7469  /* Data header is MVCC undoredo */
7470  data_header_size = sizeof (*mvcc_undoredo);
7471  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, data_header_size, &log_lsa, log_pgptr);
7472  mvcc_undoredo = (LOG_REC_MVCC_UNDOREDO *) ((char *) log_pgptr->area + log_lsa.offset);
7473 
7474  /* Get undoredo info */
7475  undoredo = &mvcc_undoredo->undoredo;
7476 
7477  /* Save transaction MVCCID for recovery */
7478  rcv.mvcc_id = mvcc_undoredo->mvccid;
7479  }
7480  else
7481  {
7482  data_header_size = sizeof (*undoredo);
7483  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, data_header_size, &log_lsa, log_pgptr);
7484  undoredo = (LOG_REC_UNDOREDO *) ((char *) log_pgptr->area + log_lsa.offset);
7485 
7486  rcv.mvcc_id = MVCCID_NULL;
7487  }
7488 
7489  rcvindex = undoredo->data.rcvindex;
7490  rcv.length = undoredo->ulength;
7491  rcv.offset = undoredo->data.offset;
7492  rcv_vpid.volid = undoredo->data.volid;
7493  rcv_vpid.pageid = undoredo->data.pageid;
7494 
7495  LOG_READ_ADD_ALIGN (thread_p, data_header_size, &log_lsa, log_pgptr);
7496 
7497  log_rollback_record (thread_p, &log_lsa, log_pgptr, rcvindex, &rcv_vpid, &rcv, tdes, log_unzip_ptr);
7498  break;
7499 
7500  case LOG_MVCC_UNDO_DATA:
7501  case LOG_UNDO_DATA:
7502  /* Does record belong to a MVCC op? */
7503  is_mvcc_op = (log_rec->type == LOG_MVCC_UNDO_DATA);
7504 
7505  /* Read the DATA HEADER */
7506  LOG_READ_ADD_ALIGN (thread_p, sizeof (*log_rec), &log_lsa, log_pgptr);
7507  if (is_mvcc_op)
7508  {
7509  /* Data header is MVCC undo */
7510  data_header_size = sizeof (*mvcc_undo);
7511  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, data_header_size, &log_lsa, log_pgptr);
7512  mvcc_undo = (LOG_REC_MVCC_UNDO *) ((char *) log_pgptr->area + log_lsa.offset);
7513  /* Get undo info */
7514  undo = &mvcc_undo->undo;
7515 
7516  /* Save transaction MVCCID for recovery */
7517  rcv.mvcc_id = mvcc_undo->mvccid;
7518  }
7519  else
7520  {
7521  data_header_size = sizeof (*undo);
7522  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, data_header_size, &log_lsa, log_pgptr);
7523  undo = (LOG_REC_UNDO *) ((char *) log_pgptr->area + log_lsa.offset);
7524 
7525  rcv.mvcc_id = MVCCID_NULL;
7526  }
7527  rcvindex = undo->data.rcvindex;
7528  rcv.offset = undo->data.offset;
7529  rcv_vpid.volid = undo->data.volid;
7530  rcv_vpid.pageid = undo->data.pageid;
7531  rcv.length = undo->length;
7532 
7533  LOG_READ_ADD_ALIGN (thread_p, data_header_size, &log_lsa, log_pgptr);
7534 
7535  log_rollback_record (thread_p, &log_lsa, log_pgptr, rcvindex, &rcv_vpid, &rcv, tdes, log_unzip_ptr);
7536  break;
7537 
7538  case LOG_COMPENSATE:
7539  /*
7540  * We found a partial rollback, use the CLR to find the next record
7541  * to undo
7542  */
7543 
7544  /* Read the DATA HEADER */
7545  LOG_READ_ADD_ALIGN (thread_p, sizeof (*log_rec), &log_lsa, log_pgptr);
7546  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*compensate), &log_lsa, log_pgptr);
7547  compensate = (LOG_REC_COMPENSATE *) ((char *) log_pgptr->area + log_lsa.offset);
7548  LSA_COPY (&prev_tranlsa, &compensate->undo_nxlsa);
7549  break;
7550 
7551  case LOG_SYSOP_END:
7552  /*
7553  * We found a system top operation that should be skipped from rollback.
7554  */
7555 
7556  /* Read the DATA HEADER */
7557  LOG_READ_ADD_ALIGN (thread_p, sizeof (*log_rec), &log_lsa, log_pgptr);
7558  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*sysop_end), &log_lsa, log_pgptr);
7559  sysop_end = ((LOG_REC_SYSOP_END *) ((char *) log_pgptr->area + log_lsa.offset));
7560 
7561  if (sysop_end->type == LOG_SYSOP_END_LOGICAL_UNDO)
7562  {
7563  rcvindex = sysop_end->undo.data.rcvindex;
7564  rcv.offset = sysop_end->undo.data.offset;
7565  rcv_vpid.volid = sysop_end->undo.data.volid;
7566  rcv_vpid.pageid = sysop_end->undo.data.pageid;
7567  rcv.length = sysop_end->undo.length;
7568  rcv.mvcc_id = MVCCID_NULL;
7569 
7570  /* will jump to parent LSA. save it now before advancing to undo data */
7571  LSA_COPY (&prev_tranlsa, &sysop_end->lastparent_lsa);
7572  LSA_COPY (&tdes->undo_nxlsa, &sysop_end->lastparent_lsa);
7573 
7574  LOG_READ_ADD_ALIGN (thread_p, sizeof (*sysop_end), &log_lsa, log_pgptr);
7575  log_rollback_record (thread_p, &log_lsa, log_pgptr, rcvindex, &rcv_vpid, &rcv, tdes, log_unzip_ptr);
7576  }
7577  else if (sysop_end->type == LOG_SYSOP_END_LOGICAL_MVCC_UNDO)
7578  {
7579  rcvindex = sysop_end->mvcc_undo.undo.data.rcvindex;
7580  rcv.offset = sysop_end->mvcc_undo.undo.data.offset;
7581  rcv_vpid.volid = sysop_end->mvcc_undo.undo.data.volid;
7582  rcv_vpid.pageid = sysop_end->mvcc_undo.undo.data.pageid;
7583  rcv.length = sysop_end->mvcc_undo.undo.length;
7584  rcv.mvcc_id = sysop_end->mvcc_undo.mvccid;
7585 
7586  /* will jump to parent LSA. save it now before advancing to undo data */
7587  LSA_COPY (&prev_tranlsa, &sysop_end->lastparent_lsa);
7588  LSA_COPY (&tdes->undo_nxlsa, &sysop_end->lastparent_lsa);
7589 
7590  LOG_READ_ADD_ALIGN (thread_p, sizeof (*sysop_end), &log_lsa, log_pgptr);
7591  log_rollback_record (thread_p, &log_lsa, log_pgptr, rcvindex, &rcv_vpid, &rcv, tdes, log_unzip_ptr);
7592  }
7593  else if (sysop_end->type == LOG_SYSOP_END_LOGICAL_COMPENSATE)
7594  {
7595  /* compensate */
7596  LSA_COPY (&prev_tranlsa, &sysop_end->compensate_lsa);
7597  }
7598  else if (sysop_end->type == LOG_SYSOP_END_LOGICAL_RUN_POSTPONE)
7599  {
7600  /* this must be partial rollback during recovery of another logical run postpone */
7601  assert (!LOG_ISRESTARTED ());
7602  /* we have to stop */
7603  LSA_SET_NULL (&prev_tranlsa);
7604  }
7605  else
7606  {
7607  /* jump to last parent */
7608  LSA_COPY (&prev_tranlsa, &sysop_end->lastparent_lsa);
7609  }
7610  break;
7611 
7612  case LOG_REDO_DATA:
7613  case LOG_MVCC_REDO_DATA:
7616  case LOG_POSTPONE:
7617  case LOG_START_CHKPT:
7618  case LOG_END_CHKPT:
7619  case LOG_SAVEPOINT:
7620  case LOG_2PC_PREPARE:
7621  case LOG_2PC_START:
7624  case LOG_REPLICATION_DATA:
7628  case LOG_DUMMY_OVF_RECORD:
7629  case LOG_DUMMY_GENERIC:
7630  break;
7631 
7632  case LOG_RUN_POSTPONE:
7635  /* Undo of run postpone system operation. End here. */
7636  assert (!LOG_ISRESTARTED ());
7637  LSA_SET_NULL (&prev_tranlsa);
7638  break;
7639 
7640  case LOG_WILL_COMMIT:
7641  case LOG_COMMIT:
7642  case LOG_ABORT:
7645  case LOG_2PC_RECV_ACK:
7647  case LOG_END_OF_LOG:
7650  default:
7651  {
7652  char msg[LINE_MAX];
7653 
7655  log_dump_record_header_to_string (log_rec, msg, LINE_MAX);
7656  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, msg);
7657  break;
7658  }
7659  } /* switch */
7660 
7661  /* Just in case, it was changed or the previous address has changed */
7662  LSA_COPY (&tdes->undo_nxlsa, &prev_tranlsa);
7663  } /* while */
7664 
7665  } /* while */
7666 
7667  /* Remember the undo next lsa for partial rollbacks */
7668  LSA_COPY (&tdes->undo_nxlsa, &prev_tranlsa);
7669  (void) xlogtb_reset_wait_msecs (thread_p, old_wait_msecs);
7670 
7671  if (log_unzip_ptr != NULL)
7672  {
7673  log_zip_free (log_unzip_ptr);
7674  }
7675  tdes->m_log_postpone_cache.reset ();
7676 
7677  return;
7678 
7679 }
7680 
7681 /*
7682  * log_get_next_nested_top - Get top system action list
7683  *
7684  * return: top system action count
7685  *
7686  * tdes(in): Transaction descriptor
7687  * start_postpone_lsa(in): Where to start looking for postpone records
7688  * out_nxtop_range_stack(in/out): Set as a side effect to topop range stack.
7689  *
7690  * NOTE: Find a nested top system operation which start after
7691  * start_postpone_lsa and before tdes->tail_lsa.
7692  */
7693 int
7694 log_get_next_nested_top (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_LSA * start_postpone_lsa,
7695  LOG_TOPOP_RANGE ** out_nxtop_range_stack)
7696 {
7697  LOG_REC_SYSOP_END *top_result;
7698  char log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT];
7699  char *aligned_log_pgbuf;
7700  LOG_PAGE *log_pgptr = NULL;
7701  LOG_RECORD_HEADER *log_rec;
7702  LOG_LSA tmp_log_lsa;
7703  LOG_LSA top_result_lsa;
7704  LOG_LSA prev_last_parent_lsa;
7705  LOG_TOPOP_RANGE *nxtop_stack;
7706  LOG_TOPOP_RANGE *prev_nxtop_stack;
7707  int nxtop_count = 0;
7708  int nxtop_stack_size = 0;
7709  LOG_PAGEID last_fetch_page_id = NULL_PAGEID;
7710 
7711  if (LSA_ISNULL (&tdes->tail_topresult_lsa) || !LSA_GT (&tdes->tail_topresult_lsa, start_postpone_lsa))
7712  {
7713  return 0;
7714  }
7715 
7716  LSA_COPY (&top_result_lsa, &tdes->tail_topresult_lsa);
7717  LSA_SET_NULL (&prev_last_parent_lsa);
7718 
7719  aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
7720  log_pgptr = (LOG_PAGE *) aligned_log_pgbuf;
7721 
7722  nxtop_stack = *out_nxtop_range_stack;
7723  nxtop_stack_size = LOG_TOPOP_STACK_INIT_SIZE;
7724 
7725  do
7726  {
7727  if (nxtop_count >= nxtop_stack_size)
7728  {
7729  prev_nxtop_stack = nxtop_stack;
7730 
7731  nxtop_stack_size *= 2;
7732  nxtop_stack = (LOG_TOPOP_RANGE *) malloc (nxtop_stack_size * sizeof (LOG_TOPOP_RANGE));
7733  if (nxtop_stack == NULL)
7734  {
7735  if (prev_nxtop_stack != *out_nxtop_range_stack)
7736  {
7737  free_and_init (prev_nxtop_stack);
7738  }
7739  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_get_next_nested_top");
7740  return 0;
7741  }
7742 
7743  memcpy (nxtop_stack, prev_nxtop_stack, (nxtop_stack_size / 2) * sizeof (LOG_TOPOP_RANGE));
7744 
7745  if (prev_nxtop_stack != *out_nxtop_range_stack)
7746  {
7747  free_and_init (prev_nxtop_stack);
7748  }
7749  }
7750 
7751  if (last_fetch_page_id != top_result_lsa.pageid)
7752  {
7753  if (logpb_fetch_page (thread_p, &top_result_lsa, LOG_CS_FORCE_USE, log_pgptr) != NO_ERROR)
7754  {
7755  if (nxtop_stack != *out_nxtop_range_stack)
7756  {
7757  free_and_init (nxtop_stack);
7758  }
7759  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_get_next_nested_top");
7760  return 0;
7761  }
7762  }
7763 
7764  log_rec = LOG_GET_LOG_RECORD_HEADER (log_pgptr, &top_result_lsa);
7765 
7766  if (log_rec->type == LOG_SYSOP_END)
7767  {
7768  /* Read the DATA HEADER */
7769  LOG_LSA prev_tran_lsa = log_rec->back_lsa;
7770 
7771  LSA_COPY (&tmp_log_lsa, &top_result_lsa);
7772  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), &tmp_log_lsa, log_pgptr);
7773  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_SYSOP_END), &tmp_log_lsa, log_pgptr);
7774  top_result = (LOG_REC_SYSOP_END *) ((char *) log_pgptr->area + tmp_log_lsa.offset);
7775  last_fetch_page_id = tmp_log_lsa.pageid;
7776 
7777  /*
7778  * There may be some nested top system operations that are committed
7779  * and aborted in the desired region
7780  */
7781  if (LSA_ISNULL (&prev_last_parent_lsa) || LSA_LE (&top_result_lsa, &prev_last_parent_lsa))
7782  {
7783  LSA_COPY (&(nxtop_stack[nxtop_count].start_lsa), &top_result->lastparent_lsa);
7784  if (top_result->type == LOG_SYSOP_END_LOGICAL_RUN_POSTPONE)
7785  {
7786  /* we need to process this log record. end range at previous log record. */
7787  LSA_COPY (&(nxtop_stack[nxtop_count].end_lsa), &prev_tran_lsa);
7788  }
7789  else
7790  {
7791  /* end range at system op end log record */
7792  LSA_COPY (&(nxtop_stack[nxtop_count].end_lsa), &top_result_lsa);
7793  }
7794 
7795  nxtop_count++;
7796 
7797  LSA_COPY (&prev_last_parent_lsa, &top_result->lastparent_lsa);
7798  }
7799 
7800  LSA_COPY (&top_result_lsa, &top_result->prv_topresult_lsa);
7801  }
7802  else
7803  {
7804  if (nxtop_stack != *out_nxtop_range_stack)
7805  {
7806  free_and_init (nxtop_stack);
7807  }
7808  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_get_next_nested_top");
7809  return 0;
7810  }
7811  }
7812  while (top_result_lsa.pageid != NULL_PAGEID && LSA_GT (&top_result_lsa, start_postpone_lsa));
7813 
7814  *out_nxtop_range_stack = nxtop_stack;
7815 
7816  return nxtop_count;
7817 }
7818 
7819 /*
7820  * log_tran_do_postpone () - do postpone for transaction.
7821  *
7822  * return : void
7823  * thread_p (in) : thread entry
7824  * tdes (in) : transaction descriptor
7825  */
7826 static void
7828 {
7829  if (LSA_ISNULL (&tdes->posp_nxlsa))
7830  {
7831  /* nothing to do */
7832  return;
7833  }
7834 
7835  assert (tdes->topops.last < 0);
7836 
7837  log_append_commit_postpone (thread_p, tdes, &tdes->posp_nxlsa);
7838 
7839  if (tdes->m_log_postpone_cache.do_postpone (*thread_p, tdes->posp_nxlsa))
7840  {
7841  // do postpone from cache first
7843  return;
7844  }
7846 
7847  log_do_postpone (thread_p, tdes, &tdes->posp_nxlsa);
7848 }
7849 
7850 /*
7851  * log_sysop_do_postpone () - do postpone for system operation
7852  *
7853  * return : void
7854  * thread_p (in) : thread entry
7855  * tdes (in) : transaction descriptor
7856  * sysop_end (in) : system end op log record
7857  * data_size (in) : data size (for logical undo)
7858  * data (in) : data (for logical undo)
7859  */
7860 static void
7861 log_sysop_do_postpone (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_REC_SYSOP_END * sysop_end, int data_size,
7862  const char *data)
7863 {
7864  LOG_REC_SYSOP_START_POSTPONE sysop_start_postpone;
7865  TRAN_STATE save_state = tdes->state;
7866 
7868  {
7869  /* nothing to postpone */
7870  return;
7871  }
7872 
7873  assert (sysop_end != NULL);
7874  assert (sysop_end->type != LOG_SYSOP_END_ABORT);
7875  /* we cannot have TRAN_UNACTIVE_TOPOPE_COMMITTED_WITH_POSTPONE inside TRAN_UNACTIVE_TOPOPE_COMMITTED_WITH_POSTPONE */
7877 
7878  sysop_start_postpone.sysop_end = *sysop_end;
7879  sysop_start_postpone.posp_lsa = *LOG_TDES_LAST_SYSOP_POSP_LSA (tdes);
7880  log_append_sysop_start_postpone (thread_p, tdes, &sysop_start_postpone, data_size, data);
7881 
7882  if (tdes->m_log_postpone_cache.do_postpone (*thread_p, *(LOG_TDES_LAST_SYSOP_POSP_LSA (tdes))))
7883  {
7884  /* Do postpone was run from cached postpone entries. */
7885  tdes->state = save_state;
7887  return;
7888  }
7890 
7891  log_do_postpone (thread_p, tdes, LOG_TDES_LAST_SYSOP_POSP_LSA (tdes));
7892 
7893  tdes->state = save_state;
7894 }
7895 
7896 /*
7897  * log_do_postpone - Scan forward doing postpone operations of given transaction
7898  *
7899  * return: nothing
7900  *
7901  * tdes(in): Transaction descriptor
7902  * start_posplsa(in): Where to start looking for postpone records
7903  *
7904  * NOTE: Scan the log forward doing postpone operations of given transaction.
7905  * This function is invoked after a transaction is declared committed with postpone actions.
7906  */
7907 void
7908 log_do_postpone (THREAD_ENTRY * thread_p, LOG_TDES * tdes, LOG_LSA * start_postpone_lsa)
7909 {
7910  LOG_LSA end_postpone_lsa; /* The last postpone record of transaction cannot be after this address */
7911  LOG_LSA start_seek_lsa; /* start looking for postpone records at this address */
7912  LOG_LSA *end_seek_lsa; /* Stop looking for postpone records at this address */
7913  LOG_LSA next_start_seek_lsa; /* Next address to look for postpone records. Usually the end of a top system
7914  * operation. */
7915  LOG_LSA log_lsa;
7916  LOG_LSA forward_lsa;
7917 
7918  char log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT];
7919  char *aligned_log_pgbuf;
7920  LOG_PAGE *log_pgptr = NULL;
7921  LOG_RECORD_HEADER *log_rec;
7922  bool isdone;
7923 
7925  LOG_TOPOP_RANGE *nxtop_stack = NULL;
7926  LOG_TOPOP_RANGE *nxtop_range = NULL;
7927  int nxtop_count = 0;
7928 
7929  assert (!LSA_ISNULL (start_postpone_lsa));
7932 
7933  aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
7934  log_pgptr = (LOG_PAGE *) aligned_log_pgbuf;
7935 
7936  LSA_COPY (&end_postpone_lsa, &tdes->tail_lsa);
7937  LSA_COPY (&next_start_seek_lsa, start_postpone_lsa);
7938 
7939  nxtop_stack = nxtop_array;
7940  nxtop_count = log_get_next_nested_top (thread_p, tdes, start_postpone_lsa, &nxtop_stack);
7941 
7942  while (!LSA_ISNULL (&next_start_seek_lsa))
7943  {
7944  LSA_COPY (&start_seek_lsa, &next_start_seek_lsa);
7945 
7946  if (nxtop_count > 0)
7947  {
7948  nxtop_count--;
7949  nxtop_range = &(nxtop_stack[nxtop_count]);
7950 
7951  if (LSA_LT (&start_seek_lsa, &(nxtop_range->start_lsa)))
7952  {
7953  end_seek_lsa = &(nxtop_range->start_lsa);
7954  LSA_COPY (&next_start_seek_lsa, &(nxtop_range->end_lsa));
7955  }
7956  else if (LSA_EQ (&start_seek_lsa, &(nxtop_range->end_lsa)))
7957  {
7958  end_seek_lsa = &end_postpone_lsa;
7959  LSA_SET_NULL (&next_start_seek_lsa);
7960  }
7961  else
7962  {
7963  LSA_COPY (&next_start_seek_lsa, &(nxtop_range->end_lsa));
7964  continue;
7965  }
7966  }
7967  else
7968  {
7969  end_seek_lsa = &end_postpone_lsa;
7970  LSA_SET_NULL (&next_start_seek_lsa);
7971  }
7972 
7973  /*
7974  * Start doing postpone operation for this range
7975  */
7976 
7977  LSA_COPY (&forward_lsa, &start_seek_lsa);
7978 
7979  isdone = false;
7980  while (!LSA_ISNULL (&forward_lsa) && !isdone)
7981  {
7982  LOG_LSA fetch_lsa;
7983 
7984  /* Fetch the page where the postpone LSA record is located */
7985  LSA_COPY (&log_lsa, &forward_lsa);
7986  fetch_lsa.pageid = log_lsa.pageid;
7987  fetch_lsa.offset = LOG_PAGESIZE;
7988  if (logpb_fetch_page (thread_p, &fetch_lsa, LOG_CS_FORCE_USE, log_pgptr) != NO_ERROR)
7989  {
7990  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_do_postpone");
7991  goto end;
7992  }
7993 
7994  while (forward_lsa.pageid == log_lsa.pageid)
7995  {
7996  if (LSA_GT (&forward_lsa, end_seek_lsa))
7997  {
7998  /* Finish at this point */
7999  isdone = true;
8000  break;
8001  }
8002 
8003  /*
8004  * If an offset is missing, it is because we archive an incomplete log record.
8005  * This log_record was completed later.
8006  * Thus, we have to find the offset by searching for the next log_record in the page.
8007  */
8008  if (forward_lsa.offset == NULL_OFFSET)
8009  {
8010  forward_lsa.offset = log_pgptr->hdr.offset;
8011  if (forward_lsa.offset == NULL_OFFSET)
8012  {
8013  /* Continue at next pageid */
8014  if (logpb_is_page_in_archive (log_lsa.pageid))
8015  {
8016  forward_lsa.pageid = log_lsa.pageid + 1;
8017  }
8018  else
8019  {
8020  forward_lsa.pageid = NULL_PAGEID;
8021  }
8022  continue;
8023  }
8024  }
8025 
8026  /* Find the postpone log record to execute */
8027  log_lsa.offset = forward_lsa.offset;
8028  log_rec = LOG_GET_LOG_RECORD_HEADER (log_pgptr, &log_lsa);
8029 
8030  /* Find the next log record in the log */
8031  LSA_COPY (&forward_lsa, &log_rec->forw_lsa);
8032 
8033  if (forward_lsa.pageid == NULL_PAGEID && logpb_is_page_in_archive (log_lsa.pageid))
8034  {
8035  forward_lsa.pageid = log_lsa.pageid + 1;
8036  }
8037 
8038  if (log_rec->trid == tdes->trid)
8039  {
8040  switch (log_rec->type)
8041  {
8042  case LOG_UNDOREDO_DATA:
8044  case LOG_UNDO_DATA:
8045  case LOG_REDO_DATA:
8048  case LOG_MVCC_UNDO_DATA:
8049  case LOG_MVCC_REDO_DATA:
8051  case LOG_RUN_POSTPONE:
8052  case LOG_COMPENSATE:
8053  case LOG_SAVEPOINT:
8055  case LOG_REPLICATION_DATA:
8059  case LOG_DUMMY_OVF_RECORD:
8060  case LOG_DUMMY_GENERIC:
8061  break;
8062 
8063  case LOG_POSTPONE:
8064  {
8065  int mod_factor = 5000; /* 0.02% */
8066 
8068  }
8069 
8070  if (log_run_postpone_op (thread_p, &log_lsa, log_pgptr) != NO_ERROR)
8071  {
8072  goto end;
8073  }
8074 
8075  /* TODO: consider to add FI here */
8076  break;
8077 
8078  case LOG_WILL_COMMIT:
8081  case LOG_2PC_PREPARE:
8082  case LOG_2PC_START:
8084  /* This is it */
8085  LSA_SET_NULL (&forward_lsa);
8086  break;
8087 
8088  case LOG_SYSOP_END:
8089  if (!LSA_EQ (&log_lsa, &start_seek_lsa))
8090  {
8091 #if defined(CUBRID_DEBUG)
8093  "log_do_postpone: SYSTEM ERROR.. Bad log_rectype = %d\n (%s)."
8094  " Maybe BAD POSTPONE RANGE\n", log_rec->type, log_to_string (log_rec->type));
8095 #endif /* CUBRID_DEBUG */
8096  ; /* Nothing */
8097  }
8098  break;
8099 
8100  case LOG_END_OF_LOG:
8101  if (forward_lsa.pageid == NULL_PAGEID && logpb_is_page_in_archive (log_lsa.pageid))
8102  {
8103  forward_lsa.pageid = log_lsa.pageid + 1;
8104  }
8105  break;
8106 
8107  case LOG_COMMIT:
8108  case LOG_ABORT:
8109  case LOG_START_CHKPT:
8110  case LOG_END_CHKPT:
8114  case LOG_2PC_RECV_ACK:
8118  default:
8119 #if defined(CUBRID_DEBUG)
8121  "log_do_postpone: SYSTEM ERROR..Bad log_rectype = %d (%s)... ignored\n",
8122  log_rec->type, log_to_string (log_rec->type));
8123 #endif /* CUBRID_DEBUG */
8124  break;
8125  }
8126  }
8127 
8128  /*
8129  * We can fix the lsa.pageid in the case of log_records without forward address at this moment.
8130  */
8131 
8132  if (forward_lsa.offset == NULL_OFFSET && forward_lsa.pageid != NULL_PAGEID
8133  && forward_lsa.pageid < log_lsa.pageid)
8134  {
8135  forward_lsa.pageid = log_lsa.pageid;
8136  }
8137  }
8138  }
8139  }
8140 
8141 end:
8142  if (nxtop_stack != nxtop_array && nxtop_stack != NULL)
8143  {
8144  free_and_init (nxtop_stack);
8145  }
8146 
8147  return;
8148 }
8149 
8150 static int
8151 log_run_postpone_op (THREAD_ENTRY * thread_p, LOG_LSA * log_lsa, LOG_PAGE * log_pgptr)
8152 {
8153  LOG_LSA ref_lsa; /* The address of a postpone record */
8154  LOG_REC_REDO redo; /* A redo log record */
8155  char *rcv_data = NULL;
8156  char *area = NULL;
8157 
8158  LSA_COPY (&ref_lsa, log_lsa);
8159 
8160  /* Get the DATA HEADER */
8161  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), log_lsa, log_pgptr);
8162  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_REDO), log_lsa, log_pgptr);
8163 
8164  redo = *((LOG_REC_REDO *) ((char *) log_pgptr->area + log_lsa->offset));
8165 
8166  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_REDO), log_lsa, log_pgptr);
8167 
8168  /* GET AFTER DATA */
8169 
8170  /* If data is contained in only one buffer, pass pointer directly. Otherwise, allocate a contiguous area, copy
8171  * data and pass this area. At the end deallocate the area.
8172  */
8173  if (log_lsa->offset + redo.length < (int) LOGAREA_SIZE)
8174  {
8175  rcv_data = (char *) log_pgptr->area + log_lsa->offset;
8176  }
8177  else
8178  {
8179  /* Need to copy the data into a contiguous area */
8180  area = (char *) malloc (redo.length);
8181  if (area == NULL)
8182  {
8183  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_run_postpone_op");
8184 
8185  return ER_FAILED;
8186  }
8187 
8188  /* Copy the data */
8189  logpb_copy_from_log (thread_p, area, redo.length, log_lsa, log_pgptr);
8190  rcv_data = area;
8191  }
8192 
8193  (void) log_execute_run_postpone (thread_p, &ref_lsa, &redo, rcv_data);
8194 
8195  if (area != NULL)
8196  {
8197  free_and_init (area);
8198  }
8199 
8200  return NO_ERROR;
8201 }
8202 
8203 /*
8204  * log_execute_run_postpone () - Execute run postpone.
8205  *
8206  * return : Error code.
8207  * thread_p (in) : Thread entry.
8208  * log_lsa (in) : Postpone log LSA.
8209  * redo (in) : Redo log data.
8210  * redo_rcv_data (in) : Redo recovery data.
8211  */
8212 int
8213 log_execute_run_postpone (THREAD_ENTRY * thread_p, LOG_LSA * log_lsa, LOG_REC_REDO * redo, char *redo_rcv_data)
8214 {
8215  int error_code = NO_ERROR;
8216  LOG_RCV rcv; /* Recovery structure for execution */
8217  VPID rcv_vpid; /* Location of data to redo */
8218  LOG_RCVINDEX rcvindex; /* The recovery index */
8219  LOG_DATA_ADDR rvaddr;
8220 
8221  rcvindex = redo->data.rcvindex;
8222  rcv_vpid.volid = redo->data.volid;
8223  rcv_vpid.pageid = redo->data.pageid;
8224  rcv.offset = redo->data.offset;
8225  rcv.length = redo->length;
8226  rcv.data = redo_rcv_data;
8227 
8228  if (VPID_ISNULL (&rcv_vpid))
8229  {
8230  /* logical */
8231  rcv.pgptr = NULL;
8232  }
8233  else
8234  {
8235  error_code =
8237  if (error_code != NO_ERROR)
8238  {
8239  assert (false);
8241  fileio_get_volume_label (rcv_vpid.volid, PEEK));
8243  }
8244  if (rcv.pgptr == NULL)
8245  {
8246  /* deallocated */
8247  return NO_ERROR;
8248  }
8249  }
8250 
8251  /* Now call the REDO recovery function */
8252 
8253  if (RCV_IS_LOGICAL_RUN_POSTPONE_MANUAL (rcvindex))
8254  {
8255  LSA_COPY (&rcv.reference_lsa, log_lsa);
8256 
8257  error_code = (*RV_fun[rcvindex].redofun) (thread_p, &rcv);
8258  assert (error_code == NO_ERROR);
8259  }
8260  else if (RCV_IS_LOGICAL_LOG (&rcv_vpid, rcvindex))
8261  {
8262  /* Logical postpone. Use a system operation and commit with run postpone */
8263  log_sysop_start (thread_p);
8264 
8265  error_code = (*RV_fun[rcvindex].redofun) (thread_p, &rcv);
8266  assert (error_code == NO_ERROR);
8267 
8268  log_sysop_end_logical_run_postpone (thread_p, log_lsa);
8269  }
8270  else
8271  {
8272  /* Write the corresponding run postpone record for the postpone action */
8273  rvaddr.offset = rcv.offset;
8274  rvaddr.pgptr = rcv.pgptr;
8275 
8276  log_append_run_postpone (thread_p, rcvindex, &rvaddr, &rcv_vpid, rcv.length, rcv.data, log_lsa);
8277 
8278  error_code = (*RV_fun[rcvindex].redofun) (thread_p, &rcv);
8279  assert (error_code == NO_ERROR);
8280  }
8281 
8282  if (rcv.pgptr != NULL)
8283  {
8284  pgbuf_unfix (thread_p, rcv.pgptr);
8285  }
8286 
8287  return error_code;
8288 }
8289 
8290 /*
8291  * log_find_end_log - FIND END OF LOG
8292  *
8293  * return: nothing
8294  *
8295  * end_lsa(in/out): Address of end of log
8296  *
8297  * NOTE: Find the end of the log (i.e., the end of the active portion of the log).
8298  */
8299 static void
8300 log_find_end_log (THREAD_ENTRY * thread_p, LOG_LSA * end_lsa)
8301 {
8302  LOG_PAGEID pageid; /* Log page identifier */
8303  char log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT], *aligned_log_pgbuf;
8304  LOG_PAGE *log_pgptr = NULL; /* Pointer to a log page */
8305  LOG_RECORD_HEADER *eof = NULL; /* End of log record */
8306  LOG_RECTYPE type; /* Type of a log record */
8307 
8308  aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
8309 
8310  /* Guess the end of the log from the header */
8311 
8312  LSA_COPY (end_lsa, &log_Gl.hdr.append_lsa);
8313  type = LOG_LARGER_LOGREC_TYPE;
8314 
8315  log_pgptr = (LOG_PAGE *) aligned_log_pgbuf;
8316 
8317  while (type != LOG_END_OF_LOG && !LSA_ISNULL (end_lsa))
8318  {
8319  LOG_LSA fetch_lsa;
8320 
8321  fetch_lsa.pageid = end_lsa->pageid;
8322  fetch_lsa.offset = LOG_PAGESIZE;
8323 
8324  /* Fetch the page */
8325  if ((logpb_fetch_page (thread_p, &fetch_lsa, LOG_CS_FORCE_USE, log_pgptr)) != NO_ERROR)
8326  {
8327  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_find_end_log");
8328  goto error;
8329 
8330  }
8331  pageid = end_lsa->pageid;
8332 
8333  while (end_lsa->pageid == pageid)
8334  {
8335  /*
8336  * If an offset is missing, it is because we archive an incomplete
8337  * log record. This log_record was completed later. Thus, we have to
8338  * find the offset by searching for the next log_record in the page
8339  */
8340  if (!(end_lsa->offset == NULL_OFFSET && (end_lsa->offset = log_pgptr->hdr.offset) == NULL_OFFSET))
8341  {
8342  eof = LOG_GET_LOG_RECORD_HEADER (log_pgptr, end_lsa);
8343  /*
8344  * If the type is an EOF located at the active portion of the log,
8345  * stop
8346  */
8347  if ((type = eof->type) == LOG_END_OF_LOG)
8348  {
8349  if (logpb_is_page_in_archive (pageid))
8350  {
8351  type = LOG_LARGER_LOGREC_TYPE;
8352  }
8353  else
8354  {
8355  break;
8356  }
8357  }
8358  else if (type <= LOG_SMALLER_LOGREC_TYPE || type >= LOG_LARGER_LOGREC_TYPE)
8359  {
8360 #if defined(CUBRID_DEBUG)
8361  er_log_debug (ARG_FILE_LINE, "log_find_end_log: Unknown record type = %d (%s).\n", type,
8362  log_to_string (type));
8363 #endif /* CUBRID_DEBUG */
8364  LSA_SET_NULL (end_lsa);
8365  break;
8366  }
8367  else
8368  {
8369  LSA_COPY (end_lsa, &eof->forw_lsa);
8370  }
8371  }
8372  else
8373  {
8374  LSA_SET_NULL (end_lsa);
8375  }
8376 
8377  /*
8378  * If the next page is NULL_PAGEID and the current page is an archive
8379  * page, this is not the end, this situation happens because of an
8380  * incomplete log record was archived.
8381  */
8382 
8383  if (LSA_ISNULL (end_lsa) && logpb_is_page_in_archive (pageid))
8384  {
8385  end_lsa->pageid = pageid + 1;
8386  }
8387  }
8388 
8389  if (type == LOG_END_OF_LOG && eof != NULL && !LSA_EQ (end_lsa, &log_Gl.hdr.append_lsa))
8390  {
8391  /*
8392  * Reset the log header for future reads, multiple restart crashes,
8393  * and so on
8394  */
8395  LOG_RESET_APPEND_LSA (end_lsa);
8396  log_Gl.hdr.next_trid = eof->trid;
8397  }
8398  }
8399 
8400  return;
8401 
8402 error:
8403 
8404  LSA_SET_NULL (end_lsa);
8405  return;
8406 }
8407 
8408 /*
8409  * log_recreate - RECREATE THE LOG WITHOUT REMOVING THE DATABASE
8410  *
8411  * return:
8412  *
8413  * db_fullname(in): Full name of the database
8414  * logpath(in): Directory where the log volumes reside
8415  * prefix_logname(in): Name of the log volumes. It is usually set the same as
8416  * database name. For example, if the value is equal to
8417  * "db", the names of the log volumes created are as
8418  * follow:
8419  * Active_log = db_logactive
8420  * Archive_logs = db_logarchive.0
8421  * db_logarchive.1
8422  * .
8423  * .
8424  * .
8425  * db_logarchive.n
8426  * Log_information = db_loginfo
8427  * Database Backup = db_backup
8428  * log_npages(in): Size of active log in pages
8429  * out_fp (in) :
8430  *
8431  * NOTE: Recreate the active log volume with the new specifications.
8432  * All recovery information in each data volume is removed.
8433  * If there are anything to recover (e.g., the database suffered
8434  * a crash), it is not done. Therefore, it is very important to
8435  * make sure that the database does not need to be recovered. You
8436  * could restart the database and then shutdown to enfore any
8437  * recovery. The database will end up as it is currently on disk.
8438  * This function can also be used to restart a database when the
8439  * log is corrupted somehow (e.g., system bug, isn't) or the log
8440  * is not available or it suffered a media crash. It can also be
8441  * used to move the log to another location. It is recommended to
8442  * backup the database before and after the operation is
8443  * executed.
8444  *
8445  * This function must be run offline. That is, it should not be
8446  * run when there are multiusers in the system.
8447  */
8448 int
8449 log_recreate (THREAD_ENTRY * thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname,
8450  DKNPAGES log_npages, FILE * out_fp)
8451 {
8452  const char *vlabel;
8453  INT64 db_creation;
8454  DISK_VOLPURPOSE vol_purpose;
8455  DISK_VOLUME_SPACE_INFO space_info;
8456  VOLID volid;
8457  int vdes;
8458  LOG_LSA init_nontemp_lsa;
8459  int ret = NO_ERROR;
8460 
8461  ret = disk_get_creation_time (thread_p, LOG_DBFIRST_VOLID, &db_creation);
8462  if (ret != NO_ERROR)
8463  {
8464  return ret;
8465  }
8466 
8467  ret = log_create_internal (thread_p, db_fullname, logpath, prefix_logname, log_npages, &db_creation);
8468  if (ret != NO_ERROR)
8469  {
8470  return ret;
8471  }
8472 
8473  (void) log_initialize_internal (thread_p, db_fullname, logpath, prefix_logname, false, NULL, true);
8474 
8475  /*
8476  * RESET RECOVERY INFORMATION ON ALL DATA VOLUMES
8477  */
8478 
8479  LSA_SET_NULL (&init_nontemp_lsa);
8480 
8481  for (volid = LOG_DBFIRST_VOLID; volid != NULL_VOLID; volid = fileio_find_next_perm_volume (thread_p, volid))
8482  {
8483  char vol_fullname[PATH_MAX];
8484 
8485  vlabel = fileio_get_volume_label (volid, PEEK);
8486 
8487  /* Find the current pages of the volume and its descriptor */
8488 
8489  if (xdisk_get_purpose_and_space_info (thread_p, volid, &vol_purpose, &space_info) != NO_ERROR)
8490  {
8491  /* we just give up? */
8492  continue;
8493  }
8494 
8495  vdes = fileio_get_volume_descriptor (volid);
8496 
8497  /*
8498  * Flush all dirty pages and then invalidate them from page buffer pool.
8499  * So that we can reset the recovery information directly using the io
8500  * module
8501  */
8502 
8503  LOG_CS_ENTER (thread_p);
8504  logpb_flush_pages_direct (thread_p);
8505  LOG_CS_EXIT (thread_p);
8506 
8507  (void) pgbuf_flush_all (thread_p, volid);
8508  (void) pgbuf_invalidate_all (thread_p, volid); /* it flush and invalidate */
8509 
8510  if (vol_purpose != DB_TEMPORARY_DATA_PURPOSE)
8511  {
8512  (void) fileio_reset_volume (thread_p, vdes, vlabel, DISK_SECTS_NPAGES (space_info.n_total_sects),
8513  &init_nontemp_lsa);
8514  }
8515 
8516  (void) disk_set_creation (thread_p, volid, vlabel, &log_Gl.hdr.db_creation, &log_Gl.hdr.chkpt_lsa, false,
8517  DISK_DONT_FLUSH);
8518  LOG_CS_ENTER (thread_p);
8519  logpb_flush_pages_direct (thread_p);
8520  LOG_CS_EXIT (thread_p);
8521 
8522  (void) pgbuf_flush_all_unfixed_and_set_lsa_as_null (thread_p, volid);
8523 
8524  /*
8525  * reset temp LSA to special temp LSA
8526  */
8527  (void) logpb_check_and_reset_temp_lsa (thread_p, volid);
8528 
8529  /*
8530  * add volume info to vinf
8531  */
8532  xdisk_get_fullname (thread_p, volid, vol_fullname);
8533  logpb_add_volume (NULL, volid, vol_fullname, vol_purpose);
8534 
8535  if (out_fp != NULL)
8536  {
8537  fprintf (out_fp, "%s... done\n", vol_fullname);
8538  fflush (out_fp);
8539  }
8540  }
8541 
8542  (void) pgbuf_flush_all (thread_p, NULL_VOLID);
8543  (void) fileio_synchronize_all (thread_p, false);
8544  (void) log_commit (thread_p, NULL_TRAN_INDEX, false);
8545 
8546  return ret;
8547 }
8548 
8549 /*
8550  * log_get_io_page_size - FIND SIZE OF DATABASE PAGE
8551  *
8552  * return:
8553  *
8554  * db_fullname(in): Full name of the database
8555  * logpath(in): Directory where the log volumes reside
8556  * prefix_logname(in): Name of the log volumes. It is usually set as database
8557  * name. For example, if the value is equal to "db", the
8558  * names of the log volumes created are as follow:
8559  * Active_log = db_logactive
8560  * Archive_logs = db_logarchive.0
8561  * db_logarchive.1
8562  * .
8563  * .
8564  * .
8565  * db_logarchive.n
8566  * Log_information = db_loginfo
8567  * Database Backup = db_backup
8568  *
8569  * NOTE: Find size of database page according to the log manager.
8570  */
8571 PGLENGTH
8572 log_get_io_page_size (THREAD_ENTRY * thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname)
8573 {
8574  PGLENGTH db_iopagesize;
8575  PGLENGTH log_page_size;
8576  INT64 ignore_dbcreation;
8577  float ignore_dbcomp;
8578  int dummy;
8579 
8580  LOG_CS_ENTER (thread_p);
8581  if (logpb_find_header_parameters (thread_p, false, db_fullname, logpath, prefix_logname, &db_iopagesize,
8582  &log_page_size, &ignore_dbcreation, &ignore_dbcomp, &dummy) == -1)
8583  {
8584  /*
8585  * For case where active log could not be found, user still needs
8586  * an error.
8587  */
8588  if (er_errid () == NO_ERROR)
8589  {
8591  }
8592 
8593  LOG_CS_EXIT (thread_p);
8594  return -1;
8595  }
8596  else
8597  {
8598  if (IO_PAGESIZE != db_iopagesize || LOG_PAGESIZE != log_page_size)
8599  {
8600  if (db_set_page_size (db_iopagesize, log_page_size) != NO_ERROR)
8601  {
8602  LOG_CS_EXIT (thread_p);
8603  return -1;
8604  }
8605  else
8606  {
8608  {
8609  LOG_CS_EXIT (thread_p);
8610  return -1;
8611  }
8612 
8613  /* page size changed, reinit tran tables only if previously initialized */
8614  if (log_Gl.trantable.area == NULL)
8615  {
8616  LOG_CS_EXIT (thread_p);
8617  return db_iopagesize;
8618  }
8619 
8621  {
8622  LOG_CS_EXIT (thread_p);
8623  return -1;
8624  }
8625  }
8626 
8627  }
8628 
8629  LOG_CS_EXIT (thread_p);
8630 
8631  return db_iopagesize;
8632  }
8633 }
8634 
8635 /*
8636  * log_get_charset_from_header_page - get charset stored in header page
8637  *
8638  * return: charset id (non-negative values are valid)
8639  * -1 if header page cannot be used to determine database charset
8640  * -2 if an error occurs
8641  *
8642  * See log_get_io_page_size for arguments
8643  */
8644 int
8645 log_get_charset_from_header_page (THREAD_ENTRY * thread_p, const char *db_fullname, const char *logpath,
8646  const char *prefix_logname)
8647 {
8648  PGLENGTH dummy_db_iopagesize;
8649  PGLENGTH dummy_ignore_log_page_size;
8650  INT64 dummy_ignore_dbcreation;
8651  float dummy_ignore_dbcomp;
8653 
8654  LOG_CS_ENTER (thread_p);
8655  if (logpb_find_header_parameters (thread_p, false, db_fullname, logpath, prefix_logname, &dummy_db_iopagesize,
8656  &dummy_ignore_log_page_size, &dummy_ignore_dbcreation, &dummy_ignore_dbcomp,
8657  &db_charset) == -1)
8658  {
8659  /*
8660  * For case where active log could not be found, user still needs
8661  * an error.
8662  */
8663  if (er_errid () == NO_ERROR)
8664  {
8666  }
8667 
8668  LOG_CS_EXIT (thread_p);
8669  return INTL_CODESET_ERROR;
8670  }
8671  else
8672  {
8673  LOG_CS_EXIT (thread_p);
8674  return db_charset;
8675  }
8676 }
8677 
8678 /*
8679  *
8680  * GENERIC RECOVERY FUNCTIONS
8681  *
8682  */
8683 
8684 /*
8685  * log_rv_copy_char - Recover (undo or redo) a string of chars/bytes
8686  *
8687  * return: nothing
8688  *
8689  * rcv(in): Recovery structure
8690  *
8691  * NOTE: Recover (undo/redo) by copying a string of characters/bytes
8692  * onto the specified location. This function can be used for
8693  * physical logging.
8694  */
8695 int
8697 {
8698  char *to_data;
8699 
8700  assert (rcv->offset + rcv->length <= DB_PAGESIZE);
8701 
8702  to_data = (char *) rcv->pgptr + rcv->offset;
8703  memcpy (to_data, rcv->data, rcv->length);
8704  pgbuf_set_dirty (thread_p, rcv->pgptr, DONT_FREE);
8705  return NO_ERROR;
8706 }
8707 
8708 /*
8709  * log_rv_dump_char - DUMP INFORMATION TO RECOVER A SET CHARS/BYTES
8710  *
8711  * return: nothing
8712  *
8713  * length(in): Length of Recovery Data
8714  * data(in): The data being logged
8715  *
8716  * NOTE:Dump the information to recover a set of characters/bytes.
8717  */
8718 void
8719 log_rv_dump_char (FILE * fp, int length, void *data)
8720 {
8721  log_ascii_dump (fp, length, data);
8722  fprintf (fp, "\n");
8723 }
8724 
8725 /*
8726  * log_rv_dump_hexa () - Point recovery data as hexadecimals.
8727  *
8728  * return : Void.
8729  * fp (in) : Print output.
8730  * length (in) : Recovery data length.
8731  * data (in) : Recovery data.
8732  */
8733 void
8734 log_rv_dump_hexa (FILE * fp, int length, void *data)
8735 {
8736  log_hexa_dump (fp, length, data);
8737 }
8738 
8739 /*
8740  * log_rv_outside_noop_redo - NO-OP of an outside REDO
8741  *
8742  * return: nothing
8743  *
8744  * rcv(in): Recovery structure
8745  *
8746  * NOTE: No-op of an outside redo.
8747  * This can used to fool the recovery manager when doing a
8748  * logical UNDO which fails (e.g., unregistering a file that has
8749  * already been unregistered) or when doing an external/outside
8750  * (e.g., removing a temporary volume) the data base domain.
8751  */
8752 int
8754 {
8755  return NO_ERROR;
8756 }
8757 
8758 #if defined (ENABLE_UNUSED_FUNCTION)
8759 /*
8760  * log_simulate_crash - Simulate a system crash
8761  *
8762  * return: nothing
8763  *
8764  * flush_log(in): Flush the log before the crash simulation?
8765  * flush_data_pages(in): Flush the data pages (page buffer pool) before the
8766  * crash simulation?
8767  *
8768  * NOTE:Simulate a system crash. If flush_data_pages is true, the
8769  * data page buffer pool is flushed and the log buffer pool is
8770  * flushed too regardless of the value of flush_log. If flush_log
8771  * is true, the log buffer pool is flushed.
8772  */
8773 void
8774 log_simulate_crash (THREAD_ENTRY * thread_p, int flush_log, int flush_data_pages)
8775 {
8776  LOG_CS_ENTER (thread_p);
8777 
8779  {
8780  LOG_CS_EXIT (thread_p);
8781  return;
8782  }
8783 
8784  if (flush_log != false || flush_data_pages != false)
8785  {
8786  logpb_flush_pages_direct (thread_p);
8787  }
8788 
8789  if (flush_data_pages)
8790  {
8791  (void) pgbuf_flush_all (thread_p, NULL_VOLID);
8792  (void) fileio_synchronize_all (thread_p, false);
8793  }
8794 
8795  /* Undefine log buffer pool and transaction table */
8796 
8797  logpb_finalize_pool (thread_p);
8798  logtb_undefine_trantable (thread_p);
8799 
8800  LOG_CS_EXIT (thread_p);
8801 
8803 }
8804 #endif /* ENABLE_UNUSED_FUNCTION */
8805 
8806 /*
8807  * log_active_log_header_start_scan () -
8808  * return: NO_ERROR, or ER_code
8809  *
8810  * thread_p(in):
8811  * show_type(in):
8812  * arg_values(in):
8813  * arg_cnt(in):
8814  * ptr(out): allocate new context. should free by end_scan() function
8815  */
8816 int
8817 log_active_log_header_start_scan (THREAD_ENTRY * thread_p, int show_type, DB_VALUE ** arg_values, int arg_cnt,
8818  void **ptr)
8819 {
8820  int error = NO_ERROR;
8821  const char *path;
8822  int fd = -1;
8824 
8825  *ptr = NULL;
8826 
8827  assert (arg_cnt == 1);
8828 
8830 
8831  if (ctx == NULL)
8832  {
8833  assert (er_errid () != NO_ERROR);
8834  error = er_errid ();
8835  goto exit_on_error;
8836  }
8837 
8838  /* In the case of omit file path, first argument is db null */
8839  if (DB_VALUE_TYPE (arg_values[0]) == DB_TYPE_NULL)
8840  {
8841  LOG_CS_ENTER_READ_MODE (thread_p);
8842  memcpy (&ctx->header, &log_Gl.hdr, sizeof (LOG_HEADER));
8843  LOG_CS_EXIT (thread_p);
8844  }
8845  else
8846  {
8847  char buf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT];
8848  LOG_PAGE *page_hdr = (LOG_PAGE *) PTR_ALIGN (buf, MAX_ALIGNMENT);
8849 
8850  assert (DB_VALUE_TYPE (arg_values[0]) == DB_TYPE_CHAR);
8851  path = db_get_string (arg_values[0]);
8852 
8853  fd = fileio_open (path, O_RDONLY, 0);
8854  if (fd == -1)
8855  {
8857  error = ER_IO_MOUNT_FAIL;
8858  goto exit_on_error;
8859  }
8860 
8861  if (read (fd, page_hdr, LOG_PAGESIZE) != LOG_PAGESIZE)
8862  {
8864  error = ER_IO_MOUNT_FAIL;
8865  goto exit_on_error;
8866  }
8867 
8868  memcpy (&ctx->header, page_hdr->area, sizeof (LOG_HEADER));
8869 
8870  ctx->header.magic[sizeof (ctx->header.magic) - 1] = 0;
8871  ctx->header.db_release[sizeof (ctx->header.db_release) - 1] = 0;
8872  ctx->header.prefix_name[sizeof (ctx->header.prefix_name) - 1] = 0;
8873 
8874  close (fd);
8875  fd = -1;
8876 
8878  {
8880  error = ER_IO_MOUNT_FAIL;
8881  goto exit_on_error;
8882  }
8883  }
8884 
8885  *ptr = ctx;
8886  ctx = NULL;
8887 
8888 exit_on_error:
8889  if (fd != -1)
8890  {
8891  close (fd);
8892  }
8893 
8894  if (ctx != NULL)
8895  {
8896  db_private_free_and_init (thread_p, ctx);
8897  }
8898 
8899  return error;
8900 }
8901 
8902 /*
8903  * log_active_log_header_next_scan () -
8904  * return: NO_ERROR, or ER_code
8905  *
8906  * thread_p(in):
8907  * cursor(in):
8908  * out_values(in):
8909  * out_cnt(in):
8910  * ptr(in): context pointer
8911  */
8912 SCAN_CODE
8913 log_active_log_header_next_scan (THREAD_ENTRY * thread_p, int cursor, DB_VALUE ** out_values, int out_cnt, void *ptr)
8914 {
8915  int error = NO_ERROR;
8916  int idx = 0;
8917  int val;
8918  const char *str;
8919  char buf[256];
8920  DB_DATETIME time_val;
8922  LOG_HEADER *header = &ctx->header;
8923 
8924  if (cursor >= 1)
8925  {
8926  return S_END;
8927  }
8928 
8929  db_make_int (out_values[idx], LOG_DBLOG_ACTIVE_VOLID);
8930  idx++;
8931 
8932  error = db_make_string_copy (out_values[idx], header->magic);
8933  idx++;
8934 
8935  if (error != NO_ERROR)
8936  {
8937  goto exit_on_error;
8938  }
8939 
8940  val = offsetof (LOG_PAGE, area) + offsetof (LOG_HEADER, magic);
8941  db_make_int (out_values[idx], val);
8942  idx++;
8943 
8944  db_localdatetime ((time_t *) (&header->db_creation), &time_val);
8945  error = db_make_datetime (out_values[idx], &time_val);
8946  idx++;
8947  if (error != NO_ERROR)
8948  {
8949  goto exit_on_error;
8950  }
8951 
8952  error = db_make_string_copy (out_values[idx], header->db_release);
8953  idx++;
8954 
8955  snprintf (buf, sizeof (buf), "%g", header->db_compatibility);
8956  buf[sizeof (buf) - 1] = 0;
8957  error = db_make_string_copy (out_values[idx], buf);
8958  idx++;
8959  if (error != NO_ERROR)
8960  {
8961  goto exit_on_error;
8962  }
8963 
8964  db_make_int (out_values[idx], header->db_iopagesize);
8965  idx++;
8966 
8967  db_make_int (out_values[idx], header->db_logpagesize);
8968  idx++;
8969 
8970  db_make_int (out_values[idx], header->is_shutdown);
8971  idx++;
8972 
8973  db_make_int (out_values[idx], header->next_trid);
8974  idx++;
8975 
8976  db_make_int (out_values[idx], header->avg_ntrans);
8977  idx++;
8978 
8979  db_make_int (out_values[idx], header->avg_nlocks);
8980  idx++;
8981 
8982  db_make_int (out_values[idx], header->npages);
8983  idx++;
8984 
8985  db_make_int (out_values[idx], header->db_charset);
8986  idx++;
8987 
8988  db_make_bigint (out_values[idx], header->fpageid);
8989  idx++;
8990 
8991  lsa_to_string (buf, sizeof (buf), &header->append_lsa);
8992  error = db_make_string_copy (out_values[idx], buf);
8993  idx++;
8994  if (error != NO_ERROR)
8995  {
8996  goto exit_on_error;
8997  }
8998 
8999  lsa_to_string (buf, sizeof (buf), &header->chkpt_lsa);
9000  error = db_make_string_copy (out_values[idx], buf);
9001  idx++;
9002  if (error != NO_ERROR)
9003  {
9004  goto exit_on_error;
9005  }
9006 
9007  db_make_bigint (out_values[idx], header->nxarv_pageid);
9008  idx++;
9009 
9010  db_make_int (out_values[idx], header->nxarv_phy_pageid);
9011  idx++;
9012 
9013  db_make_int (out_values[idx], header->nxarv_num);
9014  idx++;
9015 
9016  db_make_int (out_values[idx], header->last_arv_num_for_syscrashes);
9017  idx++;
9018 
9019  db_make_int (out_values[idx], header->last_deleted_arv_num);
9020  idx++;
9021 
9022  lsa_to_string (buf, sizeof (buf), &header->bkup_level0_lsa);
9023  error = db_make_string_copy (out_values[idx], buf);
9024  idx++;
9025  if (error != NO_ERROR)
9026  {
9027  goto exit_on_error;
9028  }
9029 
9030  lsa_to_string (buf, sizeof (buf), &header->bkup_level1_lsa);
9031  error = db_make_string_copy (out_values[idx], buf);
9032  idx++;
9033  if (error != NO_ERROR)
9034  {
9035  goto exit_on_error;
9036  }
9037 
9038  lsa_to_string (buf, sizeof (buf), &header->bkup_level2_lsa);
9039  error = db_make_string_copy (out_values[idx], buf);
9040  idx++;
9041  if (error != NO_ERROR)
9042  {
9043  goto exit_on_error;
9044  }
9045 
9046  error = db_make_string_copy (out_values[idx], header->prefix_name);
9047  idx++;
9048  if (error != NO_ERROR)
9049  {
9050  goto exit_on_error;
9051  }
9052 
9053  db_make_int (out_values[idx], header->has_logging_been_skipped);
9054  idx++;
9055 
9056  db_make_string (out_values[idx], "LOG_PSTATUS_OBSOLETE");
9057  idx++;
9058 
9059  logpb_backup_level_info_to_string (buf, sizeof (buf), header->bkinfo + FILEIO_BACKUP_FULL_LEVEL);
9060  error = db_make_string_copy (out_values[idx], buf);
9061  idx++;
9062  if (error != NO_ERROR)
9063  {
9064  goto exit_on_error;
9065  }
9066 
9068  error = db_make_string_copy (out_values[idx], buf);
9069  idx++;
9070  if (error != NO_ERROR)
9071  {
9072  goto exit_on_error;
9073  }
9074 
9076  error = db_make_string_copy (out_values[idx], buf);
9077  idx++;
9078  if (error != NO_ERROR)
9079  {
9080  goto exit_on_error;
9081  }
9082 
9084  db_make_string (out_values[idx], str);
9085  idx++;
9086 
9088  db_make_string (out_values[idx], str);
9089  idx++;
9090 
9091  lsa_to_string (buf, sizeof (buf), &header->eof_lsa);
9092  error = db_make_string_copy (out_values[idx], buf);
9093  idx++;
9094  if (error != NO_ERROR)
9095  {
9096  goto exit_on_error;
9097  }
9098 
9099  lsa_to_string (buf, sizeof (buf), &header->smallest_lsa_at_last_chkpt);
9100  error = db_make_string_copy (out_values[idx], buf);
9101  idx++;
9102  if (error != NO_ERROR)
9103  {
9104  goto exit_on_error;
9105  }
9106 
9107  db_make_bigint (out_values[idx], header->mvcc_next_id);
9108  idx++;
9109 
9110  lsa_to_string (buf, sizeof (buf), &header->mvcc_op_log_lsa);
9111  error = db_make_string_copy (out_values[idx], buf);
9112  idx++;
9113  if (error != NO_ERROR)
9114  {
9115  goto exit_on_error;
9116  }
9117 
9118  if (header->oldest_visible_mvccid == MVCCID_NULL)
9119  {
9120  db_make_null (out_values[idx]);
9121  }
9122  else
9123  {
9124  db_make_bigint (out_values[idx], header->oldest_visible_mvccid);
9125  }
9126  idx++;
9127 
9128  if (header->newest_block_mvccid == MVCCID_NULL)
9129  {
9130  db_make_null (out_values[idx]);
9131  }
9132  else
9133  {
9134  db_make_bigint (out_values[idx], header->newest_block_mvccid);
9135  }
9136  idx++;
9137 
9138  assert (idx == out_cnt);
9139 
9140  return S_SUCCESS;
9141 
9142 exit_on_error:
9143  return error == NO_ERROR ? S_SUCCESS : S_ERROR;
9144 }
9145 
9146 /*
9147  * log_active_log_header_end_scan () - free the context
9148  * return: NO_ERROR, or ER_code
9149  *
9150  * thread_p(in):
9151  * ptr(in): context pointer
9152  */
9153 int
9155 {
9156  if (*ptr != NULL)
9157  {
9158  db_private_free_and_init (thread_p, *ptr);
9159  }
9160 
9161  return NO_ERROR;
9162 }
9163 
9164 /*
9165  * log_archive_log_header_start_scan () -
9166  * return: NO_ERROR, or ER_code
9167  *
9168  * thread_p(in):
9169  * show_type(in):
9170  * arg_values(in):
9171  * arg_cnt(in):
9172  * ptr(out): allocate new context. should free by end_scan() function
9173  */
9174 int
9175 log_archive_log_header_start_scan (THREAD_ENTRY * thread_p, int show_type, DB_VALUE ** arg_values, int arg_cnt,
9176  void **ptr)
9177 {
9178  int error = NO_ERROR;
9179  const char *path;
9180  int fd;
9181  char buf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT];
9182  LOG_PAGE *page_hdr;
9184 
9185  *ptr = NULL;
9186 
9187  assert (DB_VALUE_TYPE (arg_values[0]) == DB_TYPE_CHAR);
9188 
9190  if (ctx == NULL)
9191  {
9192  assert (er_errid () != NO_ERROR);
9193  error = er_errid ();
9194  goto exit_on_error;
9195  }
9196 
9197  path = db_get_string (arg_values[0]);
9198 
9199  page_hdr = (LOG_PAGE *) PTR_ALIGN (buf, MAX_ALIGNMENT);
9200 
9201  fd = fileio_open (path, O_RDONLY, 0);
9202  if (fd == -1)
9203  {
9205  error = ER_IO_MOUNT_FAIL;
9206  goto exit_on_error;
9207  }
9208 
9209  if (read (fd, page_hdr, LOG_PAGESIZE) != LOG_PAGESIZE)
9210  {
9212  error = ER_IO_MOUNT_FAIL;
9213  goto exit_on_error;
9214  }
9215 
9216  memcpy (&ctx->header, page_hdr->area, sizeof (LOG_ARV_HEADER));
9217  close (fd);
9218  fd = -1;
9219 
9220  ctx->header.magic[sizeof (ctx->header.magic) - 1] = 0;
9221 
9223  {
9225  error = ER_IO_MOUNT_FAIL;
9226  goto exit_on_error;
9227  }
9228 
9229  *ptr = ctx;
9230  ctx = NULL;
9231 
9232 exit_on_error:
9233  if (ctx != NULL)
9234  {
9235  db_private_free_and_init (thread_p, ctx);
9236  }
9237 
9238  return error;
9239 }
9240 
9241 /*
9242  * log_archive_log_header_next_scan () -
9243  * return: NO_ERROR, or ER_code
9244  *
9245  * thread_p(in):
9246  * cursor(in):
9247  * out_values(in):
9248  * out_cnt(in):
9249  * ptr(in): context pointer
9250  */
9251 SCAN_CODE
9252 log_archive_log_header_next_scan (THREAD_ENTRY * thread_p, int cursor, DB_VALUE ** out_values, int out_cnt, void *ptr)
9253 {
9254  int error = NO_ERROR;
9255  int idx = 0;
9256  int val;
9257  DB_DATETIME time_val;
9258 
9260  LOG_ARV_HEADER *header = &ctx->header;
9261 
9262  if (cursor >= 1)
9263  {
9264  return S_END;
9265  }
9266 
9267  db_make_int (out_values[idx], LOG_DBLOG_ARCHIVE_VOLID);
9268  idx++;
9269 
9270  error = db_make_string_copy (out_values[idx], header->magic);
9271  idx++;
9272 
9273  if (error != NO_ERROR)
9274  {
9275  goto exit_on_error;
9276  }
9277 
9278  val = offsetof (LOG_PAGE, area) + offsetof (LOG_ARV_HEADER, magic);
9279  db_make_int (out_values[idx], val);
9280  idx++;
9281 
9282  db_localdatetime ((time_t *) (&header->db_creation), &time_val);
9283  error = db_make_datetime (out_values[idx], &time_val);
9284  idx++;
9285  if (error != NO_ERROR)
9286  {
9287  goto exit_on_error;
9288  }
9289 
9290  db_make_bigint (out_values[idx], header->next_trid);
9291  idx++;
9292 
9293  db_make_int (out_values[idx], header->npages);
9294  idx++;
9295 
9296  db_make_bigint (out_values[idx], header->fpageid);
9297  idx++;
9298 
9299  db_make_int (out_values[idx], header->arv_num);
9300  idx++;
9301 
9302  assert (idx == out_cnt);
9303 
9304 exit_on_error:
9305  return error == NO_ERROR ? S_SUCCESS : S_ERROR;
9306 }
9307 
9308 /*
9309  * log_archive_log_header_end_scan () - free the context
9310  * return: NO_ERROR, or ER_code
9311  *
9312  * thread_p(in):
9313  * ptr(in): context pointer
9314  */
9315 int
9317 {
9318  if (*ptr != NULL)
9319  {
9320  db_private_free_and_init (thread_p, *ptr);
9321  }
9322 
9323  return NO_ERROR;
9324 }
9325 
9326 /*
9327  * log_set_ha_promotion_time () - set ha promotion time
9328  * return: none
9329  *
9330  * thread_p(in):
9331  * ha_promotion_time(in):
9332  */
9333 void
9334 log_set_ha_promotion_time (THREAD_ENTRY * thread_p, INT64 ha_promotion_time)
9335 {
9336  LOG_CS_ENTER (thread_p);
9337  log_Gl.hdr.ha_promotion_time = ha_promotion_time;
9338  LOG_CS_EXIT (thread_p);
9339 
9340  return;
9341 }
9342 
9343 /*
9344  * log_set_db_restore_time () - set db restore time
9345  * return: none
9346  *
9347  * thread_p(in):
9348  * db_restore_time(in):
9349  */
9350 void
9351 log_set_db_restore_time (THREAD_ENTRY * thread_p, INT64 db_restore_time)
9352 {
9353  LOG_CS_ENTER (thread_p);
9354 
9355  log_Gl.hdr.db_restore_time = db_restore_time;
9356 
9357  LOG_CS_EXIT (thread_p);
9358 }
9359 
9360 /*
9361  * log_get_undo_record () - gets undo record from log lsa adress
9362  * return: S_SUCCESS or ER_code
9363  *
9364  * thread_p (in):
9365  * lsa_addr (in):
9366  * page (in):
9367  * record (in/out):
9368  */
9369 SCAN_CODE
9370 log_get_undo_record (THREAD_ENTRY * thread_p, LOG_PAGE * log_page_p, LOG_LSA process_lsa, RECDES * recdes)
9371 {
9373  LOG_REC_MVCC_UNDO *mvcc_undo = NULL;
9374  LOG_REC_MVCC_UNDOREDO *mvcc_undoredo = NULL;
9375  LOG_REC_UNDO *undo = NULL;
9376  LOG_REC_UNDOREDO *undoredo = NULL;
9377  int udata_length;
9378  int udata_size;
9379  char *undo_data;
9380  LOG_LSA oldest_prior_lsa;
9381  bool is_zipped = false;
9382  char log_buf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT];
9383  LOG_ZIP *log_unzip_ptr = NULL;
9384  char *area = NULL;
9385  SCAN_CODE scan = S_SUCCESS;
9386  bool area_was_mallocated = false;
9387 
9388  /* assert log record is not in prior list */
9389  oldest_prior_lsa = *log_get_append_lsa ();
9390  assert (LSA_LT (&process_lsa, &oldest_prior_lsa));
9391 
9392  log_rec_header = LOG_GET_LOG_RECORD_HEADER (log_page_p, &process_lsa);
9393  LOG_READ_ADD_ALIGN (thread_p, sizeof (*log_rec_header), &process_lsa, log_page_p);
9394 
9395  if (log_rec_header->type == LOG_MVCC_UNDO_DATA)
9396  {
9397  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*mvcc_undo), &process_lsa, log_page_p);
9398  mvcc_undo = (LOG_REC_MVCC_UNDO *) (log_page_p->area + process_lsa.offset);
9399 
9400  udata_length = mvcc_undo->undo.length;
9401  LOG_READ_ADD_ALIGN (thread_p, sizeof (*mvcc_undo), &process_lsa, log_page_p);
9402  }
9403  else if (log_rec_header->type == LOG_MVCC_UNDOREDO_DATA || log_rec_header->type == LOG_MVCC_DIFF_UNDOREDO_DATA)
9404  {
9405  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*mvcc_undoredo), &process_lsa, log_page_p);
9406  mvcc_undoredo = (LOG_REC_MVCC_UNDOREDO *) (log_page_p->area + process_lsa.offset);
9407 
9408  udata_length = mvcc_undoredo->undoredo.ulength;
9409  LOG_READ_ADD_ALIGN (thread_p, sizeof (*mvcc_undoredo), &process_lsa, log_page_p);
9410  }
9411  else if (log_rec_header->type == LOG_UNDO_DATA)
9412  {
9413  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*undo), &process_lsa, log_page_p);
9414  undo = (LOG_REC_UNDO *) (log_page_p->area + process_lsa.offset);
9415 
9416  udata_length = undo->length;
9417  LOG_READ_ADD_ALIGN (thread_p, sizeof (*undo), &process_lsa, log_page_p);
9418  }
9419  else if (log_rec_header->type == LOG_UNDOREDO_DATA || log_rec_header->type == LOG_DIFF_UNDOREDO_DATA)
9420  {
9421  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*undoredo), &process_lsa, log_page_p);
9422  undoredo = (LOG_REC_UNDOREDO *) (log_page_p->area + process_lsa.offset);
9423 
9424  udata_length = undoredo->ulength;
9425  LOG_READ_ADD_ALIGN (thread_p, sizeof (*undoredo), &process_lsa, log_page_p);
9426  }
9427  else
9428  {
9429  assert_release (log_rec_header->type == LOG_MVCC_UNDO_DATA || log_rec_header->type == LOG_MVCC_UNDOREDO_DATA
9430  || log_rec_header->type == LOG_MVCC_DIFF_UNDOREDO_DATA || log_rec_header->type == LOG_UNDO_DATA
9431  || log_rec_header->type == LOG_UNDOREDO_DATA
9432  || log_rec_header->type == LOG_MVCC_DIFF_UNDOREDO_DATA);
9433  er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOG_FATAL_ERROR, 1, "Expecting undo/undoredo log record");
9434  scan = S_ERROR;
9435  goto exit;
9436  }
9437 
9438  /* get undo record */
9439  if (ZIP_CHECK (udata_length))
9440  {
9441  /* Get real size */
9442  udata_size = (int) GET_ZIP_LEN (udata_length);
9443  is_zipped = true;
9444  }
9445  else
9446  {
9447  udata_size = udata_length;
9448  }
9449 
9450  /*
9451  * If data is contained in only one buffer, pass pointer directly.
9452  * Otherwise, copy the data into a contiguous area and pass this area.
9453  */
9454  if (process_lsa.offset + udata_size < (int) LOGAREA_SIZE)
9455  {
9456  undo_data = (char *) log_page_p->area + process_lsa.offset;
9457  }
9458  else
9459  {
9460  /* Need to copy the data into a contiguous area */
9461 
9462  if (udata_size <= IO_MAX_PAGE_SIZE)
9463  {
9464  area = PTR_ALIGN (log_buf, MAX_ALIGNMENT);
9465  }
9466  else
9467  {
9468  area = (char *) malloc (udata_size);
9469  if (area == NULL)
9470  {
9472  scan = S_ERROR;
9473  goto exit;
9474  }
9475  area_was_mallocated = true;
9476  }
9477 
9478  /* Copy the data */
9479  logpb_copy_from_log (thread_p, area, udata_size, &process_lsa, log_page_p);
9480  undo_data = area;
9481  }
9482 
9483  if (is_zipped)
9484  {
9485  log_unzip_ptr = log_zip_alloc (IO_PAGESIZE);
9486  if (log_unzip_ptr == NULL)
9487  {
9488  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_get_undo_record");
9489  scan = S_ERROR;
9490  goto exit;
9491  }
9492 
9493  if (log_unzip (log_unzip_ptr, udata_size, (char *) undo_data))
9494  {
9495  udata_size = (int) log_unzip_ptr->data_length;
9496  undo_data = (char *) log_unzip_ptr->log_data;
9497  }
9498  else
9499  {
9500  assert (false);
9501  scan = S_ERROR;
9502  goto exit;
9503  }
9504  }
9505 
9506  /* copy the record */
9507  recdes->type = *(INT16 *) (undo_data);
9508  recdes->length = udata_size - sizeof (recdes->type);
9509  if (recdes->area_size < 0 || recdes->area_size < (int) recdes->length)
9510  {
9511  /*
9512  * DOES NOT FIT
9513  * Give a hint to the user of the needed length. Hint is given as a
9514  * negative value
9515  */
9516  /* do not use unary minus because slot_p->record_length is unsigned */
9517  recdes->length *= -1;
9518 
9519  scan = S_DOESNT_FIT;
9520  goto exit;
9521  }
9522 
9523  memcpy (recdes->data, (char *) (undo_data) + sizeof (recdes->type), recdes->length);
9524 
9525 exit:
9526  if (area_was_mallocated)
9527  {
9528  free (area);
9529  }
9530  if (log_unzip_ptr != NULL)
9531  {
9532  log_zip_free (log_unzip_ptr);
9533  }
9534 
9535  return scan;
9536 }
9537 
9538 /*
9539  * log_read_sysop_start_postpone () - read system op start postpone and its recovery data
9540  *
9541  * return : error code
9542  * thread_p (in) : thread entry
9543  * log_lsa (in/out) : log address
9544  * log_page (in/out) : log page
9545  * with_undo_data (in) : true to read undo data
9546  * sysop_start_postpone (out) : output system op start postpone log record
9547  * undo_buffer_size (in/out) : size for undo data buffer
9548  * undo_buffer (in/out) : undo data buffer
9549  * undo_size (out) : output undo data size
9550  * undo_data (out) : output undo data
9551  */
9552 int
9553 log_read_sysop_start_postpone (THREAD_ENTRY * thread_p, LOG_LSA * log_lsa, LOG_PAGE * log_page, bool with_undo_data,
9554  LOG_REC_SYSOP_START_POSTPONE * sysop_start_postpone, int *undo_buffer_size,
9555  char **undo_buffer, int *undo_size, char **undo_data)
9556 {
9557  int error_code = NO_ERROR;
9558 
9559  if (log_page->hdr.logical_pageid != log_lsa->pageid)
9560  {
9561  error_code = logpb_fetch_page (thread_p, log_lsa, LOG_CS_FORCE_USE, log_page);
9562  if (error_code != NO_ERROR)
9563  {
9564  ASSERT_ERROR ();
9565  return error_code;
9566  }
9567  }
9568 
9569  assert (((LOG_RECORD_HEADER *) (log_page->area + log_lsa->offset))->type == LOG_SYSOP_START_POSTPONE);
9570 
9571  /* skip log record header */
9572  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), log_lsa, log_page);
9573 
9574  /* read sysop_start_postpone */
9575  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_SYSOP_START_POSTPONE), log_lsa, log_page);
9576  *sysop_start_postpone = *(LOG_REC_SYSOP_START_POSTPONE *) (log_page->area + log_lsa->offset);
9577  if (!with_undo_data
9578  || (sysop_start_postpone->sysop_end.type != LOG_SYSOP_END_LOGICAL_UNDO
9579  && sysop_start_postpone->sysop_end.type != LOG_SYSOP_END_LOGICAL_MVCC_UNDO))
9580  {
9581  /* no undo */
9582  return NO_ERROR;
9583  }
9584 
9585  /* read undo data and size */
9586  assert (undo_buffer_size != NULL);
9587  assert (undo_buffer != NULL);
9588  assert (undo_size != NULL);
9589  assert (undo_data != NULL);
9590 
9591  if (sysop_start_postpone->sysop_end.type == LOG_SYSOP_END_LOGICAL_UNDO)
9592  {
9593  *undo_size = sysop_start_postpone->sysop_end.undo.length;
9594  }
9595  else
9596  {
9597  assert (sysop_start_postpone->sysop_end.type == LOG_SYSOP_END_LOGICAL_MVCC_UNDO);
9598  *undo_size = sysop_start_postpone->sysop_end.mvcc_undo.undo.length;
9599  }
9600 
9601  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_SYSOP_START_POSTPONE), log_lsa, log_page);
9602  if (log_lsa->offset + (*undo_size) < (int) LOGAREA_SIZE)
9603  {
9604  *undo_data = log_page->area + log_lsa->offset;
9605  }
9606  else
9607  {
9608  if (*undo_buffer_size == 0)
9609  {
9610  *undo_buffer = (char *) db_private_alloc (thread_p, *undo_size);
9611  }
9612  else if (*undo_buffer_size < *undo_size)
9613  {
9614  char *new_ptr = (char *) db_private_realloc (thread_p, *undo_buffer, *undo_size);
9615  if (new_ptr == NULL)
9616  {
9618  return ER_OUT_OF_VIRTUAL_MEMORY;
9619  }
9620  *undo_buffer_size = *undo_size;
9621  *undo_buffer = new_ptr;
9622  }
9623  *undo_data = *undo_buffer;
9624  logpb_copy_from_log (thread_p, *undo_data, *undo_size, log_lsa, log_page);
9625  }
9626  return NO_ERROR;
9627 }
9628 
9629 /*
9630  * log_get_log_group_commit_interval () - setup flush daemon period based on system parameter
9631  */
9632 void
9634 {
9635  is_timed_wait = true;
9636 
9637 #if defined (SERVER_MODE)
9638  if (log_Flush_has_been_requested)
9639  {
9640  period = std::chrono::milliseconds (0);
9641  return;
9642  }
9643 #endif /* SERVER_MODE */
9644 
9645  const int MAX_WAIT_TIME_MSEC = 1000;
9646  int log_group_commit_interval_msec = prm_get_integer_value (PRM_ID_LOG_GROUP_COMMIT_INTERVAL_MSECS);
9647 
9648  assert (log_group_commit_interval_msec >= 0);
9649 
9650  if (log_group_commit_interval_msec == 0)
9651  {
9652  period = std::chrono::milliseconds (MAX_WAIT_TIME_MSEC);
9653  }
9654  else
9655  {
9656  period = std::chrono::milliseconds (log_group_commit_interval_msec);
9657  }
9658 }
9659 
9660 /*
9661  * log_get_checkpoint_interval () - setup log checkpoint daemon period based on system parameter
9662  */
9663 void
9664 log_get_checkpoint_interval (bool & is_timed_wait, cubthread::delta_time & period)
9665 {
9666  int log_checkpoint_interval_sec = prm_get_integer_value (PRM_ID_LOG_CHECKPOINT_INTERVAL_SECS);
9667 
9668  assert (log_checkpoint_interval_sec >= 0);
9669 
9670  if (log_checkpoint_interval_sec > 0)
9671  {
9672  // if log_checkpoint_interval_sec > 0 (zero) then loop for fixed interval
9673  is_timed_wait = true;
9674  period = std::chrono::seconds (log_checkpoint_interval_sec);
9675  }
9676  else
9677  {
9678  // infinite wait
9679  is_timed_wait = false;
9680  }
9681 }
9682 
9683 #if defined (SERVER_MODE)
9684 /*
9685  * log_wakeup_remove_log_archive_daemon () - wakeup remove log archive daemon
9686  */
9687 void
9689 {
9690  if (log_Remove_log_archive_daemon)
9691  {
9692  log_Remove_log_archive_daemon->wakeup ();
9693  }
9694 }
9695 #endif /* SERVER_MODE */
9696 
9697 #if defined (SERVER_MODE)
9698 /*
9699  * log_wakeup_checkpoint_daemon () - wakeup checkpoint daemon
9700  */
9701 void
9703 {
9704  if (log_Checkpoint_daemon)
9705  {
9706  log_Checkpoint_daemon->wakeup ();
9707  }
9708 }
9709 #endif /* SERVER_MODE */
9710 
9711 /*
9712  * log_wakeup_log_flush_daemon () - wakeup log flush daemon
9713  */
9714 void
9716 {
9718  {
9719 #if defined (SERVER_MODE)
9720  log_Flush_has_been_requested = true;
9721  log_Flush_daemon->wakeup ();
9722 #endif /* SERVER_MODE */
9723  }
9724 }
9725 
9726 /*
9727  * log_is_log_flush_daemon_available () - check if log flush daemon is available
9728  */
9729 bool
9731 {
9732 #if defined (SERVER_MODE)
9733  return log_Flush_daemon != NULL;
9734 #else
9735  return false;
9736 #endif
9737 }
9738 
9739 #if defined (SERVER_MODE)
9740 /*
9741  * log_flush_daemon_get_stats () - get log flush daemon thread statistics into statsp
9742  */
9743 void
9744 log_flush_daemon_get_stats (UINT64 * statsp)
9745 {
9746  if (log_Flush_daemon != NULL)
9747  {
9748  log_Flush_daemon->get_stats (statsp);
9749  }
9750 }
9751 #endif // SERVER_MODE
9752 
9753 // *INDENT-OFF*
9754 #if defined(SERVER_MODE)
9755 static void
9756 log_checkpoint_execute (cubthread::entry & thread_ref)
9757 {
9758  if (!BO_IS_SERVER_RESTARTED ())
9759  {
9760  // wait for boot to finish
9761  return;
9762  }
9763 
9764  logpb_checkpoint (&thread_ref);
9765 }
9766 #endif /* SERVER_MODE */
9767 
9768 #if defined(SERVER_MODE)
9769 // class log_remove_log_archive_daemon_task
9770 //
9771 // description:
9772 // remove archive logs daemon task
9773 //
9774 class log_remove_log_archive_daemon_task : public cubthread::entry_task
9775 {
9776  private:
9777  using clock = std::chrono::system_clock;
9778 
9779  bool m_is_timed_wait;
9780  cubthread::delta_time m_period;
9781  std::chrono::milliseconds m_param_period;
9782  clock::time_point m_log_deleted_time;
9783 
9784  void compute_period ()
9785  {
9786  // fetch remove log archives interval
9787  int remove_log_archives_interval_sec = prm_get_integer_value (PRM_ID_REMOVE_LOG_ARCHIVES_INTERVAL);
9788  assert (remove_log_archives_interval_sec >= 0);
9789 
9790  // cache interval for later use
9791  m_param_period = std::chrono::milliseconds (remove_log_archives_interval_sec * 1000);
9792 
9793  if (m_param_period > std::chrono::milliseconds (0))
9794  {
9795  m_is_timed_wait = true;
9796  clock::time_point now = clock::now ();
9797 
9798  // now - m_log_deleted_time: represents time elapsed since last log archive deletion
9799  if ((now - m_log_deleted_time) > m_param_period)
9800  {
9801  m_period = m_param_period;
9802  }
9803  else
9804  {
9805  m_period = m_param_period - (now - m_log_deleted_time);
9806  }
9807  }
9808  else
9809  {
9810  // infinite wait
9811  m_is_timed_wait = false;
9812  }
9813  }
9814 
9815  public:
9816  log_remove_log_archive_daemon_task ()
9817  : m_is_timed_wait (true)
9818  , m_period (0)
9819  , m_param_period (0)
9820  , m_log_deleted_time ()
9821  {
9822  // initialize period
9823  compute_period ();
9824  }
9825 
9826  void get_remove_log_archives_interval (bool & is_timed_wait, cubthread::delta_time & period)
9827  {
9828  period = m_period;
9829  is_timed_wait = m_is_timed_wait;
9830  }
9831 
9832  void execute (cubthread::entry & thread_ref) override
9833  {
9834  if (!BO_IS_SERVER_RESTARTED ())
9835  {
9836  // wait for boot to finish
9837  return;
9838  }
9839 
9840  // compute wait period based on configured interval
9841  compute_period ();
9842 
9843  if (m_is_timed_wait)
9844  {
9845  if (m_period != m_param_period)
9846  {
9847  // do not delete logs. wait more time
9848  return;
9849  }
9850  if (logpb_remove_archive_logs_exceed_limit (&thread_ref, 1) > 0)
9851  {
9852  // a log was deleted
9853  m_log_deleted_time = clock::now ();
9854  }
9855  }
9856  else
9857  {
9858  // remove all unnecessary logs
9859  logpb_remove_archive_logs_exceed_limit (&thread_ref, 0);
9860  }
9861  }
9862 };
9863 #endif /* SERVER_MODE */
9864 
9865 #if defined(SERVER_MODE)
9866 static void
9867 log_clock_execute (cubthread::entry & thread_ref)
9868 {
9869  if (!BO_IS_SERVER_RESTARTED ())
9870  {
9871  // wait for boot to finish
9872  return;
9873  }
9874 
9875  struct timeval now;
9876  gettimeofday (&now, NULL);
9877 
9878  log_Clock_msec = (now.tv_sec * 1000LL) + (now.tv_usec / 1000LL);
9879 }
9880 #endif /* SERVER_MODE */
9881 
9882 #if defined(SERVER_MODE)
9883 static void
9884 log_check_ha_delay_info_execute (cubthread::entry &thread_ref)
9885 {
9886 #if defined(WINDOWS)
9887  return;
9888 #endif /* WINDOWS */
9889 
9890  if (!BO_IS_SERVER_RESTARTED ())
9891  {
9892  // wait for boot to finish
9893  return;
9894  }
9895 
9896  time_t log_record_time = 0;
9897  int error_code;
9898  int delay_limit_in_secs;
9899  int acceptable_delay_in_secs;
9900  int curr_delay_in_secs;
9901  HA_SERVER_STATE server_state;
9902 
9903  csect_enter (&thread_ref, CSECT_HA_SERVER_STATE, INF_WAIT);
9904 
9905  server_state = css_ha_server_state ();
9906 
9907  if (server_state == HA_SERVER_STATE_ACTIVE || server_state == HA_SERVER_STATE_TO_BE_STANDBY)
9908  {
9910  perfmon_set_stat (&thread_ref, PSTAT_HA_REPL_DELAY, 0, true);
9911 
9912  log_append_ha_server_state (&thread_ref, server_state);
9913 
9914  csect_exit (&thread_ref, CSECT_HA_SERVER_STATE);
9915  }
9916  else
9917  {
9918  csect_exit (&thread_ref, CSECT_HA_SERVER_STATE);
9919 
9920  delay_limit_in_secs = prm_get_integer_value (PRM_ID_HA_DELAY_LIMIT_IN_SECS);
9921  acceptable_delay_in_secs = delay_limit_in_secs - prm_get_integer_value (PRM_ID_HA_DELAY_LIMIT_DELTA_IN_SECS);
9922 
9923  if (acceptable_delay_in_secs < 0)
9924  {
9925  acceptable_delay_in_secs = 0;
9926  }
9927 
9928  error_code = catcls_get_apply_info_log_record_time (&thread_ref, &log_record_time);
9929 
9930  if (error_code == NO_ERROR && log_record_time > 0)
9931  {
9932  curr_delay_in_secs = (int) (time (NULL) - log_record_time);
9933  if (curr_delay_in_secs > 0)
9934  {
9935  curr_delay_in_secs -= HA_DELAY_ERR_CORRECTION;
9936  }
9937 
9938  if (delay_limit_in_secs > 0)
9939  {
9940  if (curr_delay_in_secs > delay_limit_in_secs)
9941  {
9942  if (!css_is_ha_repl_delayed ())
9943  {
9945  curr_delay_in_secs, delay_limit_in_secs);
9946 
9948  }
9949  }
9950  else if (curr_delay_in_secs <= acceptable_delay_in_secs)
9951  {
9952  if (css_is_ha_repl_delayed ())
9953  {
9955  curr_delay_in_secs, acceptable_delay_in_secs);
9956 
9958  }
9959  }
9960  }
9961 
9962  perfmon_set_stat (&thread_ref, PSTAT_HA_REPL_DELAY, curr_delay_in_secs, true);
9963  }
9964  }
9965 }
9966 #endif /* SERVER_MODE */
9967 
9968 #if defined(SERVER_MODE)
9969 static void
9970 log_flush_execute (cubthread::entry & thread_ref)
9971 {
9972  if (!BO_IS_SERVER_RESTARTED () || !log_Flush_has_been_requested)
9973  {
9974  return;
9975  }
9976 
9977  // refresh log trace flush time
9979 
9980  LOG_CS_ENTER (&thread_ref);
9981  logpb_flush_pages_direct (&thread_ref);
9982  LOG_CS_EXIT (&thread_ref);
9983 
9985 
9987  pthread_cond_broadcast (&log_Gl.group_commit_info.gc_cond);
9988  log_Flush_has_been_requested = false;
9990 }
9991 #endif /* SERVER_MODE */
9992 
9993 #if defined(SERVER_MODE)
9994 /*
9995  * log_checkpoint_daemon_init () - initialize checkpoint daemon
9996  */
9997 void
9998 log_checkpoint_daemon_init ()
9999 {
10000  assert (log_Checkpoint_daemon == NULL);
10001 
10003  cubthread::entry_callable_task *daemon_task = new cubthread::entry_callable_task (log_checkpoint_execute);
10004 
10005  // create checkpoint daemon thread
10006  log_Checkpoint_daemon = cubthread::get_manager ()->create_daemon (looper, daemon_task, "log_checkpoint");
10007 }
10008 #endif /* SERVER_MODE */
10009 
10010 #if defined(SERVER_MODE)
10011 /*
10012  * log_remove_log_archive_daemon_init () - initialize remove log archive daemon
10013  */
10014 void
10015 log_remove_log_archive_daemon_init ()
10016 {
10017  assert (log_Remove_log_archive_daemon == NULL);
10018 
10019  log_remove_log_archive_daemon_task *daemon_task = new log_remove_log_archive_daemon_task ();
10020  cubthread::period_function setup_period_function = std::bind (
10021  &log_remove_log_archive_daemon_task::get_remove_log_archives_interval,
10022  daemon_task,
10023  std::placeholders::_1,
10024  std::placeholders::_2);
10025 
10026  cubthread::looper looper = cubthread::looper (setup_period_function);
10027 
10028  // create log archive remover daemon thread
10029  log_Remove_log_archive_daemon = cubthread::get_manager ()->create_daemon (looper, daemon_task,
10030  "log_remove_log_archive");
10031 }
10032 #endif /* SERVER_MODE */
10033 
10034 #if defined(SERVER_MODE)
10035 /*
10036  * log_clock_daemon_init () - initialize log clock daemon
10037  */
10038 void
10039 log_clock_daemon_init ()
10040 {
10041  assert (log_Clock_daemon == NULL);
10042 
10043  cubthread::looper looper = cubthread::looper (std::chrono::milliseconds (200));
10044  log_Clock_daemon =
10045  cubthread::get_manager ()->create_daemon (looper, new cubthread::entry_callable_task (log_clock_execute),
10046  "log_clock");
10047 }
10048 #endif /* SERVER_MODE */
10049 
10050 #if defined(SERVER_MODE)
10051 /*
10052  * log_check_ha_delay_info_daemon_init () - initialize check ha delay info daemon
10053  */
10054 void
10055 log_check_ha_delay_info_daemon_init ()
10056 {
10057  assert (log_Check_ha_delay_info_daemon == NULL);
10058 
10059  cubthread::looper looper = cubthread::looper (std::chrono::seconds (1));
10060  cubthread::entry_callable_task *daemon_task = new cubthread::entry_callable_task (log_check_ha_delay_info_execute);
10061 
10062  log_Check_ha_delay_info_daemon = cubthread::get_manager ()->create_daemon (looper, daemon_task,
10063  "log_check_ha_delay_info");
10064 }
10065 #endif /* SERVER_MODE */
10066 
10067 #if defined(SERVER_MODE)
10068 /*
10069  * log_flush_daemon_init () - initialize log flush daemon
10070  */
10071 void
10072 log_flush_daemon_init ()
10073 {
10074  assert (log_Flush_daemon == NULL);
10075 
10077  cubthread::entry_callable_task *daemon_task = new cubthread::entry_callable_task (log_flush_execute);
10078 
10079  log_Flush_daemon = cubthread::get_manager ()->create_daemon (looper, daemon_task, "log_flush");
10080 }
10081 #endif /* SERVER_MODE */
10082 
10083 #if defined(SERVER_MODE)
10084 /*
10085  * log_daemons_init () - initialize daemon threads
10086  */
10087 static void
10088 log_daemons_init ()
10089 {
10090  log_remove_log_archive_daemon_init ();
10091  log_checkpoint_daemon_init ();
10092  log_check_ha_delay_info_daemon_init ();
10093  log_clock_daemon_init ();
10094  log_flush_daemon_init ();
10095 }
10096 #endif /* SERVER_MODE */
10097 
10098 #if defined(SERVER_MODE)
10099 /*
10100  * log_daemons_destroy () - destroy daemon threads
10101  */
10102 static void
10103 log_daemons_destroy ()
10104 {
10105  cubthread::get_manager ()->destroy_daemon (log_Remove_log_archive_daemon);
10106  cubthread::get_manager ()->destroy_daemon (log_Checkpoint_daemon);
10107  cubthread::get_manager ()->destroy_daemon (log_Check_ha_delay_info_daemon);
10108  cubthread::get_manager ()->destroy_daemon (log_Clock_daemon);
10109  cubthread::get_manager ()->destroy_daemon (log_Flush_daemon);
10110 }
10111 #endif /* SERVER_MODE */
10112 // *INDENT-ON*
10113 
10114 /*
10115  * log_get_clock_msec () - get current system time in milliseconds.
10116  * return cached value by log_Clock_daemon if SERVER_MODE is defined
10117  */
10118 INT64
10120 {
10121 #if defined (SERVER_MODE)
10122  if (log_Clock_msec > 0)
10123  {
10124  return log_Clock_msec;
10125  }
10126 #endif /* SERVER_MODE */
10127 
10128  struct timeval now;
10129  gettimeofday (&now, NULL);
10130 
10131  return (now.tv_sec * 1000LL) + (now.tv_usec / 1000LL);
10132 }
10133 
10134 // *INDENT-OFF*
10135 #if defined (SERVER_MODE)
10136 static void
10137 log_abort_task_execute (cubthread::entry &thread_ref, LOG_TDES &tdes)
10138 {
10139  (void) log_abort_by_tdes (&thread_ref, &tdes);
10140 }
10141 #endif // SERVER_MODE
10142 // *INDENT-ON*
10143 
10144 void
10146 {
10147  LOG_TDES *tdes = LOG_FIND_TDES (LOG_FIND_THREAD_TRAN_INDEX (thread_p));
10148  int error_code = NO_ERROR;
10149 
10150  if (tdes == NULL)
10151  {
10152  return;
10153  }
10154 
10155  error_code =
10157 
10158  if (error_code != NO_ERROR)
10159  {
10160  assert (false);
10161  }
10162 }
10163 
10164 /*
10165  * logtb_tran_update_stats_online_index_rb - Updates statistics during an online index when a transaction
10166  * gets rollbacked.
10167  *
10168  * TODO: This can be easily optimized since it is slow. Try to find a better approach!
10169  */
10170 static int
10171 logtb_tran_update_stats_online_index_rb (THREAD_ENTRY * thread_p, void *data, void *args)
10172 {
10173  /* This is called only during a rollback on a transaction that has updated an index which was under
10174  * online loading.
10175  */
10176  LOG_TRAN_BTID_UNIQUE_STATS *unique_stats = (LOG_TRAN_BTID_UNIQUE_STATS *) data;
10177  int error_code = NO_ERROR;
10178  OID class_oid;
10179 #if !defined (NDEBUG)
10180  LOG_TDES *tdes = LOG_FIND_TDES (LOG_FIND_THREAD_TRAN_INDEX (thread_p));
10181 
10182  assert (LOG_ISTRAN_ABORTED (tdes));
10183 #endif /* !NDEBUG */
10184 
10185  if (unique_stats->deleted)
10186  {
10187  /* ignore if deleted */
10188  return NO_ERROR;
10189  }
10190 
10191  OID_SET_NULL (&class_oid);
10192 
10193  error_code = btree_get_class_oid_of_unique_btid (thread_p, &unique_stats->btid, &class_oid);
10194  if (error_code != NO_ERROR)
10195  {
10196  assert (false);
10197  return error_code;
10198  }
10199 
10200  assert (!OID_ISNULL (&class_oid));
10201 
10202  if (!btree_is_btid_online_index (thread_p, &class_oid, &unique_stats->btid))
10203  {
10204  /* We can skip. */
10205  return NO_ERROR;
10206  }
10207 
10208  /* We can update the statistics. */
10209  error_code =
10210  logtb_update_global_unique_stats_by_delta (thread_p, &unique_stats->btid, unique_stats->tran_stats.num_oids,
10211  unique_stats->tran_stats.num_nulls, unique_stats->tran_stats.num_keys,
10212  false);
10213 
10214  return error_code;
10215 }
10216 
10217 //
10218 // log critical section
10219 //
10220 
10221 void
10223 {
10224 #if defined (SERVER_MODE)
10225  if (csect_enter (thread_p, CSECT_LOG, INF_WAIT) != NO_ERROR)
10226  {
10227  assert (false);
10228  }
10229 #endif
10230 }
10231 
10232 void
10234 {
10235 #if defined (SERVER_MODE)
10236  if (csect_enter_as_reader (thread_p, CSECT_LOG, INF_WAIT) != NO_ERROR)
10237  {
10238  assert (false);
10239  }
10240 #endif
10241 }
10242 
10243 void
10245 {
10246 #if defined (SERVER_MODE)
10247  if (csect_exit (thread_p, CSECT_LOG) != NO_ERROR)
10248  {
10249  assert (false);
10250  }
10251 #endif
10252 }
10253 
10254 void
10256 {
10257 #if defined (SERVER_MODE)
10258  if (csect_demote (thread_p, CSECT_LOG, INF_WAIT) != NO_ERROR)
10259  {
10260  assert (false);
10261  }
10262 #endif
10263 }
10264 
10265 void
10267 {
10268 #if defined (SERVER_MODE)
10269  if (csect_promote (thread_p, CSECT_LOG, INF_WAIT) != NO_ERROR)
10270  {
10271  assert (false);
10272  }
10273 #endif
10274 }
10275 
10276 bool
10278 {
10279 #if defined (SERVER_MODE)
10280  /* TODO: Vacuum workers never hold CSECT_LOG lock. Investigate any possible
10281  * unwanted consequences.
10282  * NOTE: It is considered that a vacuum worker holds a "shared" lock.
10283  * TODO: remove vacuum code from LOG_CS_OWN
10284  */
10285  return vacuum_is_process_log_for_vacuum (thread_p) || (csect_check_own (thread_p, CSECT_LOG) >= 1);
10286 #else // not server mode
10287  return true;
10288 #endif // not server mode
10289 }
10290 
10291 bool
10293 {
10294 #if defined (SERVER_MODE)
10295  return csect_check_own (thread_p, CSECT_LOG) == 1;
10296 #else // not server mode
10297  return true;
10298 #endif // not server mode
10299 }
#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
PGLENGTH offset
Definition: recovery.h:201
char * PAGE_PTR
LOG_REC_UNDO undo
Definition: log_record.hpp:209
void tx_lob_locator_clear(cubthread::entry *thread_p, log_tdes *tdes, bool at_commit, LOG_LSA *savept_lsa)
int num_coord_loose_end_indices
Definition: log_impl.h:584
#define ER_LK_UNILATERALLY_ABORTED
Definition: error_code.h:130
unsigned long gc_flush_count
Definition: log_impl.h:756
void partition_decache_class(THREAD_ENTRY *thread_p, const OID *class_oid)
Definition: partition.c:775
static int logtb_tran_update_stats_online_index_rb(THREAD_ENTRY *thread_p, void *data, void *args)
LOG_SYSOP_END_TYPE type
Definition: log_record.hpp:297
void log_initialize(THREAD_ENTRY *thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname, int ismedia_crash, BO_RESTART_ARG *r_args)
Definition: log_manager.c:1005
char prefix_name[MAXLOGNAME]
int db_make_datetime(DB_VALUE *value, const DB_DATETIME *datetime)
CSS_CONN_ENTRY * css_find_conn_by_tran_index(int tran_index)
int tran_index
Definition: log_impl.h:465
LOG_LSA restart_repl_lsa
Definition: boot_sr.h:106
cubthread::entry * thread_get_thread_entry_info(void)
#define NO_ERROR
Definition: error_code.h:46
const VFID * vfid
Definition: log_record.hpp:299
void reset_start_mvccid()
Definition: mvcc_table.cpp:601
int mht_map_no_key(THREAD_ENTRY *thread_p, const MHT_TABLE *ht, int(*map_func)(THREAD_ENTRY *thread_p, void *data, void *args), void *func_args)
Definition: memory_hash.c:2231
int cur_repl_record
Definition: log_impl.h:506
DKNPAGES npages
int logpb_initialize_log_names(THREAD_ENTRY *thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname)
int area_size
void log_append_redo_data(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, int length, const void *data)
Definition: log_manager.c:1979
#define __attribute__(X)
Definition: porting.h:36
void LOG_CS_PROMOTE(THREAD_ENTRY *thread_p)
TRAN_STATE log_commit_local(THREAD_ENTRY *thread_p, LOG_TDES *tdes, bool retain_lock, bool is_local_tran)
Definition: log_manager.c:4883
void log_append_repl_info(THREAD_ENTRY *thread_p, LOG_TDES *tdes, bool is_commit)
Definition: log_manager.c:4564
#define ER_LOG_REDO_INTERFACE
Definition: error_code.h:149
void add(const char *classname, const OID &class_oid, const LOG_LSA &lsa)
void log_update_global_btid_online_index_stats(THREAD_ENTRY *thread_p)
float db_compatibility
#define ER_LOG_UNKNOWN_SAVEPOINT
Definition: error_code.h:648
#define ER_LOG_MAYNEED_MEDIA_RECOVERY
Definition: error_code.h:155
void logtb_complete_mvcc(THREAD_ENTRY *thread_p, LOG_TDES *tdes, bool committed)
const char * log_Db_fullname
Definition: log_global.c:89
void log_append_undoredo_data2(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, const VFID *vfid, PAGE_PTR pgptr, PGLENGTH offset, int undo_length, int redo_length, const void *undo_data, const void *redo_data)
Definition: log_manager.c:1861
void LOG_CS_DEMOTE(THREAD_ENTRY *thread_p)
MHT_TABLE * unique_stats_hash
Definition: log_impl.h:439
int xdisk_get_purpose_and_space_info(THREAD_ENTRY *thread_p, VOLID volid, DISK_VOLPURPOSE *vol_purpose, DISK_VOLUME_SPACE_INFO *space_info)
void css_set_ha_repl_delayed(void)
bool restore_slave
Definition: boot_sr.h:103
bool pgbuf_is_lsa_temporary(PAGE_PTR pgptr)
Definition: page_buffer.c:4885
#define LOG_TDES_LAST_SYSOP(tdes)
Definition: log_manager.c:182
#define IO_PAGESIZE
TRANTABLE trantable
Definition: log_impl.h:650
#define BO_IS_SERVER_RESTARTED()
Definition: boot_sr.h:84
STATIC_INLINE void log_sysop_end_final(THREAD_ENTRY *thread_p, LOG_TDES *tdes) __attribute__((ALWAYS_INLINE))
Definition: log_manager.c:3746
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
int logpb_initialize_header(THREAD_ENTRY *thread_p, LOG_HEADER *loghdr, const char *prefix_logname, DKNPAGES npages, INT64 *db_creation)
PGLENGTH log_get_io_page_size(THREAD_ENTRY *thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname)
Definition: log_manager.c:8572
TRAN_STATE log_abort(THREAD_ENTRY *thread_p, int tran_index)
Definition: log_manager.c:5185
void log_append_undoredo_crumbs(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, int num_undo_crumbs, int num_redo_crumbs, const LOG_CRUMB *undo_crumbs, const LOG_CRUMB *redo_crumbs)
Definition: log_manager.c:2030
int pgbuf_flush_all_unfixed_and_set_lsa_as_null(THREAD_ENTRY *thread_p, VOLID volid)
Definition: page_buffer.c:3116
#define ASSERT_ERROR()
SCAN_CODE
int locator_drop_transient_class_name_entries(THREAD_ENTRY *thread_p, LOG_LSA *savep_lsa)
Definition: locator_sr.c:1258
bool LOG_CS_OWN(THREAD_ENTRY *thread_p)
void qmgr_clear_trans_wakeup(THREAD_ENTRY *thread_p, int tran_index, bool is_tran_died, bool is_abort)
LOG_DATA data
Definition: log_record.hpp:182
pthread_mutex_t gc_mutex
Definition: log_impl.h:319
#define HA_DELAY_ERR_CORRECTION
static LOG_PAGE * log_dump_record_2pc_prepare_commit(THREAD_ENTRY *thread_p, FILE *out_fp, LOG_LSA *lsa_p, LOG_PAGE *log_page_p)
Definition: log_manager.c:6531
LOG_LSA chkpt_redo_lsa
Definition: log_impl.h:660
char user_name[DB_MAX_USER_LENGTH+1]
Definition: log_record.hpp:390
LOG_LSA bkup_level1_lsa
size_t css_count_transaction_worker_threads(THREAD_ENTRY *thread_p, int tran_index, int client_id)
const char * rv_rcvindex_string(LOG_RCVINDEX rcvindex)
Definition: recovery.c:846
void logpb_fatal_error(THREAD_ENTRY *thread_p, bool logexit, const char *file_name, const int lineno, const char *fmt,...)
bool LSA_EQ(const log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:160
int TRANID
static void log_append_commit_log_with_lock(THREAD_ENTRY *thread_p, LOG_TDES *tdes, LOG_LSA *commit_lsa)
Definition: log_manager.c:4725
#define ER_LOG_FATAL_ERROR
Definition: error_code.h:777
int(* undofun)(THREAD_ENTRY *thread_p, LOG_RCV *logrcv)
Definition: recovery.h:215
INT64 db_creation
Definition: boot_sr.h:105
LOG_TRAN_UPDATE_STATS log_upd_stats
Definition: log_impl.h:534
EVENT_STAT event_stats
void LSA_COPY(log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:139
void log_sysop_end_logical_compensate(THREAD_ENTRY *thread_p, LOG_LSA *undo_nxlsa)
Definition: log_manager.c:3963
int fileio_reset_volume(THREAD_ENTRY *thread_p, int vol_fd, const char *vlabel, DKNPAGES npages, const LOG_LSA *reset_lsa_p)
Definition: file_io.c:2903
LOG_LSA repl_update_lsa
Definition: log_impl.h:511
static LOG_PAGE * log_dump_record_dbout_redo(THREAD_ENTRY *thread_p, FILE *out_fp, LOG_LSA *lsa_p, LOG_PAGE *log_page_p)
Definition: log_manager.c:6195
void log_append_dboutside_redo(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, int length, const void *data)
Definition: log_manager.c:2627
enum log_getnewtrid LOG_GETNEWTRID
Definition: log_impl.h:287
PAGEID DKNPAGES
#define ER_LOG_PAGE_CORRUPTED
Definition: error_code.h:140
int db_make_bigint(DB_VALUE *value, const DB_BIGINT num)
LOG_VACUUM_INFO vacuum_info
Definition: log_record.hpp:211
static LOG_PAGE * log_dump_record_mvcc_undo(THREAD_ENTRY *thread_p, FILE *out_fp, LOG_LSA *lsa_p, LOG_PAGE *log_page_p, LOG_ZIP *log_zip_p)
Definition: log_manager.c:6107
#define LOGAREA_SIZE
Definition: log_impl.h:116
LOG_2PC_COORDINATOR * coord
Definition: log_impl.h:489
LOG_REC_UNDO undo
Definition: log_record.hpp:302
LOG_PRIOR_LSA_LOCK
Definition: log_append.hpp:65
LOG_LSA sysop_start_postpone_lsa
Definition: log_impl.h:448
LOG_RCVINDEX
Definition: recovery.h:36
#define GET_ZIP_LEN(length)
Definition: log_compress.h:36
LOG_LSA * log_get_append_lsa(void)
Definition: log_manager.c:559
int logpb_fetch_page(THREAD_ENTRY *thread_p, const LOG_LSA *req_lsa, LOG_CS_ACCESS_MODE access_mode, LOG_PAGE *log_pgptr)
#define CUBRID_MAGIC_LOG_ACTIVE
void log_sysop_start_atomic(THREAD_ENTRY *thread_p)
Definition: log_manager.c:3644
#define DISK_VOLPURPOSE
void log_rv_dump_hexa(FILE *fp, int length, void *data)
Definition: log_manager.c:8734
#define ER_FAILED
Definition: error_code.h:47
const int LOG_SYSTEM_TRAN_INDEX
#define RCV_IS_LOGICAL_LOG(vpid, idx)
Definition: recovery.h:252
LOG_REC_REDO redo
Definition: log_record.hpp:218
#define CUBRID_MAGIC_LOG_ARCHIVE
static LOG_PAGE * log_dump_record_undo(THREAD_ENTRY *thread_p, FILE *out_fp, LOG_LSA *lsa_p, LOG_PAGE *log_page_p, LOG_ZIP *log_zip_p)
Definition: log_manager.c:6015
LOG_LSA * log_get_eof_lsa(void)
Definition: log_manager.c:572
LOG_GLOBAL log_Gl
LOG_HEADER hdr
Definition: log_impl.h:653
#define csect_enter(a, b, c)
Definition: cnv.c:138
#define ALWAYS_INLINE
#define NULL_TRANID
VOLID fileio_find_next_perm_volume(THREAD_ENTRY *thread_p, VOLID volid)
Definition: file_io.c:6410
static LOG_LSA * log_get_savepoint_lsa(THREAD_ENTRY *thread_p, const char *savept_name, LOG_TDES *tdes, LOG_LSA *savept_lsa)
Definition: log_manager.c:3419
static int log_initialize_internal(THREAD_ENTRY *thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname, bool ismedia_crash, BO_RESTART_ARG *r_args, bool init_emergency)
Definition: log_manager.c:1046
time_t stopat
Definition: boot_sr.h:95
LOG_LSA topop_lsa
Definition: log_impl.h:479
LOG_HDRPAGE hdr
Definition: log_storage.hpp:84
int logpb_flush_page(THREAD_ENTRY *thread_p, LOG_PAGE *log_pgptr)
int logpb_background_archiving(THREAD_ENTRY *thread_p)
static LOG_PAGE * log_dump_record_sysop_start_postpone(THREAD_ENTRY *thread_p, FILE *out_fp, LOG_LSA *lsa_p, LOG_PAGE *log_page_p, LOG_ZIP *log_zip_p)
Definition: log_manager.c:6336
int log_set_no_logging(void)
Definition: log_manager.c:951
#define pgbuf_unfix(thread_p, pgptr)
Definition: page_buffer.h:276
MVCCID oldest_visible_mvccid
static void log_cleanup_modified_class(const tx_transient_class_entry &t, bool &stop)
Definition: log_manager.c:4819
#define LOG_GET_LOG_RECORD_HEADER(log_page_p, lsa)
Definition: log_record.hpp:406
LOG_LSA forw_lsa
Definition: log_record.hpp:146
#define ER_LOG_HAS_TOPOPS_DURING_COMMIT_ABORT
Definition: error_code.h:776
LOG_LSA prev_tranlsa
Definition: log_record.hpp:144
void xlogtb_dump_trantable(THREAD_ENTRY *thread_p, FILE *out_fp)
const LOG_PAGEID LOGPB_HEADER_PAGE_ID
Definition: log_storage.hpp:51
int log_execute_run_postpone(THREAD_ENTRY *thread_p, LOG_LSA *log_lsa, LOG_REC_REDO *redo, char *redo_rcv_data)
Definition: log_manager.c:8213
void log_skip_logging_set_lsa(THREAD_ENTRY *thread_p, LOG_DATA_ADDR *addr)
Definition: log_manager.c:3204
void thread_sleep(double millisec)
char user_name[DB_MAX_USER_LENGTH+1]
Definition: log_record.hpp:378
void logtb_clear_tdes(THREAD_ENTRY *thread_p, LOG_TDES *tdes)
#define ER_LOG_POSTPONE_INTERFACE
Definition: error_code.h:150
#define LSA_INITIALIZER
Definition: log_lsa.hpp:76
enum log_wrote_eot_log LOG_WRITE_EOT_LOG
Definition: log_impl.h:291
LOG_PAGE * loghdr_pgptr
Definition: log_impl.h:672
void get_stats(cubperf::stat_value *stats_out)
#define assert_release(e)
Definition: error_manager.h:96
#define REL_MAX_RELEASE_LENGTH
static bool log_verify_dbcreation(THREAD_ENTRY *thread_p, VOLID volid, const INT64 *log_dbcreation)
Definition: log_manager.c:631
void pgbuf_set_dirty(THREAD_ENTRY *thread_p, PAGE_PTR pgptr, bool free_page)
Definition: page_buffer.c:4280
#define LOG_CHECK_LOG_APPLIER(thread_p)
Definition: log_impl.h:240
LOG_LSA * log_get_restart_lsa(void)
Definition: log_manager.c:515
INT64 log_get_clock_msec(void)
void LOG_CS_ENTER(THREAD_ENTRY *thread_p)
#define VACUUM_IS_THREAD_VACUUM
Definition: vacuum.h:215
void pgbuf_notify_vacuum_follows(THREAD_ENTRY *thread_p, PAGE_PTR page)
LOG_PRIOR_NODE * prior_lsa_alloc_and_copy_crumbs(THREAD_ENTRY *thread_p, LOG_RECTYPE rec_type, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, const int num_ucrumbs, const LOG_CRUMB *ucrumbs, const int num_rcrumbs, const LOG_CRUMB *rcrumbs)
Definition: log_append.cpp:407
int csect_promote(THREAD_ENTRY *thread_p, int cs_index, int wait_secs)
static const int LOG_REC_UNDO_MAX_ATTEMPTS
Definition: log_manager.c:177
VOLID logpb_add_volume(const char *db_fullname, VOLID new_volid, const char *new_volfullname, DISK_VOLPURPOSE new_volpurpose)
#define VFID_AS_ARGS(vfidp)
Definition: dbtype_def.h:892
void log_append_undo_data2(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, const VFID *vfid, PAGE_PTR pgptr, PGLENGTH offset, int length, const void *data)
Definition: log_manager.c:1933
#define ER_LOG_THEREARE_PENDING_ACTIONS_MUST_LOG
Definition: error_code.h:732
INT16 VOLID
#define MVCCID_NULL
char log_Name_active[PATH_MAX]
Definition: log_global.c:90
void log_sysop_start(THREAD_ENTRY *thread_p)
Definition: log_manager.c:3578
static void log_ascii_dump(FILE *out_fp, int length, void *data)
Definition: log_manager.c:5780
const VOLID LOG_DBLOG_ACTIVE_VOLID
Definition: log_volids.hpp:49
unsigned long commit_count
Definition: log_impl.h:733
void xlog_dump(THREAD_ENTRY *thread_p, FILE *out_fp, int isforward, LOG_PAGEID start_logpageid, DKNPAGES dump_npages, TRANID desired_tranid)
Definition: log_manager.c:6759
VOLID volid
Definition: log_record.hpp:158
LOG_LSA tail_lsa
Definition: log_impl.h:473
log_postpone_cache m_log_postpone_cache
Definition: log_impl.h:543
#define OID_SET_NULL(oidp)
Definition: oid.h:85
#define LOG_MAY_CONTAIN_USER_DATA(rcvindex)
Definition: tde.h:107
int log_get_charset_from_header_page(THREAD_ENTRY *thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname)
Definition: log_manager.c:8645
int log_archive_log_header_start_scan(THREAD_ENTRY *thread_p, int show_type, DB_VALUE **arg_values, int arg_cnt, void **ptr)
Definition: log_manager.c:9175
LOG_LSA end_lsa
Definition: log_manager.h:56
#define ER_LOG_MOUNT_FAIL
Definition: error_code.h:141
char * data
void(* REL_FIXUP_FUNCTION)(void)
LOG_GROUP_COMMIT_INFO group_commit_info
Definition: log_impl.h:678
LOG_TDES * LOG_FIND_TDES(int tran_index)
Definition: log_impl.h:1095
int pgbuf_flush_all_unfixed(THREAD_ENTRY *thread_p, VOLID volid)
Definition: page_buffer.c:3099
LOG_PAGEID fpageid
MVCCID mvcc_id
Definition: recovery.h:198
int logpb_create_volume_info(const char *db_fullname)
#define VACUUM_ER_LOG_TOPOPS
Definition: vacuum.h:56
char * or_unpack_string_nocopy(char *ptr, char **string)
int32_t pageid
Definition: dbtype_def.h:879
#define LSA_AS_ARGS(lsa_ptr)
Definition: log_lsa.hpp:78
bool log_2pc_clear_and_is_tran_distributed(log_tdes *tdes)
Definition: log_2pc.c:2412
int er_errid(void)
#define VACUUM_ER_LOG_WORKER
Definition: vacuum.h:53
#define LOG_TOPOP_STACK_INIT_SIZE
Definition: log_manager.h:50
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
LOG_ZIP_SIZE_T data_length
Definition: log_compress.h:55
STATIC_INLINE int log_sysop_get_level(THREAD_ENTRY *thread_p) __attribute__((ALWAYS_INLINE))
Definition: log_manager.c:4124
void rv_check_rvfuns(void)
Definition: recovery.c:861
#define ER_LOG_COMPENSATE_INTERFACE
Definition: error_code.h:151
const VOLID LOG_DBLOG_BKUPINFO_VOLID
Definition: log_volids.hpp:47
static void log_cleanup_modified_class_list(THREAD_ENTRY *thread_p, LOG_TDES *tdes, LOG_LSA *savept_lsa, bool release, bool decache_classrepr)
Definition: log_manager.c:4847
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
void xcache_remove_by_oid(THREAD_ENTRY *thread_p, const OID *oid)
Definition: xasl_cache.c:1869
#define PTR_ALIGN(addr, boundary)
Definition: memory_alloc.h:77
int logpb_check_and_reset_temp_lsa(THREAD_ENTRY *thread_p, VOLID volid)
static LOG_PAGE * log_dump_record_sysop_end(THREAD_ENTRY *thread_p, LOG_LSA *log_lsa, LOG_PAGE *log_page_p, LOG_ZIP *log_zip_p, FILE *out_fp)
Definition: log_manager.c:6436
std::mutex prior_lsa_mutex
Definition: log_append.hpp:125
LOG_VACUUM_INFO vacuum_info
Definition: log_record.hpp:202
bool LSA_LT(const log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:174
void log_sysop_end_logical_undo(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, const VFID *vfid, int undo_size, const char *undo_data)
Definition: log_manager.c:3920
#define er_log_debug(...)
static void log_tran_do_postpone(THREAD_ENTRY *thread_p, LOG_TDES *tdes)
Definition: log_manager.c:7827
LOG_ZIP * log_zip_alloc(LOG_ZIP_SIZE_T size)
Definition: log_compress.c:230
LOG_LSA append_lsa
struct lk_acqobj_lock LK_ACQOBJ_LOCK
Definition: lock_manager.h:103
static void log_hexa_dump(FILE *out_fp, int length, void *data)
Definition: log_manager.c:5800
#define MSGCAT_LOG_LOGINFO_ACTIVE
bool has_logging_been_skipped
tx_transient_class_registry m_modified_classes
Definition: log_impl.h:502
#define pgbuf_invalidate_all(thread_p, volid)
Definition: page_buffer.h:286
void logpb_flush_header(THREAD_ENTRY *thread_p)
LOG_LSA lastparent_lsa
Definition: log_impl.h:331
void _er_log_debug(const char *file_name, const int line_no, const char *fmt,...)
#define NULL_VOLDES
Definition: file_io.h:44
static void log_dump_data(THREAD_ENTRY *thread_p, FILE *out_fp, int length, LOG_LSA *log_lsa, LOG_PAGE *log_page_p, void(*dumpfun)(FILE *fp, int, void *), LOG_ZIP *log_dump_ptr)
#define ER_ONLY_IN_STANDALONE
Definition: error_code.h:731
#define MAX_ALIGNMENT
Definition: memory_alloc.h:70
void log_wakeup_log_flush_daemon()
Definition: log_manager.c:9715
void logpb_set_dirty(THREAD_ENTRY *thread_p, LOG_PAGE *log_pgptr)
bool has_class(const OID &class_oid) const
int fileio_mount(THREAD_ENTRY *thread_p, const char *db_full_name_p, const char *vol_label_p, VOLID vol_id, int lock_wait, bool is_do_sync)
Definition: file_io.c:2957
void add_lsa(const log_lsa &lsa)
int xlogtb_reset_wait_msecs(THREAD_ENTRY *thread_p, int wait_msecs)
STATIC_INLINE void log_sysop_end_begin(THREAD_ENTRY *thread_p, int *tran_index_out, LOG_TDES **tdes_out) __attribute__((ALWAYS_INLINE))
Definition: log_manager.c:3703
#define LOG_TDES_LAST_SYSOP_PARENT_LSA(tdes)
Definition: log_manager.c:183
void log_do_postpone(THREAD_ENTRY *thread_p, LOG_TDES *tdes, LOG_LSA *start_postpone_lsa)
Definition: log_manager.c:7908
LOG_LSA back_lsa
Definition: log_record.hpp:145
#define VFID_ISNULL(vfid_ptr)
Definition: file_manager.h:72
void THREAD_ENTRY
mvcctable mvcc_table
Definition: log_impl.h:684
#define NULL_PAGEID
char * log_data
Definition: log_compress.h:57
void describe_value(const db_value *value)
STATIC_INLINE bool vacuum_is_process_log_for_vacuum(THREAD_ENTRY *thread_p) __attribute__((ALWAYS_INLINE))
Definition: vacuum.h:209
PGLENGTH offset
Definition: log_record.hpp:157
LOG_LSA tail_topresult_lsa
Definition: log_impl.h:480
LOG_HDR_BKUP_LEVEL_INFO bkinfo[FILEIO_BACKUP_UNDEFINED_LEVEL]
void file_tempcache_drop_tran_temp_files(THREAD_ENTRY *thread_p)
const char * log_to_string(LOG_RECTYPE type)
Definition: log_manager.c:343
#define TR_TABLE_CS_ENTER(thread_p)
Definition: log_impl.h:88
#define MSGCAT_SET_LOG
void log_set_db_restore_time(THREAD_ENTRY *thread_p, INT64 db_restore_time)
Definition: log_manager.c:9351
INT64 db_creation
static void log_append_repl_info_and_commit_log(THREAD_ENTRY *thread_p, LOG_TDES *tdes, LOG_LSA *commit_lsa)
Definition: log_manager.c:4588
void log_append_redo_data2(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, const VFID *vfid, PAGE_PTR pgptr, PGLENGTH offset, int length, const void *data)
Definition: log_manager.c:1995
#define LOG_IS_SYSTEM_OP_STARTED(tdes)
Definition: log_manager.h:59
static LOG_PAGE * log_dump_record_ha_server_state(THREAD_ENTRY *thread_p, FILE *out_fp, LOG_LSA *log_lsa, LOG_PAGE *log_page_p)
Definition: log_manager.c:6599
int db_make_string(DB_VALUE *value, DB_CONST_C_CHAR str)
void LOG_RESET_PREV_LSA(const LOG_LSA *lsa)
Definition: log_append.cpp:137
REL_COMPATIBILITY
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)
STATIC_INLINE void log_sysop_get_tran_index_and_tdes(THREAD_ENTRY *thread_p, int *tran_index_out, LOG_TDES **tdes_out) __attribute__((ALWAYS_INLINE))
Definition: log_manager.c:4148
#define ER_LOG_CORRUPTED_DB_DUE_NOLOGGING
Definition: error_code.h:729
manager * get_manager(void)
int disk_set_creation(THREAD_ENTRY *thread_p, INT16 volid, const char *new_vol_fullname, const INT64 *new_dbcreation, const LOG_LSA *new_chkptlsa, bool logchange, DISK_FLUSH_TYPE flush)
Definition: disk_manager.c:850
static LOG_PAGE * log_dump_record_commit_postpone(THREAD_ENTRY *thread_p, FILE *out_fp, LOG_LSA *lsa_p, LOG_PAGE *log_page_p)
Definition: log_manager.c:6247
static LOG_PAGE * log_dump_record_redo(THREAD_ENTRY *thread_p, FILE *out_fp, LOG_LSA *lsa_p, LOG_PAGE *log_page_p, LOG_ZIP *log_zip_p)
Definition: log_manager.c:6042
static void destroy_system_transactions()
char * data_header
Definition: log_append.hpp:99
int client_id
Definition: log_impl.h:481
static void log_append_repl_info_with_lock(THREAD_ENTRY *thread_p, LOG_TDES *tdes, bool is_commit)
Definition: log_manager.c:4570
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
void lock_unlock_all(THREAD_ENTRY *thread_p)
char * xdisk_get_fullname(THREAD_ENTRY *thread_p, VOLID volid, char *vol_fullname)
void css_push_external_task(CSS_CONN_ENTRY *conn, cubthread::entry_task *task)
void spage_free_saved_spaces(THREAD_ENTRY *thread_p, void *first_save_entry)
Definition: slotted_page.c:382
INT64 db_restore_time
void logpb_flush_pages_direct(THREAD_ENTRY *thread_p)
#define csect_check_own(a, b)
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
int log_read_sysop_start_postpone(THREAD_ENTRY *thread_p, LOG_LSA *log_lsa, LOG_PAGE *log_page, bool with_undo_data, LOG_REC_SYSOP_START_POSTPONE *sysop_start_postpone, int *undo_buffer_size, char **undo_buffer, int *undo_size, char **undo_data)
Definition: log_manager.c:9553
void LOG_CS_ENTER_READ_MODE(THREAD_ENTRY *thread_p)
char * fileio_get_volume_label(VOLID vol_id, bool is_peek)
Definition: file_io.c:6182
LOG_REC_SYSOP_END sysop_end
Definition: log_record.hpp:318
#define ER_HA_REPL_DELAY_DETECTED
Definition: error_code.h:1282
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
const VOLID LOG_DBLOG_ARCHIVE_VOLID
Definition: log_volids.hpp:53
int log_rv_copy_char(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
Definition: log_manager.c:8696
PAGE_PTR pgptr
Definition: recovery.h:199
#define assert(x)
void log_skip_logging(THREAD_ENTRY *thread_p, LOG_DATA_ADDR *addr)
Definition: log_manager.c:3244
bool log_is_logged_since_restart(const LOG_LSA *lsa_ptr)
Definition: log_manager.c:593
LOG_RECVPHASE rcv_phase
Definition: log_impl.h:662
static void log_repl_schema_dump(FILE *out_fp, int length, void *data)
Definition: log_manager.c:5836
LOG_APPEND_INFO append
Definition: log_impl.h:651
clock::time_point time_point
Definition: perf_def.hpp:40
#define ER_LK_PAGE_TIMEOUT
Definition: error_code.h:134
const VOLID LOG_DBFIRST_VOLID
Definition: log_volids.hpp:38
char log_Name_info[PATH_MAX]
Definition: log_global.c:91
LOG_PAGEID fpageid
TDE_ALGORITHM
Definition: tde.h:71
void log_final(THREAD_ENTRY *thread_p)
Definition: log_manager.c:1664
int32_t fileid
Definition: dbtype_def.h:886
LOG_PAGE * log_pgptr
Definition: log_append.hpp:78
int prm_get_integer_value(PARAM_ID prm_id)
#define STATIC_INLINE
int logpb_fetch_start_append_page(THREAD_ENTRY *thread_p)
static void log_sysop_do_postpone(THREAD_ENTRY *thread_p, LOG_TDES *tdes, LOG_REC_SYSOP_END *sysop_end, int data_size, const char *data)
Definition: log_manager.c:7861
LOG_LSA * pgbuf_get_lsa(PAGE_PTR pgptr)
Definition: page_buffer.c:4318
LOG_LOGGING_STAT log_Stat
LOG_LSA undo_nxlsa
Definition: log_impl.h:474
LOG_LSA start_lsa
Definition: log_manager.h:55
#define LOG_ISTRAN_ACTIVE(tdes)
Definition: log_impl.h:182
std::chrono::high_resolution_clock clock
Definition: perf_def.hpp:39
#define LOG_NEED_TO_SET_LSA(RCVI, PGPTR)
Definition: log_manager.c:151
PGLENGTH db_logpagesize
void * logtb_realloc_topops_stack(LOG_TDES *tdes, int num_elms)
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
void LOG_CS_EXIT(THREAD_ENTRY *thread_p)
#define LOG_HAS_LOGGING_BEEN_IGNORED()
Definition: log_impl.h:229
void log_append_undo_data(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, int length, const void *data)
Definition: log_manager.c:1917
void LOG_RESET_APPEND_LSA(const LOG_LSA *lsa)
Definition: log_append.cpp:129
void logpb_initialize_logging_statistics(void)
int last_deleted_arv_num
int ha_server_state
LOG_LSA prior_lsa_next_record_with_lock(THREAD_ENTRY *thread_p, LOG_PRIOR_NODE *node, log_tdes *tdes)
int logpb_initialize_pool(THREAD_ENTRY *thread_p)
char area[1]
Definition: log_storage.hpp:85
void fpcache_remove_by_class(THREAD_ENTRY *thread_p, const OID *class_oid)
void log_wakeup_checkpoint_daemon()
bool LSA_LE(const log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:167
void lsa_to_string(char *buf, int buf_size, const log_lsa *lsa)
Definition: log_lsa.cpp:28
LOG_LSA final_restored_lsa
Definition: log_impl.h:668
void log_append_redo_recdes2(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, const VFID *vfid, PAGE_PTR pgptr, PGLENGTH offset, const RECDES *recdes)
Definition: log_manager.c:2579
#define LOG_TDES_LAST_SYSOP_POSP_LSA(tdes)
Definition: log_manager.c:184
bool log_is_log_flush_daemon_available()
Definition: log_manager.c:9730
const char * css_ha_server_state_string(HA_SERVER_STATE state)
LOG_LSA prv_savept
Definition: log_record.hpp:370
void log_sysop_end_recovery_postpone(THREAD_ENTRY *thread_p, LOG_REC_SYSOP_END *log_record, int data_size, const char *data)
Definition: log_manager.c:4003
static int log_create_internal(THREAD_ENTRY *thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname, DKNPAGES npages, INT64 *db_creation)
Definition: log_manager.c:785
#define DB_INT32_MAX
Definition: dbtype_def.h:633
#define DISK_SECTS_NPAGES(nsects)
Definition: disk_manager.h:70
struct rvfun RV_fun[]
Definition: recovery.c:49
int file_get_tde_algorithm(THREAD_ENTRY *thread_p, const VFID *vfid, PGBUF_LATCH_CONDITION fix_head_cond, TDE_ALGORITHM *tde_algo)
int prior_set_tde_encrypted(log_prior_node *node, LOG_RCVINDEX recvindex)
LOG_PAGEID logical_pageid
Definition: log_storage.hpp:65
void logpb_decache_archive_info(THREAD_ENTRY *thread_p)
void log_wakeup_remove_log_archive_daemon()
#define TRAN_LOCK_INFINITE_WAIT
Definition: log_comm.h:29
void db_localdatetime(time_t *epoch_time, DB_DATETIME *datetime)
Definition: db_date.c:1030
LOG_HA_FILESTAT
bool btree_is_btid_online_index(THREAD_ENTRY *thread_p, OID *class_oid, BTID *btid)
Definition: btree.c:35329
LOG_LSA savept_lsa
Definition: log_impl.h:478
multi_index_unique_stats m_multiupd_stats
Definition: log_impl.h:494
void log_append_compensate_with_undo_nxlsa(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, const VPID *vpid, PGLENGTH offset, PAGE_PTR pgptr, int length, const void *data, LOG_TDES *tdes, const LOG_LSA *undo_nxlsa)
Definition: log_manager.c:2990
enum log_rectype LOG_RECTYPE
Definition: log_record.hpp:138
int ha_file_status
void log_get_checkpoint_interval(bool &is_timed_wait, cubthread::delta_time &period)
Definition: log_manager.c:9664
void log_restart_emergency(THREAD_ENTRY *thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname)
Definition: log_manager.c:1811
INT64 ha_promotion_time
int logtb_update_global_unique_stats_by_delta(THREAD_ENTRY *thread_p, BTID *btid, int oid_delta, int null_delta, int key_delta, bool log)
LOG_REC_MVCC_UNDO mvcc_undo
Definition: log_record.hpp:303
int catcls_get_apply_info_log_record_time(THREAD_ENTRY *thread_p, time_t *log_record_time)
SCAN_CODE log_archive_log_header_next_scan(THREAD_ENTRY *thread_p, int cursor, DB_VALUE **out_values, int out_cnt, void *ptr)
Definition: log_manager.c:9252
#define FI_TEST_ARG(th, code, arg, state)
short volid
Definition: dbtype_def.h:880
void log_append_compensate(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, const VPID *vpid, PGLENGTH offset, PAGE_PTR pgptr, int length, const void *data, LOG_TDES *tdes)
Definition: log_manager.c:2964
float log_get_db_compatibility(void)
LOG_LSA prev_mvcc_op_log_lsa
Definition: log_record.hpp:190
#define RCV_IS_LOGICAL_RUN_POSTPONE_MANUAL(idx)
Definition: recovery.h:247
bool css_is_shutdown_timeout_expired(void)
int num_prepared_loose_end_indices
Definition: log_impl.h:586
LOG_LSA posp_nxlsa
Definition: log_impl.h:476
LOG_LSA * log_startof_nxrec(THREAD_ENTRY *thread_p, LOG_LSA *lsa, bool canuse_forwaddr)
ha_server_state
Definition: boot.h:115
int sysprm_reload_and_init(const char *db_name, const char *conf_file)
TDE_ALGORITHM pgbuf_get_tde_algorithm(PAGE_PTR pgptr)
Definition: page_buffer.c:4548
void fileio_dismount(THREAD_ENTRY *thread_p, int vol_fd)
Definition: file_io.c:3134
bool rel_is_log_compatible(const char *writer_rel_str, const char *reader_rel_str)
TRAN_STATE log_abort_partial(THREAD_ENTRY *thread_p, const char *savepoint_name, LOG_LSA *savept_lsa)
Definition: log_manager.c:5282
LOG_PAGE * logpb_create_header_page(THREAD_ENTRY *thread_p)
LOG_LSA * log_get_final_restored_lsa(void)
const char * rel_name(void)
std::int64_t pageid
Definition: log_lsa.hpp:36
int fileio_synchronize_all(THREAD_ENTRY *thread_p, bool is_include)
Definition: file_io.c:4618
static LOG_PAGE * log_dump_record_2pc_start(THREAD_ENTRY *thread_p, FILE *out_fp, LOG_LSA *lsa_p, LOG_PAGE *log_page_p)
Definition: log_manager.c:6565
int length
Definition: recovery.h:202
LOG_PAGEID nxarv_pageid
LOG_LSA * log_get_parent_lsa_system_op(THREAD_ENTRY *thread_p, LOG_LSA *parent_lsa)
Definition: log_manager.c:4198
#define MSGCAT_LOG_FINISH_ABORT
DKNPAGES chkpt_every_npages
Definition: log_impl.h:661
#define LOG_ISCHECKPOINT_TIME()
Definition: log_manager.c:113
static void log_append_sysop_end(THREAD_ENTRY *thread_p, LOG_TDES *tdes, LOG_REC_SYSOP_END *sysop_end, int data_size, const char *data)
Definition: log_manager.c:4424
INT64 LOG_PAGEID
int log_create(THREAD_ENTRY *thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname, DKNPAGES npages)
Definition: log_manager.c:749
LOG_DATA data
Definition: log_record.hpp:174
#define LOG_ISTRAN_ABORTED(tdes)
Definition: log_impl.h:192
LOG_LSA rcv_phase_lsa
Definition: log_impl.h:663
static LOG_PAGE * log_dump_record_postpone(THREAD_ENTRY *thread_p, FILE *out_fp, LOG_LSA *lsa_p, LOG_PAGE *log_page_p)
Definition: log_manager.c:6168
#define NULL
Definition: freelistheap.h:34
#define CTIME_MAX
Definition: porting.h:72
#define strncpy_bufsize(buf, str)
Definition: porting.h:340
void log_append_undo_crumbs(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, int num_crumbs, const LOG_CRUMB *crumbs)
Definition: log_manager.c:2170
int log_rv_outside_noop_redo(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
Definition: log_manager.c:8753
OID m_class_oid
int(* redofun)(THREAD_ENTRY *thread_p, LOG_RCV *logrcv)
Definition: recovery.h:216
void log_stop_ha_delay_registration()
Definition: log_manager.c:1790
if(extra_options)
Definition: dynamic_load.c:958
bool log_is_in_crash_recovery(void)
Definition: log_manager.c:476
const VFID * vfid
Definition: log_append.hpp:56
void log_append_run_postpone(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, const VPID *rcv_vpid, int length, const void *data, const LOG_LSA *ref_lsa)
Definition: log_manager.c:2860
void logpb_initialize_arv_page_info_table(void)
#define vacuum_er_log(er_log_level, msg,...)
Definition: vacuum.h:65
int logtb_define_trantable_log_latch(THREAD_ENTRY *thread_p, int num_expected_tran_indices)
#define ER_IO_MOUNT_FAIL
Definition: error_code.h:59
bool LSA_ISNULL(const log_lsa *lsa_ptr)
Definition: log_lsa.hpp:153
void log_append_undoredo_recdes(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, const RECDES *undo_recdes, const RECDES *redo_recdes)
Definition: log_manager.c:2434
LOG_LSA bkup_level2_lsa
void log_append_undoredo_recdes2(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, const VFID *vfid, PAGE_PTR pgptr, PGLENGTH offset, const RECDES *undo_recdes, const RECDES *redo_recdes)
Definition: log_manager.c:2441
bool do_postpone(cubthread::entry &thread_ref, const log_lsa &start_postpone_lsa)
PAGE_PTR pgptr
Definition: log_append.hpp:57
struct log_info_chkpt_trans LOG_INFO_CHKPT_TRANS
Definition: log_record.hpp:341
int btree_get_class_oid_of_unique_btid(THREAD_ENTRY *thread_p, BTID *btid, OID *class_oid)
Definition: btree.c:35304
int log_get_num_pages_for_creation(int db_npages)
Definition: log_manager.c:696
void log_2pc_dump_participants(FILE *fp, int block_length, void *block_particps_ids)
Definition: log_2pc.c:184
int logtb_assign_tran_index(THREAD_ENTRY *thread_p, TRANID trid, TRAN_STATE state, const BOOT_CLIENT_CREDENTIAL *client_credential, TRAN_STATE *current_state, int wait_msecs, TRAN_ISOLATION isolation)
static int log_run_postpone_op(THREAD_ENTRY *thread_p, LOG_LSA *log_lsa, LOG_PAGE *log_pgptr)
Definition: log_manager.c:8151
static void log_append_commit_postpone(THREAD_ENTRY *thread_p, LOG_TDES *tdes, LOG_LSA *start_postpone_lsa)
Definition: log_manager.c:4363
#define db_private_free_and_init(thrd, ptr)
Definition: memory_alloc.h:141
static void log_append_abort_log(THREAD_ENTRY *thread_p, LOG_TDES *tdes, LOG_LSA *abort_lsa)
Definition: log_manager.c:4739
int last_arv_num_for_syscrashes
#define pthread_mutex_lock(a)
Definition: log_manager.c:100
void log_append_undoredo_data(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, int undo_length, int redo_length, const void *undo_data, const void *redo_data)
Definition: log_manager.c:1837
LOG_LSA lastparent_lsa
Definition: log_record.hpp:295
#define pgbuf_fix(thread_p, vpid, fetch_mode, requestmode, condition)
Definition: page_buffer.h:255
static void log_append_compensate_internal(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, const VPID *vpid, PGLENGTH offset, PAGE_PTR pgptr, int length, const void *data, LOG_TDES *tdes, const LOG_LSA *undo_nxlsa)
Definition: log_manager.c:3026
LOG_LSA head_lsa
Definition: log_impl.h:472
const char * get_buffer() const
PGLENGTH offset
Definition: log_storage.hpp:66
void log_append_undo_recdes(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, const RECDES *recdes)
Definition: log_manager.c:2532
void css_unset_ha_repl_delayed(void)
#define csect_exit(a, b)
Definition: cnv.c:139
char * or_unpack_int(char *ptr, int *number)
int logpb_read_page_from_file(THREAD_ENTRY *thread_p, LOG_PAGEID pageid, LOG_CS_ACCESS_MODE access_mode, LOG_PAGE *log_pgptr)
LOG_UNIQUE_STATS tran_stats
Definition: log_impl.h:376
#define db_private_alloc(thrd, size)
Definition: memory_alloc.h:227
MVCCID newest_block_mvccid
#define LOG_IS_MVCC_OPERATION(rcvindex)
Definition: mvcc.h:255
STATIC_INLINE void log_sysop_end_random_exit(THREAD_ENTRY *thread_p) __attribute__((ALWAYS_INLINE))
Definition: log_manager.c:3686
char log_Name_bkupinfo[PATH_MAX]
Definition: log_global.c:92
int * ack_received
Definition: log_2pc.h:69
#define NULL_OFFSET
static LOG_PAGE * log_dump_record_mvcc_undoredo(THREAD_ENTRY *thread_p, FILE *out_fp, LOG_LSA *lsa_p, LOG_PAGE *log_page_p, LOG_ZIP *log_zip_p)
Definition: log_manager.c:6069
LOG_PRIOR_LSA_INFO prior_info
Definition: log_impl.h:652
int logpb_remove_archive_logs_exceed_limit(THREAD_ENTRY *thread_p, int max_count)
#define LOG_SET_CURRENT_TRAN_INDEX(thrd, index)
Definition: log_impl.h:178
char log_Name_bg_archive[PATH_MAX]
Definition: log_global.c:94
static void log_append_sysop_start_postpone(THREAD_ENTRY *thread_p, LOG_TDES *tdes, LOG_REC_SYSOP_START_POSTPONE *sysop_start_postpone, int data_size, const char *data)
Definition: log_manager.c:4396
int pgbuf_flush_all(THREAD_ENTRY *thread_p, VOLID volid)
Definition: page_buffer.c:3083
void er_set_with_oserror(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
#define ER_LOG_UNKNOWN_TRANINDEX
Definition: error_code.h:913
int pr_clear_value(DB_VALUE *value)
#define MSGCAT_CATALOG_CUBRID
char * LOG_APPEND_PTR()
Definition: log_append.cpp:145
void log_append_ha_server_state(THREAD_ENTRY *thread_p, int state)
Definition: log_manager.c:3156
int log_active_log_header_end_scan(THREAD_ENTRY *thread_p, void **ptr)
Definition: log_manager.c:9154
PGLENGTH logpb_find_header_parameters(THREAD_ENTRY *thread_p, const bool force_read_log_header, const char *db_fullname, const char *logpath, const char *prefix_logname, PGLENGTH *io_page_size, PGLENGTH *log_page_size, INT64 *db_creation, float *db_compatibility, int *db_charset)
offset_type offset
Definition: log_append.hpp:58
char * or_unpack_mem_value(char *buf, DB_VALUE *value)
static LOG_PAGE * log_dump_record_mvcc_redo(THREAD_ENTRY *thread_p, FILE *out_fp, LOG_LSA *lsa_p, LOG_PAGE *log_page_p, LOG_ZIP *log_zip_p)
Definition: log_manager.c:6139
LOG_REC_UNDOREDO undoredo
Definition: log_record.hpp:200
pthread_cond_t gc_cond
Definition: log_impl.h:320
const LOG_LSA * pgbuf_set_lsa(THREAD_ENTRY *thread_p, PAGE_PTR pgptr, const LOG_LSA *lsa_ptr)
Definition: page_buffer.c:4364
char db_release[REL_MAX_RELEASE_LENGTH]
void log_sysop_abort(THREAD_ENTRY *thread_p)
Definition: log_manager.c:4017
#define ER_LOG_MISSING_COMPENSATING_RECORD
Definition: error_code.h:779
struct log_repl * repl_records
Definition: log_impl.h:509
static void log_change_tran_as_completed(THREAD_ENTRY *thread_p, LOG_TDES *tdes, LOG_RECTYPE iscommitted, LOG_LSA *lsa)
Definition: log_manager.c:4654
LOG_LSA prv_topresult_lsa
Definition: log_record.hpp:296
int data_header_length
Definition: log_append.hpp:98
bool LSA_GE(const log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:181
LOG_LSA reference_lsa
Definition: recovery.h:204
static void log_find_end_log(THREAD_ENTRY *thread_p, LOG_LSA *end_lsa)
Definition: log_manager.c:8300
std::function< void(Context &)> exec_func_type
Definition: thread_task.hpp:86
#define LOG_FLUSH_LOGGING_HAS_BEEN_SKIPPED(thread_p)
Definition: log_manager.c:132
SCAN_CODE log_active_log_header_next_scan(THREAD_ENTRY *thread_p, int cursor, DB_VALUE **out_values, int out_cnt, void *ptr)
Definition: log_manager.c:8913
#define LOG_ISTRAN_2PC_PREPARE(tdes)
Definition: log_impl.h:217
MVCCID logtb_get_current_mvccid(THREAD_ENTRY *thread_p)
LOG_PAGEID run_nxchkpt_atpageid
Definition: log_impl.h:655
#define RCV_IS_BTREE_LOGICAL_LOG(idx)
Definition: recovery.h:228
const char * envvar_get(const char *name)
#define NULL_TRAN_INDEX
static LOG_PAGE * log_dump_record_transaction_finish(THREAD_ENTRY *thread_p, FILE *out_fp, LOG_LSA *lsa_p, LOG_PAGE *log_page_p)
Definition: log_manager.c:6261
bool LOG_CS_OWN_WRITE_MODE(THREAD_ENTRY *thread_p)
int append_repl_recidx
Definition: log_impl.h:507
static void error(const char *msg)
Definition: gencat.c:331
PGLENGTH db_iopagesize
void log_append_postpone(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, int length, const void *data)
Definition: log_manager.c:2698
LOG_LSA prev_lsa
Definition: log_append.hpp:77
#define VPID_ISNULL(vpid_ptr)
Definition: dbtype_def.h:925
LOG_PHY_PAGEID nxarv_phy_pageid
static LOG_PAGE * log_dump_record_replication(THREAD_ENTRY *thread_p, FILE *out_fp, LOG_LSA *lsa_p, LOG_PAGE *log_page_p)
Definition: log_manager.c:6278
const char * data
Definition: recovery.h:203
REL_COMPATIBILITY rel_get_disk_compatible(float db_level, REL_FIXUP_FUNCTION **fixups)
void log_append_undo_recdes2(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, const VFID *vfid, PAGE_PTR pgptr, PGLENGTH offset, const RECDES *recdes)
Definition: log_manager.c:2538
static LOG_PAGE * log_dump_record_save_point(THREAD_ENTRY *thread_p, FILE *out_fp, LOG_LSA *lsa_p, LOG_PAGE *log_page_p)
Definition: log_manager.c:6509
STATIC_INLINE void perfmon_inc_stat(THREAD_ENTRY *thread_p, PERF_STAT_ID psid) __attribute__((ALWAYS_INLINE))
std::chrono::system_clock::duration delta_time
LOG_TDES * LOG_FIND_CURRENT_TDES(THREAD_ENTRY *thread_p=NULL)
Definition: log_impl.h:1115
void logtb_free_tran_index(THREAD_ENTRY *thread_p, int tran_index)
bool log_check_system_op_is_started(THREAD_ENTRY *thread_p)
Definition: log_manager.c:4166
#define pgbuf_fix_if_not_deallocated(thread_p, vpid, latch_mode, latch_condition, page)
Definition: page_buffer.h:441
#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 ER_HA_REPL_DELAY_RESOLVED
Definition: error_code.h:1283
#define ARG_FILE_LINE
Definition: error_manager.h:44
static int rv
Definition: log_manager.c:102
void destroy_daemon(daemon *&daemon_arg)
static LOG_PAGE * log_dump_record(THREAD_ENTRY *thread_p, FILE *out_fp, LOG_RECTYPE record_type, LOG_LSA *lsa_p, LOG_PAGE *log_page_p, LOG_ZIP *log_zip_p)
Definition: log_manager.c:6612
#define LOGPAGEID_MAX
const char * logwr_log_ha_filestat_to_string(enum LOG_HA_FILESTAT val)
Definition: log_writer.c:2041
bool log_unzip(LOG_ZIP *log_unzip, LOG_ZIP_SIZE_T length, void *data)
Definition: log_compress.c:123
int log_add_to_modified_class_list(THREAD_ENTRY *thread_p, const char *classname, const OID *class_oid)
Definition: log_manager.c:4757
LOG_TOPOPS_STACK topops
Definition: log_impl.h:486
INT16 PGLENGTH
DKNPAGES fileio_get_number_of_volume_pages(int vol_fd, size_t page_size)
Definition: file_io.c:4918
LOG_LSA compensate_lsa
Definition: log_record.hpp:304
void * first_save_entry
Definition: log_impl.h:512
TRAN_STATE log_complete(THREAD_ENTRY *thread_p, LOG_TDES *tdes, LOG_RECTYPE iscommitted, LOG_GETNEWTRID get_newtrid, LOG_WRITE_EOT_LOG wrote_eot_log)
Definition: log_manager.c:5377
static void log_append_donetime_internal(THREAD_ENTRY *thread_p, LOG_TDES *tdes, LOG_LSA *eot_lsa, LOG_RECTYPE iscommitted, enum LOG_PRIOR_LSA_LOCK with_lock)
Definition: log_manager.c:4611
LOG_ADDR_TDESAREA * area
Definition: log_impl.h:594
static void log_sysop_commit_internal(THREAD_ENTRY *thread_p, LOG_REC_SYSOP_END *log_record, int data_size, const char *data, bool is_rv_finish_postpone)
Definition: log_manager.c:3804
LOG_LSA redo_lsa
Definition: log_record.hpp:335
BACKGROUND_ARCHIVING_INFO bg_archive_info
Definition: log_impl.h:682
#define csect_enter_as_reader(a, b, c)
void log_zip_free(LOG_ZIP *log_zip)
Definition: log_compress.c:265
bool isloose_end
Definition: log_impl.h:468
static bool log_can_skip_undo_logging(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, const LOG_TDES *tdes, LOG_DATA_ADDR *addr)
Definition: log_manager.c:4272
PAGEID pageid
Definition: log_record.hpp:156
#define free_and_init(ptr)
Definition: memory_alloc.h:147
#define LOG_ISRESTARTED()
Definition: log_impl.h:232
LOG_LSA repl_insert_lsa
Definition: log_impl.h:510
#define strlen(s1)
Definition: intl_support.c:43
void LSA_SET_NULL(log_lsa *lsa_ptr)
Definition: log_lsa.hpp:146
int csect_demote(THREAD_ENTRY *thread_p, int cs_index, int wait_secs)
STATIC_INLINE bool vacuum_worker_state_is_execute(THREAD_ENTRY *thread_p) __attribute__((ALWAYS_INLINE))
Definition: vacuum.h:202
static bool log_No_logging
Definition: log_manager.c:180
TRANID trid
Definition: log_impl.h:466
const VOLID LOG_DBLOG_BG_ARCHIVE_VOLID
Definition: log_volids.hpp:51
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)
int db_make_string_copy(DB_VALUE *value, DB_CONST_C_CHAR str)
#define DB_PAGESIZE
std::function< void(bool &, delta_time &)> period_function
enum log_2pc_execute LOG_2PC_EXECUTE
Definition: log_2pc.h:54
bool LSA_GT(const log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:188
LOG_RCV_TDES rcv
Definition: log_impl.h:541
bool is_shutdown
static void log_dump_checkpoint_topops(FILE *out_fp, int length, void *data)
Definition: log_manager.c:6460
bool logpb_is_pool_initialized(void)
void log_append_empty_record(THREAD_ENTRY *thread_p, LOG_RECTYPE logrec_type, LOG_DATA_ADDR *addr)
Definition: log_manager.c:3117
static void log_append_repl_info_internal(THREAD_ENTRY *thread_p, LOG_TDES *tdes, bool is_commit, int with_lock)
Definition: log_manager.c:4496
static bool log_can_skip_redo_logging(LOG_RCVINDEX rcvindex, const LOG_TDES *ignore_tdes, LOG_DATA_ADDR *addr)
Definition: log_manager.c:4324
void log_rv_dump_char(FILE *fp, int length, void *data)
Definition: log_manager.c:8719
bool logpb_is_page_in_archive(LOG_PAGEID pageid)
LOG_LSA smallest_lsa_at_last_chkpt
bool prm_get_bool_value(PARAM_ID prm_id)
char magic[CUBRID_MAGIC_MAX_LENGTH]
#define ZIP_CHECK(length)
Definition: log_compress.h:39
bool css_is_ha_repl_delayed(void)
#define ER_LOG_INCOMPATIBLE_DATABASE
Definition: error_code.h:145
HA_SERVER_STATE css_ha_server_state(void)
static LOG_PAGE * log_dump_record_2pc_acknowledgement(THREAD_ENTRY *thread_p, FILE *out_fp, LOG_LSA *lsa_p, LOG_PAGE *log_page_p)
Definition: log_manager.c:6586
#define ER_LOG_NOTACTIVE_TOPOPS
Definition: error_code.h:775
LOG_LSA sysop_start_postpone_lsa
Definition: log_record.hpp:363
void log_sysop_attach_to_outer(THREAD_ENTRY *thread_p)
Definition: log_manager.c:4076
int log_recreate(THREAD_ENTRY *thread_p, const char *db_fullname, const char *logpath, const char *prefix_logname, DKNPAGES log_npages, FILE *out_fp)
Definition: log_manager.c:8449
int log_archive_log_header_end_scan(THREAD_ENTRY *thread_p, void **ptr)
Definition: log_manager.c:9316
void logpb_dump_checkpoint_trans(FILE *out_fp, int length, void *data)
void log_sysop_commit(THREAD_ENTRY *thread_p)
Definition: log_manager.c:3895
void reset_transaction_lowest_active(int tran_index)
Definition: mvcc_table.cpp:594
void log_recovery(THREAD_ENTRY *thread_p, int ismedia_crash, time_t *stopat)
Definition: log_recovery.c:648
static void log_rollback(THREAD_ENTRY *thread_p, LOG_TDES *tdes, const LOG_LSA *upto_lsa_ptr)
Definition: log_manager.c:7336
TRAN_STATE log_abort_local(THREAD_ENTRY *thread_p, LOG_TDES *tdes, bool is_local_tran)
Definition: log_manager.c:5001
int fileio_format(THREAD_ENTRY *thread_p, const char *db_full_name_p, const char *vol_label_p, VOLID vol_id, DKNPAGES npages, bool is_sweep_clean, bool is_do_lock, bool is_do_sync, size_t page_size, int kbytes_to_be_written_per_sec, bool reuse_file)
Definition: file_io.c:2314
#define pthread_mutex_unlock(a)
Definition: log_manager.c:101
#define DB_VALUE_TYPE(value)
Definition: dbtype.h:72
void log_append_redo_crumbs(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, int num_crumbs, const LOG_CRUMB *crumbs)
Definition: log_manager.c:2307
int i
Definition: dynamic_load.c:954
int log_active_log_header_start_scan(THREAD_ENTRY *thread_p, int show_type, DB_VALUE **arg_values, int arg_cnt, void **ptr)
Definition: log_manager.c:8817
int db_make_null(DB_VALUE *value)
char * msgcat_message(int cat_id, int set_id, int msg_id)
#define ER_LOG_DOESNT_CORRESPOND_TO_DATABASE
Definition: error_code.h:148
void logpb_fetch_header(THREAD_ENTRY *thread_p, LOG_HEADER *hdr)
void decache_heap_repr(const LOG_LSA &downto_lsa)
static int log_undo_rec_restartable(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, LOG_RCV *rcv)
Definition: log_manager.c:7279
LOG_LSA * log_get_crash_point_lsa(void)
Definition: log_manager.c:537
void log_abort_all_active_transaction(THREAD_ENTRY *thread_p)
Definition: log_manager.c:1552
bool log_is_in_crash_recovery_and_not_yet_completes_redo(void)
Definition: log_manager.c:495
void log_get_log_group_commit_interval(bool &is_timed_wait, cubthread::delta_time &period)
Definition: log_manager.c:9633
LOG_LSA eof_lsa
STATIC_INLINE void perfmon_set_stat(THREAD_ENTRY *thread_p, PERF_STAT_ID psid, int statval, bool check_watchers) __attribute__((ALWAYS_INLINE))
INT16 type
LOG_TOPOPS_ADDRESSES * stack
Definition: log_impl.h:351
void map(const map_func_type &func) const
int log_dump_log_info(const char *logname_info, bool also_stdout, const char *fmt,...)
Definition: log_comm.c:205
char magic[CUBRID_MAGIC_MAX_LENGTH]
static void log_rollback_record(THREAD_ENTRY *thread_p, LOG_LSA *log_lsa, LOG_PAGE *log_page_p, LOG_RCVINDEX rcvindex, VPID *rcv_vpid, LOG_RCV *rcv, LOG_TDES *tdes, LOG_ZIP *log_unzip_ptr)
Definition: log_manager.c:7021
#define NULL_VOLID
LOG_RCVINDEX rcvindex
Definition: log_record.hpp:155
enum log_sysop_end_type LOG_SYSOP_END_TYPE
Definition: log_record.hpp:282
static void log_dump_record_header_to_string(LOG_RECORD_HEADER *log, char *buf, size_t len)
Definition: log_manager.c:7313
TRAN_STATE state
Definition: log_impl.h:469
TRAN_STATE
Definition: log_comm.h:36
#define IO_MAX_PAGE_SIZE
static LOG_PAGE * log_dump_record_sysop_end_internal(THREAD_ENTRY *thread_p, LOG_REC_SYSOP_END *sysop_end, LOG_LSA *log_lsa, LOG_PAGE *log_page_p, LOG_ZIP *log_zip_p, FILE *out_fp)
Definition: log_manager.c:6364
int logtb_get_new_tran_id(THREAD_ENTRY *thread_p, LOG_TDES *tdes)
#define LOG_PAGESIZE
_exit(1)
void add_redo_data(const log_prior_node &node)
static void log_dump_header(FILE *out_fp, LOG_HEADER *log_header_p)
Definition: log_manager.c:5947
int db_make_int(DB_VALUE *value, const int num)
#define RCV_IS_LOGICAL_COMPENSATE_MANUAL(idx)
Definition: recovery.h:240
bool log_is_tran_in_system_op(THREAD_ENTRY *thread_p)
Definition: log_manager.c:4234
short volid
Definition: dbtype_def.h:887
void log_sysop_end_logical_run_postpone(THREAD_ENTRY *thread_p, LOG_LSA *posp_lsa)
Definition: log_manager.c:3982
#define ER_LOG_INCOMPATIBLE_PREFIX_NAME
Definition: error_code.h:144
void logtb_undefine_trantable(THREAD_ENTRY *thread_p)
#define VOLATILE_ACCESS(v, t)
Definition: area_alloc.c:85
int disk_get_creation_time(THREAD_ENTRY *thread_p, INT16 volid, INT64 *db_creation)
enum ha_server_state HA_SERVER_STATE
Definition: boot.h:126
int log_Tran_index
Definition: log_global.c:43
#define OID_ISNULL(oidp)
Definition: oid.h:81
LOG_LSA bkup_level0_lsa
TRANID next_trid
#define DONT_FREE
Definition: page_buffer.h:41
LOG_PAGEID logpb_checkpoint(THREAD_ENTRY *thread_p)
void logpb_finalize_pool(THREAD_ENTRY *thread_p)
bool log_does_allow_replication(void)
Definition: log_comm.c:270
#define ER_LOG_RECOVER_ON_OLD_RELEASE
Definition: error_code.h:146
static LOG_PAGE * log_dump_record_checkpoint(THREAD_ENTRY *thread_p, FILE *out_fp, LOG_LSA *lsa_p, LOG_PAGE *log_page_p)
Definition: log_manager.c:6483
#define ER_LOG_NONAME_SAVEPOINT
Definition: error_code.h:774
MVCCID mvcc_next_id
STATIC_INLINE void log_sysop_end_unstack(THREAD_ENTRY *thread_p, LOG_TDES *tdes) __attribute__((ALWAYS_INLINE))
Definition: log_manager.c:3725
TRAN_STATE log_commit(THREAD_ENTRY *thread_p, int tran_index, bool retain_lock)
Definition: log_manager.c:5076
LOG_LSA * log_append_savepoint(THREAD_ENTRY *thread_p, const char *savept_name)
Definition: log_manager.c:3344
static void log_append_commit_log(THREAD_ENTRY *thread_p, LOG_TDES *tdes, LOG_LSA *commit_lsa)
Definition: log_manager.c:4711
static LOG_PAGE * log_dump_record_compensate(THREAD_ENTRY *thread_p, FILE *out_fp, LOG_LSA *lsa_p, LOG_PAGE *log_page_p)
Definition: log_manager.c:6220
daemon * create_daemon(const looper &looper_arg, entry_task *exec_p, const char *daemon_name="", entry_manager *context_manager=NULL)
const char * rel_release_string(void)
const void * data
Definition: log_append.hpp:48
int trace_log_flush_time
#define ER_LOG_CANNOT_ADD_SAVEPOINT
Definition: error_code.h:773
char * logpb_backup_level_info_to_string(char *buf, int buf_size, const LOG_HDR_BKUP_LEVEL_INFO *info)
#define db_private_realloc(thrd, ptr, size)
Definition: memory_alloc.h:231
static void log_repl_data_dump(FILE *out_fp, int length, void *data)
Definition: log_manager.c:5818
#define TR_TABLE_CS_EXIT(thread_p)
Definition: log_impl.h:90
void logpb_create_log_info(const char *logname_info, const char *db_fullname)
int log_get_next_nested_top(THREAD_ENTRY *thread_p, LOG_TDES *tdes, LOG_LSA *start_postpone_lsa, LOG_TOPOP_RANGE **out_nxtop_range_stack)
Definition: log_manager.c:7694
#define PEEK
Definition: file_io.h:74
LOG_LSA mvcc_op_log_lsa
callable_task< entry > entry_callable_task
LOG_RCVINDEX rcvindex
Definition: log_record.hpp:252
int log_get_db_start_parameters(INT64 *db_creation, LOG_LSA *chkpt_lsa)
Definition: log_manager.c:668
#define MSGCAT_LOG_FINISH_COMMIT
int fileio_open(const char *vol_label_p, int flags, int mode)
Definition: file_io.c:1957
LOG_LSA atomic_sysop_start_lsa
Definition: log_impl.h:454
SCAN_CODE log_get_undo_record(THREAD_ENTRY *thread_p, LOG_PAGE *log_page_p, LOG_LSA process_lsa, RECDES *recdes)
Definition: log_manager.c:9370
LOG_LSA chkpt_lsa
std::int64_t offset
Definition: log_lsa.hpp:37
void log_set_ha_promotion_time(THREAD_ENTRY *thread_p, INT64 ha_promotion_time)
Definition: log_manager.c:9334
#define LOG_ISUNSAFE_TO_SKIP_RCVINDEX(RCVI)
Definition: log_manager.c:148
DB_CONST_C_CHAR db_get_string(const DB_VALUE *value)
#define ER_LOG_COMPILATION_RELEASE
Definition: error_code.h:147
int db_set_page_size(PGLENGTH io_page_size, PGLENGTH log_page_size)
bool log_is_class_being_modified(THREAD_ENTRY *thread_p, const OID *class_oid)
Definition: log_manager.c:4786
bool fileio_map_mounted(THREAD_ENTRY *thread_p, bool(*fun)(THREAD_ENTRY *thread_p, VOLID vol_id, void *args), void *args)
Definition: file_io.c:3463
const log_lsa NULL_LSA
Definition: log_lsa.hpp:59
void log_append_redo_recdes(THREAD_ENTRY *thread_p, LOG_RCVINDEX rcvindex, LOG_DATA_ADDR *addr, const RECDES *recdes)
Definition: log_manager.c:2573
STATIC_INLINE VACUUM_WORKER_STATE vacuum_get_worker_state(THREAD_ENTRY *thread_p) __attribute__((ALWAYS_INLINE))
Definition: vacuum.h:177
const char * log_sysop_end_type_string(LOG_SYSOP_END_TYPE end_type)
Definition: log_manager.c:3549
#define LOG_READ_ADVANCE_WHEN_DOESNT_FIT(thread_p, length, lsa, log_pgptr)
Definition: log_impl.h:149
struct log_rec_sysop_end::@180::@182 run_postpone
static LOG_PAGE * log_dump_record_undoredo(THREAD_ENTRY *thread_p, FILE *out_fp, LOG_LSA *lsa_p, LOG_PAGE *log_page_p, LOG_ZIP *log_zip_p)
Definition: log_manager.c:5982
int fileio_get_volume_descriptor(VOLID vol_id)
Definition: file_io.c:6488