CUBRID Engine  latest
log_recovery.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_recovery.c -
21  */
22 
23 #ident "$Id$"
24 
25 #include "config.h"
26 
27 #include <stdio.h>
28 #include <stddef.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
32 #include <assert.h>
33 
34 #include "log_2pc.h"
35 #include "log_append.hpp"
36 #include "log_impl.h"
37 #include "log_lsa.hpp"
38 #include "log_manager.h"
39 #include "log_record.hpp"
40 #include "log_system_tran.hpp"
41 #include "log_volids.hpp"
42 #include "recovery.h"
43 #include "error_manager.h"
44 #include "system_parameter.h"
45 #include "message_catalog.h"
46 #include "msgcat_set_log.hpp"
47 #include "object_representation.h"
48 #include "slotted_page.h"
49 #include "boot_sr.h"
50 #include "locator_sr.h"
51 #include "page_buffer.h"
52 #include "porting_inline.hpp"
53 #include "log_compress.h"
54 #include "thread_entry.hpp"
55 #include "thread_manager.hpp"
56 
57 static void log_rv_undo_record (THREAD_ENTRY * thread_p, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
58  LOG_RCVINDEX rcvindex, const VPID * rcv_vpid, LOG_RCV * rcv,
59  const LOG_LSA * rcv_lsa_ptr, LOG_TDES * tdes, LOG_ZIP * undo_unzip_ptr);
60 static void log_rv_redo_record (THREAD_ENTRY * thread_p, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
61  int (*redofun) (THREAD_ENTRY * thread_p, LOG_RCV *), LOG_RCV * rcv,
62  LOG_LSA * rcv_lsa_ptr, int undo_length, char *undo_data, LOG_ZIP * redo_unzip_ptr);
63 static bool log_rv_find_checkpoint (THREAD_ENTRY * thread_p, VOLID volid, LOG_LSA * rcv_lsa);
64 static bool log_rv_get_unzip_log_data (THREAD_ENTRY * thread_p, int length, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
65  LOG_ZIP * undo_unzip_ptr);
66 static int log_rv_analysis_undo_redo (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa);
67 static int log_rv_analysis_dummy_head_postpone (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa);
68 static int log_rv_analysis_postpone (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa);
69 static int log_rv_analysis_run_postpone (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
70  LOG_LSA * check_point);
71 static int log_rv_analysis_compensate (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa, LOG_PAGE * log_page_p);
72 static int log_rv_analysis_will_commit (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa);
73 static int log_rv_analysis_commit_with_postpone (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa,
74  LOG_PAGE * log_page_p);
75 static int log_rv_analysis_sysop_start_postpone (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa,
76  LOG_PAGE * log_page_p);
77 static int log_rv_analysis_atomic_sysop_start (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa);
78 static int log_rv_analysis_complete (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
79  LOG_LSA * prev_lsa, bool is_media_crash, time_t * stop_at,
80  bool * did_incom_recovery);
81 static int log_rv_analysis_sysop_end (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa, LOG_PAGE * log_page_p);
82 static int log_rv_analysis_start_checkpoint (LOG_LSA * log_lsa, LOG_LSA * start_lsa, bool * may_use_checkpoint);
83 static int log_rv_analysis_end_checkpoint (THREAD_ENTRY * thread_p, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
84  LOG_LSA * check_point, LOG_LSA * start_redo_lsa, bool * may_use_checkpoint,
85  bool * may_need_synch_checkpoint_2pc);
86 static int log_rv_analysis_save_point (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa);
87 static int log_rv_analysis_2pc_prepare (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa);
88 static int log_rv_analysis_2pc_start (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa);
89 static int log_rv_analysis_2pc_commit_decision (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa);
90 static int log_rv_analysis_2pc_abort_decision (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa);
91 static int log_rv_analysis_2pc_commit_inform_particps (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa);
92 static int log_rv_analysis_2pc_abort_inform_particps (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa);
93 static int log_rv_analysis_2pc_recv_ack (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa);
94 static int log_rv_analysis_log_end (int tran_id, LOG_LSA * log_lsa);
95 static void log_rv_analysis_record (THREAD_ENTRY * thread_p, LOG_RECTYPE log_type, int tran_id, LOG_LSA * log_lsa,
96  LOG_PAGE * log_page_p, LOG_LSA * check_point, LOG_LSA * prev_lsa,
97  LOG_LSA * start_lsa, LOG_LSA * start_redo_lsa, bool is_media_crash,
98  time_t * stop_at, bool * did_incom_recovery, bool * may_use_checkpoint,
99  bool * may_need_synch_checkpoint_2pc);
100 static bool log_is_page_of_record_broken (THREAD_ENTRY * thread_p, const LOG_LSA * log_lsa,
102 static void log_recovery_analysis (THREAD_ENTRY * thread_p, LOG_LSA * start_lsa, LOG_LSA * start_redolsa,
103  LOG_LSA * end_redo_lsa, bool ismedia_crash, time_t * stopat,
104  bool * did_incom_recovery, INT64 * num_redo_log_records);
105 static bool log_recovery_needs_skip_logical_redo (THREAD_ENTRY * thread_p, TRANID tran_id, LOG_RECTYPE log_rtype,
106  LOG_RCVINDEX rcv_index, const LOG_LSA * lsa);
107 static void log_recovery_redo (THREAD_ENTRY * thread_p, const LOG_LSA * start_redolsa, const LOG_LSA * end_redo_lsa,
108  time_t * stopat);
109 static void log_recovery_abort_interrupted_sysop (THREAD_ENTRY * thread_p, LOG_TDES * tdes,
110  const LOG_LSA * postpone_start_lsa);
111 static void log_recovery_finish_sysop_postpone (THREAD_ENTRY * thread_p, LOG_TDES * tdes);
112 static void log_recovery_finish_postpone (THREAD_ENTRY * thread_p, LOG_TDES * tdes);
113 static void log_recovery_finish_all_postpone (THREAD_ENTRY * thread_p);
114 static void log_recovery_abort_atomic_sysop (THREAD_ENTRY * thread_p, LOG_TDES * tdes);
115 static void log_recovery_abort_all_atomic_sysops (THREAD_ENTRY * thread_p);
116 static void log_recovery_undo (THREAD_ENTRY * thread_p);
117 static void log_recovery_notpartof_archives (THREAD_ENTRY * thread_p, int start_arv_num, const char *info_reason);
118 static bool log_unformat_ahead_volumes (THREAD_ENTRY * thread_p, VOLID volid, VOLID * start_volid);
119 static void log_recovery_notpartof_volumes (THREAD_ENTRY * thread_p);
120 static void log_recovery_resetlog (THREAD_ENTRY * thread_p, const LOG_LSA * new_append_lsa,
121  const LOG_LSA * new_prev_lsa);
122 static int log_recovery_find_first_postpone (THREAD_ENTRY * thread_p, LOG_LSA * ret_lsa, LOG_LSA * start_postpone_lsa,
123  LOG_TDES * tdes);
124 
125 static int log_rv_record_modify_internal (THREAD_ENTRY * thread_p, LOG_RCV * rcv, bool is_undo);
126 static int log_rv_undoredo_partial_changes_recursive (THREAD_ENTRY * thread_p, OR_BUF * rcv_buf, RECDES * record,
127  bool is_undo);
128 
129 STATIC_INLINE PAGE_PTR log_rv_redo_fix_page (THREAD_ENTRY * thread_p, const VPID * vpid_rcv, LOG_RCVINDEX rcvindex)
131 
132 static void log_rv_simulate_runtime_worker (THREAD_ENTRY * thread_p, LOG_TDES * tdes);
133 static void log_rv_end_simulation (THREAD_ENTRY * thread_p);
134 
135 /*
136  * CRASH RECOVERY PROCESS
137  */
138 
139 /*
140  * log_rv_undo_record - EXECUTE AN UNDO RECORD
141  *
142  * return: nothing
143  *
144  * log_lsa(in/out): Log address identifier containing the log record
145  * log_page_p(in/out): Pointer to page where data starts (Set as a side
146  * effect to the page where data ends)
147  * rcvindex(in): Index to recovery functions
148  * rcv_vpid(in): Address of page to recover
149  * rcv(in/out): Recovery structure for recovery function
150  * rcv_undo_lsa(in): Address of the undo record
151  * tdes(in/out): State structure of transaction undoing data
152  * undo_unzip_ptr(in):
153  *
154  * NOTE:Execute an undo log record during restart recovery undo phase.
155  * A compensating log record for operation page level logging is
156  * written by the current function. For logical level logging,
157  * the undo function is responsible to log a redo record, which
158  * is converted into a compensating record by the log manager.
159  *
160  * This function is very similar than log_rollback_rec, however,
161  * page locking is not done.. and the transaction index that is
162  * running is set to the one in the tdes. Probably, this
163  * function should have not been duplicated for the above few
164  * things.
165  */
166 static void
167 log_rv_undo_record (THREAD_ENTRY * thread_p, LOG_LSA * log_lsa, LOG_PAGE * log_page_p, LOG_RCVINDEX rcvindex,
168  const VPID * rcv_vpid, LOG_RCV * rcv, const LOG_LSA * rcv_undo_lsa, LOG_TDES * tdes,
169  LOG_ZIP * undo_unzip_ptr)
170 {
171  char *area = NULL;
172  TRAN_STATE save_state; /* The current state of the transaction. Must be returned to this state */
173  bool is_zip = false;
174  int error_code = NO_ERROR;
175  thread_type save_thread_type = thread_type::TT_NONE;
176 
177  if (thread_p == NULL)
178  {
179  /* Thread entry info is required. */
180  thread_p = thread_get_thread_entry_info ();
181  }
182 
183  log_rv_simulate_runtime_worker (thread_p, tdes);
184 
185  if (MVCCID_IS_VALID (rcv->mvcc_id))
186  {
187  /* Assign the MVCCID to transaction. */
188 
189  assert (LOG_IS_MVCC_OPERATION (rcvindex));
190 
192  }
193 
194  /*
195  * Fetch the page for physical log records. The page is not locked since the
196  * recovery process is the only one running. If the page does not exist
197  * anymore or there are problems fetching the page, continue anyhow, so that
198  * compensating records are logged.
199  */
200 
201  if (RCV_IS_LOGICAL_LOG (rcv_vpid, rcvindex))
202  {
203  rcv->pgptr = NULL;
204  }
205  else
206  {
207  rcv->pgptr = pgbuf_fix (thread_p, rcv_vpid, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
208  if (rcv->pgptr == NULL)
209  {
210  assert (false);
211  }
212  }
213 
214  /* GET BEFORE DATA */
215 
216  /*
217  * If data is contained in only one buffer, pass pointer directly.
218  * Otherwise, allocate a contiguous area, copy the data and pass this area.
219  * At the end deallocate the area.
220  */
221 
222  if (ZIP_CHECK (rcv->length))
223  { /* check compress data */
224  rcv->length = (int) GET_ZIP_LEN (rcv->length); /* convert compress length */
225  is_zip = true;
226  }
227 
228  if (log_lsa->offset + rcv->length < (int) LOGAREA_SIZE)
229  {
230  rcv->data = (char *) log_page_p->area + log_lsa->offset;
231  log_lsa->offset += rcv->length;
232  }
233  else
234  {
235  /* Need to copy the data into a contiguous area */
236  area = (char *) malloc (rcv->length);
237  if (area == NULL)
238  {
239  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rv_undo_record");
240  goto end;
241  }
242  /* Copy the data */
243  logpb_copy_from_log (thread_p, area, rcv->length, log_lsa, log_page_p);
244  rcv->data = area;
245  }
246 
247  if (is_zip)
248  {
249  if (log_unzip (undo_unzip_ptr, rcv->length, (char *) rcv->data))
250  {
251  rcv->length = (int) undo_unzip_ptr->data_length;
252  rcv->data = (char *) undo_unzip_ptr->log_data;
253  }
254  else
255  {
256  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rv_undo_record");
257  goto end;
258  }
259  }
260 
261  /* Now call the UNDO recovery function */
262  if (rcv->pgptr != NULL || RCV_IS_LOGICAL_LOG (rcv_vpid, rcvindex))
263  {
264  /*
265  * Write a compensating log record for operation page level logging.
266  * For logical level logging, the recovery undo function must log an
267  * redo/CLR log to describe the undo.
268  */
269 
270  if (rcvindex == RVBT_MVCC_INCREMENTS_UPD)
271  {
272  /* nothing to do during recovery */
273  }
274  else if (rcvindex == RVBT_MVCC_NOTIFY_VACUUM || rcvindex == RVES_NOTIFY_VACUUM)
275  {
276  /* nothing to do */
277  }
278  else if (rcvindex == RVBT_LOG_GLOBAL_UNIQUE_STATS_COMMIT)
279  {
280  /* this only modifies in memory data that is only flushed to disk on checkpoints. we need to execute undo
281  * every time recovery is run, and we cannot compensate it. */
282  error_code = (*RV_fun[rcvindex].undofun) (thread_p, rcv);
283  assert (error_code == NO_ERROR);
284  }
285  else if (RCV_IS_LOGICAL_COMPENSATE_MANUAL (rcvindex))
286  {
287  /* B-tree logical logs will add a regular compensate in the modified pages. They do not require a logical
288  * compensation since the "undone" page can be accessed and logged. Only no-page logical operations require
289  * logical compensation. */
290  /* Invoke Undo recovery function */
291  LSA_COPY (&rcv->reference_lsa, &tdes->undo_nxlsa);
292  error_code = (*RV_fun[rcvindex].undofun) (thread_p, rcv);
293  if (error_code != NO_ERROR)
294  {
295  logpb_fatal_error (thread_p, true, ARG_FILE_LINE,
296  "log_rv_undo_record: Error applying compensation at log_lsa=(%lld, %d), "
297  "rcv = {mvccid=%llu, offset = %d, data_length = %d}",
298  (long long int) rcv_undo_lsa->pageid, (int) rcv_undo_lsa->offset,
299  (unsigned long long int) rcv->mvcc_id, (int) rcv->offset, (int) rcv->length);
300  }
302  {
304  "BTREE_UNDO: Successfully executed undo/compensate for log entry at "
305  "lsa=%lld|%d, before lsa=%lld|%d, undo_nxlsa=%lld|%d. "
306  "Transaction=%d, rcvindex=%d.\n", (long long int) rcv_undo_lsa->pageid,
307  (int) rcv_undo_lsa->offset, (long long int) log_lsa->pageid, (int) log_lsa->offset,
308  (long long int) tdes->undo_nxlsa.pageid, (int) tdes->undo_nxlsa.offset, tdes->tran_index,
309  rcvindex);
310  }
311  }
312  else if (!RCV_IS_LOGICAL_LOG (rcv_vpid, rcvindex))
313  {
314  log_append_compensate (thread_p, rcvindex, rcv_vpid, rcv->offset, rcv->pgptr, rcv->length, rcv->data, tdes);
315 
316  error_code = (*RV_fun[rcvindex].undofun) (thread_p, rcv);
317 
318  if (error_code != NO_ERROR)
319  {
320  VPID vpid;
321 
322  if (rcv->pgptr != NULL)
323  {
324  pgbuf_get_vpid (rcv->pgptr, &vpid);
325  }
326  else
327  {
328  VPID_SET_NULL (&vpid);
329  }
330 
331  logpb_fatal_error (thread_p, true, ARG_FILE_LINE,
332  "log_rv_undo_record: Error applying compensation at log_lsa=(%lld, %d), "
333  "rcv = {mvccid=%llu, vpid=(%d, %d), offset = %d, data_length = %d}",
334  (long long int) rcv_undo_lsa->pageid, (int) rcv_undo_lsa->offset,
335  (unsigned long long int) rcv->mvcc_id, (int) vpid.pageid, (int) vpid.volid,
336  (int) rcv->offset, (int) rcv->length);
337  goto end;
338  }
339  }
340  else
341  {
342  /* Logical logging? This is a logical undo. For now, we also use a logical compensation, meaning that we
343  * open a system operation that is committed & compensate at the same time.
344  * However, there might be cases when compensation is not necessarily logical. If the compensation can be
345  * made in a single log record and can be attached to a page, the system operation becomes useless. Take the
346  * example of some b-tree cases for compensations. There might be other cases too.
347  */
348  save_state = tdes->state;
349 
350  LSA_COPY (&rcv->reference_lsa, &tdes->undo_nxlsa);
351  log_sysop_start (thread_p);
352 
353 #if defined(CUBRID_DEBUG)
354  {
355  /* TODO: What is this? We might remove the block. */
356  LOG_LSA check_tail_lsa;
357 
358  LSA_COPY (&check_tail_lsa, &tdes->tail_lsa);
359  (void) (*RV_fun[rcvindex].undofun) (rcv);
360 
361  /*
362  * Make sure that a CLR was logged.
363  *
364  * If we do not log anything and the logical undo_nxlsa is not the
365  * tail, give a warning.. unless it is a temporary file deletion.
366  *
367  * WARNING: the if condition is different from the one of normal
368  * rollback.
369  */
370 
371  if (LSA_EQ (&check_tail_lsa, &tdes->tail_lsa) && !LSA_EQ (rcv_undo_lsa, &tdes->tail_lsa))
372  {
374  rv_rcvindex_string (rcvindex));
375  }
376  }
377 #else /* CUBRID_DEBUG */
378  (void) (*RV_fun[rcvindex].undofun) (thread_p, rcv);
379 #endif /* CUBRID_DEBUG */
380 
382  tdes->state = save_state;
383  }
384  }
385  else
386  {
387  log_append_compensate (thread_p, rcvindex, rcv_vpid, rcv->offset, NULL, rcv->length, rcv->data, tdes);
388  /*
389  * Unable to fetch page of volume... May need media recovery on such
390  * page
391  */
393  fileio_get_volume_label (rcv_vpid->volid, PEEK));
394  }
395 
396 end:
397  if (area != NULL)
398  {
399  free_and_init (area);
400  }
401 
402  if (rcv->pgptr != NULL)
403  {
404  pgbuf_unfix (thread_p, rcv->pgptr);
405  }
406 
407  /* Convert thread back to system transaction. */
408  log_rv_end_simulation (thread_p);
409 }
410 
411 /*
412  * log_rv_redo_record - EXECUTE A REDO RECORD
413  *
414  * return: nothing
415  *
416  * log_lsa(in/out): Log address identifier containing the log record
417  * log_page_p(in/out): Pointer to page where data starts (Set as a side
418  * effect to the page where data ends)
419  * redofun(in): Function to invoke to redo the data
420  * rcv(in/out): Recovery structure for recovery function(Set as a side
421  * effect)
422  * rcv_lsa_ptr(in): Reset data page (rcv->pgptr) to this LSA
423  * ignore_redofunc(in):
424  * undo_length(in):
425  * undo_data(in):
426  * redo_unzip_ptr(in):
427  *
428  * NOTE: Execute a redo log record.
429  */
430 static void
431 log_rv_redo_record (THREAD_ENTRY * thread_p, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
432  int (*redofun) (THREAD_ENTRY * thread_p, LOG_RCV *), LOG_RCV * rcv, LOG_LSA * rcv_lsa_ptr,
433  int undo_length, char *undo_data, LOG_ZIP * redo_unzip_ptr)
434 {
435  char *area = NULL;
436  bool is_zip = false;
437  int error_code;
438 
439  /* Note the the data page rcv->pgptr has been fetched by the caller */
440 
441  /*
442  * If data is contained in only one buffer, pass pointer directly.
443  * Otherwise, allocate a contiguous area, copy the data and pass this area.
444  * At the end deallocate the area.
445  */
446 
447  if (ZIP_CHECK (rcv->length))
448  {
449  rcv->length = (int) GET_ZIP_LEN (rcv->length);
450  is_zip = true;
451  }
452 
453  if (log_lsa->offset + rcv->length < (int) LOGAREA_SIZE)
454  {
455  rcv->data = (char *) log_page_p->area + log_lsa->offset;
456  log_lsa->offset += rcv->length;
457  }
458  else
459  {
460  area = (char *) malloc (rcv->length);
461  if (area == NULL)
462  {
463  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rvredo_rec");
464  return;
465  }
466  /* Copy the data */
467  logpb_copy_from_log (thread_p, area, rcv->length, log_lsa, log_page_p);
468  rcv->data = area;
469  }
470 
471  if (is_zip)
472  {
473  if (log_unzip (redo_unzip_ptr, rcv->length, (char *) rcv->data))
474  {
475  if ((undo_length > 0) && (undo_data != NULL))
476  {
477  (void) log_diff (undo_length, undo_data, redo_unzip_ptr->data_length, redo_unzip_ptr->log_data);
478  rcv->length = (int) redo_unzip_ptr->data_length;
479  rcv->data = (char *) redo_unzip_ptr->log_data;
480  }
481  else
482  {
483  rcv->length = (int) redo_unzip_ptr->data_length;
484  rcv->data = (char *) redo_unzip_ptr->log_data;
485  }
486  }
487  else
488  {
489  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rvredo_rec");
490  }
491  }
492 
493  if (redofun != NULL)
494  {
495  error_code = (*redofun) (thread_p, rcv);
496  if (error_code != NO_ERROR)
497  {
498  VPID vpid;
499  if (rcv->pgptr != NULL)
500  {
501  pgbuf_get_vpid (rcv->pgptr, &vpid);
502  }
503  else
504  {
505  VPID_SET_NULL (&vpid);
506  }
507 
508  logpb_fatal_error (thread_p, true, ARG_FILE_LINE,
509  "log_rvredo_rec: Error applying redo record at log_lsa=(%lld, %d), "
510  "rcv = {mvccid=%llu, vpid=(%d, %d), offset = %d, data_length = %d}",
511  (long long int) rcv_lsa_ptr->pageid, (int) rcv_lsa_ptr->offset,
512  (long long int) rcv->mvcc_id, (int) vpid.pageid, (int) vpid.volid, (int) rcv->offset,
513  (int) rcv->length);
514  }
515  }
516  else
517  {
519  "log_rvredo_rec: WARNING.. There is not a"
520  " REDO function to execute. May produce recovery problems.");
521  }
522 
523  if (rcv->pgptr != NULL)
524  {
525  (void) pgbuf_set_lsa (thread_p, rcv->pgptr, rcv_lsa_ptr);
526  }
527 
528  if (area != NULL)
529  {
530  free_and_init (area);
531  }
532 }
533 
534 /*
535  * log_rv_find_checkpoint - FIND RECOVERY CHECKPOINT
536  *
537  * return: true
538  *
539  * volid(in): Volume identifier
540  * rcv_lsa(in/out): Recovery log sequence address
541  *
542  * NOTE: Find the recovery checkpoint address of the given volume. If
543  * it is smaller than rcv_lsa, rcv_lsa is reset to such value.
544  */
545 static bool
546 log_rv_find_checkpoint (THREAD_ENTRY * thread_p, VOLID volid, LOG_LSA * rcv_lsa)
547 {
548  LOG_LSA chkpt_lsa; /* Checkpoint LSA of volume */
549  int ret = NO_ERROR;
550 
551  ret = disk_get_checkpoint (thread_p, volid, &chkpt_lsa);
552  if (LSA_ISNULL (rcv_lsa) || LSA_LT (&chkpt_lsa, rcv_lsa))
553  {
554  LSA_COPY (rcv_lsa, &chkpt_lsa);
555  }
556 
557  return true;
558 }
559 
560 /*
561  * get_log_data - GET UNZIP LOG DATA FROM LOG
562  *
563  * return:
564  *
565  * length(in): log data size
566  * log_lsa(in/out): Log address identifier containing the log record
567  * log_page_p(in): Log page pointer where LSA is located
568  * undo_unzip_ptr(in):
569  *
570  * NOTE:if log_data is unzip data return LOG_ZIP data
571  * else log_data is zip data return unzip log data
572  */
573 static bool
574 log_rv_get_unzip_log_data (THREAD_ENTRY * thread_p, int length, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
575  LOG_ZIP * undo_unzip_ptr)
576 {
577  char *ptr; /* Pointer to data to be printed */
578  char *area = NULL;
579  bool is_zip = false;
580 
581  /*
582  * If data is contained in only one buffer, pass pointer directly.
583  * Otherwise, allocate a contiguous area,
584  * copy the data and pass this area. At the end deallocate the area
585  */
586 
587  if (ZIP_CHECK (length))
588  {
589  length = (int) GET_ZIP_LEN (length);
590  is_zip = true;
591  }
592 
593  if (log_lsa->offset + length < (int) LOGAREA_SIZE)
594  {
595  /* Data is contained in one buffer */
596  ptr = (char *) log_page_p->area + log_lsa->offset;
597  log_lsa->offset += length;
598  }
599  else
600  {
601  /* Need to copy the data into a contiguous area */
602  area = (char *) malloc (length);
603  if (area == NULL)
604  {
605  return false;
606  }
607  /* Copy the data */
608  logpb_copy_from_log (thread_p, area, length, log_lsa, log_page_p);
609  ptr = area;
610  }
611 
612  if (is_zip)
613  {
614  if (!log_unzip (undo_unzip_ptr, length, ptr))
615  {
616  if (area != NULL)
617  {
618  free_and_init (area);
619  }
620  return false;
621  }
622  }
623  else
624  {
625  undo_unzip_ptr->data_length = length;
626  memcpy (undo_unzip_ptr->log_data, ptr, length);
627  }
628  LOG_READ_ALIGN (thread_p, log_lsa, log_page_p);
629 
630  if (area != NULL)
631  {
632  free_and_init (area);
633  }
634 
635  return true;
636 }
637 
638 /*
639  * log_recovery - Recover information
640  *
641  * return: nothing
642  *
643  * ismedia_crash(in):Are we recovering from a media crash ?
644  * stopat(in):
645  *
646  */
647 void
648 log_recovery (THREAD_ENTRY * thread_p, int ismedia_crash, time_t * stopat)
649 {
650  LOG_TDES *rcv_tdes; /* Tran. descriptor for the recovery phase */
651  int rcv_tran_index; /* Saved transaction index */
652  LOG_RECORD_HEADER *eof; /* End of the log record */
653  LOG_LSA rcv_lsa; /* Where to start the recovery */
654  LOG_LSA start_redolsa; /* Where to start redo phase */
655  LOG_LSA end_redo_lsa; /* Where to stop the redo phase */
656  bool did_incom_recovery;
657  int tran_index;
658  INT64 num_redo_log_records;
659  int error_code = NO_ERROR;
660 
661  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
662 
663  /* Save the transaction index and find the transaction descriptor */
664 
665  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
666  rcv_tdes = LOG_FIND_TDES (tran_index);
667  if (rcv_tdes == NULL)
668  {
670  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery:LOG_FIND_TDES");
671  return;
672  }
673 
674  rcv_tran_index = tran_index;
675  rcv_tdes->state = TRAN_RECOVERY;
676 
678  {
679  /*
680  * Your database is corrupted since it crashed when logging was ignored
681  */
683  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery:LOG_HAS_LOGGING_BEEN_IGNORED");
685  }
686 
687  er_log_debug (ARG_FILE_LINE, "RECOVERY: start with %lld|%d and stop at %lld", LSA_AS_ARGS (&log_Gl.hdr.chkpt_lsa),
688  stopat != NULL ? *stopat : -1);
689 
690  /* Find the starting LSA for the analysis phase */
691 
692  LSA_COPY (&rcv_lsa, &log_Gl.hdr.chkpt_lsa);
693  if (ismedia_crash != false)
694  {
695  /*
696  * Media crash, we may have to start from an older checkpoint...
697  * check disk headers
698  */
699  (void) fileio_map_mounted (thread_p, (bool (*)(THREAD_ENTRY *, VOLID, void *)) log_rv_find_checkpoint, &rcv_lsa);
700  }
701  else
702  {
703  /*
704  * We do incomplete recovery only when we are comming from a media crash.
705  * That is, we are restarting from a backup
706  */
707  if (stopat != NULL)
708  {
709  *stopat = -1;
710  }
711  }
712 
713  /* Notify vacuum it may need to recover the lost block data.
714  * There are two possible cases here:
715  * 1. recovery finds MVCC op log records after last checkpoint, so vacuum can start its recovery from last MVCC op
716  * log record.
717  * 2. no MVCC op log record is found, so vacuum has to start recovery from checkpoint LSA. It will go
718  * backwards record by record until it either finds a MVCC op log record or until it reaches last block in
719  * vacuum data.
720  */
721  vacuum_notify_server_crashed (&rcv_lsa);
722 
723  /*
724  * First, ANALYSIS the log to find the state of the transactions
725  * Second, REDO going forward
726  * Last, UNDO going backwards
727  */
728 
730  log_recovery_analysis (thread_p, &rcv_lsa, &start_redolsa, &end_redo_lsa, ismedia_crash, stopat, &did_incom_recovery,
731  &num_redo_log_records);
732 
734  start_redolsa.pageid, end_redo_lsa.pageid);
735 
736  LSA_COPY (&log_Gl.chkpt_redo_lsa, &start_redolsa);
737 
738  LOG_SET_CURRENT_TRAN_INDEX (thread_p, rcv_tran_index);
739  if (logpb_fetch_start_append_page (thread_p) != NO_ERROR)
740  {
741  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery:logpb_fetch_start_append_page");
742  // dead-ended. not reach here
743  return;
744  }
745 
746  if (did_incom_recovery == false)
747  {
748  /* Read the End of file record to find out the previous address */
749  eof = (LOG_RECORD_HEADER *) LOG_APPEND_PTR ();
751  }
752 
753 #if !defined(SERVER_MODE)
755 #endif /* SERVER_MODE */
756 
758 
759  /*
760  * Save the crash point lsa for use during the remaining recovery
761  * phases.
762  */
763  LSA_COPY (&log_Gl.rcv_phase_lsa, &rcv_tdes->tail_lsa);
764 
765  /* Redo phase */
767 
768  LOG_SET_CURRENT_TRAN_INDEX (thread_p, rcv_tran_index);
769 
770  log_recovery_redo (thread_p, &start_redolsa, &end_redo_lsa, stopat);
771  boot_reset_db_parm (thread_p);
772 
773  /* Undo phase */
775 
776  LOG_SET_CURRENT_TRAN_INDEX (thread_p, rcv_tran_index);
777 
778  log_recovery_undo (thread_p);
779  boot_reset_db_parm (thread_p);
780 
781  // *INDENT-OFF*
783  // *INDENT-ON*
784 
785  if (did_incom_recovery == true)
786  {
788  }
789 
790  /* Client loose ends */
791  rcv_tdes->state = TRAN_ACTIVE;
792 
793  LOG_SET_CURRENT_TRAN_INDEX (thread_p, rcv_tran_index);
794 
795  (void) logtb_set_num_loose_end_trans (thread_p);
796 
797  /* Try to finish any 2PC blocked transactions */
799  {
800 
802 
803  LOG_SET_CURRENT_TRAN_INDEX (thread_p, rcv_tran_index);
804 
805  log_2pc_recovery (thread_p);
806 
807  /* Check number of loose end transactions again.. */
808  rcv_tdes->state = TRAN_ACTIVE;
809 
810  LOG_SET_CURRENT_TRAN_INDEX (thread_p, rcv_tran_index);
811 
812  (void) logtb_set_num_loose_end_trans (thread_p);
813  }
814 
815  /* Dismount any archive and checkpoint the database */
816  logpb_decache_archive_info (thread_p);
817 
818  LOG_CS_EXIT (thread_p);
819  (void) logpb_checkpoint (thread_p);
820  LOG_CS_ENTER (thread_p);
821 
822  /* Flush all dirty pages */
823  logpb_flush_pages_direct (thread_p);
824  (void) pgbuf_flush_all (thread_p, NULL_VOLID);
825  (void) fileio_synchronize_all (thread_p, false);
826 
827  logpb_flush_header (thread_p);
828 
829  /* re-cache Tracker */
830  error_code = locator_initialize (thread_p);
831  if (error_code != NO_ERROR)
832  {
833  assert (false);
834  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery:locator_initialize");
835  // dead-ended. not reach here
836  return;
837  }
838 
839  /* Remove all class representations. */
840  error_code = heap_classrepr_restart_cache ();
841  if (error_code != NO_ERROR)
842  {
843  assert (false);
844  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery:heap_classrepr_restart_cache");
845  // dead-ended. not reach here
846  return;
847  }
848 
850 }
851 
852 /*
853  * log_rv_analysis_undo_redo -
854  *
855  * return: error code
856  *
857  * tran_id(in):
858  * lsa(in/out):
859  * Note:
860  */
861 static int
862 log_rv_analysis_undo_redo (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa)
863 {
864  LOG_TDES *tdes;
865 
866  /*
867  * If this is the first time, the transaction is seen. Assign a new
868  * index to describe it and assume that the transaction was active
869  * at the time of the crash, and thus it will be unilateraly
870  * aborted. The truth of this statement will be find reading the
871  * rest of the log
872  */
873  tdes = logtb_rv_find_allocate_tran_index (thread_p, tran_id, log_lsa);
874  if (tdes == NULL)
875  {
876  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rv_analysis_undo_redo");
877  return ER_FAILED;
878  }
879 
880  /* New tail and next to undo */
881  LSA_COPY (&tdes->tail_lsa, log_lsa);
882  LSA_COPY (&tdes->undo_nxlsa, &tdes->tail_lsa);
883 
884  return NO_ERROR;
885 }
886 
887 /*
888  * log_rv_analysis_dummy_head_postpone -
889  *
890  * return: error code
891  *
892  * tran_id(in):
893  * lsa(in/out):
894  * Note:
895  */
896 static int
897 log_rv_analysis_dummy_head_postpone (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa)
898 {
899  LOG_TDES *tdes;
900 
901  /*
902  * If this is the first time, the transaction is seen. Assign a new
903  * index to describe it and assume that the transaction was active
904  * at the time of the crash, and thus it will be unilateraly
905  * aborted. The truth of this statement will be find reading the
906  * rest of the log
907  */
908  tdes = logtb_rv_find_allocate_tran_index (thread_p, tran_id, log_lsa);
909  if (tdes == NULL)
910  {
911  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rv_analysis_dummy_head_postpone");
912  return ER_FAILED;
913  }
914 
915  /* New tail and next to undo */
916  LSA_COPY (&tdes->tail_lsa, log_lsa);
917  LSA_COPY (&tdes->undo_nxlsa, &tdes->tail_lsa);
918 
919  /* if first postpone, then set address late */
920  if (LSA_ISNULL (&tdes->posp_nxlsa))
921  {
922  LSA_COPY (&tdes->posp_nxlsa, &tdes->tail_lsa);
923  }
924 
925  return NO_ERROR;
926 }
927 
928 /*
929  * log_rv_analysis_postpone -
930  *
931  * return: error code
932  *
933  * tran_id(in):
934  * lsa(in/out):
935  *
936  * Note:
937  */
938 static int
939 log_rv_analysis_postpone (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa)
940 {
941  LOG_TDES *tdes;
942 
943  /*
944  * If this is the first time, the transaction is seen. Assign a new
945  * index to describe it and assume that the transaction was active
946  * at the time of the crash, and thus it will be unilateraly
947  * aborted. The truth of this statement will be find reading the
948  * rest of the log
949  */
950  tdes = logtb_rv_find_allocate_tran_index (thread_p, tran_id, log_lsa);
951  if (tdes == NULL)
952  {
953  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rv_analysis_postpone");
954  return ER_FAILED;
955  }
956 
957  /* if first postpone, then set address early */
958  if (LSA_ISNULL (&tdes->posp_nxlsa))
959  {
960  LSA_COPY (&tdes->posp_nxlsa, &tdes->tail_lsa);
961  }
962 
963  /* New tail and next to undo */
964  LSA_COPY (&tdes->tail_lsa, log_lsa);
965  LSA_COPY (&tdes->undo_nxlsa, &tdes->tail_lsa);
966 
967  return NO_ERROR;
968 }
969 
970 /*
971  * log_rv_analysis_run_postpone -
972  *
973  * return: error code
974  *
975  * tran_id(in):
976  * lsa(in/out):
977  * log_page_p(in/out):
978  * check_point(in/out):
979  *
980  * Note:
981  */
982 static int
983 log_rv_analysis_run_postpone (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
984  LOG_LSA * check_point)
985 {
986  LOG_TDES *tdes;
987  LOG_REC_RUN_POSTPONE *run_posp;
988 
989  tdes = logtb_rv_find_allocate_tran_index (thread_p, tran_id, log_lsa);
990  if (tdes == NULL)
991  {
992  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rv_analysis_run_postpone");
993  return ER_FAILED;
994  }
995 
998  {
999  /*
1000  * If we are comming from a checkpoint this is the result of a
1001  * system error since the transaction must have been already in
1002  * one of these states.
1003  * If we are not comming from a checkpoint, it is likely that
1004  * we are in a commit point of either a transaction or a top
1005  * operation.
1006  */
1007  if (!LSA_ISNULL (check_point))
1008  {
1010  "log_recovery_analysis: SYSTEM ERROR\n Incorrect state = %s\n at log_rec at %lld|%d\n"
1011  " for transaction = %d (index %d).\n State should have been either of\n %s\n %s\n %s\n",
1012  log_state_string (tdes->state), (long long int) log_lsa->pageid, (int) log_lsa->offset,
1016  }
1017  /*
1018  * Continue the execution by guessing that the transaction has
1019  * been committed
1020  */
1021  if (tdes->topops.last == -1)
1022  {
1024  }
1025  else
1026  {
1028  }
1029  }
1030 
1032  {
1033  /* Nothing to undo */
1034  LSA_SET_NULL (&tdes->undo_nxlsa);
1035  }
1036 
1037  LSA_COPY (&tdes->tail_lsa, log_lsa);
1038 
1039  /*
1040  * Need to read the log_run_postpone record to reset the posp_nxlsa
1041  * of transaction or top action to the value of log_ref
1042  */
1043 
1044  /* Read the DATA HEADER */
1045  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), log_lsa, log_page_p);
1046  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_RUN_POSTPONE), log_lsa, log_page_p);
1047 
1048  run_posp = (LOG_REC_RUN_POSTPONE *) ((char *) log_page_p->area + log_lsa->offset);
1049 
1051  {
1052  /* Reset start of postpone transaction for the top action */
1053  LSA_COPY (&tdes->topops.stack[tdes->topops.last].posp_lsa, &run_posp->ref_lsa);
1054  }
1055  else
1056  {
1058 
1059  /* Reset start of postpone transaction */
1060  LSA_COPY (&tdes->posp_nxlsa, &run_posp->ref_lsa);
1061  }
1062 
1063  return NO_ERROR;
1064 }
1065 
1066 /*
1067  * log_rv_analysis_compensate -
1068  *
1069  * return: error code
1070  *
1071  * tran_id(in):
1072  * lsa(in/out):
1073  * log_page_p(in/out):
1074  *
1075  * Note:
1076  */
1077 static int
1078 log_rv_analysis_compensate (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa, LOG_PAGE * log_page_p)
1079 {
1080  LOG_TDES *tdes;
1081  LOG_REC_COMPENSATE *compensate;
1082 
1083  /*
1084  * If this is the first time, the transaction is seen. Assign a new
1085  * index to describe it and assume that the transaction was active
1086  * at the time of the crash, and thus it will be unilateraly
1087  * aborted. The truth of this statement will be find reading the
1088  * rest of the log
1089  */
1090  tdes = logtb_rv_find_allocate_tran_index (thread_p, tran_id, log_lsa);
1091  if (tdes == NULL)
1092  {
1093  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rv_analysis_compensate");
1094  return ER_FAILED;
1095  }
1096 
1097  /*
1098  * Need to read the compensating record to set the next undo address
1099  */
1100 
1101  /* Read the DATA HEADER */
1102  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), log_lsa, log_page_p);
1103  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_COMPENSATE), log_lsa, log_page_p);
1104 
1105  compensate = (LOG_REC_COMPENSATE *) ((char *) log_page_p->area + log_lsa->offset);
1106  LSA_COPY (&tdes->undo_nxlsa, &compensate->undo_nxlsa);
1107 
1108  return NO_ERROR;
1109 }
1110 
1111 /*
1112  * log_rv_analysis_will_commit -
1113  *
1114  * return: error code
1115  *
1116  * tran_id(in):
1117  * lsa(in/out):
1118  *
1119  * Note:
1120  */
1121 static int
1122 log_rv_analysis_will_commit (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa)
1123 {
1124  LOG_TDES *tdes;
1125 
1126  /*
1127  * If this is the first time, the transaction is seen. Assign a new
1128  * index to describe it. The transaction was in the process of
1129  * getting committed at this point.
1130  */
1131  tdes = logtb_rv_find_allocate_tran_index (thread_p, tran_id, log_lsa);
1132  if (tdes == NULL)
1133  {
1134  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rv_analysis_will_commit");
1135  return ER_FAILED;
1136  }
1137 
1139 
1140  /* Nothing to undo */
1141  LSA_SET_NULL (&tdes->undo_nxlsa);
1142  LSA_COPY (&tdes->tail_lsa, log_lsa);
1143 
1144  return NO_ERROR;
1145 }
1146 
1147 /*
1148  * log_rv_analysis_commit_with_postpone -
1149  *
1150  * return: error code
1151  *
1152  * tran_id(in):
1153  * lsa(in/out):
1154  * log_page_p(in/out):
1155  *
1156  * Note:
1157  */
1158 static int
1159 log_rv_analysis_commit_with_postpone (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa, LOG_PAGE * log_page_p)
1160 {
1161  LOG_TDES *tdes;
1162  LOG_REC_START_POSTPONE *start_posp;
1163 
1164  /*
1165  * If this is the first time, the transaction is seen. Assign a new
1166  * index to describe it. The transaction was in the process of
1167  * getting committed at this point.
1168  */
1169  tdes = logtb_rv_find_allocate_tran_index (thread_p, tran_id, log_lsa);
1170  if (tdes == NULL)
1171  {
1172  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rv_analysis_commit_with_postpone");
1173  return ER_FAILED;
1174  }
1175 
1177 
1178  /* Nothing to undo */
1179  LSA_SET_NULL (&tdes->undo_nxlsa);
1180  LSA_COPY (&tdes->tail_lsa, log_lsa);
1181  tdes->rcv.tran_start_postpone_lsa = tdes->tail_lsa;
1182 
1183  /*
1184  * Need to read the start postpone record to set the postpone address
1185  * of the transaction
1186  */
1187  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), log_lsa, log_page_p);
1188  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_START_POSTPONE), log_lsa, log_page_p);
1189 
1190  start_posp = (LOG_REC_START_POSTPONE *) ((char *) log_page_p->area + log_lsa->offset);
1191  LSA_COPY (&tdes->posp_nxlsa, &start_posp->posp_lsa);
1192 
1193  return NO_ERROR;
1194 }
1195 
1196 /*
1197  * log_rv_analysis_sysop_start_postpone - start system op postpone.
1198  *
1199  * return: error code
1200  *
1201  * tran_id(in):
1202  * lsa(in/out):
1203  * log_page_p(in/out):
1204  *
1205  * Note:
1206  */
1207 static int
1208 log_rv_analysis_sysop_start_postpone (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa, LOG_PAGE * log_page_p)
1209 {
1210  LOG_TDES *tdes;
1211  LOG_REC_SYSOP_START_POSTPONE *sysop_start_posp;
1212 
1213  /*
1214  * If this is the first time, the transaction is seen. Assign a new
1215  * index to describe it. A top system operation was in the process
1216  * of getting committed at this point.
1217  */
1218  tdes = logtb_rv_find_allocate_tran_index (thread_p, tran_id, log_lsa);
1219  if (tdes == NULL)
1220  {
1221  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rv_analysis_sysop_start_postpone");
1222  return ER_FAILED;
1223  }
1224 
1225  LSA_COPY (&tdes->tail_lsa, log_lsa);
1226  LSA_COPY (&tdes->undo_nxlsa, &tdes->tail_lsa);
1227 
1228  tdes->rcv.sysop_start_postpone_lsa = tdes->tail_lsa;
1229 
1230  /*
1231  * Need to read the start postpone record to set the start address
1232  * of top system operation
1233  */
1234  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), log_lsa, log_page_p);
1235  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_SYSOP_START_POSTPONE), log_lsa, log_page_p);
1236  sysop_start_posp = ((LOG_REC_SYSOP_START_POSTPONE *) ((char *) log_page_p->area + log_lsa->offset));
1237 
1239  {
1240  /* this is not a valid situation */
1241  assert_release (false);
1242  }
1243  else if (sysop_start_posp->sysop_end.type == LOG_SYSOP_END_LOGICAL_RUN_POSTPONE)
1244  {
1245  if (sysop_start_posp->sysop_end.run_postpone.is_sysop_postpone)
1246  {
1247  /* system op postpone inside system op postpone. not a valid situation */
1248  assert (false);
1249  }
1250  else
1251  {
1252  /* no undo. it is possible that the transaction state is TRAN_UNACTIVE_UNILATERALLY_ABORTED because this might
1253  * be the first log record discovered for current transaction. it will be set correctly when the system op end
1254  * is found or executed.
1255  */
1256  LSA_SET_NULL (&tdes->undo_nxlsa);
1257  }
1258  }
1259  else
1260  {
1261  assert (sysop_start_posp->sysop_end.type != LOG_SYSOP_END_ABORT);
1262  }
1263 
1264  /* update state */
1266 
1267  if (tdes->topops.max == 0 || (tdes->topops.last + 1) >= tdes->topops.max)
1268  {
1269  if (logtb_realloc_topops_stack (tdes, 1) == NULL)
1270  {
1271  /* Out of memory */
1272  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rv_analysis_atomic_sysop_start");
1273  return ER_OUT_OF_VIRTUAL_MEMORY;
1274  }
1275  }
1276 
1277  /*
1278  * NOTE if tdes->topops.last >= 0, there is an already
1279  * defined top system operation. However, I do not think so
1280  * do to the nested fashion of top system operations. Outer
1281  * top nested system operations will come later in the log.
1282  */
1283 
1284  if (tdes->topops.last == -1)
1285  {
1286  tdes->topops.last++;
1287  }
1288  else
1289  {
1290  /* not expected */
1291  assert (false);
1292  }
1293 
1294  LSA_COPY (&tdes->topops.stack[tdes->topops.last].lastparent_lsa, &sysop_start_posp->sysop_end.lastparent_lsa);
1295  LSA_COPY (&tdes->topops.stack[tdes->topops.last].posp_lsa, &sysop_start_posp->posp_lsa);
1296 
1297  if (LSA_LT (&sysop_start_posp->sysop_end.lastparent_lsa, &tdes->rcv.atomic_sysop_start_lsa))
1298  {
1299  /* reset tdes->rcv.atomic_sysop_start_lsa */
1301  }
1302 
1303  return NO_ERROR;
1304 }
1305 
1306 /*
1307  * log_rv_analysis_atomic_sysop_start () - analyze start atomic system operation
1308  *
1309  * return : error code
1310  * thread_p (in) : thread entry
1311  * tran_id (in) : transaction ID
1312  * log_lsa (in) : log record LSA. will be used as marker for start system operation.
1313  */
1314 static int
1315 log_rv_analysis_atomic_sysop_start (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa)
1316 {
1317  LOG_TDES *tdes;
1318 
1319  tdes = logtb_rv_find_allocate_tran_index (thread_p, tran_id, log_lsa);
1320  if (tdes == NULL)
1321  {
1322  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rv_analysis_sysop_start_postpone");
1323  return ER_FAILED;
1324  }
1325 
1326  tdes->tail_lsa = *log_lsa;
1327  tdes->undo_nxlsa = tdes->tail_lsa;
1328 
1329  /* this is a marker for system operations that need to be atomic. they will be rollbacked before postpone is finished.
1330  */
1331  tdes->rcv.atomic_sysop_start_lsa = *log_lsa;
1332 
1333  return NO_ERROR;
1334 }
1335 
1336 /*
1337  * log_rv_analysis_complete -
1338  *
1339  * return: error code
1340  *
1341  * tran_id(in):
1342  * log_lsa(in/out):
1343  * log_page_p(in/out):
1344  * lsa(in/out):
1345  * is_media_crash(in):
1346  * stop_at(in):
1347  * did_incom_recovery(in/out):
1348  *
1349  * Note:
1350  */
1351 static int
1352 log_rv_analysis_complete (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
1353  LOG_LSA * prev_lsa, bool is_media_crash, time_t * stop_at, bool * did_incom_recovery)
1354 {
1355  LOG_REC_DONETIME *donetime;
1356  int tran_index;
1357  time_t last_at_time;
1358  char time_val[CTIME_MAX];
1359  LOG_LSA record_header_lsa;
1360 
1361  /*
1362  * The transaction has been fully completed. therefore, it was not
1363  * active at the time of the crash
1364  */
1365  tran_index = logtb_find_tran_index (thread_p, tran_id);
1366 
1367  if (is_media_crash != true)
1368  {
1369  goto end;
1370  }
1371 
1372  LSA_COPY (&record_header_lsa, log_lsa);
1373 
1374  /*
1375  * Need to read the donetime record to find out if we need to stop
1376  * the recovery at this point.
1377  */
1378  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), log_lsa, log_page_p);
1379  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_DONETIME), log_lsa, log_page_p);
1380 
1381  donetime = (LOG_REC_DONETIME *) ((char *) log_page_p->area + log_lsa->offset);
1382  last_at_time = (time_t) donetime->at_time;
1383  if (stop_at != NULL && *stop_at != (time_t) (-1) && difftime (*stop_at, last_at_time) < 0)
1384  {
1385 #if !defined(NDEBUG)
1387  {
1389  (void) ctime_r (&last_at_time, time_val);
1391  record_header_lsa.pageid, record_header_lsa.offset, time_val);
1393  fflush (stdout);
1394  }
1395 #endif /* !NDEBUG */
1396  /*
1397  * Reset the log active and stop the recovery process at this
1398  * point. Before reseting the log, make sure that we are not
1399  * holding a page.
1400  */
1401  log_lsa->pageid = NULL_PAGEID;
1402  log_recovery_resetlog (thread_p, &record_header_lsa, prev_lsa);
1403  *did_incom_recovery = true;
1404 
1405  return NO_ERROR;
1406  }
1407 
1408 end:
1409 
1410  /*
1411  * The transaction has been fully completed. Therefore, it was not
1412  * active at the time of the crash
1413  */
1414  if (tran_index != NULL_TRAN_INDEX)
1415  {
1416  logtb_free_tran_index (thread_p, tran_index);
1417  }
1418 
1419  return NO_ERROR;
1420 }
1421 
1422 /* TODO: We need to understand how recovery of system operations really works. We need to find its limitations.
1423  * For now, I did find out this:
1424  * 1. if tdes->topops.last is 0 (cannot be bigger during recovery), it means the transaction should be in
1425  * state TRAN_UNACTIVE_TOPOPE_COMMITTED_WITH_POSTPONE. tdes->topops.last may be incremented by
1426  * log_rv_analysis_sysop_start_postpone or may be already 0 from checkpoint collected topops.
1427  * 2. In all other cases it must be -1.
1428  * 3. We used to consider that first sys op commit (or abort) that follows is the one that should end the postpone
1429  * phase.
1430  *
1431  * Now, for TRAN_UNACTIVE_TOPOPE_COMMITTED_WITH_POSTPONE state we will expect last to be always 0.
1432  * We will handle sys op ends like:
1433  * - commit, logical undo, logical compensate: we consider this ends the
1434  * TRAN_UNACTIVE_TOPOPE_COMMITTED_WITH_POSTPONE phase.
1435  * - logical run postpone: it depends on is_sysop_postpone. if true, then
1436  * TRAN_UNACTIVE_TOPOPE_COMMITTED_WITH_POSTPONE continues. If it is false, then it commits the system op and
1437  * transitions to TRAN_UNACTIVE_COMMITTED_WITH_POSTPONE.
1438  * - abort: we assume this was a nested run postpone that got aborted
1439  *
1440  * In the future, I hope we can come up with a more clear and less restrictive system to handle system operations
1441  * during recovery.
1442  */
1443 
1444 /*
1445  * log_rv_analysis_sysop_end () - Analyze system operation commit log record.
1446  *
1447  * return : Error code.
1448  * thread_p (in) : Thread entry.
1449  * tran_id (in) : Transaction ID.
1450  * log_lsa (in) : LSA of log record.
1451  * log_page_p (in) : Page of log record.
1452  */
1453 static int
1454 log_rv_analysis_sysop_end (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa, LOG_PAGE * log_page_p)
1455 {
1456  LOG_TDES *tdes;
1457  LOG_REC_SYSOP_END *sysop_end;
1458  bool commit_start_postpone = false;
1459 
1460  /* The top system action is declared as finished. Pop it from the stack of finished actions */
1461  tdes = logtb_rv_find_allocate_tran_index (thread_p, tran_id, log_lsa);
1462  if (tdes == NULL)
1463  {
1464  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rv_analysis_complete_topope");
1465  return ER_FAILED;
1466  }
1467 
1468  LSA_COPY (&tdes->tail_lsa, log_lsa);
1469  LSA_COPY (&tdes->undo_nxlsa, &tdes->tail_lsa);
1470  LSA_COPY (&tdes->tail_topresult_lsa, &tdes->tail_lsa);
1471 
1472  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), log_lsa, log_page_p);
1473  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*sysop_end), log_lsa, log_page_p);
1474  sysop_end = (LOG_REC_SYSOP_END *) (log_page_p->area + log_lsa->offset);
1475 
1476  LOG_SYSOP_END_TYPE_CHECK (sysop_end->type);
1477 
1478  switch (sysop_end->type)
1479  {
1480  case LOG_SYSOP_END_ABORT:
1481  /* abort does not change state and does not finish TRAN_UNACTIVE_TOPOPE_COMMITTED_WITH_POSTPONE */
1483  {
1484  /* no undo */
1485  LSA_SET_NULL (&tdes->undo_nxlsa);
1486  }
1487  tdes->rcv.analysis_last_aborted_sysop_lsa = *log_lsa;
1489  break;
1490 
1491  case LOG_SYSOP_END_COMMIT:
1495  /* todo: I think it will be safer to save previous states in nested system operations, rather than rely on context
1496  * to guess it. we should consider that for cherry. */
1497  commit_start_postpone = true;
1498  break;
1499 
1501  /* compensate undo */
1502  tdes->undo_nxlsa = sysop_end->compensate_lsa;
1503  commit_start_postpone = true;
1504  break;
1505 
1507  /* we have a complicated story here, because logical run postpone can be run in two situations: transaction
1508  * postpone or system op postpone.
1509  * logical run postpone in transaction postpone can have other postpones inside it (e.g. file destroy).
1510  *
1511  * as a consequence, if state is TRAN_UNACTIVE_TOPOPE_COMMITTED_WITH_POSTPONE, we have an ambiguous case:
1512  * 1. it can be from a system op postpone and the logical run postpone is run for a postpone log record inside the
1513  * system op.
1514  * 2. it can be from a transaction postpone and this is the postpone phase of logical run postpone system op.
1515  * the ambiguity is solved with run_postpone.is_sysop_postpone field, which is true if run postpone belongs to
1516  * system op postpone state and false if it belongs to transaction postpone phase.
1517  */
1518 
1519  if (sysop_end->run_postpone.is_sysop_postpone)
1520  {
1521  /* run postpone for log record inside a system op */
1523  {
1524  if (tdes->topops.max == 0 && logtb_realloc_topops_stack (tdes, 1) == NULL)
1525  {
1526  /* Out of memory */
1527  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_analysis");
1528  return ER_OUT_OF_VIRTUAL_MEMORY;
1529  }
1530  tdes->topops.last = 0;
1532  }
1533  tdes->topops.stack[tdes->topops.last].posp_lsa = sysop_end->run_postpone.postpone_lsa;
1534  }
1535  else
1536  {
1537  /* run postpone for log record inside transaction */
1538  tdes->posp_nxlsa = sysop_end->run_postpone.postpone_lsa;
1539  if (tdes->topops.last != -1)
1540  {
1541  assert (tdes->topops.last == 0);
1543  }
1544  else
1545  {
1546  /* state must be TRAN_UNACTIVE_COMMITTED_WITH_POSTPONE. it may be TRAN_UNACTIVE_UNILATERALLY_ABORTED */
1548  }
1549 
1550  /* no undo */
1551  LSA_SET_NULL (&tdes->undo_nxlsa);
1552 
1553  /* TRAN_UNACTIVE_TOPOPE_COMMITTED_WITH_POSTPONE transition to TRAN_UNACTIVE_COMMITTED_WITH_POSTPONE */
1554  commit_start_postpone = true;
1555  }
1556  break;
1557  }
1558 
1560  {
1561  assert (tdes->topops.last == 0);
1562  if (commit_start_postpone)
1563  {
1564  /* change state to previous state, which is either TRAN_UNACTIVE_COMMITTED_WITH_POSTPONE or
1565  * TRAN_UNACTIVE_UNILATERALLY_ABORTED. Use tdes->rcv.tran_start_postpone_lsa to determine which case it is. */
1566  if (!LSA_ISNULL (&tdes->rcv.tran_start_postpone_lsa))
1567  {
1568  /* this must be after start postpone */
1569  assert (LSA_LE (&tdes->rcv.tran_start_postpone_lsa, &sysop_end->lastparent_lsa));
1571  }
1572  else
1573  {
1574  /* default state in recovery is TRAN_UNACTIVE_UNILATERALLY_ABORTED */
1576  }
1577  tdes->topops.last = -1;
1578  }
1579  else
1580  {
1581  tdes->topops.last = 0;
1582  }
1583  }
1584  else
1585  {
1586  assert (tdes->topops.last == -1);
1587  tdes->topops.last = -1;
1588  }
1589 
1590  // if this is the end of atomic system operation or system operation postpone phase, now it is time to reset it
1591  //
1592  // NOTE - we might actually be in both a system operation postpone phase and an atomic system operation, one nested
1593  // in the other. we need to check which is last and end sysop should belong to that.
1594  //
1595  // NOTE - I really hate this guessing state system and we really, really should consider a more deterministic way.
1596  // Logging ALL started system operations and replicating the system operation stack precisely would really
1597  // help us avoiding all these ambiguities.
1598  //
1599 
1600  // do we reset atomic sysop? next conditions must be met:
1601  // 1. is there atomic system operation started?
1602  // 2. is atomic system operation more recent than start postpone?
1603  // 3. is atomic system operation equal or more recent to system operation last parent?
1604  if (!LSA_ISNULL (&tdes->rcv.atomic_sysop_start_lsa) /* 1 */
1605  && LSA_GT (&tdes->rcv.atomic_sysop_start_lsa, &tdes->rcv.sysop_start_postpone_lsa) /* 2 */
1606  && LSA_GT (&tdes->rcv.atomic_sysop_start_lsa, &sysop_end->lastparent_lsa) /* 3 */ )
1607  {
1608  /* reset tdes->rcv.atomic_sysop_start_lsa */
1610  }
1611  // do we reset sysop start postpone? next conditions must be met:
1612  // 1. is there system operation start postpone in progress?
1613  // 2. is system operation start postpone more recent than atomic system operation?
1614  // 3. is system operation start postpone more recent than system operation last parent?
1617  && LSA_GT (&tdes->rcv.sysop_start_postpone_lsa, &sysop_end->lastparent_lsa))
1618  {
1619  /* reset tdes->rcv.sysop_start_postpone_lsa */
1621  }
1622 
1623  return NO_ERROR;
1624 }
1625 
1626 /*
1627  * log_rv_analysis_start_checkpoint -
1628  *
1629  * return: error code
1630  *
1631  * lsa(in/out):
1632  * start_lsa(in/out):
1633  * may_use_checkpoint(in/out):
1634  *
1635  * Note:
1636  */
1637 static int
1638 log_rv_analysis_start_checkpoint (LOG_LSA * log_lsa, LOG_LSA * start_lsa, bool * may_use_checkpoint)
1639 {
1640  /*
1641  * Use the checkpoint record only if it is the first record in the
1642  * analysis. If it is not, it is likely that we are restarting from
1643  * crashes when the multimedia crashes were off. We skip the
1644  * checkpoint since it can contain stuff which does not exist any
1645  * longer.
1646  */
1647 
1648  if (LSA_EQ (log_lsa, start_lsa))
1649  {
1650  *may_use_checkpoint = true;
1651  }
1652 
1653  return NO_ERROR;
1654 }
1655 
1656 /*
1657  * log_rv_analysis_end_checkpoint -
1658  *
1659  * return: error code
1660  *
1661  * lsa(in/out):
1662  * log_page_p(in/out):
1663  * check_point(in/out):
1664  * start_redo_lsa(in/out):
1665  * may_use_checkpoint(in/out):
1666  * may_need_synch_checkpoint_2pc(in/out):
1667  *
1668  * Note:
1669  */
1670 static int
1671 log_rv_analysis_end_checkpoint (THREAD_ENTRY * thread_p, LOG_LSA * log_lsa, LOG_PAGE * log_page_p,
1672  LOG_LSA * check_point, LOG_LSA * start_redo_lsa, bool * may_use_checkpoint,
1673  bool * may_need_synch_checkpoint_2pc)
1674 {
1675  LOG_TDES *tdes;
1676  LOG_REC_CHKPT *tmp_chkpt;
1677  LOG_REC_CHKPT chkpt;
1678  LOG_INFO_CHKPT_TRANS *chkpt_trans;
1679  LOG_INFO_CHKPT_TRANS *chkpt_one;
1680  LOG_INFO_CHKPT_SYSOP *chkpt_topops;
1681  LOG_INFO_CHKPT_SYSOP *chkpt_topone;
1682  int size;
1683  void *area;
1684  int i;
1685 
1686  LOG_PAGE *log_page_local = NULL;
1687  char log_page_buffer[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT];
1688  LOG_LSA log_lsa_local;
1689  LOG_REC_SYSOP_START_POSTPONE sysop_start_postpone;
1690 
1691  int error_code = NO_ERROR;
1692 
1693  /*
1694  * Use the checkpoint record only if it is the first record in the
1695  * analysis. If it is not, it is likely that we are restarting from
1696  * crashes when the multimedia crashes were off. We skip the
1697  * checkpoint since it can contain stuff which does not exist any
1698  * longer.
1699  */
1700 
1701  if (*may_use_checkpoint == false)
1702  {
1703  return NO_ERROR;
1704  }
1705  *may_use_checkpoint = false;
1706 
1707  /*
1708  * Read the checkpoint record information to find out the
1709  * start_redolsa and the active transactions
1710  */
1711 
1712  LSA_COPY (check_point, log_lsa);
1713 
1714  /* Read the DATA HEADER */
1715  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), log_lsa, log_page_p);
1716  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_CHKPT), log_lsa, log_page_p);
1717  tmp_chkpt = (LOG_REC_CHKPT *) ((char *) log_page_p->area + log_lsa->offset);
1718  chkpt = *tmp_chkpt;
1719 
1720  /* GET THE CHECKPOINT TRANSACTION INFORMATION */
1721  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_CHKPT), log_lsa, log_page_p);
1722 
1723  /* Now get the data of active transactions */
1724 
1725  area = NULL;
1726  size = sizeof (LOG_INFO_CHKPT_TRANS) * chkpt.ntrans;
1727  if (log_lsa->offset + size < (int) LOGAREA_SIZE)
1728  {
1729  chkpt_trans = (LOG_INFO_CHKPT_TRANS *) ((char *) log_page_p->area + log_lsa->offset);
1730  log_lsa->offset += size;
1731  }
1732  else
1733  {
1734  /* Need to copy the data into a contiguous area */
1735  area = malloc (size);
1736  if (area == NULL)
1737  {
1738  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_analysis");
1739  return ER_OUT_OF_VIRTUAL_MEMORY;
1740  }
1741  /* Copy the data */
1742  logpb_copy_from_log (thread_p, (char *) area, size, log_lsa, log_page_p);
1743  chkpt_trans = (LOG_INFO_CHKPT_TRANS *) area;
1744  }
1745 
1746  /* Add the transactions to the transaction table */
1747  for (i = 0; i < chkpt.ntrans; i++)
1748  {
1749  /*
1750  * If this is the first time, the transaction is seen. Assign a
1751  * new index to describe it and assume that the transaction was
1752  * active at the time of the crash, and thus it will be
1753  * unilaterally aborted. The truth of this statement will be find
1754  * reading the rest of the log
1755  */
1756  tdes = logtb_rv_find_allocate_tran_index (thread_p, chkpt_trans[i].trid, log_lsa);
1757  if (tdes == NULL)
1758  {
1759  if (area != NULL)
1760  {
1761  free_and_init (area);
1762  }
1763 
1764  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_analysis");
1765  return ER_FAILED;
1766  }
1767  chkpt_one = &chkpt_trans[i];
1768 
1769  /*
1770  * Clear the transaction since it may have old stuff in it.
1771  * Use the one that is find in the checkpoint record
1772  */
1773  logtb_clear_tdes (thread_p, tdes);
1774 
1775  tdes->isloose_end = chkpt_one->isloose_end;
1776  if (chkpt_one->state == TRAN_ACTIVE || chkpt_one->state == TRAN_UNACTIVE_ABORTED)
1777  {
1779  }
1780  else
1781  {
1782  tdes->state = chkpt_one->state;
1783  }
1784  LSA_COPY (&tdes->head_lsa, &chkpt_one->head_lsa);
1785  LSA_COPY (&tdes->tail_lsa, &chkpt_one->tail_lsa);
1786  LSA_COPY (&tdes->undo_nxlsa, &chkpt_one->undo_nxlsa);
1787  LSA_COPY (&tdes->posp_nxlsa, &chkpt_one->posp_nxlsa);
1788  LSA_COPY (&tdes->savept_lsa, &chkpt_one->savept_lsa);
1789  LSA_COPY (&tdes->tail_topresult_lsa, &chkpt_one->tail_topresult_lsa);
1791  tdes->client.set_system_internal_with_user (chkpt_one->user_name);
1792  if (LOG_ISTRAN_2PC (tdes))
1793  {
1794  *may_need_synch_checkpoint_2pc = true;
1795  }
1796  }
1797 
1798  if (area != NULL)
1799  {
1800  free_and_init (area);
1801  }
1802 
1803  /*
1804  * Now add top system operations that were in the process of
1805  * commit to this transactions
1806  */
1807 
1808  log_page_local = (LOG_PAGE *) PTR_ALIGN (log_page_buffer, MAX_ALIGNMENT);
1809  log_page_local->hdr.logical_pageid = NULL_PAGEID;
1810  log_page_local->hdr.offset = NULL_OFFSET;
1811 
1812  if (chkpt.ntops > 0)
1813  {
1814  size = sizeof (LOG_INFO_CHKPT_SYSOP) * chkpt.ntops;
1815  if (log_lsa->offset + size < (int) LOGAREA_SIZE)
1816  {
1817  chkpt_topops = ((LOG_INFO_CHKPT_SYSOP *) ((char *) log_page_p->area + log_lsa->offset));
1818  log_lsa->offset += size;
1819  }
1820  else
1821  {
1822  /* Need to copy the data into a contiguous area */
1823  area = malloc (size);
1824  if (area == NULL)
1825  {
1826  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_analysis");
1827  return ER_OUT_OF_VIRTUAL_MEMORY;
1828  }
1829  /* Copy the data */
1830  logpb_copy_from_log (thread_p, (char *) area, size, log_lsa, log_page_p);
1831  chkpt_topops = (LOG_INFO_CHKPT_SYSOP *) area;
1832  }
1833 
1834  /* Add the top system operations to the transactions */
1835 
1836  for (i = 0; i < chkpt.ntops; i++)
1837  {
1838  chkpt_topone = &chkpt_topops[i];
1839  tdes = logtb_rv_find_allocate_tran_index (thread_p, chkpt_topone->trid, log_lsa);
1840  if (tdes == NULL)
1841  {
1842  if (area != NULL)
1843  {
1844  free_and_init (area);
1845  }
1846 
1847  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_analysis");
1848  return ER_FAILED;
1849  }
1850 
1851  if (tdes->topops.max == 0 || (tdes->topops.last + 1) >= tdes->topops.max)
1852  {
1853  if (logtb_realloc_topops_stack (tdes, chkpt.ntops) == NULL)
1854  {
1855  if (area != NULL)
1856  {
1857  free_and_init (area);
1858  }
1859 
1860  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_analysis");
1861  return ER_OUT_OF_VIRTUAL_MEMORY;
1862  }
1863  }
1864 
1865  if (tdes->topops.last == -1)
1866  {
1867  tdes->topops.last++;
1868  }
1869  else
1870  {
1871  assert (tdes->topops.last == 0);
1872  }
1874  tdes->rcv.atomic_sysop_start_lsa = chkpt_topone->atomic_sysop_start_lsa;
1875  log_lsa_local = chkpt_topone->sysop_start_postpone_lsa;
1876  error_code =
1877  log_read_sysop_start_postpone (thread_p, &log_lsa_local, log_page_local, false, &sysop_start_postpone,
1878  NULL, NULL, NULL, NULL);
1879  if (error_code != NO_ERROR)
1880  {
1881  assert (false);
1882  return error_code;
1883  }
1884  tdes->topops.stack[tdes->topops.last].lastparent_lsa = sysop_start_postpone.sysop_end.lastparent_lsa;
1885  tdes->topops.stack[tdes->topops.last].posp_lsa = sysop_start_postpone.posp_lsa;
1886  }
1887  }
1888 
1889  if (LSA_LT (&chkpt.redo_lsa, start_redo_lsa))
1890  {
1891  LSA_COPY (start_redo_lsa, &chkpt.redo_lsa);
1892  }
1893 
1894  if (area != NULL)
1895  {
1896  free_and_init (area);
1897  }
1898 
1899  return NO_ERROR;
1900 }
1901 
1902 /*
1903  * log_rv_analysis_save_point -
1904  *
1905  * return: error code
1906  *
1907  * tran_id(in):
1908  * lsa(in/out):
1909  *
1910  * Note:
1911  */
1912 static int
1913 log_rv_analysis_save_point (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa)
1914 {
1915  LOG_TDES *tdes;
1916 
1917  /*
1918  * If this is the first time, the transaction is seen. Assign a new
1919  * index to describe it and assume that the transaction was active
1920  * at the time of the crash, and thus it will be unilateraly
1921  * aborted. The truth of this statement will be find reading the
1922  * rest of the log
1923  */
1924  tdes = logtb_rv_find_allocate_tran_index (thread_p, tran_id, log_lsa);
1925  if (tdes == NULL)
1926  {
1927  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rv_analysis_save_point");
1928  return ER_FAILED;
1929  }
1930 
1931  /* New tail, next to undo and savepoint */
1932  LSA_COPY (&tdes->tail_lsa, log_lsa);
1933  LSA_COPY (&tdes->undo_nxlsa, &tdes->tail_lsa);
1934  LSA_COPY (&tdes->savept_lsa, &tdes->tail_lsa);
1935 
1936  return NO_ERROR;
1937 }
1938 
1939 /*
1940  * log_rv_analysis_2pc_prepare -
1941  *
1942  * return: error code
1943  *
1944  * tran_id(in):
1945  * lsa(in/out):
1946  *
1947  * Note:
1948  */
1949 static int
1950 log_rv_analysis_2pc_prepare (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa)
1951 {
1952  LOG_TDES *tdes;
1953 
1954  /*
1955  * If this is the first time, the transaction is seen. Assign a new
1956  * index to describe it. The transaction has agreed not to
1957  * unilaterally abort the transaction.
1958  * This is a participant of the transaction
1959  */
1960 
1961  tdes = logtb_rv_find_allocate_tran_index (thread_p, tran_id, log_lsa);
1962  if (tdes == NULL)
1963  {
1964  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rv_analysis_2pc_prepare");
1965  return ER_FAILED;
1966  }
1967 
1969  LSA_COPY (&tdes->tail_lsa, log_lsa);
1970 
1971  /* Put a note that prepare_to_commit log record needs to be read during either redo phase, or during
1972  * finish_commit_protocol phase */
1973  tdes->gtrid = LOG_2PC_NULL_GTRID;
1974 
1975  return NO_ERROR;
1976 }
1977 
1978 /*
1979  * log_rv_analysis_2pc_start -
1980  *
1981  * return: error code
1982  *
1983  * tran_id(in):
1984  * lsa(in/out):
1985  *
1986  * Note:
1987  */
1988 static int
1989 log_rv_analysis_2pc_start (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa)
1990 {
1991  LOG_TDES *tdes;
1992 
1993  /*
1994  * If this is the first time, the transaction is seen. Assign a new
1995  * index to describe it. The transaction was part of the two phase
1996  * commit process. This is a coordinator site.
1997  */
1998  tdes = logtb_rv_find_allocate_tran_index (thread_p, tran_id, log_lsa);
1999  if (tdes == NULL)
2000  {
2001  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rv_analysis_2pc_start");
2002  return ER_FAILED;
2003  }
2004 
2006  LSA_COPY (&tdes->tail_lsa, log_lsa);
2007 
2008  /* Put a note that prepare_to_commit log record needs to be read during either redo phase, or during
2009  * finish_commit_protocol phase */
2010  tdes->gtrid = LOG_2PC_NULL_GTRID;
2011 
2012  return NO_ERROR;
2013 }
2014 
2015 /*
2016  * log_rv_analysis_2pc_commit_decision -
2017  *
2018  * return: error code
2019  *
2020  * tran_id(in):
2021  * lsa(in/out):
2022  *
2023  * Note:
2024  */
2025 static int
2026 log_rv_analysis_2pc_commit_decision (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa)
2027 {
2028  LOG_TDES *tdes;
2029 
2030  /*
2031  * If this is the first time, the transaction is seen. Assign a new
2032  * index to describe it. The transaction was part of the two phase
2033  * commit process. A commit decsion has been agreed.
2034  * This is a coordinator site.
2035  */
2036  tdes = logtb_rv_find_allocate_tran_index (thread_p, tran_id, log_lsa);
2037  if (tdes == NULL)
2038  {
2039  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rv_analysis_2pc_commit_decision");
2040  return ER_FAILED;
2041  }
2042 
2044  LSA_COPY (&tdes->tail_lsa, log_lsa);
2045 
2046  return NO_ERROR;
2047 }
2048 
2049 /*
2050  * log_rv_analysis_2pc_abort_decision -
2051  *
2052  * return: error code
2053  *
2054  * tran_id(in):
2055  * lsa(in/out):
2056  *
2057  * Note:
2058  */
2059 static int
2060 log_rv_analysis_2pc_abort_decision (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa)
2061 {
2062  LOG_TDES *tdes;
2063 
2064  /*
2065  * If this is the first time, the transaction is seen. Assign a new
2066  * index to describe it. The transaction was part of the two phase
2067  * commit process. An abort decsion has been decided.
2068  * This is a coordinator site.
2069  */
2070  tdes = logtb_rv_find_allocate_tran_index (thread_p, tran_id, log_lsa);
2071  if (tdes == NULL)
2072  {
2073  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rv_analysis_2pc_abort_decision");
2074  return ER_FAILED;
2075  }
2076 
2078  LSA_COPY (&tdes->tail_lsa, log_lsa);
2079 
2080  return NO_ERROR;
2081 }
2082 
2083 /*
2084  * log_rv_analysis_2pc_commit_inform_particps -
2085  *
2086  * return: error code
2087  *
2088  * tran_id(in):
2089  * lsa(in/out):
2090  *
2091  * Note:
2092  */
2093 static int
2095 {
2096  LOG_TDES *tdes;
2097 
2098  /*
2099  * If this is the first time, the transaction is seen. Assign a new
2100  * index to describe it. The transaction was part of the two phase
2101  * commit process. A commit decsion has been agreed and the
2102  * transaction was waiting on acknowledgment from participants
2103  * This is a coordinator site.
2104  */
2105  tdes = logtb_rv_find_allocate_tran_index (thread_p, tran_id, log_lsa);
2106  if (tdes == NULL)
2107  {
2108  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_rv_analysis_2pc_commit_inform_particps");
2109  return ER_FAILED;
2110  }
2111 
2113  LSA_COPY (&tdes->tail_lsa, log_lsa);
2114 
2115  return NO_ERROR;
2116 }
2117 
2118 /*
2119  * log_rv_analysis_2pc_abort_inform_particps -
2120  *
2121  * return: error code
2122  *
2123  * tran_id(in):
2124  * lsa(in/out):
2125  *
2126  * Note:
2127  */
2128 static int
2130 {
2131  LOG_TDES *tdes;
2132 
2133  /*
2134  * If this is the first time, the transaction is seen. Assign a new
2135  * index to describe it. The transaction was part of the two phase
2136  * commit process. An abort decsion has been decided and the
2137  * transaction was waiting on acknowledgment from participants
2138  * This is a coordinator site.
2139  */
2140  tdes = logtb_rv_find_allocate_tran_index (thread_p, tran_id, log_lsa);
2141  if (tdes == NULL)
2142  {
2143  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_analysis");
2144  return ER_FAILED;
2145  }
2146 
2148  LSA_COPY (&tdes->tail_lsa, log_lsa);
2149 
2150  return NO_ERROR;
2151 }
2152 
2153 /*
2154  * log_rv_analysis_2pc_recv_ack -
2155  *
2156  * return: error code
2157  *
2158  * tran_id(in):
2159  * lsa(in/out):
2160  *
2161  * Note:
2162  */
2163 static int
2164 log_rv_analysis_2pc_recv_ack (THREAD_ENTRY * thread_p, int tran_id, LOG_LSA * log_lsa)
2165 {
2166  LOG_TDES *tdes;
2167 
2168  tdes = logtb_rv_find_allocate_tran_index (thread_p, tran_id, log_lsa);
2169  if (tdes == NULL)
2170  {
2171  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_analysis");
2172  return ER_FAILED;
2173  }
2174 
2175  LSA_COPY (&tdes->tail_lsa, log_lsa);
2176 
2177  return NO_ERROR;
2178 }
2179 
2180 /*
2181  * log_rv_analysis_log_end -
2182  *
2183  * return: error code
2184  *
2185  * tran_id(in):
2186  * lsa(in/out):
2187  *
2188  * Note:
2189  */
2190 static int
2191 log_rv_analysis_log_end (int tran_id, LOG_LSA * log_lsa)
2192 {
2193  if (!logpb_is_page_in_archive (log_lsa->pageid))
2194  {
2195  /*
2196  * Reset the log header for the recovery undo operation
2197  */
2198  LOG_RESET_APPEND_LSA (log_lsa);
2199  log_Gl.hdr.next_trid = tran_id;
2200  }
2201 
2202  return NO_ERROR;
2203 }
2204 
2205 /*
2206  * log_rv_analysis_record -
2207  *
2208  * return: error code
2209  *
2210  *
2211  * Note:
2212  */
2213 static void
2214 log_rv_analysis_record (THREAD_ENTRY * thread_p, LOG_RECTYPE log_type, int tran_id, LOG_LSA * log_lsa,
2215  LOG_PAGE * log_page_p, LOG_LSA * checkpoint_lsa, LOG_LSA * prev_lsa, LOG_LSA * start_lsa,
2216  LOG_LSA * start_redo_lsa, bool is_media_crash, time_t * stop_at, bool * did_incom_recovery,
2217  bool * may_use_checkpoint, bool * may_need_synch_checkpoint_2pc)
2218 {
2219  switch (log_type)
2220  {
2221  case LOG_UNDOREDO_DATA:
2223  case LOG_UNDO_DATA:
2224  case LOG_REDO_DATA:
2227  case LOG_MVCC_UNDO_DATA:
2228  case LOG_MVCC_REDO_DATA:
2230  (void) log_rv_analysis_undo_redo (thread_p, tran_id, log_lsa);
2231  break;
2232 
2234  (void) log_rv_analysis_dummy_head_postpone (thread_p, tran_id, log_lsa);
2235  break;
2236 
2237  case LOG_POSTPONE:
2238  (void) log_rv_analysis_postpone (thread_p, tran_id, log_lsa);
2239  break;
2240 
2241  case LOG_RUN_POSTPONE:
2242  (void) log_rv_analysis_run_postpone (thread_p, tran_id, log_lsa, log_page_p, checkpoint_lsa);
2243  break;
2244 
2245  case LOG_COMPENSATE:
2246  (void) log_rv_analysis_compensate (thread_p, tran_id, log_lsa, log_page_p);
2247  break;
2248 
2249  case LOG_WILL_COMMIT:
2250  (void) log_rv_analysis_will_commit (thread_p, tran_id, log_lsa);
2251  break;
2252 
2254  (void) log_rv_analysis_commit_with_postpone (thread_p, tran_id, log_lsa, log_page_p);
2255  break;
2256 
2258  (void) log_rv_analysis_sysop_start_postpone (thread_p, tran_id, log_lsa, log_page_p);
2259  break;
2260 
2261  case LOG_COMMIT:
2262  case LOG_ABORT:
2263  (void) log_rv_analysis_complete (thread_p, tran_id, log_lsa, log_page_p, prev_lsa, is_media_crash, stop_at,
2264  did_incom_recovery);
2265  break;
2266 
2267  case LOG_SYSOP_END:
2268  log_rv_analysis_sysop_end (thread_p, tran_id, log_lsa, log_page_p);
2269  break;
2270 
2271  case LOG_START_CHKPT:
2272  log_rv_analysis_start_checkpoint (log_lsa, start_lsa, may_use_checkpoint);
2273  break;
2274 
2275  case LOG_END_CHKPT:
2276  log_rv_analysis_end_checkpoint (thread_p, log_lsa, log_page_p, checkpoint_lsa, start_redo_lsa, may_use_checkpoint,
2277  may_need_synch_checkpoint_2pc);
2278  break;
2279 
2280  case LOG_SAVEPOINT:
2281  (void) log_rv_analysis_save_point (thread_p, tran_id, log_lsa);
2282  break;
2283 
2284  case LOG_2PC_PREPARE:
2285  (void) log_rv_analysis_2pc_prepare (thread_p, tran_id, log_lsa);
2286  break;
2287 
2288  case LOG_2PC_START:
2289  (void) log_rv_analysis_2pc_start (thread_p, tran_id, log_lsa);
2290  break;
2291 
2293  (void) log_rv_analysis_2pc_commit_decision (thread_p, tran_id, log_lsa);
2294  break;
2295 
2297  (void) log_rv_analysis_2pc_abort_decision (thread_p, tran_id, log_lsa);
2298  break;
2299 
2301  (void) log_rv_analysis_2pc_commit_inform_particps (thread_p, tran_id, log_lsa);
2302  break;
2303 
2305  (void) log_rv_analysis_2pc_abort_inform_particps (thread_p, tran_id, log_lsa);
2306  break;
2307 
2308  case LOG_2PC_RECV_ACK:
2309  (void) log_rv_analysis_2pc_recv_ack (thread_p, tran_id, log_lsa);
2310  break;
2311 
2312  case LOG_END_OF_LOG:
2313  (void) log_rv_analysis_log_end (tran_id, log_lsa);
2314  break;
2315 
2317  (void) log_rv_analysis_atomic_sysop_start (thread_p, tran_id, log_lsa);
2318  break;
2319 
2321  case LOG_REPLICATION_DATA:
2324  case LOG_DUMMY_OVF_RECORD:
2325  case LOG_DUMMY_GENERIC:
2326  break;
2327 
2330  default:
2331 #if defined(CUBRID_DEBUG)
2333  "log_recovery_analysis: Unknown record type = %d (%s) ... May be a system error\n", log_rtype,
2334  log_to_string (log_rtype));
2335 #endif /* CUBRID_DEBUG */
2336  /* If we are here, probably the log is corrupted. */
2338  assert (false);
2339  break;
2340  }
2341 }
2342 
2343 /*
2344  * log_is_page_of_record_broken - check last page of the record
2345  *
2346  * return: true, if last page of the record is broken. false, if it is sane
2347  *
2348  * log_lsa(in): Log record address
2349  * log_rec_header(in): Log record header
2350  */
2351 static bool
2354 {
2355  char fwd_log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT];
2356  char *fwd_aligned_log_pgbuf;
2357  LOG_PAGE *log_fwd_page_p;
2358  LOG_LSA fwd_log_lsa;
2359  bool is_log_page_broken = false;
2360 
2361  assert (log_lsa != NULL && log_rec_header != NULL);
2362 
2363  fwd_aligned_log_pgbuf = PTR_ALIGN (fwd_log_pgbuf, MAX_ALIGNMENT);
2364  log_fwd_page_p = (LOG_PAGE *) fwd_aligned_log_pgbuf;
2365 
2366  LSA_COPY (&fwd_log_lsa, &log_rec_header->forw_lsa);
2367 
2368  /* TODO - Do we need to handle NULL fwd_log_lsa? */
2369  if (!LSA_ISNULL (&fwd_log_lsa))
2370  {
2371  assert (fwd_log_lsa.pageid >= log_lsa->pageid);
2372 
2373  if (fwd_log_lsa.pageid != log_lsa->pageid
2374  && (fwd_log_lsa.offset != 0 || fwd_log_lsa.pageid > log_lsa->pageid + 1))
2375  {
2376  // The current log record spreads into several log pages.
2377  // Check whether the last page of the record exists.
2378  if (logpb_fetch_page (thread_p, &fwd_log_lsa, LOG_CS_FORCE_USE, log_fwd_page_p) != NO_ERROR)
2379  {
2380  /* The forward log page does not exists. */
2381  is_log_page_broken = true;
2382  }
2383  }
2384  }
2385 
2386  return is_log_page_broken;
2387 }
2388 
2389 /*
2390  * log_recovery_analysis - FIND STATE OF TRANSACTIONS AT SYSTEM CRASH
2391  *
2392  * return: nothing
2393  *
2394  * start_lsa(in): Starting address for the analysis phase
2395  * start_redolsa(in/out): Starting address for redo phase
2396  * end_redo_lsa(in):
2397  * ismedia_crash(in): Are we recovering from a media crash ?
2398  * stopat(in/out): Where to stop the recovery process.
2399  * (It may be set as a side effectto the location of last
2400  * recovery transaction).
2401  * did_incom_recovery(in):
2402  *
2403  * NOTE: The recovery analysis phase scans the log forward since the
2404  * last checkpoint record reflected in the log and the data
2405  * volumes. The transaction table and the starting address for
2406  * redo phase is created. When this phase is finished, we know
2407  * the transactions that need to be unilateraly aborted (active)
2408  * and the transactions that have to be completed due to postpone
2409  * actions and client loose ends.
2410  */
2411 
2412 static void
2413 log_recovery_analysis (THREAD_ENTRY * thread_p, LOG_LSA * start_lsa, LOG_LSA * start_redo_lsa, LOG_LSA * end_redo_lsa,
2414  bool is_media_crash, time_t * stop_at, bool * did_incom_recovery, INT64 * num_redo_log_records)
2415 {
2416  LOG_LSA checkpoint_lsa = { -1, -1 };
2417  LOG_LSA lsa; /* LSA of log record to analyse */
2418  char log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT], *aligned_log_pgbuf;
2419  LOG_PAGE *log_page_p = NULL; /* Log page pointer where LSA is located */
2420  LOG_LSA log_lsa;
2421  LOG_LSA prev_lsa;
2422  LOG_LSA prev_prev_lsa;
2423  LOG_LSA first_corrupted_rec_lsa;
2424  LOG_RECTYPE log_rtype; /* Log record type */
2425  LOG_RECORD_HEADER *log_rec = NULL;
2426  LOG_REC_CHKPT *tmp_chkpt; /* Temp Checkpoint log record */
2427  LOG_REC_CHKPT chkpt; /* Checkpoint log record */
2428  LOG_INFO_CHKPT_TRANS *chkpt_trans;
2429  time_t last_at_time = -1;
2430  char time_val[CTIME_MAX];
2431  bool may_need_synch_checkpoint_2pc = false, may_use_checkpoint = false, is_log_page_corrupted = false;
2432  int tran_index;
2433  TRANID tran_id;
2434  LOG_TDES *tdes; /* Transaction descriptor */
2435  void *area = NULL;
2436  int size, i;
2437  const int block_size = 4 * ONE_K;
2438  int start_record_block, end_record_block;
2439  char null_buffer[block_size + MAX_ALIGNMENT], *null_block;
2440  int max_num_blocks = LOG_PAGESIZE / block_size;
2441  int last_checked_page_id = NULL_PAGEID;
2442  bool is_log_page_broken;
2443 
2444  aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
2445  null_block = PTR_ALIGN (null_buffer, MAX_ALIGNMENT);
2446  memset (null_block, LOG_PAGE_INIT_VALUE, block_size);
2447 
2448  if (num_redo_log_records != NULL)
2449  {
2450  *num_redo_log_records = 0;
2451  }
2452 
2453  /*
2454  * Find the committed, aborted, and unilaterally aborted (active) transactions at system crash
2455  */
2456 
2457  LSA_SET_NULL (&first_corrupted_rec_lsa);
2458  LSA_COPY (&lsa, start_lsa);
2459 
2460  LSA_COPY (start_redo_lsa, &lsa);
2461  LSA_COPY (end_redo_lsa, &lsa);
2462  LSA_COPY (&prev_lsa, &lsa);
2463  prev_prev_lsa.set_null ();
2464  *did_incom_recovery = false;
2465 
2466  log_page_p = (LOG_PAGE *) aligned_log_pgbuf;
2467 
2468  is_log_page_broken = false;
2469  while (!LSA_ISNULL (&lsa))
2470  {
2471  /* Fetch the page where the LSA record to undo is located */
2472  LSA_COPY (&log_lsa, &lsa);
2473 
2474  /* We may fetch only if log page not already broken, but is better in this way. */
2475  if (logpb_fetch_page (thread_p, &log_lsa, LOG_CS_FORCE_USE, log_page_p) != NO_ERROR)
2476  {
2477  // unable to fetch the current log page.
2478  is_log_page_broken = true;
2479  }
2480 
2481  if (is_log_page_broken)
2482  {
2483  if (is_media_crash == true)
2484  {
2485  if (stop_at != NULL)
2486  {
2487  *stop_at = last_at_time;
2488  }
2489 
2490 #if !defined(NDEBUG)
2492  {
2494  (void) ctime_r (&last_at_time, time_val);
2495  fprintf (stdout,
2497  end_redo_lsa->pageid, end_redo_lsa->offset, ((last_at_time == -1) ? "???...\n" : time_val));
2499  fflush (stdout);
2500  }
2501 #endif /* !NDEBUG */
2502 
2503  /* if previous log record exists, reset tdes->tail_lsa/undo_nxlsa as previous of end_redo_lsa */
2504  if (log_rec != NULL)
2505  {
2506  LOG_TDES *last_log_tdes = LOG_FIND_TDES (logtb_find_tran_index (thread_p, log_rec->trid));
2507  if (last_log_tdes != NULL)
2508  {
2509  LSA_COPY (&last_log_tdes->tail_lsa, &log_rec->prev_tranlsa);
2510  LSA_COPY (&last_log_tdes->undo_nxlsa, &log_rec->prev_tranlsa);
2511  er_log_debug (ARG_FILE_LINE, "logpb_recovery_analysis: trid = %d, tail_lsa=%lld|%d\n",
2512  log_rec->trid, last_log_tdes->tail_lsa.pageid, last_log_tdes->tail_lsa.offset);
2513  }
2514  }
2515  assert (!prev_lsa.is_null ());
2516  if (logpb_fetch_page (thread_p, &prev_lsa, LOG_CS_FORCE_USE, log_page_p) != NO_ERROR)
2517  {
2518  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "reset log is impossible");
2519  return;
2520  }
2521  log_recovery_resetlog (thread_p, &prev_lsa, &prev_prev_lsa);
2522  *did_incom_recovery = true;
2523 
2525  return;
2526  }
2527  else
2528  {
2530  {
2531  /* TDE Moudle has to be loaded because there are some TDE-encrypted log pages */
2532  logpb_fatal_error (thread_p, true, ARG_FILE_LINE,
2533  "log_recovery_analysis: log page %lld has been encrypted (TDE) and cannot be decrypted",
2534  log_page_p->hdr.logical_pageid);
2535  }
2536  else
2537  {
2538  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_analysis");
2539  }
2540  return;
2541  }
2542  }
2543 
2544  /* Check all log records in this phase */
2545  while (!LSA_ISNULL (&lsa) && lsa.pageid == log_lsa.pageid)
2546  {
2547  /*
2548  * If an offset is missing, it is because an incomplete log record was
2549  * archived. This log_record was completed later. Thus, we have to
2550  * find the offset by searching for the next log_record in the page
2551  */
2552  if (lsa.offset == NULL_OFFSET)
2553  {
2554  lsa.offset = log_page_p->hdr.offset;
2555  if (lsa.offset == NULL_OFFSET)
2556  {
2557  /* Continue with next pageid */
2558  if (logpb_is_page_in_archive (log_lsa.pageid))
2559  {
2560  lsa.pageid = log_lsa.pageid + 1;
2561  }
2562  else
2563  {
2564  lsa.pageid = NULL_PAGEID;
2565  }
2566  continue;
2567  }
2568  }
2569 
2570  /* If the page changed, check whether is corrupted. */
2571  if (last_checked_page_id != log_lsa.pageid)
2572  {
2573 #if !defined(NDEBUG)
2574  er_log_debug (ARG_FILE_LINE, "logpb_recovery_analysis: log page %lld, checksum %d\n",
2575  log_page_p->hdr.logical_pageid, log_page_p->hdr.checksum);
2577  {
2578  fileio_page_hexa_dump ((const char *) log_page_p, LOG_PAGESIZE);
2579  }
2580 #endif /* !NDEBUG */
2581 
2582  /* Check whether active log pages are corrupted. This may happen in case of partial page flush for instance. */
2583  if (logpb_page_check_corruption (thread_p, log_page_p, &is_log_page_corrupted) != NO_ERROR)
2584  {
2585  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_analysis");
2586  return;
2587  }
2588 
2589  if (is_log_page_corrupted)
2590  {
2591  if (logpb_is_page_in_archive (log_lsa.pageid))
2592  {
2593  /* Should not happen. */
2594  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_analysis");
2595  return;
2596  }
2597 
2598  /* Set first corrupted record lsa, if a block is corrupted. */
2599  logpb_page_get_first_null_block_lsa (thread_p, log_page_p, &first_corrupted_rec_lsa);
2600 
2601  /* Found corrupted log page. */
2603  {
2605  "logpb_recovery_analysis: log page %lld is corrupted due to partial flush.\n",
2606  (long long int) log_lsa.pageid);
2607  }
2608  }
2609 
2610  /* Set last checked page id. */
2611  last_checked_page_id = log_lsa.pageid;
2612  }
2613 
2614  /* Find the log record */
2615  log_lsa.offset = lsa.offset;
2616  log_rec = LOG_GET_LOG_RECORD_HEADER (log_page_p, &log_lsa);
2617 
2618  if (is_media_crash == true)
2619  {
2620  /* Check also the last log page of current record. We need to check after obtaining log_rec. */
2621  is_log_page_broken = log_is_page_of_record_broken (thread_p, &log_lsa, log_rec);
2622  if (is_log_page_broken)
2623  {
2624  /* Needs to reset the log. It is done in the outer loop. Set end_redo and prev used at reset. */
2625  LSA_COPY (end_redo_lsa, &lsa);
2626  LSA_COPY (&prev_lsa, end_redo_lsa);
2627  prev_prev_lsa = prev_lsa;
2628  er_log_debug (ARG_FILE_LINE, "logpb_recovery_analysis: broken record at LSA=%lld|%d ", log_lsa.pageid,
2629  log_lsa.offset);
2630  break;
2631  }
2632  }
2633 
2634  /* Check whether null LSA is reached. */
2635  if (!is_log_page_corrupted)
2636  {
2637  /* For safety reason. Normally, checksum must detect corrupted pages. */
2638  if (LSA_ISNULL (&log_rec->forw_lsa)
2639  && log_rec->type != LOG_END_OF_LOG && !logpb_is_page_in_archive (log_lsa.pageid))
2640  {
2641  /* Can't find the end of log. The next log is null. Consider the page corrupted. */
2642  logpb_page_get_first_null_block_lsa (thread_p, log_page_p, &first_corrupted_rec_lsa);
2643  is_log_page_corrupted = true;
2644 
2646  "log_recovery_analysis: ** WARNING: An end of the log record was not found."
2647  "Latest log record at lsa = %lld|%d, first_corrupted_lsa = %lld|%d\n",
2648  log_lsa.pageid, log_lsa.offset, first_corrupted_rec_lsa.pageid,
2649  first_corrupted_rec_lsa.offset);
2650  }
2651  else if (log_rec->forw_lsa.pageid == log_lsa.pageid)
2652  {
2653  /* Quick fix. Sometimes page corruption is not detected. Check whether the current log record
2654  * is in corrupted block. If true, consider the page corrupted.
2655  */
2656  LOG_LSA temp_log_lsa;
2657  LSA_COPY (&temp_log_lsa, &log_rec->forw_lsa);
2658  temp_log_lsa.offset--;
2659  assert (log_lsa.offset >= 0 && temp_log_lsa.offset > log_lsa.offset);
2660 
2661  start_record_block = ((int) log_lsa.offset + sizeof (LOG_HDRPAGE)) / block_size;
2662  assert (start_record_block >= 0 && start_record_block < max_num_blocks);
2663  end_record_block = ((int) temp_log_lsa.offset + sizeof (LOG_HDRPAGE)) / block_size;
2664  assert (end_record_block >= 0 && end_record_block < max_num_blocks);
2665 
2666  if (start_record_block != end_record_block)
2667  {
2668  assert (start_record_block < end_record_block);
2669  if (memcmp (((char *) log_page_p) + (end_record_block * block_size), null_block, block_size) == 0)
2670  {
2671  /* The current record is corrupted - ends into a corrupted block. */
2672  LSA_COPY (&first_corrupted_rec_lsa, &log_lsa);
2673  is_log_page_corrupted = true;
2674 
2676  "log_recovery_analysis: ** WARNING: An end of the log record was not found."
2677  "Latest log record at lsa = %lld|%d, first_corrupted_lsa = %lld|%d\n",
2678  log_lsa.pageid, log_lsa.offset, first_corrupted_rec_lsa.pageid,
2679  first_corrupted_rec_lsa.offset);
2680  }
2681  }
2682  }
2683  }
2684 
2685  if (is_log_page_corrupted && !LSA_ISNULL (&first_corrupted_rec_lsa))
2686  {
2687  /* If the record is corrupted - it resides in a corrupted block, then
2688  * resets append lsa to last valid address and stop.
2689  */
2690  if (LSA_GT (&log_lsa, &first_corrupted_rec_lsa))
2691  {
2692  LOG_RESET_APPEND_LSA (end_redo_lsa);
2693  LSA_SET_NULL (&lsa);
2694  break;
2695  }
2696  else
2697  {
2698  LOG_LSA temp_log_lsa;
2699  bool is_log_lsa_corrupted = false;
2700 
2701  if (LSA_EQ (&log_lsa, &first_corrupted_rec_lsa)
2702  || LSA_GT (&log_rec->forw_lsa, &first_corrupted_rec_lsa))
2703  {
2704  /* When log_lsa = first_corrupted_rec_lsa, forw_lsa may be NULL. */
2705  is_log_lsa_corrupted = true;
2706  }
2707  else
2708  {
2709  /* Check correctness of information from log header. */
2710  LSA_COPY (&temp_log_lsa, &log_lsa);
2711  temp_log_lsa.offset += sizeof (LOG_RECORD_HEADER);
2712  temp_log_lsa.offset = DB_ALIGN (temp_log_lsa.offset, DOUBLE_ALIGNMENT);
2713 
2714  if ((temp_log_lsa.offset > (int) LOGAREA_SIZE)
2715  || (LSA_GT (&temp_log_lsa, &first_corrupted_rec_lsa)))
2716  {
2717  is_log_lsa_corrupted = true;
2718  }
2719  }
2720 
2721  if (is_log_lsa_corrupted)
2722  {
2724  {
2726  "logpb_recovery_analysis: Partial page flush - first corrupted log record LSA = (%lld, %d)\n",
2727  (long long int) log_lsa.pageid, log_lsa.offset);
2728  }
2729  LOG_RESET_APPEND_LSA (&log_lsa);
2730  LSA_SET_NULL (&lsa);
2731  break;
2732  }
2733  }
2734  }
2735 
2736  tran_id = log_rec->trid;
2737  log_rtype = log_rec->type;
2738 
2739  /*
2740  * Save the address of last redo log record.
2741  * Get the address of next log record to scan
2742  */
2743 
2744  LSA_COPY (end_redo_lsa, &lsa);
2745  LSA_COPY (&lsa, &log_rec->forw_lsa);
2746 
2747  if ((is_log_page_corrupted) && (log_rtype != LOG_END_OF_LOG) && (lsa.pageid != log_lsa.pageid))
2748  {
2749  /* The page is corrupted, do not allow to advance to the next page. */
2750  LSA_SET_NULL (&lsa);
2751  }
2752 
2753  /*
2754  * If the next page is NULL_PAGEID and the current page is an archive
2755  * page, this is not the end of the log. This situation happens when an
2756  * incomplete log record is archived. Thus, its forward address is NULL.
2757  * Note that we have to set lsa.pageid here since the log_lsa.pageid value
2758  * can be changed (e.g., the log record is stored in two pages: an
2759  * archive page, and an active page. Later, we try to modify it whenever
2760  * is possible.
2761  */
2762 
2763  if (LSA_ISNULL (&lsa) && logpb_is_page_in_archive (log_lsa.pageid))
2764  {
2765  lsa.pageid = log_lsa.pageid + 1;
2766  }
2767 
2768  if (!LSA_ISNULL (&lsa) && log_lsa.pageid != NULL_PAGEID
2769  && (lsa.pageid < log_lsa.pageid || (lsa.pageid == log_lsa.pageid && lsa.offset <= log_lsa.offset)))
2770  {
2771  /* It seems to be a system error. Maybe a loop in the log */
2773  "log_recovery_analysis: ** System error: It seems to be a loop in the log\n."
2774  " Current log_rec at %lld|%d. Next log_rec at %lld|%d\n", (long long int) log_lsa.pageid,
2775  log_lsa.offset, (long long int) lsa.pageid, lsa.offset);
2776  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_analysis");
2777  LSA_SET_NULL (&lsa);
2778  break;
2779  }
2780 
2781  if (LSA_ISNULL (&lsa) && log_rtype != LOG_END_OF_LOG && *did_incom_recovery == false)
2782  {
2783  LOG_RESET_APPEND_LSA (end_redo_lsa);
2784  if (log_startof_nxrec (thread_p, &log_Gl.hdr.append_lsa, true) == NULL)
2785  {
2786  /* We may destroy a record */
2787  LOG_RESET_APPEND_LSA (end_redo_lsa);
2788  }
2789  else
2790  {
2792 
2793  /*
2794  * Reset the forward address of current record to next record,
2795  * and then flush the page.
2796  */
2797  LSA_COPY (&log_rec->forw_lsa, &log_Gl.hdr.append_lsa);
2798 
2799  assert (log_lsa.pageid == log_page_p->hdr.logical_pageid);
2800  logpb_write_page_to_disk (thread_p, log_page_p, log_lsa.pageid);
2801  }
2803  "log_recovery_analysis: ** WARNING: An end of the log record was not found."
2804  " Will Assume = %lld|%d and Next Trid = %d\n", (long long int) log_Gl.hdr.append_lsa.pageid,
2805  log_Gl.hdr.append_lsa.offset, tran_id);
2806  log_Gl.hdr.next_trid = tran_id;
2807  }
2808 
2809  if (num_redo_log_records)
2810  {
2811  switch (log_rtype)
2812  {
2813  /* count redo log */
2814  case LOG_REDO_DATA:
2815  case LOG_UNDOREDO_DATA:
2818  case LOG_MVCC_REDO_DATA:
2821  case LOG_RUN_POSTPONE:
2822  case LOG_COMPENSATE:
2823  case LOG_2PC_PREPARE:
2824  case LOG_2PC_START:
2825  case LOG_2PC_RECV_ACK:
2826  (*num_redo_log_records)++;
2827  break;
2828  default:
2829  break;
2830  }
2831  }
2832 
2833  log_rv_analysis_record (thread_p, log_rtype, tran_id, &log_lsa, log_page_p, &checkpoint_lsa, &prev_lsa,
2834  start_lsa, start_redo_lsa, is_media_crash, stop_at, did_incom_recovery,
2835  &may_use_checkpoint, &may_need_synch_checkpoint_2pc);
2836  if (*did_incom_recovery == true)
2837  {
2838  LSA_SET_NULL (&lsa);
2839  break;
2840  }
2841  if (LSA_EQ (end_redo_lsa, &lsa))
2842  {
2843  assert_release (!LSA_EQ (end_redo_lsa, &lsa));
2844  LSA_SET_NULL (&lsa);
2845  break;
2846  }
2847  if ((is_log_page_corrupted) && (log_rtype == LOG_END_OF_LOG))
2848  {
2849  /* The page is corrupted. Stop if end of log was found in page. In this case,
2850  * the remaining data in log page is corrupted. If end of log is not found,
2851  * then we will advance up to NULL LSA. It is important to initialize page with -1.
2852  * Another option may be to store the previous LSA in header page.
2853  * Or, to use checksum on log records, but this may slow down the system.
2854  */
2855  LSA_SET_NULL (&lsa);
2856  break;
2857  }
2858 
2859  LSA_COPY (&prev_lsa, end_redo_lsa);
2860  prev_prev_lsa = prev_lsa;
2861 
2862  /*
2863  * We can fix the lsa.pageid in the case of log_records without forward
2864  * address at this moment.
2865  */
2866  if (lsa.offset == NULL_OFFSET && lsa.pageid != NULL_PAGEID && lsa.pageid < log_lsa.pageid)
2867  {
2868  lsa.pageid = log_lsa.pageid;
2869  }
2870  }
2871  }
2872 
2873  if (may_need_synch_checkpoint_2pc == true)
2874  {
2875  /*
2876  * We may need to obtain 2PC information of distributed transactions that
2877  * were in the 2PC at the time of the checkpoint and they were still 2PC
2878  * at the time of the crash.
2879  * GET the checkpoint log record information one more time..
2880  */
2881  log_lsa.pageid = checkpoint_lsa.pageid;
2882  log_lsa.offset = checkpoint_lsa.offset;
2883 
2884  log_page_p = (LOG_PAGE *) aligned_log_pgbuf;
2885 
2886  if (logpb_fetch_page (thread_p, &log_lsa, LOG_CS_FORCE_USE, log_page_p) != NO_ERROR)
2887  {
2888  /*
2889  * There is a problem. We have just read this page a little while ago
2890  */
2891  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_analysis");
2892  return;
2893  }
2894 
2895  log_rec = LOG_GET_LOG_RECORD_HEADER (log_page_p, &log_lsa);
2896 
2897  /* Read the DATA HEADER */
2898  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), &log_lsa, log_page_p);
2899  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_CHKPT), &log_lsa, log_page_p);
2900  tmp_chkpt = (LOG_REC_CHKPT *) ((char *) log_page_p->area + log_lsa.offset);
2901  chkpt = *tmp_chkpt;
2902 
2903  /* GET THE CHECKPOINT TRANSACTION INFORMATION */
2904  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_CHKPT), &log_lsa, log_page_p);
2905 
2906  /* Now get the data of active transactions */
2907  area = NULL;
2908  size = sizeof (LOG_INFO_CHKPT_TRANS) * chkpt.ntrans;
2909  if (log_lsa.offset + size < (int) LOGAREA_SIZE)
2910  {
2911  chkpt_trans = (LOG_INFO_CHKPT_TRANS *) ((char *) log_page_p->area + log_lsa.offset);
2912  }
2913  else
2914  {
2915  /* Need to copy the data into a contiguous area */
2916  area = malloc (size);
2917  if (area == NULL)
2918  {
2919  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_analysis");
2920  return;
2921  }
2922  /* Copy the data */
2923  logpb_copy_from_log (thread_p, (char *) area, size, &log_lsa, log_page_p);
2924  chkpt_trans = (LOG_INFO_CHKPT_TRANS *) area;
2925  }
2926 
2927  /* Add the transactions to the transaction table */
2928  for (i = 0; i < chkpt.ntrans; i++)
2929  {
2930  tran_index = logtb_find_tran_index (thread_p, chkpt_trans[i].trid);
2931  if (tran_index != NULL_TRAN_INDEX)
2932  {
2933  tdes = LOG_FIND_TDES (tran_index);
2934  if (tdes != NULL && LOG_ISTRAN_2PC (tdes))
2935  {
2936  log_2pc_recovery_analysis_info (thread_p, tdes, &chkpt_trans[i].tail_lsa);
2937  }
2938  }
2939  }
2940  if (area != NULL)
2941  {
2942  free_and_init (area);
2943  }
2944  }
2945 
2947 
2949  {
2950  _er_log_debug (ARG_FILE_LINE, "log_recovery_analysis: end of analysis phase, append_lsa = (%lld|%d) \n",
2951  (long long int) log_Gl.hdr.append_lsa.pageid, log_Gl.hdr.append_lsa.offset);
2952  }
2953 
2954  return;
2955 }
2956 
2957 /*
2958  * log_recovery_needs_skip_logical_redo - Check whether we need to skip logical redo.
2959  *
2960  * return: true if skip logical redo, false otherwise
2961  *
2962  * thread_p(in): Thread entry
2963  * tran_id(in) : Transaction id.
2964  * log_rtype(in): Log record type
2965  * rcv_index(in): Recovery index
2966  * lsa(in) : lsa to check
2967  *
2968  * NOTE: When logical redo logging is applied and the system crashes repeatedly, we need to
2969  * skip redo logical record already applied. This function checks whether the logical redo must be skipped.
2970  */
2971 static bool
2973  LOG_RCVINDEX rcv_index, const LOG_LSA * lsa)
2974 {
2975  int tran_index;
2976  LOG_TDES *tdes = NULL; /* Transaction descriptor */
2977 
2978  assert (lsa != NULL);
2979 
2980  if (log_rtype != LOG_DBEXTERN_REDO_DATA)
2981  {
2982  return false;
2983  }
2984 
2985  tran_index = logtb_find_tran_index (thread_p, tran_id);
2986  if (tran_index == NULL_TRAN_INDEX)
2987  {
2988  return false;
2989  }
2990 
2991  tdes = LOG_FIND_TDES (tran_index);
2992  if (tdes == NULL)
2993  {
2994  return false;
2995  }
2996 
2997  /* logical redo logging */
2998  // analysis_last_aborted_sysop_start_lsa < lsa < analysis_last_aborted_sysop_lsa
3000  && LSA_LT (lsa, &tdes->rcv.analysis_last_aborted_sysop_lsa))
3001  {
3002  /* Logical redo already applied. */
3003  er_log_debug (ARG_FILE_LINE, "log_recovery_needs_skip_logical_redo: LSA = %lld|%d, Rv_index = %s, "
3004  "analysis_last_aborted_sysop_lsa = %lld|%d, analysis_last_aborted_sysop_start_lsa = %lld|%d\n",
3005  LSA_AS_ARGS (lsa), rv_rcvindex_string (rcv_index),
3008  return true;
3009  }
3010 
3011  return false;
3012 }
3013 
3014 /*
3015  * log_recovery_redo - SCAN FORWARD REDOING DATA
3016  *
3017  * return: nothing
3018  *
3019  * start_redolsa(in): Starting address for recovery redo phase
3020  * end_redo_lsa(in):
3021  * stopat(in):
3022  *
3023  * NOTE:In the redo phase, updates that are not reflected in the
3024  * database are repeated for not only the committed transaction
3025  * but also for all aborted transactions and the transactions
3026  * that were in progress at the time of the failure. This phase
3027  * reestablishes the state of the database as of the time of the
3028  * failure. The redo phase starts by scanning the log records
3029  * from the redo LSA address determined in the analysis phase.
3030  * When a redoable record is found, a check is done to find out
3031  * if the redo action is already reflected in the page. If it is
3032  * not, then the redo actions are executed. A redo action can be
3033  * skipped if the LSA of the affected page is greater or equal
3034  * than that of the LSA of the log record. Any postpone actions
3035  * (after commit actions) of committed transactions that have not
3036  * been executed are done. Loose_ends of client actions that have
3037  * not been done are postponed until the client is restarted.
3038  * At the end of the recovery phase, all data dirty pages are
3039  * flushed.
3040  * The redo of aborted transactions are undone executing its
3041  * respective compensating log records.
3042  */
3043 static void
3044 log_recovery_redo (THREAD_ENTRY * thread_p, const LOG_LSA * start_redolsa, const LOG_LSA * end_redo_lsa,
3045  time_t * stopat)
3046 {
3047  LOG_LSA lsa; /* LSA of log record to redo */
3048  char log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT], *aligned_log_pgbuf;
3049  LOG_PAGE *log_pgptr = NULL; /* Log page pointer where LSA is located */
3050  LOG_LSA log_lsa;
3051  LOG_RECORD_HEADER *log_rec = NULL; /* Pointer to log record */
3052  LOG_REC_UNDOREDO *undoredo = NULL; /* Undo_redo log record */
3053  LOG_REC_MVCC_UNDOREDO *mvcc_undoredo = NULL; /* MVCC op undo/redo log record */
3054  LOG_REC_REDO *redo = NULL; /* Redo log record */
3055  LOG_REC_MVCC_REDO *mvcc_redo = NULL; /* MVCC op redo log record */
3056  LOG_REC_MVCC_UNDO *mvcc_undo = NULL; /* MVCC op undo log record */
3057  LOG_REC_DBOUT_REDO *dbout_redo = NULL; /* A external redo log record */
3058  LOG_REC_COMPENSATE *compensate = NULL; /* Compensating log record */
3059  LOG_REC_RUN_POSTPONE *run_posp = NULL; /* A run postpone action */
3060  LOG_REC_2PC_START *start_2pc = NULL; /* Start 2PC commit log record */
3061  LOG_REC_2PC_PARTICP_ACK *received_ack = NULL; /* A 2PC participant ack */
3062  LOG_REC_DONETIME *donetime = NULL;
3063  LOG_REC_SYSOP_END *sysop_end; /* Result of top system op */
3064  LOG_RCV rcv; /* Recovery structure */
3065  VPID rcv_vpid; /* VPID of data to recover */
3066  LOG_RCVINDEX rcvindex; /* Recovery index function */
3067  LOG_LSA rcv_lsa; /* Address of redo log record */
3068  LOG_LSA *rcv_page_lsaptr; /* LSA of data page for log record to redo */
3069  LOG_TDES *tdes; /* Transaction descriptor */
3070  int num_particps; /* Number of participating sites */
3071  int particp_id_length; /* Length of particp_ids block */
3072  void *block_particps_ids; /* A block of participant ids */
3073  int temp_length;
3074  int tran_index;
3075  volatile TRANID tran_id;
3076  volatile LOG_RECTYPE log_rtype;
3077  int i;
3078  int data_header_size = 0;
3079  MVCCID mvccid = MVCCID_NULL;
3080  LOG_ZIP *undo_unzip_ptr = NULL;
3081  LOG_ZIP *redo_unzip_ptr = NULL;
3082  bool is_diff_rec;
3083  bool is_mvcc_op = false;
3084 
3085  aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
3086 
3087  /*
3088  * GO FORWARD, redoing records of all transactions including aborted ones.
3089  *
3090  * Compensating records undo the redo of already executed undo records.
3091  * Transactions that were active at the time of the crash are aborted
3092  * during the log_recovery_undo phase
3093  */
3094 
3095  LSA_COPY (&lsa, start_redolsa);
3096 
3097  /* Defense for illegal start_redolsa */
3098  if ((lsa.offset + (int) sizeof (LOG_RECORD_HEADER)) >= LOGAREA_SIZE)
3099  {
3100  assert (false);
3101  /* move first record of next page */
3102  lsa.pageid++;
3103  lsa.offset = NULL_OFFSET;
3104  }
3105 
3106  log_pgptr = (LOG_PAGE *) aligned_log_pgbuf;
3107 
3108  undo_unzip_ptr = log_zip_alloc (LOGAREA_SIZE);
3109  redo_unzip_ptr = log_zip_alloc (LOGAREA_SIZE);
3110 
3111  if (undo_unzip_ptr == NULL || redo_unzip_ptr == NULL)
3112  {
3113  if (undo_unzip_ptr)
3114  {
3115  log_zip_free (undo_unzip_ptr);
3116  }
3117  if (redo_unzip_ptr)
3118  {
3119  log_zip_free (redo_unzip_ptr);
3120  }
3121  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_redo");
3122  return;
3123  }
3124 
3125  while (!LSA_ISNULL (&lsa))
3126  {
3127  /* Fetch the page where the LSA record to undo is located */
3128  LSA_COPY (&log_lsa, &lsa);
3129  if (logpb_fetch_page (thread_p, &log_lsa, LOG_CS_FORCE_USE, log_pgptr) != NO_ERROR)
3130  {
3131  if (end_redo_lsa != NULL && (LSA_ISNULL (end_redo_lsa) || LSA_GT (&lsa, end_redo_lsa)))
3132  {
3133  goto exit;
3134  }
3135  else
3136  {
3138  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_redo");
3139  return;
3140  }
3141  }
3142 
3143  /* Check all log records in this phase */
3144  while (lsa.pageid == log_lsa.pageid)
3145  {
3146  tdes = NULL;
3147  /*
3148  * Do we want to stop the recovery redo process at this time ?
3149  */
3150  if (end_redo_lsa != NULL && !LSA_ISNULL (end_redo_lsa) && LSA_GT (&lsa, end_redo_lsa))
3151  {
3152  LSA_SET_NULL (&lsa);
3153  break;
3154  }
3155 
3156  /*
3157  * If an offset is missing, it is because we archive an incomplete
3158  * log record. This log_record was completed later. Thus, we have to
3159  * find the offset by searching for the next log_record in the page
3160  */
3161  if (lsa.offset == NULL_OFFSET && (lsa.offset = log_pgptr->hdr.offset) == NULL_OFFSET)
3162  {
3163  /* Continue with next pageid */
3164  if (logpb_is_page_in_archive (log_lsa.pageid))
3165  {
3166  lsa.pageid = log_lsa.pageid + 1;
3167  }
3168  else
3169  {
3170  lsa.pageid = NULL_PAGEID;
3171  }
3172  continue;
3173  }
3174 
3176 
3177  /* Find the log record */
3178  log_lsa.offset = lsa.offset;
3179  log_rec = LOG_GET_LOG_RECORD_HEADER (log_pgptr, &log_lsa);
3180 
3181  tran_id = log_rec->trid;
3182  log_rtype = log_rec->type;
3183 
3184  /* Get the address of next log record to scan */
3185  LSA_COPY (&lsa, &log_rec->forw_lsa);
3186 
3187  /*
3188  * If the next page is NULL_PAGEID and the current page is an archive
3189  * page, this is not the end, this situation happens when an incomplete
3190  * log record is archived. Thus, its forward address is NULL.
3191  * Note that we have to set lsa.pageid here since the log_lsa.pageid value
3192  * can be changed (e.g., the log record is stored in an archive page and
3193  * in an active page. Later, we try to modify it whenever is possible.
3194  */
3195 
3196  if (LSA_ISNULL (&lsa) && logpb_is_page_in_archive (log_lsa.pageid))
3197  {
3198  lsa.pageid = log_lsa.pageid + 1;
3199  }
3200 
3201  if (!LSA_ISNULL (&lsa) && log_lsa.pageid != NULL_PAGEID
3202  && (lsa.pageid < log_lsa.pageid || (lsa.pageid == log_lsa.pageid && lsa.offset <= log_lsa.offset)))
3203  {
3204  /* It seems to be a system error. Maybe a loop in the log */
3205 
3207 
3209  "log_recovery_redo: ** System error: It seems to be a loop in the log\n."
3210  " Current log_rec at %lld|%d. Next log_rec at %lld|%d\n", (long long int) log_lsa.pageid,
3211  log_lsa.offset, (long long int) lsa.pageid, lsa.offset);
3212  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_redo");
3213  LSA_SET_NULL (&lsa);
3214  break;
3215  }
3216 
3217  switch (log_rtype)
3218  {
3221  case LOG_UNDOREDO_DATA:
3223  /* Is diff record type? */
3224  if (log_rtype == LOG_DIFF_UNDOREDO_DATA || log_rtype == LOG_MVCC_DIFF_UNDOREDO_DATA)
3225  {
3226  is_diff_rec = true;
3227  }
3228  else
3229  {
3230  is_diff_rec = false;
3231  }
3232 
3233  /* Does record belong to a MVCC op */
3234  if (log_rtype == LOG_MVCC_UNDOREDO_DATA || log_rtype == LOG_MVCC_DIFF_UNDOREDO_DATA)
3235  {
3236  is_mvcc_op = true;
3237  }
3238  else
3239  {
3240  is_mvcc_op = false;
3241  }
3242 
3243  /* REDO the record if needed */
3244  LSA_COPY (&rcv_lsa, &log_lsa);
3245 
3246  /* Get the DATA HEADER */
3247  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), &log_lsa, log_pgptr);
3248 
3249  if (is_mvcc_op)
3250  {
3251  /* Data header is a MVCC undoredo */
3252  data_header_size = sizeof (LOG_REC_MVCC_UNDOREDO);
3253  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, data_header_size, &log_lsa, log_pgptr);
3254  mvcc_undoredo = (LOG_REC_MVCC_UNDOREDO *) ((char *) log_pgptr->area + log_lsa.offset);
3255 
3256  /* Get undoredo structure */
3257  undoredo = &mvcc_undoredo->undoredo;
3258 
3259  /* Get transaction MVCCID */
3260  mvccid = mvcc_undoredo->mvccid;
3261 
3262  /* Check if MVCC next ID must be updated */
3263  if (!MVCC_ID_PRECEDES (mvccid, log_Gl.hdr.mvcc_next_id))
3264  {
3265  log_Gl.hdr.mvcc_next_id = mvccid;
3267  }
3268  }
3269  else
3270  {
3271  /* Data header is a regular undoredo */
3272  data_header_size = sizeof (LOG_REC_UNDOREDO);
3273  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, data_header_size, &log_lsa, log_pgptr);
3274  undoredo = (LOG_REC_UNDOREDO *) ((char *) log_pgptr->area + log_lsa.offset);
3275 
3276  mvccid = MVCCID_NULL;
3277  }
3278 
3279  if (is_mvcc_op)
3280  {
3281  /* Save last MVCC operation LOG_LSA. */
3282  LSA_COPY (&log_Gl.hdr.mvcc_op_log_lsa, &rcv_lsa);
3283  }
3284 
3285  /* Do we need to redo anything ? */
3286 
3287  /*
3288  * Fetch the page for physical log records and check if redo
3289  * is needed by comparing the log sequence numbers
3290  */
3291 
3292  rcv_vpid.volid = undoredo->data.volid;
3293  rcv_vpid.pageid = undoredo->data.pageid;
3294 
3295  rcv.pgptr = NULL;
3296  rcvindex = undoredo->data.rcvindex;
3297  /* If the page does not exit, there is nothing to redo */
3298  if (rcv_vpid.pageid != NULL_PAGEID && rcv_vpid.volid != NULL_VOLID)
3299  {
3300  rcv.pgptr = log_rv_redo_fix_page (thread_p, &rcv_vpid, rcvindex);
3301  if (rcv.pgptr == NULL)
3302  {
3303  /* deallocated */
3304  break;
3305  }
3306  }
3307 
3308  if (rcv.pgptr != NULL)
3309  {
3310  rcv_page_lsaptr = pgbuf_get_lsa (rcv.pgptr);
3311  /*
3312  * Do we need to execute the redo operation ?
3313  * If page_lsa >= lsa... already updated. In this case make sure
3314  * that the redo is not far from the end_redo_lsa
3315  */
3316  assert (end_redo_lsa == NULL || LSA_ISNULL (end_redo_lsa) || LSA_LE (rcv_page_lsaptr, end_redo_lsa));
3317  if (LSA_LE (&rcv_lsa, rcv_page_lsaptr))
3318  {
3319  /* It is already done */
3320  pgbuf_unfix (thread_p, rcv.pgptr);
3321  break;
3322  }
3323  }
3324  else
3325  {
3326  rcv_page_lsaptr = NULL;
3327  }
3328 
3329  temp_length = undoredo->ulength;
3330 
3331  rcv.length = undoredo->rlength;
3332  rcv.offset = undoredo->data.offset;
3333  rcv.mvcc_id = mvccid;
3334 
3335  LOG_READ_ADD_ALIGN (thread_p, data_header_size, &log_lsa, log_pgptr);
3336 
3337  if (is_diff_rec)
3338  {
3339  /* Get Undo data */
3340  if (!log_rv_get_unzip_log_data (thread_p, temp_length, &log_lsa, log_pgptr, undo_unzip_ptr))
3341  {
3343  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_redo");
3344  }
3345  }
3346  else
3347  {
3348  temp_length = (int) GET_ZIP_LEN (temp_length);
3349  /* Undo Data Pass */
3350  if (log_lsa.offset + temp_length < (int) LOGAREA_SIZE)
3351  {
3352  log_lsa.offset += temp_length;
3353  }
3354  else
3355  {
3356  while (temp_length > 0)
3357  {
3358  if (temp_length + log_lsa.offset >= (int) LOGAREA_SIZE)
3359  {
3360  LOG_LSA fetch_lsa;
3361 
3362  temp_length -= LOGAREA_SIZE - (int) (log_lsa.offset);
3363  assert (log_pgptr != NULL);
3364 
3365  fetch_lsa.pageid = ++log_lsa.pageid;
3366  fetch_lsa.offset = LOG_PAGESIZE;
3367 
3368  if ((logpb_fetch_page (thread_p, &fetch_lsa, LOG_CS_FORCE_USE, log_pgptr)) != NO_ERROR)
3369  {
3371  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_redo");
3372  return;
3373  }
3374  log_lsa.offset = 0;
3375  LOG_READ_ALIGN (thread_p, &log_lsa, log_pgptr);
3376  }
3377  else
3378  {
3379  log_lsa.offset += temp_length;
3380  temp_length = 0;
3381  }
3382  }
3383  }
3384  }
3385 
3386  /* GET AFTER DATA */
3387  LOG_READ_ALIGN (thread_p, &log_lsa, log_pgptr);
3388 #if !defined(NDEBUG)
3390  {
3391  fprintf (stdout,
3392  "TRACE REDOING[1]: LSA = %lld|%d, Rv_index = %s,\n"
3393  " volid = %d, pageid = %d, offset = %d,\n", LSA_AS_ARGS (&rcv_lsa),
3394  rv_rcvindex_string (rcvindex), rcv_vpid.volid, rcv_vpid.pageid, rcv.offset);
3395  if (rcv_page_lsaptr != NULL)
3396  {
3397  fprintf (stdout, " page_lsa = %lld|%d\n", LSA_AS_ARGS (rcv_page_lsaptr));
3398  }
3399  else
3400  {
3401  fprintf (stdout, " page_lsa = %d|%d\n", -1, -1);
3402  }
3403  fflush (stdout);
3404  }
3405 #endif /* !NDEBUG */
3406 
3407  if (is_diff_rec)
3408  {
3409  /* XOR Process */
3410  log_rv_redo_record (thread_p, &log_lsa, log_pgptr, RV_fun[rcvindex].redofun, &rcv, &rcv_lsa,
3411  (int) undo_unzip_ptr->data_length, (char *) undo_unzip_ptr->log_data,
3412  redo_unzip_ptr);
3413  }
3414  else
3415  {
3416  log_rv_redo_record (thread_p, &log_lsa, log_pgptr, RV_fun[rcvindex].redofun, &rcv, &rcv_lsa, 0, NULL,
3417  redo_unzip_ptr);
3418  }
3419  if (rcv.pgptr != NULL)
3420  {
3421  pgbuf_unfix (thread_p, rcv.pgptr);
3422  }
3423  break;
3424 
3425  case LOG_MVCC_REDO_DATA:
3426  case LOG_REDO_DATA:
3427  /* Does log record belong to a MVCC op? */
3428  is_mvcc_op = (log_rtype == LOG_MVCC_REDO_DATA);
3429 
3430  LSA_COPY (&rcv_lsa, &log_lsa);
3431 
3432  /* Get the DATA HEADER */
3433  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), &log_lsa, log_pgptr);
3434 
3435  if (is_mvcc_op)
3436  {
3437  /* Data header is MVCC redo */
3438  data_header_size = sizeof (LOG_REC_MVCC_REDO);
3439  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, data_header_size, &log_lsa, log_pgptr);
3440  mvcc_redo = (LOG_REC_MVCC_REDO *) ((char *) log_pgptr->area + log_lsa.offset);
3441  /* Get redo info */
3442  redo = &mvcc_redo->redo;
3443 
3444  /* Get transaction MVCCID */
3445  mvccid = mvcc_redo->mvccid;
3446 
3447  /* Check if MVCC next ID must be updated */
3448  if (!MVCC_ID_PRECEDES (mvccid, log_Gl.hdr.mvcc_next_id))
3449  {
3450  log_Gl.hdr.mvcc_next_id = mvccid;
3452  }
3453  }
3454  else
3455  {
3456  /* Data header is regular redo */
3457  data_header_size = sizeof (LOG_REC_REDO);
3458  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, data_header_size, &log_lsa, log_pgptr);
3459 
3460  redo = (LOG_REC_REDO *) ((char *) log_pgptr->area + log_lsa.offset);
3461 
3462  mvccid = MVCCID_NULL;
3463  }
3464 
3465  /* Do we need to redo anything ? */
3466 
3467  if (redo->data.rcvindex == RVVAC_COMPLETE)
3468  {
3469  /* Reset log header MVCC info */
3471  }
3472 
3473  /*
3474  * Fetch the page for physical log records and check if redo
3475  * is needed by comparing the log sequence numbers
3476  */
3477 
3478  rcv_vpid.volid = redo->data.volid;
3479  rcv_vpid.pageid = redo->data.pageid;
3480 
3481  rcv.pgptr = NULL;
3482  rcvindex = redo->data.rcvindex;
3483  /* If the page does not exit, there is nothing to redo */
3484  if (rcv_vpid.pageid != NULL_PAGEID && rcv_vpid.volid != NULL_VOLID)
3485  {
3486  rcv.pgptr = log_rv_redo_fix_page (thread_p, &rcv_vpid, rcvindex);
3487  if (rcv.pgptr == NULL)
3488  {
3489  /* deallocated */
3490  break;
3491  }
3492  }
3493 
3494  if (rcv.pgptr != NULL)
3495  {
3496  rcv_page_lsaptr = pgbuf_get_lsa (rcv.pgptr);
3497  /*
3498  * Do we need to execute the redo operation ?
3499  * If page_lsa >= rcv_lsa... already updated
3500  */
3501  assert (end_redo_lsa == NULL || LSA_ISNULL (end_redo_lsa) || LSA_LE (rcv_page_lsaptr, end_redo_lsa));
3502  if (LSA_LE (&rcv_lsa, rcv_page_lsaptr))
3503  {
3504  /* It is already done */
3505  pgbuf_unfix (thread_p, rcv.pgptr);
3506  break;
3507  }
3508  }
3509  else
3510  {
3511  rcv.pgptr = NULL;
3512  rcv_page_lsaptr = NULL;
3513  }
3514 
3515  rcv.length = redo->length;
3516  rcv.offset = redo->data.offset;
3517  rcv.mvcc_id = mvccid;
3518 
3519  LOG_READ_ADD_ALIGN (thread_p, data_header_size, &log_lsa, log_pgptr);
3520 
3521 #if !defined(NDEBUG)
3523  {
3524  fprintf (stdout,
3525  "TRACE REDOING[2]: LSA = %lld|%d, Rv_index = %s,\n"
3526  " volid = %d, pageid = %d, offset = %d,\n", LSA_AS_ARGS (&rcv_lsa),
3527  rv_rcvindex_string (rcvindex), rcv_vpid.volid, rcv_vpid.pageid, rcv.offset);
3528  if (rcv_page_lsaptr != NULL)
3529  {
3530  fprintf (stdout, " page_lsa = %lld|%d\n", LSA_AS_ARGS (rcv_page_lsaptr));
3531  }
3532  else
3533  {
3534  fprintf (stdout, " page_lsa = %lld|%d\n", -1LL, -1);
3535  }
3536  fflush (stdout);
3537  }
3538 #endif /* !NDEBUG */
3539 
3540  log_rv_redo_record (thread_p, &log_lsa, log_pgptr, RV_fun[rcvindex].redofun, &rcv, &rcv_lsa, 0, NULL,
3541  redo_unzip_ptr);
3542 
3543  if (rcv.pgptr != NULL)
3544  {
3545  pgbuf_unfix (thread_p, rcv.pgptr);
3546  }
3547  break;
3548 
3550  LSA_COPY (&rcv_lsa, &log_lsa);
3551 
3552  /* Get the DATA HEADER */
3553  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), &log_lsa, log_pgptr);
3554  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_DBOUT_REDO), &log_lsa, log_pgptr);
3555 
3556  dbout_redo = ((LOG_REC_DBOUT_REDO *) ((char *) log_pgptr->area + log_lsa.offset));
3557 
3558  VPID_SET_NULL (&rcv_vpid);
3559  rcv.offset = -1;
3560  rcv.pgptr = NULL;
3561 
3562  rcvindex = dbout_redo->rcvindex;
3563  rcv.length = dbout_redo->length;
3564 
3565  /* GET AFTER DATA */
3566  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_DBOUT_REDO), &log_lsa, log_pgptr);
3567 
3568 #if !defined(NDEBUG)
3570  {
3571  fprintf (stdout, "TRACE EXT REDOING[3]: LSA = %lld|%d, Rv_index = %s\n", LSA_AS_ARGS (&rcv_lsa),
3572  rv_rcvindex_string (rcvindex));
3573  fflush (stdout);
3574  }
3575 #endif /* !NDEBUG */
3576 
3577  if (!log_recovery_needs_skip_logical_redo (thread_p, tran_id, log_rtype, rcvindex, &rcv_lsa))
3578  {
3579  log_rv_redo_record (thread_p, &log_lsa, log_pgptr, RV_fun[rcvindex].redofun, &rcv, &rcv_lsa, 0, NULL,
3580  NULL);
3581  }
3582 
3583  break;
3584 
3585  case LOG_RUN_POSTPONE:
3586  LSA_COPY (&rcv_lsa, &log_lsa);
3587 
3588  /* Get the DATA HEADER */
3589  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), &log_lsa, log_pgptr);
3590  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_RUN_POSTPONE), &log_lsa, log_pgptr);
3591  run_posp = (LOG_REC_RUN_POSTPONE *) ((char *) log_pgptr->area + log_lsa.offset);
3592 
3593  /* Do we need to redo anything ? */
3594 
3595  /*
3596  * Fetch the page for physical log records and check if redo
3597  * is needed by comparing the log sequence numbers
3598  */
3599 
3600  rcv_vpid.volid = run_posp->data.volid;
3601  rcv_vpid.pageid = run_posp->data.pageid;
3602 
3603  rcv.pgptr = NULL;
3604  rcvindex = run_posp->data.rcvindex;
3605  /* If the page does not exit, there is nothing to redo */
3606  if (rcv_vpid.pageid != NULL_PAGEID && rcv_vpid.volid != NULL_VOLID)
3607  {
3608  rcv.pgptr = log_rv_redo_fix_page (thread_p, &rcv_vpid, rcvindex);
3609  if (rcv.pgptr == NULL)
3610  {
3611  /* deallocated */
3612  break;
3613  }
3614  }
3615 
3616  if (rcv.pgptr != NULL)
3617  {
3618  rcv_page_lsaptr = pgbuf_get_lsa (rcv.pgptr);
3619  /*
3620  * Do we need to execute the redo operation ?
3621  * If page_lsa >= rcv_lsa... already updated
3622  */
3623  assert (end_redo_lsa == NULL || LSA_ISNULL (end_redo_lsa) || LSA_LE (rcv_page_lsaptr, end_redo_lsa));
3624  if (LSA_LE (&rcv_lsa, rcv_page_lsaptr))
3625  {
3626  /* It is already done */
3627  pgbuf_unfix (thread_p, rcv.pgptr);
3628  break;
3629  }
3630  }
3631  else
3632  {
3633  rcv.pgptr = NULL;
3634  rcv_page_lsaptr = NULL;
3635  }
3636 
3637  rcv.length = run_posp->length;
3638  rcv.offset = run_posp->data.offset;
3639 
3640  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_RUN_POSTPONE), &log_lsa, log_pgptr);
3641  /* GET AFTER DATA */
3642  LOG_READ_ALIGN (thread_p, &log_lsa, log_pgptr);
3643 
3644 #if !defined(NDEBUG)
3646  {
3647  fprintf (stdout,
3648  "TRACE REDOING[4]: LSA = %lld|%d, Rv_index = %s,\n"
3649  " volid = %d, pageid = %d, offset = %d,\n", LSA_AS_ARGS (&rcv_lsa),
3650  rv_rcvindex_string (rcvindex), rcv_vpid.volid, rcv_vpid.pageid, rcv.offset);
3651  if (rcv_page_lsaptr != NULL)
3652  {
3653  fprintf (stdout, " page_lsa = %lld|%d\n", LSA_AS_ARGS (rcv_page_lsaptr));
3654  }
3655  else
3656  {
3657  fprintf (stdout, " page_lsa = %lld|%d\n", -1LL, -1);
3658  }
3659  fflush (stdout);
3660  }
3661 #endif /* !NDEBUG */
3662 
3663  log_rv_redo_record (thread_p, &log_lsa, log_pgptr, RV_fun[rcvindex].redofun, &rcv, &rcv_lsa, 0, NULL,
3664  NULL);
3665 
3666  if (rcv.pgptr != NULL)
3667  {
3668  pgbuf_unfix (thread_p, rcv.pgptr);
3669  }
3670  break;
3671 
3672  case LOG_COMPENSATE:
3673  LSA_COPY (&rcv_lsa, &log_lsa);
3674 
3675  /* Get the DATA HEADER */
3676  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), &log_lsa, log_pgptr);
3677  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_COMPENSATE), &log_lsa, log_pgptr);
3678  compensate = (LOG_REC_COMPENSATE *) ((char *) log_pgptr->area + log_lsa.offset);
3679 
3680  /* Do we need to redo anything ? */
3681 
3682  /*
3683  * Fetch the page for physical log records and check if redo
3684  * is needed by comparing the log sequence numbers
3685  */
3686 
3687  rcv_vpid.volid = compensate->data.volid;
3688  rcv_vpid.pageid = compensate->data.pageid;
3689 
3690  rcv.pgptr = NULL;
3691  rcvindex = compensate->data.rcvindex;
3692  /* If the page does not exit, there is nothing to redo */
3693  if (rcv_vpid.pageid != NULL_PAGEID && rcv_vpid.volid != NULL_VOLID)
3694  {
3695  rcv.pgptr = log_rv_redo_fix_page (thread_p, &rcv_vpid, rcvindex);
3696  if (rcv.pgptr == NULL)
3697  {
3698  /* deallocated */
3699  break;
3700  }
3701  }
3702 
3703  if (rcv.pgptr != NULL)
3704  {
3705  rcv_page_lsaptr = pgbuf_get_lsa (rcv.pgptr);
3706  /*
3707  * Do we need to execute the redo operation ?
3708  * If page_lsa >= rcv_lsa... already updated
3709  */
3710  assert (end_redo_lsa == NULL || LSA_ISNULL (end_redo_lsa) || LSA_LE (rcv_page_lsaptr, end_redo_lsa));
3711  if (LSA_LE (&rcv_lsa, rcv_page_lsaptr))
3712  {
3713  /* It is already done */
3714  pgbuf_unfix (thread_p, rcv.pgptr);
3715  break;
3716  }
3717  }
3718  else
3719  {
3720  rcv.pgptr = NULL;
3721  rcv_page_lsaptr = NULL;
3722  }
3723 
3724  rcv.length = compensate->length;
3725  rcv.offset = compensate->data.offset;
3726 
3727  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_COMPENSATE), &log_lsa, log_pgptr);
3728  /* GET COMPENSATING DATA */
3729  LOG_READ_ALIGN (thread_p, &log_lsa, log_pgptr);
3730 #if !defined(NDEBUG)
3732  {
3733  fprintf (stdout,
3734  "TRACE REDOING[5]: LSA = %lld|%d, Rv_index = %s,\n"
3735  " volid = %d, pageid = %d, offset = %d,\n", LSA_AS_ARGS (&rcv_lsa),
3736  rv_rcvindex_string (rcvindex), rcv_vpid.volid, rcv_vpid.pageid, rcv.offset);
3737  if (rcv_page_lsaptr != NULL)
3738  {
3739  fprintf (stdout, " page_lsa = %lld|%d\n", LSA_AS_ARGS (rcv_page_lsaptr));
3740  }
3741  else
3742  {
3743  fprintf (stdout, " page_lsa = %lld|%d\n", -1LL, -1);
3744  }
3745  fflush (stdout);
3746  }
3747 #endif /* !NDEBUG */
3748 
3749  log_rv_redo_record (thread_p, &log_lsa, log_pgptr, RV_fun[rcvindex].undofun, &rcv, &rcv_lsa, 0, NULL,
3750  NULL);
3751  if (rcv.pgptr != NULL)
3752  {
3753  pgbuf_unfix (thread_p, rcv.pgptr);
3754  }
3756  {
3758  "BTREE_REDO: Successfully applied compensate lsa=%lld|%d, undo_nxlsa=%lld|%d.\n",
3759  (long long int) rcv_lsa.pageid, (int) rcv_lsa.offset,
3760  (long long int) compensate->undo_nxlsa.pageid, (int) compensate->undo_nxlsa.offset);
3761  }
3762  break;
3763 
3764  case LOG_2PC_PREPARE:
3765  tran_index = logtb_find_tran_index (thread_p, tran_id);
3766  if (tran_index == NULL_TRAN_INDEX)
3767  {
3768  break;
3769  }
3770  tdes = LOG_FIND_TDES (tran_index);
3771  if (tdes == NULL)
3772  {
3773  break;
3774  }
3775  /*
3776  * The transaction was still alive at the time of crash, therefore,
3777  * the decision of the 2PC is not known. Reacquire the locks
3778  * acquired at the time of the crash
3779  */
3780 
3781  /* Get the DATA HEADER */
3782  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), &log_lsa, log_pgptr);
3783 
3784  if (tdes->state == TRAN_UNACTIVE_2PC_PREPARE)
3785  {
3786  /* The transaction was still prepared_to_commit state at the time of crash. So, read the global
3787  * transaction identifier and list of locks from the log record, and acquire all of the locks. */
3788 
3789  log_2pc_read_prepare (thread_p, LOG_2PC_OBTAIN_LOCKS, tdes, &log_lsa, log_pgptr);
3790  }
3791  else
3792  {
3793  /* The transaction was not in prepared_to_commit state anymore at the time of crash. So, there is no
3794  * need to read the list of locks from the log record. Read only the global transaction from the log
3795  * record. */
3796  log_2pc_read_prepare (thread_p, LOG_2PC_DONT_OBTAIN_LOCKS, tdes, &log_lsa, log_pgptr);
3797  }
3798  break;
3799 
3800  case LOG_2PC_START:
3801  tran_index = logtb_find_tran_index (thread_p, tran_id);
3802  if (tran_index != NULL_TRAN_INDEX)
3803  {
3804  /* The transaction was still alive at the time of crash. */
3805  tdes = LOG_FIND_TDES (tran_index);
3806  if (tdes != NULL && LOG_ISTRAN_2PC (tdes))
3807  {
3808  /* The transaction was still alive at the time of crash. So, copy the coordinator information
3809  * from the log record to the transaction descriptor. */
3810 
3811  /* Get the DATA HEADER */
3812  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), &log_lsa, log_pgptr);
3813 
3814  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_2PC_START), &log_lsa, log_pgptr);
3815  start_2pc = ((LOG_REC_2PC_START *) ((char *) log_pgptr->area + log_lsa.offset));
3816 
3817  /*
3818  * Obtain the participant information
3819  */
3820  tdes->client.set_system_internal_with_user (start_2pc->user_name);
3821  tdes->gtrid = start_2pc->gtrid;
3822 
3823  num_particps = start_2pc->num_particps;
3824  particp_id_length = start_2pc->particp_id_length;
3825  block_particps_ids = malloc (particp_id_length * num_particps);
3826  if (block_particps_ids == NULL)
3827  {
3828  /* Out of memory */
3830  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_redo");
3831  break;
3832  }
3833 
3834  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_2PC_START), &log_lsa, log_pgptr);
3835  LOG_READ_ALIGN (thread_p, &log_lsa, log_pgptr);
3836 
3837  /* Read in the participants info. block from the log */
3838  logpb_copy_from_log (thread_p, (char *) block_particps_ids, particp_id_length * num_particps,
3839  &log_lsa, log_pgptr);
3840 
3841  /* Initialize the coordinator information */
3842  if (log_2pc_alloc_coord_info (tdes, num_particps, particp_id_length, block_particps_ids) == NULL)
3843  {
3845  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_redo");
3846  break;
3847  }
3848 
3849  /* Initialize the acknowledgment vector to 0 since we do not know what acknowledgments have
3850  * already been received. we need to continue reading the log */
3851 
3852  i = sizeof (int) * tdes->coord->num_particps;
3853  if ((tdes->coord->ack_received = (int *) malloc (i)) == NULL)
3854  {
3855  /* Out of memory */
3857  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_redo");
3858  break;
3859  }
3860  for (i = 0; i < tdes->coord->num_particps; i++)
3861  {
3862  tdes->coord->ack_received[i] = false;
3863  }
3864  }
3865  }
3866  break;
3867 
3868  case LOG_2PC_RECV_ACK:
3869  tran_index = logtb_find_tran_index (thread_p, tran_id);
3870  if (tran_index != NULL_TRAN_INDEX)
3871  {
3872  /* The transaction was still alive at the time of crash. */
3873 
3874  tdes = LOG_FIND_TDES (tran_index);
3875  if (tdes != NULL && LOG_ISTRAN_2PC (tdes))
3876  {
3877  /*
3878  * The 2PC_START record should have already been read by this
3879  * time, otherwise, there is an error in the recovery analysis
3880  * phase.
3881  */
3882 #if defined(CUBRID_DEBUG)
3883  if (tdes->coord == NULL || tdes->coord->ack_received == NULL)
3884  {
3886  "log_recovery_redo: SYSTEM ERROR There is likely an error in the recovery"
3887  " analysis phase since coordinator information"
3888  " has not been allocated for transaction = %d with state = %s", tdes->trid,
3889  log_state_string (tdes->state));
3890  break;
3891  }
3892 #endif /* CUBRID_DEBUG */
3893 
3894  /* The transaction was still alive at the time of crash. So, read the participant index from the
3895  * log record and set the acknowledgement flag of that participant. */
3896 
3897  /* Get the DATA HEADER */
3898  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), &log_lsa, log_pgptr);
3899 
3900  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_2PC_PARTICP_ACK), &log_lsa,
3901  log_pgptr);
3902  received_ack = ((LOG_REC_2PC_PARTICP_ACK *) ((char *) log_pgptr->area + log_lsa.offset));
3903  tdes->coord->ack_received[received_ack->particp_index] = true;
3904  }
3905  }
3906  break;
3907 
3908  case LOG_COMMIT:
3909  case LOG_ABORT:
3910  {
3911  bool free_tran = false;
3912 
3913  tran_index = logtb_find_tran_index (thread_p, tran_id);
3914  if (tran_index != NULL_TRAN_INDEX && tran_index != LOG_SYSTEM_TRAN_INDEX)
3915  {
3916  tdes = LOG_FIND_TDES (tran_index);
3917  assert (tdes && tdes->state != TRAN_ACTIVE);
3918  free_tran = true;
3919  }
3920 
3921  if (stopat != NULL && *stopat != -1)
3922  {
3923  /*
3924  * Need to read the donetime record to find out if we need to stop
3925  * the recovery at this point.
3926  */
3927  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), &log_lsa, log_pgptr);
3928  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_DONETIME), &log_lsa, log_pgptr);
3929  donetime = (LOG_REC_DONETIME *) ((char *) log_pgptr->area + log_lsa.offset);
3930 
3931  if (difftime (*stopat, (time_t) donetime->at_time) < 0)
3932  {
3933  /*
3934  * Stop the recovery process at this point
3935  */
3936  LSA_SET_NULL (&lsa);
3937 
3938  /* Commit/abort record was recorded after the stopat recovery time. The transaction needs to
3939  * undo all its changes (log_recovery_undo), so transaction descriptor needs to be kept,
3940  * and transaction state should be changed to aborted. The undo process starts from this
3941  * record's LSA and undoes all previous changes of the transaction
3942  * (See log_find_unilaterally_largest_undo_lsa usage from log_recovery_undo) */
3943  if (tdes != NULL)
3944  {
3946  }
3947  free_tran = false;
3948  }
3949  }
3950  if (free_tran == true)
3951  {
3952  logtb_free_tran_index (thread_p, tran_index);
3953  }
3954  }
3955 
3956  break;
3957 
3958  case LOG_MVCC_UNDO_DATA:
3959  /* Must detect MVCC operations and recover vacuum data buffer. The found operation is not actually
3960  * redone/undone, but it has information that can be used for vacuum. */
3961 
3962  LSA_COPY (&rcv_lsa, &log_lsa);
3963  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), &log_lsa, log_pgptr);
3964  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_MVCC_UNDO), &log_lsa, log_pgptr);
3965  mvcc_undo = (LOG_REC_MVCC_UNDO *) ((char *) log_pgptr->area + log_lsa.offset);
3966  mvccid = mvcc_undo->mvccid;
3967 
3968  /* Check if MVCC next ID must be updated */
3969  if (!MVCC_ID_PRECEDES (mvccid, log_Gl.hdr.mvcc_next_id))
3970  {
3971  log_Gl.hdr.mvcc_next_id = mvccid;
3973  }
3974 
3975  if (is_mvcc_op)
3976  {
3977  /* Save last MVCC operation LOG_LSA. */
3978  LSA_COPY (&log_Gl.hdr.mvcc_op_log_lsa, &rcv_lsa);
3979  }
3980  break;
3981 
3982  case LOG_UNDO_DATA:
3984  case LOG_POSTPONE:
3985  case LOG_WILL_COMMIT:
3988  case LOG_START_CHKPT:
3989  case LOG_END_CHKPT:
3990  case LOG_SAVEPOINT:
3996  case LOG_REPLICATION_DATA:
3999  case LOG_DUMMY_OVF_RECORD:
4000  case LOG_DUMMY_GENERIC:
4001  case LOG_END_OF_LOG:
4003  break;
4004 
4005  case LOG_SYSOP_END:
4006  LSA_COPY (&rcv_lsa, &log_lsa);
4007  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), &log_lsa, log_pgptr);
4008  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_SYSOP_END), &log_lsa, log_pgptr);
4009  sysop_end = ((LOG_REC_SYSOP_END *) ((char *) log_pgptr->area + log_lsa.offset));
4010  if (sysop_end->type == LOG_SYSOP_END_LOGICAL_MVCC_UNDO)
4011  {
4012  LSA_COPY (&log_Gl.hdr.mvcc_op_log_lsa, &rcv_lsa);
4013  }
4014  break;
4015 
4018  default:
4019 #if defined(CUBRID_DEBUG)
4021  "log_recovery_redo: Unknown record type = %d (%s)... May be a system error", log_rtype,
4022  log_to_string (log_rtype));
4023 #endif /* CUBRID_DEBUG */
4025  if (LSA_EQ (&lsa, &log_lsa))
4026  {
4027  LSA_SET_NULL (&lsa);
4028  }
4029  break;
4030  }
4031 
4032  /*
4033  * We can fix the lsa.pageid in the case of log_records without forward
4034  * address at this moment.
4035  */
4036  if (lsa.offset == NULL_OFFSET && lsa.pageid != NULL_PAGEID && lsa.pageid < log_lsa.pageid)
4037  {
4038  lsa.pageid = log_lsa.pageid;
4039  }
4040  }
4041  }
4042 
4043  log_zip_free (undo_unzip_ptr);
4044  log_zip_free (redo_unzip_ptr);
4045 
4047 
4048  /* Abort all atomic system operations that were open when server crashed */
4050 
4051  /* Now finish all postpone operations */
4053 
4054  /* Flush all dirty pages */
4055  logpb_flush_pages_direct (thread_p);
4056 
4057  logpb_flush_header (thread_p);
4058  (void) pgbuf_flush_all (thread_p, NULL_VOLID);
4059 
4060 exit:
4062 
4063  return;
4064 }
4065 
4066 /*
4067  * log_recovery_abort_interrupted_sysop () - find and abort interruped system operation during postpones.
4068  *
4069  * return : void
4070  * thread_p (in) : thread entry
4071  * tdes (in) : transaction descriptor
4072  * postpone_start_lsa (in) : LSA of start postpone (system op or transaction)
4073  */
4074 static void
4075 log_recovery_abort_interrupted_sysop (THREAD_ENTRY * thread_p, LOG_TDES * tdes, const LOG_LSA * postpone_start_lsa)
4076 {
4077  LOG_LSA iter_lsa, prev_lsa;
4078  LOG_RECORD_HEADER logrec_head;
4079  LOG_PAGE *log_page = NULL;
4080  char buffer_log_page[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT];
4081  LOG_LSA last_parent_lsa = LSA_INITIALIZER;
4082 
4085  assert (!LSA_ISNULL (postpone_start_lsa));
4086 
4087  if (LSA_ISNULL (&tdes->undo_nxlsa) || LSA_LE (&tdes->undo_nxlsa, postpone_start_lsa))
4088  {
4089  /* nothing to abort */
4090  return;
4091  }
4092 
4093  log_page = (LOG_PAGE *) PTR_ALIGN (buffer_log_page, MAX_ALIGNMENT);
4094 
4095  /* how it works:
4096  * we can have so-called logical run postpone system operation for some complex cases (e.g. file destroy or
4097  * deallocate). if these operations are interrupted by crash, we must abort them first before finishing the postpone
4098  * phase of system operation or transaction.
4099  *
4100  * normally, all records during the postpone execution are run postpones - physical or logical system operations.
4101  * so to rollback a logical system op during postpone we have to stop at previous run postpone (or at the start of
4102  * postpone if this system op is first). we need to manually search it.
4103  */
4104 
4105  for (iter_lsa = tdes->undo_nxlsa; LSA_GT (&iter_lsa, postpone_start_lsa); iter_lsa = prev_lsa)
4106  {
4107  if (logpb_fetch_page (thread_p, &iter_lsa, LOG_CS_FORCE_USE, log_page) != NO_ERROR)
4108  {
4109  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_abort_interrupted_sysop");
4110  return;
4111  }
4112  logrec_head = *(LOG_RECORD_HEADER *) (log_page->area + iter_lsa.offset);
4113  assert (logrec_head.trid == tdes->trid);
4114 
4115  if (logrec_head.type == LOG_RUN_POSTPONE)
4116  {
4117  /* found run postpone, stop */
4118  last_parent_lsa = iter_lsa;
4119  break;
4120  }
4121  else if (logrec_head.type == LOG_SYSOP_END)
4122  {
4123  /* we need to see why type of system op. */
4124  LOG_LSA read_lsa = iter_lsa;
4125  LOG_REC_SYSOP_END *sysop_end;
4126 
4127  /* skip header */
4128  LOG_READ_ADD_ALIGN (thread_p, sizeof (logrec_head), &read_lsa, log_page);
4129  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (*sysop_end), &read_lsa, log_page);
4130 
4131  sysop_end = (LOG_REC_SYSOP_END *) (log_page->area + read_lsa.offset);
4132  if (sysop_end->type == LOG_SYSOP_END_LOGICAL_RUN_POSTPONE)
4133  {
4134  /* found run postpone, stop */
4135  last_parent_lsa = iter_lsa;
4136  break;
4137  }
4138  else
4139  {
4140  /* go to last parent */
4141  prev_lsa = sysop_end->lastparent_lsa;
4142  }
4143  }
4144  else
4145  {
4146  /* safe-guard: we do not expect postpone starts */
4147  assert (logrec_head.type != LOG_COMMIT_WITH_POSTPONE && logrec_head.type != LOG_SYSOP_START_POSTPONE);
4148 
4149  /* move to previous */
4150  prev_lsa = logrec_head.prev_tranlsa;
4151  }
4152  assert (!LSA_ISNULL (&prev_lsa) && !LSA_EQ (&prev_lsa, &iter_lsa));
4153  }
4154 
4155  if (LSA_ISNULL (&last_parent_lsa))
4156  {
4157  /* no run postpones before system op. stop at start postpone. */
4158  assert (LSA_EQ (&iter_lsa, postpone_start_lsa));
4159  last_parent_lsa = *postpone_start_lsa;
4160  }
4161 
4162  /* simulate system op */
4163  log_sysop_start (thread_p);
4164  /* hack last parent lsa */
4165  tdes->topops.stack[tdes->topops.last].lastparent_lsa = last_parent_lsa;
4166  /* rollback */
4167  log_sysop_abort (thread_p);
4168 }
4169 
4170 /*
4171  * log_recovery_finish_sysop_postpone () - Finish postpone during recovery for one system operation.
4172  *
4173  * return : void
4174  * thread_p (in) : thread entry
4175  * tdes (in) : transaction descriptor
4176  */
4177 static void
4179 {
4180  LOG_LSA first_postpone_to_apply;
4181 
4183  {
4184  /* We need to read the log record for system op start postpone */
4185  LOG_LSA sysop_start_postpone_lsa = tdes->rcv.sysop_start_postpone_lsa;
4186  char log_page_buffer[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT];
4187  LOG_PAGE *log_page = (LOG_PAGE *) PTR_ALIGN (log_page_buffer, MAX_ALIGNMENT);
4188  LOG_REC_SYSOP_START_POSTPONE sysop_start_postpone;
4189  int undo_buffer_size = 0, undo_data_size = 0;
4190  char *undo_buffer = NULL, *undo_data = NULL;
4191 
4192  assert (tdes->topops.last == 0);
4193  assert (!LSA_ISNULL (&sysop_start_postpone_lsa));
4194  LSA_SET_NULL (&first_postpone_to_apply);
4195 
4196  /* first verify it didn't crash in the middle of a run postpone system op */
4197  log_recovery_abort_interrupted_sysop (thread_p, tdes, &sysop_start_postpone_lsa);
4198  assert (tdes->topops.last == 0);
4199 
4200  /* find first postpone */
4201  log_recovery_find_first_postpone (thread_p, &first_postpone_to_apply,
4202  &tdes->topops.stack[tdes->topops.last].posp_lsa, tdes);
4203 
4204  if (!LSA_ISNULL (&first_postpone_to_apply))
4205  {
4206  log_do_postpone (thread_p, tdes, &first_postpone_to_apply);
4207  }
4208  LSA_SET_NULL (&tdes->topops.stack[tdes->topops.last].posp_lsa);
4209 
4210  /* simulate system op commit */
4211  /* we need the data from system op start postpone */
4212  log_page->hdr.logical_pageid = NULL_PAGEID;
4213  if (log_read_sysop_start_postpone (thread_p, &sysop_start_postpone_lsa, log_page, true, &sysop_start_postpone,
4214  &undo_buffer_size, &undo_buffer, &undo_data_size, &undo_data) != NO_ERROR)
4215  {
4216  /* give up */
4217  assert_release (false);
4218  return;
4219  }
4220  /* check this is not a system op postpone during system op postpone */
4221  assert (sysop_start_postpone.sysop_end.type != LOG_SYSOP_END_LOGICAL_RUN_POSTPONE
4222  || !sysop_start_postpone.sysop_end.run_postpone.is_sysop_postpone);
4223 
4224  log_sysop_end_recovery_postpone (thread_p, &sysop_start_postpone.sysop_end, undo_data_size, undo_data);
4225  if (undo_buffer != NULL)
4226  {
4227  /* no longer needed */
4228  db_private_free (thread_p, undo_buffer);
4229  }
4230 
4231  assert (sysop_start_postpone.sysop_end.type != LOG_SYSOP_END_ABORT);
4232  if (sysop_start_postpone.sysop_end.type == LOG_SYSOP_END_LOGICAL_RUN_POSTPONE)
4233  {
4234  if (sysop_start_postpone.sysop_end.run_postpone.is_sysop_postpone)
4235  {
4236  /* this is a system op postpone during system op postpone? should not happen! */
4237  assert (false);
4239  tdes->undo_nxlsa = tdes->tail_lsa;
4240  }
4241  else
4242  {
4243  /* logical run postpone during transaction postpone. */
4245  LSA_SET_NULL (&tdes->undo_nxlsa);
4246 
4247  /* we just finished the run postpone. update tdes->posp_nxlsa */
4248  tdes->posp_nxlsa = sysop_start_postpone.sysop_end.run_postpone.postpone_lsa;
4249  }
4250  }
4251  else if (!LSA_ISNULL (&tdes->rcv.tran_start_postpone_lsa))
4252  {
4253  /* this must be after start postpone */
4254  assert (LSA_LE (&tdes->rcv.tran_start_postpone_lsa, &sysop_start_postpone.sysop_end.lastparent_lsa));
4256 
4257  /* note: this is for nested system operations inside a transaction logical run postpone. this is not really,
4258  * fully correct, covering all cases. however it should work for file_tracker_unregister case.
4259  *
4260  * however, to have a robust recovery in the future, no matter how complicated the nesting of operations,
4261  * we should considering saving previous states.
4262  */
4263  }
4264  else
4265  {
4267  tdes->undo_nxlsa = tdes->tail_lsa;
4268  }
4269 
4270  if (tdes->topops.last >= 0)
4271  {
4272  assert_release (false);
4273  tdes->topops.last = -1;
4274  }
4275  }
4277 }
4278 
4279 /*
4280  * log_recovery_finish_postpone () - Finish postpone during recovery for one
4281  * transaction descriptor.
4282  *
4283  * return : Void.
4284  * thread_p (in) : Thread entry.
4285  * tdes (in) : Transaction descriptor.
4286  */
4287 static void
4289 {
4290  LOG_LSA first_postpone_to_apply;
4291 
4292  if (tdes == NULL || tdes->trid == NULL_TRANID)
4293  {
4294  /* Nothing to do */
4295  return;
4296  }
4297 
4298  /* first finish system op postpone (if the case). */
4299  log_recovery_finish_sysop_postpone (thread_p, tdes);
4300 
4302  {
4303  LSA_SET_NULL (&first_postpone_to_apply);
4304 
4305  assert (tdes->is_active_worker_transaction ());
4307 
4308  /*
4309  * The transaction was the one that was committing
4310  */
4312  {
4313  /* make sure to abort interrupted logical postpone. */
4314  assert (tdes->topops.last == -1);
4316  assert (tdes->topops.last == -1);
4317  /* no more undo */
4318  LSA_SET_NULL (&tdes->undo_nxlsa);
4319  }
4320 
4321  log_recovery_find_first_postpone (thread_p, &first_postpone_to_apply, &tdes->posp_nxlsa, tdes);
4322  if (!LSA_ISNULL (&first_postpone_to_apply))
4323  {
4324  log_do_postpone (thread_p, tdes, &first_postpone_to_apply);
4325  }
4326 
4327  if (tdes->coord == NULL)
4328  { /* If this is a local transaction */
4330  logtb_free_tran_index (thread_p, tdes->tran_index);
4331  }
4332  }
4333  else if (tdes->state == TRAN_UNACTIVE_COMMITTED)
4334  {
4335  if (tdes->coord == NULL)
4336  {
4338  logtb_free_tran_index (thread_p, tdes->tran_index);
4339  }
4340  }
4341 }
4342 
4343 /*
4344  * log_recovery_finish_all_postpone - FINISH COMMITTING TRANSACTIONS WITH
4345  * UNFINISH POSTPONE ACTIONS
4346  *
4347  * return: nothing
4348  *
4349  * NOTE:Finish the committing of transactions which have been declared
4350  * as committed, but not all their postpone actions are done.
4351  * This happens when there is a crash in the middle of a
4352  * log_commit_with_postpone and log_commit.
4353  * This function should be called after the log_recovery_redo
4354  * function.
4355  */
4356 static void
4358 {
4359  // *INDENT-OFF*
4360  int i;
4361  LOG_TDES *tdes_it = NULL; /* Transaction descriptor */
4362 
4363  /* Finish committing transactions with unfinished postpone actions */
4364  thread_p = thread_p != NULL ? thread_p : thread_get_thread_entry_info ();
4365  assert (thread_p->tran_index == LOG_SYSTEM_TRAN_INDEX);
4366 
4367  auto finish_sys_postpone = [&] (LOG_TDES & tdes)
4368  {
4369  log_rv_simulate_runtime_worker (thread_p, &tdes);
4370  log_recovery_finish_postpone (thread_p, &tdes);
4371  log_rv_end_simulation (thread_p);
4372  };
4373 
4374  for (i = 1; i < log_Gl.trantable.num_total_indices; i++)
4375  {
4376  tdes_it = LOG_FIND_TDES (i);
4377  if (tdes_it == NULL || tdes_it->trid == NULL_TRANID)
4378  {
4379  continue;
4380  }
4381  finish_sys_postpone (*tdes_it);
4382  }
4383  log_system_tdes::map_all_tdes (finish_sys_postpone);
4384  // *INDENT-ON*
4385 }
4386 
4387 /*
4388  * log_recovery_abort_all_atomic_sysops () - abort all atomic system operation opened at the moment of the crash
4389  *
4390  * return : void
4391  * thread_p (in) : thread entry
4392  */
4393 static void
4395 {
4396  // *INDENT-OFF*
4397  int i;
4398  LOG_TDES *tdes_it = NULL; /* Transaction descriptor */
4399 
4400  /* Finish committing transactions with unfinished postpone actions */
4401  thread_p = thread_p != NULL ? thread_p : thread_get_thread_entry_info ();
4402  assert (thread_p->tran_index == LOG_SYSTEM_TRAN_INDEX);
4403  auto abort_atomic_func = [&] (LOG_TDES & tdes)
4404  {
4405  log_rv_simulate_runtime_worker (thread_p, &tdes);
4406  log_recovery_abort_atomic_sysop (thread_p, &tdes);
4407  log_rv_end_simulation (thread_p);
4408  };
4409  for (i = 1; i < log_Gl.trantable.num_total_indices; i++)
4410  {
4411  tdes_it = LOG_FIND_TDES (i);
4412  if (tdes_it == NULL || tdes_it->trid == NULL_TRANID)
4413  {
4414  continue;
4415  }
4416  abort_atomic_func (*tdes_it);
4417  }
4418  log_system_tdes::map_all_tdes (abort_atomic_func);
4419  // *INDENT-ON*
4420 }
4421 
4422 /*
4423  * log_recovery_abort_atomic_sysop () - abort all changes down to tdes->rcv.atomic_sysop_start_lsa (where atomic system
4424  * operation starts).
4425  *
4426  * return : void
4427  * thread_p (in) : thread entry
4428  * tdes (in) : transaction descriptor
4429  */
4430 static void
4432 {
4433  char log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT], *aligned_log_pgbuf;
4434  LOG_PAGE *log_pgptr = NULL;
4435  LOG_RECORD_HEADER *log_rec;
4436  LOG_LSA prev_atomic_sysop_start_lsa;
4437 
4438  if (tdes == NULL || tdes->trid == NULL_TRANID)
4439  {
4440  /* Nothing to do */
4441  return;
4442  }
4443 
4444  if (LSA_ISNULL (&tdes->rcv.atomic_sysop_start_lsa))
4445  {
4446  /* no atomic system operation */
4447  return;
4448  }
4449  if (LSA_GE (&tdes->rcv.atomic_sysop_start_lsa, &tdes->undo_nxlsa))
4450  {
4451  /* nothing after tdes->rcv.atomic_sysop_start_lsa */
4452  assert (LSA_EQ (&tdes->rcv.atomic_sysop_start_lsa, &tdes->undo_nxlsa));
4454  er_log_debug (ARG_FILE_LINE, "(trid = %d) Nothing after atomic sysop (%lld|%d), nothing to rollback.\n",
4455  tdes->trid, LSA_AS_ARGS (&tdes->rcv.atomic_sysop_start_lsa));
4456  return;
4457  }
4458  assert (tdes->topops.last <= 0);
4459 
4462  {
4463  /* we have (maybe) the next case:
4464  *
4465  * 1. atomic operation was started.
4466  * 2. nested system operation is started.
4467  * 3. nested operation has postpones.
4468  * 4. nested operation is committed with postpone.
4469  * 5. crash
4470  *
4471  * I am not sure this really happens. It might, and it might be risky to allow it. However, I assume this nested
4472  * operation will not do other complicated operations to mess with other logical operations. I hope at least. */
4473  /* finish postpone of nested system op. */
4475  "(trid = %d) Nested sysop start pospone (%lld|%d) inside atomic sysop (%lld|%d). \n", tdes->trid,
4477  log_recovery_finish_sysop_postpone (thread_p, tdes);
4478  }
4480  {
4481  /* this would be also a nested case, but the other way around:
4482  *
4483  * 1. system op starts.
4484  * 2. system op end with postpone.
4485  * 3. nested atomic system op starts.
4486  * 4. crash.
4487  *
4488  * we first have to abort atomic system op. postpone will be finished later. */
4490  "(trid = %d) Nested atomic sysop (%lld|%d) after sysop start postpone (%lld|%d). \n", tdes->trid,
4492  }
4493  else
4494  {
4495  er_log_debug (ARG_FILE_LINE, "(trid = %d) Atomic sysop (%lld|%d). Rollback. \n", tdes->trid,
4497  }
4498 
4499  /* Get transaction lsa that precede atomic_sysop_start_lsa. */
4500  aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
4501  log_pgptr = (LOG_PAGE *) aligned_log_pgbuf;
4502  if (logpb_fetch_page (thread_p, &tdes->rcv.atomic_sysop_start_lsa, LOG_CS_FORCE_USE, log_pgptr) != NO_ERROR)
4503  {
4504  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_abort_atomic_sysop");
4505  return;
4506  }
4507  log_rec = LOG_GET_LOG_RECORD_HEADER (log_pgptr, &tdes->rcv.atomic_sysop_start_lsa);
4508  LSA_COPY (&prev_atomic_sysop_start_lsa, &log_rec->prev_tranlsa);
4509 
4510  /* rollback. simulate a new system op */
4511  log_sysop_start (thread_p);
4512 
4513  /* hack last parent to stop at transaction lsa that precede atomic_sysop_start_lsa. */
4514  LSA_COPY (&tdes->topops.stack[tdes->topops.last].lastparent_lsa, &prev_atomic_sysop_start_lsa);
4515 
4516  /* rollback */
4517  log_sysop_abort (thread_p);
4518 
4519  assert (tdes->topops.last <= 0);
4520 
4521  /* this is it. reset tdes->rcv.atomic_sysop_start_lsa and we're done. */
4523 }
4524 
4525 /*
4526  * log_recovery_undo - SCAN BACKWARDS UNDOING DATA
4527  *
4528  * return: nothing
4529  *
4530  */
4531 static void
4533 {
4534  LOG_LSA max_undo_lsa; /* LSA of log record to undo */
4535  char log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT], *aligned_log_pgbuf;
4536  LOG_PAGE *log_pgptr = NULL; /* Log page pointer where LSA is located */
4537  LOG_LSA log_lsa;
4538  LOG_RECORD_HEADER *log_rec = NULL; /* Pointer to log record */
4539  LOG_REC_UNDOREDO *undoredo = NULL; /* Undo_redo log record */
4540  LOG_REC_UNDO *undo = NULL; /* Undo log record */
4541  LOG_REC_MVCC_UNDOREDO *mvcc_undoredo = NULL; /* MVCC op Undo_redo log record */
4542  LOG_REC_MVCC_UNDO *mvcc_undo = NULL; /* MVCC op Undo log record */
4543  LOG_REC_COMPENSATE *compensate; /* Compensating log record */
4544  LOG_REC_SYSOP_END *sysop_end; /* Result of top system op */
4545  LOG_RCVINDEX rcvindex; /* Recovery index function */
4546  LOG_RCV rcv; /* Recovery structure */
4547  VPID rcv_vpid; /* VPID of data to recover */
4548  LOG_LSA rcv_lsa; /* Address of redo log record */
4549  LOG_LSA prev_tranlsa; /* prev LSA of transaction */
4550  LOG_TDES *tdes; /* Transaction descriptor */
4551  int tran_index;
4552  int data_header_size = 0;
4553  LOG_ZIP *undo_unzip_ptr = NULL;
4554  bool is_mvcc_op;
4555  volatile TRANID tran_id;
4556  volatile LOG_RECTYPE log_rtype;
4557 
4558  aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
4559 
4560  /*
4561  * Remove from the list of transaction to abort, those that have finished
4562  * when the crash happens, so it does not remain dangling in the transaction
4563  * table.
4564  */
4565 
4566  for (tran_index = 1; tran_index < log_Gl.trantable.num_total_indices; tran_index++)
4567  {
4568  if ((tdes = LOG_FIND_TDES (tran_index)) != NULL && tdes->trid != NULL_TRANID
4570  && LSA_ISNULL (&tdes->undo_nxlsa))
4571  {
4573  logtb_free_tran_index (thread_p, tran_index);
4574  }
4575  }
4576  // *INDENT-OFF*
4577  auto delete_func = [] (const LOG_TDES & tdes)
4578  {
4579  return LSA_ISNULL (&tdes.undo_nxlsa);
4580  };
4582  // *INDENT-ON*
4583 
4584  /*
4585  * GO BACKWARDS, undoing records
4586  */
4587 
4588  /* Find the largest LSA to undo */
4589  log_find_unilaterally_largest_undo_lsa (thread_p, max_undo_lsa);
4590 
4591  log_pgptr = (LOG_PAGE *) aligned_log_pgbuf;
4592 
4593  undo_unzip_ptr = log_zip_alloc (LOGAREA_SIZE);
4594  if (undo_unzip_ptr == NULL)
4595  {
4596  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_undo");
4597  return;
4598  }
4599 
4600  while (!LSA_ISNULL (&max_undo_lsa))
4601  {
4602  /* Fetch the page where the LSA record to undo is located */
4603  LSA_COPY (&log_lsa, &max_undo_lsa);
4604  if (logpb_fetch_page (thread_p, &log_lsa, LOG_CS_FORCE_USE, log_pgptr) != NO_ERROR)
4605  {
4606  log_zip_free (undo_unzip_ptr);
4607 
4608  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_undo");
4609  return;
4610  }
4611 
4612  /* Check all log records in this phase */
4613  while (max_undo_lsa.pageid == log_lsa.pageid)
4614  {
4615  /* Find the log record */
4616  log_lsa.offset = max_undo_lsa.offset;
4617  log_rec = LOG_GET_LOG_RECORD_HEADER (log_pgptr, &log_lsa);
4618 
4619  tran_id = log_rec->trid;
4620  log_rtype = log_rec->type;
4621 
4622  LSA_COPY (&prev_tranlsa, &log_rec->prev_tranlsa);
4623 
4624  if (logtb_is_system_worker_tranid (tran_id))
4625  {
4626  // *INDENT-OFF*
4627  tdes = log_system_tdes::rv_get_tdes (tran_id);
4628  if (tdes == NULL)
4629  {
4630  assert (false);
4631  }
4632  // *INDENT-ON*
4633  }
4634  else
4635  {
4636  /* Active worker transaction */
4637  tran_index = logtb_find_tran_index (thread_p, tran_id);
4638  if (tran_index == NULL_TRAN_INDEX)
4639  {
4640 #if defined(CUBRID_DEBUG)
4641  er_log_debug (ARG_FILE_LINE, "log_recovery_undo: SYSTEM ERROR for log located at %lld|%d\n",
4642  (long long int) log_lsa.pageid, log_lsa.offset);
4643 #endif /* CUBRID_DEBUG */
4644  logtb_free_tran_index_with_undo_lsa (thread_p, &max_undo_lsa);
4645  }
4646  else
4647  {
4648  tdes = LOG_FIND_TDES (tran_index);
4649  if (tdes == NULL)
4650  {
4651  /* This looks like a system error in the analysis phase */
4652 #if defined(CUBRID_DEBUG)
4653  er_log_debug (ARG_FILE_LINE, "log_recovery_undo: SYSTEM ERROR for log located at %lld|%d\n",
4654  (long long int) log_lsa.pageid, log_lsa.offset);
4655 #endif /* CUBRID_DEBUG */
4656  logtb_free_tran_index_with_undo_lsa (thread_p, &max_undo_lsa);
4657  }
4658  }
4659  }
4660 
4661  if (tran_index != NULL_TRAN_INDEX && tdes != NULL)
4662  {
4663  LSA_COPY (&tdes->undo_nxlsa, &prev_tranlsa);
4664 
4665  switch (log_rtype)
4666  {
4669  case LOG_UNDOREDO_DATA:
4671  LSA_COPY (&rcv_lsa, &log_lsa);
4672  /*
4673  * The transaction was active at the time of the crash. The
4674  * transaction is unilaterally aborted by the system
4675  */
4676 
4677  if (log_rtype == LOG_MVCC_UNDOREDO_DATA || log_rtype == LOG_MVCC_DIFF_UNDOREDO_DATA)
4678  {
4679  is_mvcc_op = true;
4680  }
4681  else
4682  {
4683  is_mvcc_op = false;
4684  }
4685 
4686  /* Get the DATA HEADER */
4687  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), &log_lsa, log_pgptr);
4688 
4689  if (is_mvcc_op)
4690  {
4691  data_header_size = sizeof (LOG_REC_MVCC_UNDOREDO);
4692  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, data_header_size, &log_lsa, log_pgptr);
4693  mvcc_undoredo = (LOG_REC_MVCC_UNDOREDO *) ((char *) log_pgptr->area + log_lsa.offset);
4694 
4695  /* Get undoredo info */
4696  undoredo = &mvcc_undoredo->undoredo;
4697 
4698  /* Save transaction MVCCID to recovery */
4699  rcv.mvcc_id = mvcc_undoredo->mvccid;
4700  }
4701  else
4702  {
4703  data_header_size = sizeof (LOG_REC_UNDOREDO);
4704  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, data_header_size, &log_lsa, log_pgptr);
4705  undoredo = (LOG_REC_UNDOREDO *) ((char *) log_pgptr->area + log_lsa.offset);
4706 
4707  rcv.mvcc_id = MVCCID_NULL;
4708  }
4709 
4710  rcvindex = undoredo->data.rcvindex;
4711  rcv.length = undoredo->ulength;
4712  rcv.offset = undoredo->data.offset;
4713  rcv_vpid.volid = undoredo->data.volid;
4714  rcv_vpid.pageid = undoredo->data.pageid;
4715 
4716  LOG_READ_ADD_ALIGN (thread_p, data_header_size, &log_lsa, log_pgptr);
4717 
4718 #if !defined(NDEBUG)
4720  {
4721  fprintf (stdout,
4722  "TRACE UNDOING[1]: LSA = %lld|%d, Rv_index = %s,\n"
4723  " volid = %d, pageid = %d, offset = %d,\n", (long long int) rcv_lsa.pageid,
4724  (int) rcv_lsa.offset, rv_rcvindex_string (rcvindex), rcv_vpid.volid, rcv_vpid.pageid,
4725  rcv.offset);
4726  fflush (stdout);
4727  }
4728 #endif /* !NDEBUG */
4729 
4730  log_rv_undo_record (thread_p, &log_lsa, log_pgptr, rcvindex, &rcv_vpid, &rcv, &rcv_lsa, tdes,
4731  undo_unzip_ptr);
4732  break;
4733 
4734  case LOG_MVCC_UNDO_DATA:
4735  case LOG_UNDO_DATA:
4736  /* Does the record belong to a MVCC op? */
4737  is_mvcc_op = log_rtype == LOG_MVCC_UNDO_DATA;
4738 
4739  LSA_COPY (&rcv_lsa, &log_lsa);
4740  /*
4741  * The transaction was active at the time of the crash. The
4742  * transaction is unilaterally aborted by the system
4743  */
4744 
4745  /* Get the DATA HEADER */
4746  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), &log_lsa, log_pgptr);
4747 
4748  if (is_mvcc_op)
4749  {
4750  data_header_size = sizeof (LOG_REC_MVCC_UNDO);
4751  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, data_header_size, &log_lsa, log_pgptr);
4752  mvcc_undo = (LOG_REC_MVCC_UNDO *) ((char *) log_pgptr->area + log_lsa.offset);
4753 
4754  /* Get undo info */
4755  undo = &mvcc_undo->undo;
4756 
4757  /* Save transaction MVCCID to recovery */
4758  rcv.mvcc_id = mvcc_undo->mvccid;
4759  }
4760  else
4761  {
4762  data_header_size = sizeof (LOG_REC_UNDO);
4763  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, data_header_size, &log_lsa, log_pgptr);
4764  undo = (LOG_REC_UNDO *) ((char *) log_pgptr->area + log_lsa.offset);
4765 
4766  rcv.mvcc_id = MVCCID_NULL;
4767  }
4768 
4769  rcvindex = undo->data.rcvindex;
4770  rcv.length = undo->length;
4771  rcv.offset = undo->data.offset;
4772  rcv_vpid.volid = undo->data.volid;
4773  rcv_vpid.pageid = undo->data.pageid;
4774 
4775  LOG_READ_ADD_ALIGN (thread_p, data_header_size, &log_lsa, log_pgptr);
4776 
4777 #if !defined(NDEBUG)
4779  {
4780  fprintf (stdout,
4781  "TRACE UNDOING[2]: LSA = %lld|%d, Rv_index = %s,\n"
4782  " volid = %d, pageid = %d, offset = %hd,\n", LSA_AS_ARGS (&rcv_lsa),
4783  rv_rcvindex_string (rcvindex), rcv_vpid.volid, rcv_vpid.pageid, rcv.offset);
4784  fflush (stdout);
4785  }
4786 #endif /* !NDEBUG */
4787  log_rv_undo_record (thread_p, &log_lsa, log_pgptr, rcvindex, &rcv_vpid, &rcv, &rcv_lsa, tdes,
4788  undo_unzip_ptr);
4789  break;
4790 
4791  case LOG_REDO_DATA:
4792  case LOG_MVCC_REDO_DATA:
4795  case LOG_POSTPONE:
4796  case LOG_SAVEPOINT:
4797  case LOG_REPLICATION_DATA:
4800  case LOG_DUMMY_OVF_RECORD:
4801  case LOG_DUMMY_GENERIC:
4803  /* Not for UNDO ... */
4804  /* Break switch to go to previous record */
4805  break;
4806 
4807  case LOG_COMPENSATE:
4808  /* Only for REDO .. Go to next undo record Need to read the compensating record to set the next undo
4809  * address. */
4810 
4811  /* Get the DATA HEADER */
4812  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), &log_lsa, log_pgptr);
4813  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_COMPENSATE), &log_lsa, log_pgptr);
4814  compensate = (LOG_REC_COMPENSATE *) ((char *) log_pgptr->area + log_lsa.offset);
4815  LSA_COPY (&prev_tranlsa, &compensate->undo_nxlsa);
4816  break;
4817 
4818  case LOG_SYSOP_END:
4819  /*
4820  * We found a system top operation that should be skipped from
4821  * rollback
4822  */
4823 
4824  /* Read the DATA HEADER */
4825  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), &log_lsa, log_pgptr);
4826  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_SYSOP_END), &log_lsa, log_pgptr);
4827  sysop_end = ((LOG_REC_SYSOP_END *) ((char *) log_pgptr->area + log_lsa.offset));
4828 
4829  if (sysop_end->type == LOG_SYSOP_END_LOGICAL_UNDO)
4830  {
4831  /* execute undo */
4832  rcvindex = sysop_end->undo.data.rcvindex;
4833  rcv.length = sysop_end->undo.length;
4834  rcv.offset = sysop_end->undo.data.offset;
4835  rcv_vpid.volid = sysop_end->undo.data.volid;
4836  rcv_vpid.pageid = sysop_end->undo.data.pageid;
4837  rcv.mvcc_id = MVCCID_NULL;
4838 
4839  /* will jump to parent LSA. save it now before advancing to undo data */
4840  LSA_COPY (&prev_tranlsa, &sysop_end->lastparent_lsa);
4841  LSA_COPY (&tdes->undo_nxlsa, &sysop_end->lastparent_lsa);
4842 
4843  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_SYSOP_END), &log_lsa, log_pgptr);
4844  log_rv_undo_record (thread_p, &log_lsa, log_pgptr, rcvindex, &rcv_vpid, &rcv, &rcv_lsa, tdes,
4845  undo_unzip_ptr);
4846  }
4847  else if (sysop_end->type == LOG_SYSOP_END_LOGICAL_MVCC_UNDO)
4848  {
4849  /* execute undo */
4850  rcvindex = sysop_end->mvcc_undo.undo.data.rcvindex;
4851  rcv.length = sysop_end->mvcc_undo.undo.length;
4852  rcv.offset = sysop_end->mvcc_undo.undo.data.offset;
4853  rcv_vpid.volid = sysop_end->mvcc_undo.undo.data.volid;
4854  rcv_vpid.pageid = sysop_end->mvcc_undo.undo.data.pageid;
4855  rcv.mvcc_id = sysop_end->mvcc_undo.mvccid;
4856 
4857  /* will jump to parent LSA. save it now before advancing to undo data */
4858  LSA_COPY (&prev_tranlsa, &sysop_end->lastparent_lsa);
4859  LSA_COPY (&tdes->undo_nxlsa, &sysop_end->lastparent_lsa);
4860  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_SYSOP_END), &log_lsa, log_pgptr);
4861  log_rv_undo_record (thread_p, &log_lsa, log_pgptr, rcvindex, &rcv_vpid, &rcv, &rcv_lsa, tdes,
4862  undo_unzip_ptr);
4863  }
4864  else if (sysop_end->type == LOG_SYSOP_END_LOGICAL_COMPENSATE)
4865  {
4866  /* compensate */
4867  LSA_COPY (&prev_tranlsa, &sysop_end->compensate_lsa);
4868  }
4869  else
4870  {
4871  /* should not find run postpones on undo recovery */
4873 
4874  /* jump to parent LSA */
4875  LSA_COPY (&prev_tranlsa, &sysop_end->lastparent_lsa);
4876  }
4877  break;
4878 
4879  case LOG_RUN_POSTPONE:
4880  case LOG_WILL_COMMIT:
4882  case LOG_COMMIT:
4884  case LOG_ABORT:
4885  case LOG_START_CHKPT:
4886  case LOG_END_CHKPT:
4887  case LOG_2PC_PREPARE:
4888  case LOG_2PC_START:
4893  case LOG_2PC_RECV_ACK:
4895  case LOG_END_OF_LOG:
4896  /* This looks like a system error in the analysis phase */
4897 #if defined(CUBRID_DEBUG)
4899  "log_recovery_undo: SYSTEM ERROR for log located at %lld|%d,"
4900  " Bad log_rectype = %d\n (%s).\n", (long long int) log_lsa.pageid, log_lsa.offset,
4901  log_rtype, log_to_string (log_rtype));
4902 #endif /* CUBRID_DEBUG */
4903  /* Remove the transaction from the recovery process */
4904  assert (false);
4905 
4906  /* Clear MVCCID */
4907  tdes->mvccinfo.id = MVCCID_NULL;
4908 
4909  if (logtb_is_system_worker_tranid (tran_id))
4910  {
4911  // *INDENT-OFF*
4913  // *INDENT-ON*
4914  }
4915  else
4916  {
4918  logtb_free_tran_index (thread_p, tran_index);
4919  }
4920  tdes = NULL;
4921  break;
4922 
4925  default:
4926 #if defined(CUBRID_DEBUG)
4928  "log_recovery_undo: Unknown record type = %d (%s)\n ... May be a system error",
4929  log_rtype, log_to_string (log_rtype));
4930 #endif /* CUBRID_DEBUG */
4932  assert (false);
4933 
4934  /*
4935  * Remove the transaction from the recovery process
4936  */
4937 
4938  /* Clear MVCCID */
4939  tdes->mvccinfo.id = MVCCID_NULL;
4940 
4941  if (logtb_is_system_worker_tranid (tran_id))
4942  {
4943  // *INDENT-OFF*
4945  // *INDENT-ON*
4946  }
4947  else
4948  {
4950  logtb_free_tran_index (thread_p, tran_index);
4951  }
4952  tdes = NULL;
4953  break;
4954  }
4955 
4956  /* Just in case, it was changed */
4957  if (tdes != NULL)
4958  {
4959  /* Is this the end of transaction? */
4960  if (LSA_ISNULL (&prev_tranlsa))
4961  {
4962  /* Clear MVCCID */
4963  tdes->mvccinfo.id = MVCCID_NULL;
4964 
4965  if (logtb_is_system_worker_tranid (tran_id))
4966  {
4967  // *INDENT-OFF*
4969  // *INDENT-ON*
4970  }
4971  else
4972  {
4973  (void) log_complete (thread_p, tdes, LOG_ABORT, LOG_DONT_NEED_NEWTRID,
4975  logtb_free_tran_index (thread_p, tran_index);
4976  tdes = NULL;
4977  }
4978  }
4979  else
4980  {
4981  /* Update transaction next undo LSA */
4982  LSA_COPY (&tdes->undo_nxlsa, &prev_tranlsa);
4983  }
4984  }
4985  }
4986 
4987  /* Find the next log record to undo */
4988  log_find_unilaterally_largest_undo_lsa (thread_p, max_undo_lsa);
4989  }
4990  }
4991 
4992  log_zip_free (undo_unzip_ptr);
4993 
4994  /* Flush all dirty pages */
4995 
4996  logpb_flush_pages_direct (thread_p);
4997 
4998  logpb_flush_header (thread_p);
4999  (void) pgbuf_flush_all (thread_p, NULL_VOLID);
5000 
5001  return;
5002 }
5003 
5004 /*
5005  * log_recovery_notpartof_archives - REMOVE ARCHIVES THAT ARE NOT PART OF
5006  * DATABASE (USED for PARTIAL RECOVERY)
5007  *
5008  * return: nothing..
5009  *
5010  * start_arv_num(in): Start removing archives at this point.
5011  * info_reason(in): Reason for removal
5012  *
5013  * NOTE: Remove archives that are not part of database any longer.
5014  * This happen when we do partial recovery.
5015  */
5016 static void
5017 log_recovery_notpartof_archives (THREAD_ENTRY * thread_p, int start_arv_num, const char *info_reason)
5018 {
5019  char logarv_name[PATH_MAX]; /* Archive name */
5020  char logarv_name_first[PATH_MAX]; /* Archive name */
5021  int i;
5022  const char *catmsg;
5023  int error_code;
5024 
5025  if (log_Gl.append.vdes != NULL_VOLDES)
5026  {
5027  /*
5028  * Trust the current log header to remove any archives that are not
5029  * needed due to partial recovery
5030  */
5031  for (i = start_arv_num; i <= log_Gl.hdr.nxarv_num - 1; i++)
5032  {
5034  fileio_unformat (thread_p, logarv_name);
5035  }
5036  }
5037  else
5038  {
5039  /*
5040  * We don't know where to stop. Stop when an archive is not in the OS
5041  * This may not be good enough.
5042  */
5043  for (i = start_arv_num; i <= INT_MAX; i++)
5044  {
5046  if (fileio_is_volume_exist (logarv_name) == false)
5047  {
5048  if (i > start_arv_num)
5049  {
5051  }
5052  break;
5053  }
5054  fileio_unformat (thread_p, logarv_name);
5055  }
5056  }
5057 
5058  if (info_reason != NULL)
5059  /*
5060  * Note if start_arv_num == i, we break from the loop and did not remove
5061  * anything
5062  */
5063  if (start_arv_num != i)
5064  {
5065  if (start_arv_num == i - 1)
5066  {
5068  if (catmsg == NULL)
5069  {
5070  catmsg = "REMOVE: %d %s to \n%d %s.\nREASON: %s\n";
5071  }
5072  error_code =
5073  log_dump_log_info (log_Name_info, true, catmsg, start_arv_num, logarv_name, start_arv_num, logarv_name,
5074  info_reason);
5075  if (error_code != NO_ERROR && error_code != ER_LOG_MOUNT_FAIL)
5076  {
5077  return;
5078  }
5079  }
5080  else
5081  {
5082  fileio_make_log_archive_name (logarv_name_first, log_Archive_path, log_Prefix, start_arv_num);
5083 
5085  if (catmsg == NULL)
5086  {
5087  catmsg = "REMOVE: %d %s to \n%d %s.\nREASON: %s\n";
5088  }
5089  error_code =
5090  log_dump_log_info (log_Name_info, true, catmsg, start_arv_num, logarv_name_first, i - 1, logarv_name,
5091  info_reason);
5092  if (error_code != NO_ERROR && error_code != ER_LOG_MOUNT_FAIL)
5093  {
5094  return;
5095  }
5096  }
5097  }
5098 
5099  log_Gl.hdr.last_deleted_arv_num = (start_arv_num == i) ? i : i - 1;
5100 
5101 
5102  if (log_Gl.append.vdes != NULL_VOLDES)
5103  {
5104  logpb_flush_header (thread_p); /* to get rid off archives */
5105  }
5106 
5107 }
5108 
5109 /*
5110  * log_unformat_ahead_volumes -
5111  *
5112  * return:
5113  *
5114  * volid(in):
5115  * start_volid(in):
5116  *
5117  * NOTE:
5118  */
5119 static bool
5120 log_unformat_ahead_volumes (THREAD_ENTRY * thread_p, VOLID volid, VOLID * start_volid)
5121 {
5122  bool result = true;
5123 
5124  if (volid != NULL_VOLID && volid >= *start_volid)
5125  {
5126  /* This volume is not part of the database any longer */
5127  if (pgbuf_invalidate_all (thread_p, volid) != NO_ERROR)
5128  {
5129  result = false;
5130  }
5131  else
5132  {
5133  char *vlabel = fileio_get_volume_label (volid, ALLOC_COPY);
5134  fileio_unformat (thread_p, vlabel);
5135  if (vlabel)
5136  {
5137  free (vlabel);
5138  }
5139  }
5140  }
5141  return result;
5142 }
5143 
5144 /*
5145  * log_recovery_notpartof_volumes -
5146  *
5147  * return:
5148  *
5149  * NOTE:
5150  */
5151 static void
5153 {
5154  const char *ext_path;
5155  const char *ext_name;
5156  int vdes;
5157  VOLID start_volid;
5158  VOLID volid;
5159  char vol_fullname[PATH_MAX];
5160  INT64 vol_dbcreation; /* Database creation time in volume */
5161  char *alloc_extpath = NULL;
5162  int ret = NO_ERROR;
5163 
5164  start_volid = boot_find_next_permanent_volid (thread_p);
5165 
5166  /*
5167  * FIRST: ASSUME VOLUME INFORMATION WAS AHEAD OF US.
5168  * Start removing mounted volumes that are not part of the database any
5169  * longer due to partial recovery point. Note that these volumes were
5170  * mounted before the recovery started.
5171  */
5172 
5173  (void) fileio_map_mounted (thread_p, (bool (*)(THREAD_ENTRY *, VOLID, void *)) log_unformat_ahead_volumes,
5174  &start_volid);
5175 
5176  /*
5177  * SECOND: ASSUME RIGHT VOLUME INFORMATION.
5178  * Remove any volumes that are laying around on disk
5179  */
5180 
5181  /*
5182  * Get the name of the extension: ext_path|dbname|"ext"|volid
5183  */
5184 
5185  /* Use the directory where the primary volume is located */
5186  alloc_extpath = (char *) malloc (PATH_MAX);
5187  if (alloc_extpath != NULL)
5188  {
5189  ext_path = fileio_get_directory_path (alloc_extpath, log_Db_fullname);
5190  if (ext_path == NULL)
5191  {
5192  alloc_extpath[0] = '\0';
5193  ext_path = alloc_extpath;
5194  }
5195  }
5196  else
5197  {
5198  ext_path = ""; /* Pointer to a null terminated string */
5199  }
5200 
5202  /*
5203  * We don't know where to stop. Stop when an archive is not in the OS
5204  */
5205 
5206  for (volid = start_volid; volid < LOG_MAX_DBVOLID; volid++)
5207  {
5208  fileio_make_volume_ext_name (vol_fullname, ext_path, ext_name, volid);
5209  if (fileio_is_volume_exist (vol_fullname) == false)
5210  {
5211  break;
5212  }
5213 
5214  vdes = fileio_mount (thread_p, log_Db_fullname, vol_fullname, volid, false, false);
5215  if (vdes != NULL_VOLDES)
5216  {
5217  ret = disk_get_creation_time (thread_p, volid, &vol_dbcreation);
5218  fileio_dismount (thread_p, vdes);
5219  if (difftime ((time_t) vol_dbcreation, (time_t) log_Gl.hdr.db_creation) != 0)
5220  {
5221  /* This volume does not belong to given database */
5222  ; /* NO-OP */
5223  }
5224  else
5225  {
5226  fileio_unformat (thread_p, vol_fullname);
5227  }
5228  }
5229  }
5230 
5231  if (alloc_extpath)
5232  {
5233  free_and_init (alloc_extpath);
5234  }
5235 
5236  (void) logpb_recreate_volume_info (thread_p);
5237 
5238 }
5239 
5240 static void
5241 log_recovery_resetlog (THREAD_ENTRY * thread_p, const LOG_LSA * new_append_lsa, const LOG_LSA * new_prev_lsa)
5242 {
5243  char newappend_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT];
5244  char *aligned_newappend_pgbuf;
5245  LOG_PAGE *newappend_pgptr = NULL;
5246  int arv_num;
5247  const char *catmsg;
5248  char *catmsg_dup;
5249  int ret = NO_ERROR;
5250 
5251  assert (LOG_CS_OWN_WRITE_MODE (thread_p));
5252  assert (new_prev_lsa != NULL);
5253 
5254  aligned_newappend_pgbuf = PTR_ALIGN (newappend_pgbuf, MAX_ALIGNMENT);
5255 
5257  {
5258  logpb_flush_pages_direct (thread_p);
5259  logpb_invalid_all_append_pages (thread_p);
5260  }
5261 
5262  if (LSA_ISNULL (new_append_lsa))
5263  {
5267  }
5268  else
5269  {
5270  if (log_Gl.append.vdes == NULL_VOLDES
5271  || (log_Gl.hdr.fpageid > new_append_lsa->pageid && new_append_lsa->offset > 0))
5272  {
5273  /*
5274  * We are going to rest the header of the active log to the past.
5275  * Save the content of the new append page since it has to be
5276  * transfered to the new location. This is needed since we may not
5277  * start at location zero.
5278  *
5279  * We need to destroy any log archive created after this point
5280  */
5281 
5282  newappend_pgptr = (LOG_PAGE *) aligned_newappend_pgbuf;
5283 
5284  if ((logpb_fetch_page (thread_p, new_append_lsa, LOG_CS_FORCE_USE, newappend_pgptr)) != NO_ERROR)
5285  {
5286  newappend_pgptr = NULL;
5287  }
5288  }
5289  LOG_RESET_APPEND_LSA (new_append_lsa);
5290  }
5291 
5293  log_Gl.hdr.is_shutdown = false;
5294 
5295  logpb_invalidate_pool (thread_p);
5296 
5298  {
5299  LOG_PAGE *loghdr_pgptr = NULL;
5300  LOG_PAGE *append_pgptr = NULL;
5301 
5302  /*
5303  * Don't have the log active, or we are going to the past
5304  */
5305  arv_num = logpb_get_archive_number (thread_p, log_Gl.hdr.append_lsa.pageid - 1);
5306  if (arv_num == -1)
5307  {
5308  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_resetlog");
5309  return;
5310  }
5311  arv_num = arv_num + 1;
5312 
5314  catmsg_dup = strdup (catmsg);
5315  if (catmsg_dup != NULL)
5316  {
5317  log_recovery_notpartof_archives (thread_p, arv_num, catmsg_dup);
5318  free_and_init (catmsg_dup);
5319  }
5320  else
5321  {
5322  /* NOTE: catmsg..may get corrupted if the function calls the catalog */
5323  log_recovery_notpartof_archives (thread_p, arv_num, catmsg);
5324  }
5325 
5329  log_Gl.hdr.nxarv_num = arv_num;
5332 
5333  if (log_Gl.append.vdes == NULL_VOLDES)
5334  {
5335  /* Create the log active since we do not have one */
5337  if (ret != NO_ERROR)
5338  {
5339  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_resetlog");
5340  return;
5341  }
5342 
5343  log_Gl.append.vdes =
5345  log_get_num_pages_for_creation (-1), false, true, false, LOG_PAGESIZE, 0, false);
5346 
5347  if (log_Gl.append.vdes != NULL_VOLDES)
5348  {
5349  loghdr_pgptr = logpb_create_header_page (thread_p);
5350  }
5351 
5352  if (log_Gl.append.vdes == NULL_VOLDES || loghdr_pgptr == NULL)
5353  {
5354  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_resetlog");
5355  return;
5356  }
5357 
5358  /*
5359  * Flush the header page and first append page so that we can record
5360  * the header page on it
5361  */
5362  if (logpb_flush_page (thread_p, loghdr_pgptr) != NO_ERROR)
5363  {
5364  logpb_fatal_error (thread_p, false, ARG_FILE_LINE, "log_recovery_resetlog");
5365  }
5366  }
5367 
5368  append_pgptr = logpb_create_page (thread_p, log_Gl.hdr.fpageid);
5369  if (append_pgptr == NULL)
5370  {
5371  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_resetlog");
5372  return;
5373  }
5374  if (logpb_flush_page (thread_p, append_pgptr) != NO_ERROR)
5375  {
5376  logpb_fatal_error (thread_p, false, ARG_FILE_LINE, "log_recovery_resetlog");
5377  return;
5378  }
5379  }
5380  else
5381  {
5382  /*
5383  * There is already a log active and the new append location is in the
5384  * current range. Leave the log as it is, just reset the append location.
5385  */
5387  {
5390  }
5391  }
5392 
5393  /*
5394  * Fetch the append page and write it with and end of log mark.
5395  * Then, free the page, same for the header page.
5396  */
5397 
5398  if (logpb_fetch_start_append_page (thread_p) == NO_ERROR)
5399  {
5400  if (newappend_pgptr != NULL && log_Gl.append.log_pgptr != NULL)
5401  {
5402  memcpy ((char *) log_Gl.append.log_pgptr, (char *) newappend_pgptr, LOG_PAGESIZE);
5403  logpb_set_dirty (thread_p, log_Gl.append.log_pgptr);
5404  }
5405  logpb_flush_pages_direct (thread_p);
5406  }
5407 
5408  LOG_RESET_PREV_LSA (new_prev_lsa);
5409 
5411 
5412  // set a flag that active log was reset; some operations may be affected
5414 
5415  logpb_flush_header (thread_p);
5416  logpb_decache_archive_info (thread_p);
5417 
5418  return;
5419 }
5420 
5421 /*
5422  * log_startof_nxrec - FIND START OF NEXT RECORD (USED FOR PARTIAL RECOVERY)
5423  *
5424  * return: lsa or NULL in case of error
5425  *
5426  * lsa(in): Starting address. Set as a side effect to next address
5427  * canuse_forwaddr(in): Use forward address if available
5428  *
5429  * NOTE:Find start address of next record either by looking to forward
5430  * address or by scanning the current record.
5431  */
5432 LOG_LSA *
5433 log_startof_nxrec (THREAD_ENTRY * thread_p, LOG_LSA * lsa, bool canuse_forwaddr)
5434 {
5435  char log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT], *aligned_log_pgbuf;
5436  LOG_PAGE *log_pgptr = NULL; /* Log page pointer where LSA is located */
5437  LOG_LSA log_lsa;
5438  LOG_RECTYPE type; /* Log record type */
5439  LOG_RECORD_HEADER *log_rec; /* Pointer to log record */
5440  LOG_REC_UNDOREDO *undoredo; /* Undo_redo log record */
5441  LOG_REC_UNDO *undo; /* Undo log record */
5442  LOG_REC_REDO *redo; /* Redo log record */
5443  LOG_REC_MVCC_UNDOREDO *mvcc_undoredo; /* MVCC op undo_redo log record */
5444  LOG_REC_MVCC_UNDO *mvcc_undo; /* MVCC op undo log record */
5445  LOG_REC_MVCC_REDO *mvcc_redo; /* MVCC op redo log record */
5446  LOG_REC_DBOUT_REDO *dbout_redo; /* A external redo log record */
5447  LOG_REC_SAVEPT *savept; /* A savepoint log record */
5448  LOG_REC_COMPENSATE *compensate; /* Compensating log record */
5449  LOG_REC_RUN_POSTPONE *run_posp; /* A run postpone action */
5450  LOG_REC_CHKPT *chkpt; /* Checkpoint log record */
5451  LOG_REC_2PC_START *start_2pc; /* A 2PC start log record */
5452  LOG_REC_2PC_PREPCOMMIT *prepared; /* A 2PC prepare to commit */
5453  LOG_REC_REPLICATION *repl_log;
5454 
5455  int undo_length; /* Undo length */
5456  int redo_length; /* Redo length */
5457  unsigned int nobj_locks;
5458  int repl_log_length;
5459  size_t size;
5460 
5461  aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
5462 
5463  if (LSA_ISNULL (lsa))
5464  {
5465  return NULL;
5466  }
5467 
5468  log_pgptr = (LOG_PAGE *) aligned_log_pgbuf;
5469 
5470  if (logpb_fetch_page (thread_p, lsa, LOG_CS_FORCE_USE, log_pgptr) != NO_ERROR)
5471  {
5472  fprintf (stdout, " Error reading page %lld... Quit\n", (long long int) lsa->pageid);
5473  goto error;
5474  }
5475 
5476  /*
5477  * If offset is missing, it is because we archive an incomplete
5478  * log record or we start dumping the log not from its first page. We
5479  * have to find the offset by searching for the next log_record in the page
5480  */
5481  if (lsa->offset == NULL_OFFSET)
5482  {
5483  lsa->offset = log_pgptr->hdr.offset;
5484  if (lsa->offset == NULL_OFFSET)
5485  {
5486  goto error;
5487  }
5488  }
5489 
5490  LSA_COPY (&log_lsa, lsa);
5491  log_rec = LOG_GET_LOG_RECORD_HEADER (log_pgptr, &log_lsa);
5492  type = log_rec->type;
5493 
5494  if (canuse_forwaddr == true)
5495  {
5496  /*
5497  * Use forward address of current log record
5498  */
5499  LSA_COPY (lsa, &log_rec->forw_lsa);
5500  if (LSA_ISNULL (lsa) && logpb_is_page_in_archive (log_lsa.pageid))
5501  {
5502  lsa->pageid = log_lsa.pageid + 1;
5503  }
5504 
5505  if (!LSA_ISNULL (lsa))
5506  {
5507  return lsa;
5508  }
5509  }
5510 
5511  /* Advance the pointer to log_rec data */
5512 
5513  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), &log_lsa, log_pgptr);
5514  switch (type)
5515  {
5516  case LOG_UNDOREDO_DATA:
5518  /* Read the DATA HEADER */
5519  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_UNDOREDO), &log_lsa, log_pgptr);
5520  undoredo = (LOG_REC_UNDOREDO *) ((char *) log_pgptr->area + log_lsa.offset);
5521 
5522  undo_length = (int) GET_ZIP_LEN (undoredo->ulength);
5523  redo_length = (int) GET_ZIP_LEN (undoredo->rlength);
5524 
5525  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_UNDOREDO), &log_lsa, log_pgptr);
5526  LOG_READ_ADD_ALIGN (thread_p, undo_length, &log_lsa, log_pgptr);
5527  LOG_READ_ADD_ALIGN (thread_p, redo_length, &log_lsa, log_pgptr);
5528  break;
5529 
5532  /* Read the DATA HEADER */
5533  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_MVCC_UNDOREDO), &log_lsa, log_pgptr);
5534  mvcc_undoredo = (LOG_REC_MVCC_UNDOREDO *) ((char *) log_pgptr->area + log_lsa.offset);
5535 
5536  undo_length = (int) GET_ZIP_LEN (mvcc_undoredo->undoredo.ulength);
5537  redo_length = (int) GET_ZIP_LEN (mvcc_undoredo->undoredo.rlength);
5538 
5539  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_MVCC_UNDOREDO), &log_lsa, log_pgptr);
5540  LOG_READ_ADD_ALIGN (thread_p, undo_length, &log_lsa, log_pgptr);
5541  LOG_READ_ADD_ALIGN (thread_p, redo_length, &log_lsa, log_pgptr);
5542  break;
5543 
5544  case LOG_UNDO_DATA:
5545  /* Read the DATA HEADER */
5546  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_UNDO), &log_lsa, log_pgptr);
5547  undo = (LOG_REC_UNDO *) ((char *) log_pgptr->area + log_lsa.offset);
5548 
5549  undo_length = (int) GET_ZIP_LEN (undo->length);
5550 
5551  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_UNDO), &log_lsa, log_pgptr);
5552  LOG_READ_ADD_ALIGN (thread_p, undo_length, &log_lsa, log_pgptr);
5553  break;
5554 
5555  case LOG_MVCC_UNDO_DATA:
5556  /* Read the DATA HEADER */
5557  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_MVCC_UNDO), &log_lsa, log_pgptr);
5558  mvcc_undo = (LOG_REC_MVCC_UNDO *) ((char *) log_pgptr->area + log_lsa.offset);
5559 
5560  undo_length = (int) GET_ZIP_LEN (mvcc_undo->undo.length);
5561 
5562  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_MVCC_UNDO), &log_lsa, log_pgptr);
5563  LOG_READ_ADD_ALIGN (thread_p, undo_length, &log_lsa, log_pgptr);
5564  break;
5565 
5566  case LOG_MVCC_REDO_DATA:
5567  /* Read the DATA HEADER */
5568  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_MVCC_REDO), &log_lsa, log_pgptr);
5569  mvcc_redo = (LOG_REC_MVCC_REDO *) ((char *) log_pgptr->area + log_lsa.offset);
5570  redo_length = (int) GET_ZIP_LEN (mvcc_redo->redo.length);
5571 
5572  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_MVCC_REDO), &log_lsa, log_pgptr);
5573  LOG_READ_ADD_ALIGN (thread_p, redo_length, &log_lsa, log_pgptr);
5574  break;
5575 
5576  case LOG_REDO_DATA:
5577  case LOG_POSTPONE:
5578  /* Read the DATA HEADER */
5579  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_REDO), &log_lsa, log_pgptr);
5580  redo = (LOG_REC_REDO *) ((char *) log_pgptr->area + log_lsa.offset);
5581  redo_length = (int) GET_ZIP_LEN (redo->length);
5582 
5583  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_REDO), &log_lsa, log_pgptr);
5584  LOG_READ_ADD_ALIGN (thread_p, redo_length, &log_lsa, log_pgptr);
5585  break;
5586 
5587  case LOG_RUN_POSTPONE:
5588  /* Read the DATA HEADER */
5589  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_RUN_POSTPONE), &log_lsa, log_pgptr);
5590  run_posp = (LOG_REC_RUN_POSTPONE *) ((char *) log_pgptr->area + log_lsa.offset);
5591  redo_length = run_posp->length;
5592 
5593  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_RUN_POSTPONE), &log_lsa, log_pgptr);
5594  LOG_READ_ADD_ALIGN (thread_p, redo_length, &log_lsa, log_pgptr);
5595  break;
5596 
5598  /* Read the data header */
5599  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_DBOUT_REDO), &log_lsa, log_pgptr);
5600  dbout_redo = ((LOG_REC_DBOUT_REDO *) ((char *) log_pgptr->area + log_lsa.offset));
5601  redo_length = dbout_redo->length;
5602 
5603  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_DBOUT_REDO), &log_lsa, log_pgptr);
5604  LOG_READ_ADD_ALIGN (thread_p, redo_length, &log_lsa, log_pgptr);
5605  break;
5606 
5607  case LOG_COMPENSATE:
5608  /* Read the DATA HEADER */
5609  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_COMPENSATE), &log_lsa, log_pgptr);
5610  compensate = (LOG_REC_COMPENSATE *) ((char *) log_pgptr->area + log_lsa.offset);
5611  redo_length = compensate->length;
5612 
5613  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_COMPENSATE), &log_lsa, log_pgptr);
5614  LOG_READ_ADD_ALIGN (thread_p, redo_length, &log_lsa, log_pgptr);
5615  break;
5616 
5618  /* Read the DATA HEADER */
5619  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_START_POSTPONE), &log_lsa, log_pgptr);
5620 
5621  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_START_POSTPONE), &log_lsa, log_pgptr);
5622  break;
5623 
5624  case LOG_COMMIT:
5625  case LOG_ABORT:
5626  /* Read the DATA HEADER */
5627  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_DONETIME), &log_lsa, log_pgptr);
5628 
5629  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_DONETIME), &log_lsa, log_pgptr);
5630  break;
5631 
5633  {
5634  LOG_REC_SYSOP_START_POSTPONE *sysop_start_postpone;
5635  int undo_size = 0;
5636 
5637  /* Read the DATA HEADER */
5638  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_SYSOP_START_POSTPONE), &log_lsa, log_pgptr);
5639  sysop_start_postpone = (LOG_REC_SYSOP_START_POSTPONE *) (log_pgptr->area + log_lsa.offset);
5640  if (sysop_start_postpone->sysop_end.type == LOG_SYSOP_END_LOGICAL_UNDO)
5641  {
5642  undo_size = sysop_start_postpone->sysop_end.undo.length;
5643  }
5644  else if (sysop_start_postpone->sysop_end.type == LOG_SYSOP_END_LOGICAL_MVCC_UNDO)
5645  {
5646  undo_size = sysop_start_postpone->sysop_end.mvcc_undo.undo.length;
5647  }
5648  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_SYSOP_START_POSTPONE), &log_lsa, log_pgptr);
5649  LOG_READ_ADD_ALIGN (thread_p, undo_size, &log_lsa, log_pgptr);
5650  }
5651  break;
5652 
5653  case LOG_SYSOP_END:
5654  {
5655  LOG_REC_SYSOP_END *sysop_end;
5656  int undo_size = 0;
5657 
5658  /* Read the DATA HEADER */
5659  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_SYSOP_END), &log_lsa, log_pgptr);
5660 
5661  sysop_end = (LOG_REC_SYSOP_END *) (log_pgptr->area + log_lsa.offset);
5662 
5663  if (sysop_end->type == LOG_SYSOP_END_LOGICAL_UNDO)
5664  {
5665  undo_size = sysop_end->undo.length;
5666  }
5667  else if (sysop_end->type == LOG_SYSOP_END_LOGICAL_MVCC_UNDO)
5668  {
5669  undo_size = sysop_end->mvcc_undo.undo.length;
5670  }
5671  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_SYSOP_END), &log_lsa, log_pgptr);
5672  }
5673  break;
5674 
5675  case LOG_END_CHKPT:
5676  /* Read the DATA HEADER */
5677  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_CHKPT), &log_lsa, log_pgptr);
5678  chkpt = (LOG_REC_CHKPT *) ((char *) log_pgptr->area + log_lsa.offset);
5679  undo_length = sizeof (LOG_INFO_CHKPT_TRANS) * chkpt->ntrans;
5680  redo_length = sizeof (LOG_INFO_CHKPT_SYSOP) * chkpt->ntops;
5681 
5682  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_CHKPT), &log_lsa, log_pgptr);
5683  LOG_READ_ADD_ALIGN (thread_p, undo_length, &log_lsa, log_pgptr);
5684  if (redo_length > 0)
5685  {
5686  LOG_READ_ADD_ALIGN (thread_p, redo_length, &log_lsa, log_pgptr);
5687  }
5688  break;
5689 
5690  case LOG_SAVEPOINT:
5691  /* Read the DATA HEADER */
5692  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_SAVEPT), &log_lsa, log_pgptr);
5693  savept = (LOG_REC_SAVEPT *) ((char *) log_pgptr->area + log_lsa.offset);
5694  undo_length = savept->length;
5695 
5696  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_SAVEPT), &log_lsa, log_pgptr);
5697  LOG_READ_ADD_ALIGN (thread_p, undo_length, &log_lsa, log_pgptr);
5698  break;
5699 
5700  case LOG_2PC_PREPARE:
5701  /* Get the DATA HEADER */
5702  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_2PC_PREPCOMMIT), &log_lsa, log_pgptr);
5703  prepared = (LOG_REC_2PC_PREPCOMMIT *) ((char *) log_pgptr->area + log_lsa.offset);
5704  nobj_locks = prepared->num_object_locks;
5705  /* ignore npage_locks */
5706 
5707  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_2PC_PREPCOMMIT), &log_lsa, log_pgptr);
5708 
5709  if (prepared->gtrinfo_length > 0)
5710  {
5711  LOG_READ_ADD_ALIGN (thread_p, prepared->gtrinfo_length, &log_lsa, log_pgptr);
5712  }
5713 
5714  if (nobj_locks > 0)
5715  {
5716  size = nobj_locks * sizeof (LK_ACQOBJ_LOCK);
5717  LOG_READ_ADD_ALIGN (thread_p, (INT16) size, &log_lsa, log_pgptr);
5718  }
5719  break;
5720 
5721  case LOG_2PC_START:
5722  /* Get the DATA HEADER */
5723  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_2PC_START), &log_lsa, log_pgptr);
5724  start_2pc = (LOG_REC_2PC_START *) ((char *) log_pgptr->area + log_lsa.offset);
5725 
5726  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_2PC_START), &log_lsa, log_pgptr);
5727  LOG_READ_ADD_ALIGN (thread_p, (start_2pc->particp_id_length * start_2pc->num_particps), &log_lsa, log_pgptr);
5728  break;
5729 
5730  case LOG_2PC_RECV_ACK:
5731  /* Get the DATA HEADER */
5732  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_2PC_PARTICP_ACK), &log_lsa, log_pgptr);
5733 
5734  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_2PC_PARTICP_ACK), &log_lsa, log_pgptr);
5735  break;
5736 
5737  case LOG_WILL_COMMIT:
5738  case LOG_START_CHKPT:
5745  case LOG_DUMMY_OVF_RECORD:
5746  case LOG_DUMMY_GENERIC:
5747  case LOG_END_OF_LOG:
5749  break;
5750 
5751  case LOG_REPLICATION_DATA:
5753  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_REPLICATION), &log_lsa, log_pgptr);
5754 
5755  repl_log = (LOG_REC_REPLICATION *) ((char *) log_pgptr->area + log_lsa.offset);
5756  repl_log_length = (int) GET_ZIP_LEN (repl_log->length);
5757 
5758  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_REPLICATION), &log_lsa, log_pgptr);
5759  LOG_READ_ADD_ALIGN (thread_p, repl_log_length, &log_lsa, log_pgptr);
5760  break;
5761 
5763  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_HA_SERVER_STATE), &log_lsa, log_pgptr);
5764  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_REC_HA_SERVER_STATE), &log_lsa, log_pgptr);
5765  break;
5766 
5769  default:
5770  break;
5771  }
5772 
5773  /* Make sure you point to beginning of a next record */
5774  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_RECORD_HEADER), &log_lsa, log_pgptr);
5775 
5776  LSA_COPY (lsa, &log_lsa);
5777 
5778  return lsa;
5779 
5780 error:
5781 
5782  return NULL;
5783 }
5784 
5785 /*
5786  * log_recovery_find_first_postpone -
5787  * Find the first postpone log lsa to be applied.
5788  *
5789  * return: error code
5790  *
5791  * ret_lsa(out):
5792  * start_postpone_lsa(in):
5793  * tdes(in):
5794  *
5795  */
5796 static int
5797 log_recovery_find_first_postpone (THREAD_ENTRY * thread_p, LOG_LSA * ret_lsa, LOG_LSA * start_postpone_lsa,
5798  LOG_TDES * tdes)
5799 {
5800  LOG_LSA end_postpone_lsa;
5801  LOG_LSA start_seek_lsa;
5802  LOG_LSA *end_seek_lsa;
5803  LOG_LSA next_start_seek_lsa;
5804  LOG_LSA log_lsa;
5805  LOG_LSA forward_lsa;
5806  LOG_LSA next_postpone_lsa;
5807  LOG_LSA local_start_postpone_run_lsa;
5808  LOG_REC_RUN_POSTPONE *run_posp;
5809 
5810  char log_pgbuf[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT];
5811  char *aligned_log_pgbuf;
5812  LOG_PAGE *log_pgptr = NULL;
5813  LOG_RECORD_HEADER *log_rec;
5814  bool isdone;
5815 
5817  LOG_TOPOP_RANGE *nxtop_stack = NULL;
5818  LOG_TOPOP_RANGE *nxtop_range = NULL;
5819  int nxtop_count = 0;
5820  bool start_postpone_lsa_wasapplied = false;
5821 
5822  assert (ret_lsa && start_postpone_lsa && tdes);
5823 
5824  LSA_SET_NULL (ret_lsa);
5825 
5826  if (log_is_in_crash_recovery () == false
5829  {
5830  assert (0);
5831  return ER_FAILED;
5832  }
5833 
5834  if (LSA_ISNULL (start_postpone_lsa))
5835  {
5836  return NO_ERROR;
5837  }
5838 
5839  LSA_SET_NULL (&next_postpone_lsa);
5840 
5841  aligned_log_pgbuf = PTR_ALIGN (log_pgbuf, MAX_ALIGNMENT);
5842  log_pgptr = (LOG_PAGE *) aligned_log_pgbuf;
5843 
5844  LSA_COPY (&end_postpone_lsa, &tdes->tail_lsa);
5845  LSA_COPY (&next_start_seek_lsa, start_postpone_lsa);
5846 
5847  nxtop_stack = nxtop_array;
5848  nxtop_count = log_get_next_nested_top (thread_p, tdes, start_postpone_lsa, &nxtop_stack);
5849 
5850  while (!LSA_ISNULL (&next_start_seek_lsa))
5851  {
5852  LSA_COPY (&start_seek_lsa, &next_start_seek_lsa);
5853 
5854  if (nxtop_count > 0)
5855  {
5856  nxtop_count--;
5857  nxtop_range = &(nxtop_stack[nxtop_count]);
5858 
5859  if (LSA_LT (&start_seek_lsa, &(nxtop_range->start_lsa)))
5860  {
5861  end_seek_lsa = &(nxtop_range->start_lsa);
5862  LSA_COPY (&next_start_seek_lsa, &(nxtop_range->end_lsa));
5863  }
5864  else if (LSA_EQ (&start_seek_lsa, &(nxtop_range->end_lsa)))
5865  {
5866  end_seek_lsa = &end_postpone_lsa;
5867  LSA_SET_NULL (&next_start_seek_lsa);
5868  }
5869  else
5870  {
5871  LSA_COPY (&next_start_seek_lsa, &(nxtop_range->end_lsa));
5872  continue;
5873  }
5874  }
5875  else
5876  {
5877  end_seek_lsa = &end_postpone_lsa;
5878  LSA_SET_NULL (&next_start_seek_lsa);
5879  }
5880 
5881  /*
5882  * Start doing postpone operation for this range
5883  */
5884 
5885  LSA_COPY (&forward_lsa, &start_seek_lsa);
5886 
5887  isdone = false;
5888  while (!LSA_ISNULL (&forward_lsa) && !isdone)
5889  {
5890  /* Fetch the page where the postpone LSA record is located */
5891  LSA_COPY (&log_lsa, &forward_lsa);
5892  if (logpb_fetch_page (thread_p, &log_lsa, LOG_CS_FORCE_USE, log_pgptr) != NO_ERROR)
5893  {
5894  logpb_fatal_error (thread_p, true, ARG_FILE_LINE, "log_recovery_find_first_postpone");
5895  goto end;
5896  }
5897 
5898  while (forward_lsa.pageid == log_lsa.pageid && !isdone)
5899  {
5900  if (LSA_GT (&forward_lsa, end_seek_lsa))
5901  {
5902  /* Finish at this point */
5903  isdone = true;
5904  break;
5905  }
5906  /*
5907  * If an offset is missing, it is because we archive an incomplete
5908  * log record. This log_record was completed later.
5909  * Thus, we have to find the offset by searching
5910  * for the next log_record in the page.
5911  */
5912  if (forward_lsa.offset == NULL_OFFSET)
5913  {
5914  forward_lsa.offset = log_pgptr->hdr.offset;
5915  if (forward_lsa.offset == NULL_OFFSET)
5916  {
5917  /* Continue at next pageid */
5918  if (logpb_is_page_in_archive (log_lsa.pageid))
5919  {
5920  forward_lsa.pageid = log_lsa.pageid + 1;
5921  }
5922  else
5923  {
5924  forward_lsa.pageid = NULL_PAGEID;
5925  }
5926  continue;
5927  }
5928  }
5929 
5930  log_lsa.offset = forward_lsa.offset;
5931  log_rec = LOG_GET_LOG_RECORD_HEADER (log_pgptr, &log_lsa);
5932 
5933  /* Find the next log record in the log */
5934  LSA_COPY (&forward_lsa, &log_rec->forw_lsa);
5935 
5936  if (forward_lsa.pageid == NULL_PAGEID && logpb_is_page_in_archive (log_lsa.pageid))
5937  {
5938  forward_lsa.pageid = log_lsa.pageid + 1;
5939  }
5940 
5941  if (log_rec->trid == tdes->trid)
5942  {
5943  switch (log_rec->type)
5944  {
5945  case LOG_RUN_POSTPONE:
5946  LSA_COPY (&local_start_postpone_run_lsa, &log_lsa);
5947  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), &log_lsa, log_pgptr);
5948 
5949  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_RUN_POSTPONE), &log_lsa, log_pgptr);
5950 
5951  run_posp = (LOG_REC_RUN_POSTPONE *) ((char *) log_pgptr->area + log_lsa.offset);
5952 
5953  if (LSA_EQ (start_postpone_lsa, &run_posp->ref_lsa))
5954  {
5955  /* run_postpone_log of start_postpone is found, next_postpone_lsa is the first postpone to be
5956  * applied. */
5957 
5958  start_postpone_lsa_wasapplied = true;
5959  isdone = true;
5960  }
5961  break;
5962 
5963  case LOG_SYSOP_END:
5964  {
5965  LOG_REC_SYSOP_END *sysop_end = NULL;
5966 
5967  LOG_READ_ADD_ALIGN (thread_p, sizeof (LOG_RECORD_HEADER), &log_lsa, log_pgptr);
5968  LOG_READ_ADVANCE_WHEN_DOESNT_FIT (thread_p, sizeof (LOG_REC_SYSOP_END), &log_lsa, log_pgptr);
5969 
5970  sysop_end = (LOG_REC_SYSOP_END *) (log_pgptr->area + log_lsa.offset);
5971  if (sysop_end->type == LOG_SYSOP_END_LOGICAL_RUN_POSTPONE)
5972  {
5973  LSA_COPY (&local_start_postpone_run_lsa, &log_lsa);
5974 
5975  if (LSA_EQ (start_postpone_lsa, &sysop_end->run_postpone.postpone_lsa))
5976  {
5977  start_postpone_lsa_wasapplied = true;
5978  isdone = true;
5979  }
5980  }
5981  }
5982  break;
5983 
5984  case LOG_POSTPONE:
5985  if (LSA_ISNULL (&next_postpone_lsa) && !LSA_EQ (start_postpone_lsa, &log_lsa))
5986  {
5987  /* remember next postpone_lsa */
5988  LSA_COPY (&next_postpone_lsa, &log_lsa);
5989  }
5990  break;
5991 
5992  case LOG_END_OF_LOG:
5993  if (forward_lsa.pageid == NULL_PAGEID && logpb_is_page_in_archive (log_lsa.pageid))
5994  {
5995  forward_lsa.pageid = log_lsa.pageid + 1;
5996  }
5997  break;
5998 
5999  default:
6000  break;
6001  }
6002  }
6003 
6004  /*
6005  * We can fix the lsa.pageid in the case of log_records without
6006  * forward address at this moment.
6007  */
6008 
6009  if (forward_lsa.offset == NULL_OFFSET && forward_lsa.pageid != NULL_PAGEID
6010  && forward_lsa.pageid < log_lsa.pageid)
6011  {
6012  forward_lsa.pageid = log_lsa.pageid;
6013  }
6014  }
6015  }
6016  }
6017 
6018 end:
6019  if (nxtop_stack != nxtop_array && nxtop_stack != NULL)
6020  {
6021  free_and_init (nxtop_stack);
6022  }
6023 
6024  if (start_postpone_lsa_wasapplied == false)
6025  {
6026  LSA_COPY (ret_lsa, start_postpone_lsa);
6027  }
6028  else
6029  {
6030  LSA_COPY (ret_lsa, &next_postpone_lsa);
6031  }
6032 
6033  return NO_ERROR;
6034 }
6035 
6036 /*
6037  * log_rv_undoredo_partial_changes_recursive () - Parse log data recursively
6038  * and apply changes.
6039  *
6040  * return : Error code.
6041  * thread_p (in) : Thread entry.
6042  * rcv_buf (in) : Buffer to process log data.
6043  * record (in) : Record being modified.
6044  * is_undo (in) : True for undo, false for redo.
6045  *
6046  * NOTE: The recursive function is applied for both undo and redo data.
6047  * Changes are logged in the order they are made during runtime.
6048  * Redo will apply all changes in the same order, but undo will have
6049  * to apply them in reversed order.
6050  */
6051 static int
6052 log_rv_undoredo_partial_changes_recursive (THREAD_ENTRY * thread_p, OR_BUF * rcv_buf, RECDES * record, bool is_undo)
6053 {
6054  int error_code = NO_ERROR; /* Error code. */
6055  int offset_to_data; /* Offset to data being modified. */
6056  int old_data_size; /* Size of old data. */
6057  int new_data_size; /* Size of new data. */
6058  char *new_data = NULL; /* New data. */
6059 
6060  if (rcv_buf->ptr == rcv_buf->endptr)
6061  {
6062  /* Finished. */
6063  return NO_ERROR;
6064  }
6065 
6066  /* At least offset_to_data, old_data_size and new_data_size should be stored. */
6067  if (rcv_buf->ptr + OR_SHORT_SIZE + 2 * OR_BYTE_SIZE > rcv_buf->endptr)
6068  {
6069  assert_release (false);
6070  return or_overflow (rcv_buf);
6071  }
6072 
6073  /* Get offset_to_data. */
6074  offset_to_data = (int) or_get_short (rcv_buf, &error_code);
6075  if (error_code != NO_ERROR)
6076  {
6077  assert_release (false);
6078  return error_code;
6079  }
6080 
6081  /* Get old_data_size */
6082  old_data_size = (int) or_get_byte (rcv_buf, &error_code);
6083  if (error_code != NO_ERROR)
6084  {
6085  assert_release (false);
6086  return error_code;
6087  }
6088 
6089  /* Get new_data_size */
6090  new_data_size = (int) or_get_byte (rcv_buf, &error_code);
6091  if (error_code != NO_ERROR)
6092  {
6093  assert_release (false);
6094  return error_code;
6095  }
6096 
6097  if (new_data_size > 0)
6098  {
6099  /* Get new data. */
6100  new_data = rcv_buf->ptr;
6101  error_code = or_advance (rcv_buf, new_data_size);
6102  if (error_code != NO_ERROR)
6103  {
6104  assert_release (false);
6105  return error_code;
6106  }
6107  }
6108  else
6109  {
6110  /* No new data. */
6111  new_data = NULL;
6112  }
6113 
6114  /* Align buffer to expected alignment. */
6115  or_align (rcv_buf, INT_ALIGNMENT);
6116 
6117  if (!is_undo)
6118  {
6119  /* Changes must be applied in the same order they are logged. Change record and then advance to next changes. */
6120  RECORD_REPLACE_DATA (record, offset_to_data, old_data_size, new_data_size, new_data);
6121  }
6122  error_code = log_rv_undoredo_partial_changes_recursive (thread_p, rcv_buf, record, is_undo);
6123  if (error_code != NO_ERROR)
6124  {
6125  assert_release (false);
6126  return error_code;
6127  }
6128  if (is_undo)
6129  {
6130  /* Changes must be made in reversed order. Change record after advancing to next changes. */
6131  RECORD_REPLACE_DATA (record, offset_to_data, old_data_size, new_data_size, new_data);
6132  }
6133  return NO_ERROR;
6134 }
6135 
6136 /*
6137  * log_rv_undoredo_record_partial_changes () - Undoredo record data changes.
6138  *
6139  * return : Error code.
6140  * thread_p (in) : Thread entry.
6141  * rcv_data (in) : Recovery data pointer.
6142  * rcv_data_length (in) : Recovery data length.
6143  * record (in) : Record being modified.
6144  *
6145  * TODO: Extend this to undo and undoredo.
6146  */
6147 int
6148 log_rv_undoredo_record_partial_changes (THREAD_ENTRY * thread_p, char *rcv_data, int rcv_data_length, RECDES * record,
6149  bool is_undo)
6150 {
6151  OR_BUF rcv_buf; /* Buffer used to process recovery data. */
6152 
6153  /* Assert expected arguments. */
6154  assert (rcv_data != NULL);
6155  assert (rcv_data_length > 0);
6156  assert (record != NULL);
6157 
6158  /* Prepare buffer. */
6159  OR_BUF_INIT (rcv_buf, rcv_data, rcv_data_length);
6160 
6161  return log_rv_undoredo_partial_changes_recursive (thread_p, &rcv_buf, record, is_undo);
6162 }
6163 
6164 /*
6165  * log_rv_redo_record_modify () - Modify one record of database slotted page.
6166  * The change can be one of:
6167  * 1. New record is inserted.
6168  * 2. Existing record is removed.
6169  * 3. Existing record is entirely updated.
6170  * 4. Existing record is partially updated.
6171  *
6172  * return : Error code.
6173  * thread_p (in) : Thread entry.
6174  * rcv (in) : Recovery data.
6175  */
6176 int
6178 {
6179  return log_rv_record_modify_internal (thread_p, rcv, false);
6180 }
6181 
6182 /*
6183  * log_rv_undo_record_modify () - Modify one record of database slotted page.
6184  * The change can be one of:
6185  * 1. New record is inserted.
6186  * 2. Existing record is removed.
6187  * 3. Existing record is entirely updated.
6188  * 4. Existing record is partially updated.
6189  *
6190  * return : Error code.
6191  * thread_p (in) : Thread entry.
6192  * rcv (in) : Recovery data.
6193  */
6194 int
6196 {
6197  return log_rv_record_modify_internal (thread_p, rcv, true);
6198 }
6199 
6200 /*
6201  * log_rv_redo_record_modify () - Modify one record of database slotted page.
6202  * The change can be one of:
6203  * 1. New record is inserted.
6204  * 2. Existing record is removed.
6205  * 3. Existing record is entirely updated.
6206  * 4. Existing record is partially updated.
6207  *
6208  * return : Error code.
6209  * thread_p (in) : Thread entry.
6210  * rcv (in) : Recovery data.
6211  * is_undo (in) : True if undo recovery, false if redo recovery.
6212  */
6213 static int
6214 log_rv_record_modify_internal (THREAD_ENTRY * thread_p, LOG_RCV * rcv, bool is_undo)
6215 {
6216  INT16 flags = rcv->offset & LOG_RV_RECORD_MODIFY_MASK;
6217  PGSLOTID slotid = rcv->offset & (~LOG_RV_RECORD_MODIFY_MASK);
6218  RECDES record;
6219  char data_buffer[IO_MAX_PAGE_SIZE + MAX_ALIGNMENT];
6220  char *ptr = NULL;
6221  int error_code = NO_ERROR;
6222 
6223  if ((!is_undo && LOG_RV_RECORD_IS_INSERT (flags)) || (is_undo && LOG_RV_RECORD_IS_DELETE (flags)))
6224  {
6225  /* Insert new record. */
6226  ptr = (char *) rcv->data;
6227  /* Get record type. */
6228  record.type = OR_GET_BYTE (ptr);
6229  ptr += OR_BYTE_SIZE;
6230  /* Get record data. */
6231  record.data = ptr;
6232  record.length = rcv->length - CAST_BUFLEN (ptr - rcv->data);
6233  if (spage_insert_at (thread_p, rcv->pgptr, slotid, &record) != SP_SUCCESS)
6234  {
6235  /* Unexpected. */
6236  assert_release (false);
6237  return ER_FAILED;
6238  }
6239  /* Success. */
6240  }
6241  else if ((!is_undo && LOG_RV_RECORD_IS_DELETE (flags)) || (is_undo && LOG_RV_RECORD_IS_INSERT (flags)))
6242  {
6243  if (spage_delete (thread_p, rcv->pgptr, slotid) != slotid)
6244  {
6245  assert_release (false);
6246  return ER_FAILED;
6247  }
6248  /* Success. */
6249  }
6250  else if (LOG_RV_RECORD_IS_UPDATE_ALL (flags))
6251  {
6252  ptr = (char *) rcv->data;
6253  /* Get record type. */
6254  record.type = OR_GET_BYTE (ptr);
6255  ptr += OR_BYTE_SIZE;
6256  /* Get record data. */
6257  record.data = ptr;
6258  record.length = rcv->length - CAST_BUFLEN (ptr - rcv->data);
6259  if (spage_update (thread_p, rcv->pgptr, slotid, &record) != SP_SUCCESS)
6260  {
6261  assert_release (false);
6262  return ER_FAILED;
6263  }
6264  /* Success */
6265  }
6266  else
6267  {
6269  /* Limited changes are done to record and updating it entirely is not the most efficient way of using log-space.
6270  * Only the change is logged (change location, old data size, new data size, new data). */
6271  /* Copy existing record. */
6272  record.data = PTR_ALIGN (data_buffer, MAX_ALIGNMENT);
6273  record.area_size = DB_PAGESIZE;
6274  if (spage_get_record (thread_p, rcv->pgptr, slotid, &record, COPY) != S_SUCCESS)
6275  {
6276  /* Unexpected failure. */
6277  assert_release (false);
6278  return ER_FAILED;
6279  }
6280  /* Make recorded changes. */
6281  error_code = log_rv_undoredo_record_partial_changes (thread_p, (char *) rcv->data, rcv->length, &record, is_undo);
6282  if (error_code != NO_ERROR)
6283  {
6284  assert_release (false);
6285  return error_code;
6286  }
6287 
6288  /* Update in page. */
6289  if (spage_update (thread_p, rcv->pgptr, slotid, &record) != SP_SUCCESS)
6290  {
6291  /* Unexpected. */
6292  assert_release (false);
6293  return error_code;
6294  }
6295  /* Success. */
6296  }
6297  /* Page was successfully modified. */
6298  pgbuf_set_dirty (thread_p, rcv->pgptr, DONT_FREE);
6299  return NO_ERROR;
6300 }
6301 
6302 /*
6303  * log_rv_pack_redo_record_changes () - Pack recovery data for redo record
6304  * change.
6305  *
6306  * return : Error code.
6307  * ptr (in) : Where recovery data is packed.
6308  * offset_to_data (in) : Offset to data being modified.
6309  * old_data_size (in) : Old data size.
6310  * new_data_size (in) : New data size.
6311  * new_data (in) : New data.
6312  */
6313 char *
6314 log_rv_pack_redo_record_changes (char *ptr, int offset_to_data, int old_data_size, int new_data_size, char *new_data)
6315 {
6316  /* Assert expected arguments. */
6317  assert (ptr != NULL);
6318  assert (offset_to_data >= 0 && offset_to_data <= 0x8FFF);
6319  assert (old_data_size >= 0 && new_data_size >= 0);
6320  assert (old_data_size <= 255 && new_data_size <= 255);
6321  assert (new_data_size == 0 || new_data != NULL);
6322 
6323  ptr = PTR_ALIGN (ptr, INT_ALIGNMENT);
6324 
6325  OR_PUT_SHORT (ptr, (short) offset_to_data);
6326  ptr += OR_SHORT_SIZE;
6327 
6328  OR_PUT_BYTE (ptr, (INT16) old_data_size);
6329  ptr += OR_BYTE_SIZE;
6330 
6331  OR_PUT_BYTE (ptr, (INT16) new_data_size);
6332  ptr += OR_BYTE_SIZE;
6333 
6334  if (new_data_size > 0)
6335  {
6336  memcpy (ptr, new_data, new_data_size);
6337  ptr += new_data_size;
6338  }
6339  ptr = PTR_ALIGN (ptr, INT_ALIGNMENT);
6340 
6341  return ptr;
6342 }
6343 
6344 /*
6345  * log_rv_pack_redo_record_changes () - Pack recovery data for undo record
6346  * change.
6347  *
6348  * return : Error code.
6349  * ptr (in) : Where recovery data is packed.
6350  * offset_to_data (in) : Offset to data being modified.
6351  * old_data_size (in) : Old data size.
6352  * new_data_size (in) : New data size.
6353  * old_data (in) : Old data.
6354  */
6355 char *
6356 log_rv_pack_undo_record_changes (char *ptr, int offset_to_data, int old_data_size, int new_data_size, char *old_data)
6357 {
6358  /* Assert expected arguments. */
6359  assert (ptr != NULL);
6360  assert (offset_to_data >= 0 && offset_to_data <= 0x8FFF);
6361  assert (old_data_size >= 0 && new_data_size >= 0);
6362  assert (old_data_size <= 255 && new_data_size <= 255);
6363  assert (old_data_size == 0 || old_data != NULL);
6364 
6365  ptr = PTR_ALIGN (ptr, INT_ALIGNMENT);
6366 
6367  OR_PUT_SHORT (ptr, (short) offset_to_data);
6368  ptr += OR_SHORT_SIZE;
6369 
6370  OR_PUT_BYTE (ptr, (INT16) new_data_size);
6371  ptr += OR_BYTE_SIZE;
6372 
6373  OR_PUT_BYTE (ptr, (INT16) old_data_size);
6374  ptr += OR_BYTE_SIZE;
6375 
6376  if (old_data_size > 0)
6377  {
6378  memcpy (ptr, old_data, old_data_size);
6379  ptr += old_data_size;
6380  }
6381  ptr = PTR_ALIGN (ptr, INT_ALIGNMENT);
6382 
6383  return ptr;
6384 }
6385 
6386 /*
6387  * log_rv_redo_fix_page () - fix page for recovery
6388  *
6389  * return : fixed page or NULL
6390  * thread_p (in) : thread entry
6391  * vpid_rcv (in) : page identifier
6392  * rcvindex (in) : recovery index of log record to redo
6393  */
6395 log_rv_redo_fix_page (THREAD_ENTRY * thread_p, const VPID * vpid_rcv, LOG_RCVINDEX rcvindex)
6396 {
6397  PAGE_PTR page = NULL;
6398 
6399  assert (vpid_rcv != NULL && !VPID_ISNULL (vpid_rcv));
6400 
6401  /* how it works:
6402  * since we are during recovery, we don't know the current state of page. it may be unreserved (its file is destroyed)
6403  * or it may not be allocated. these are expected cases and we don't want to raise errors if it happens.
6404  * some redo records are used to initialize a page for the first time (also setting its page type which is necessary
6405  * to consider a page allocated). even first attempt to fix page fails, but the page's sector is reserved, we will
6406  * fix the page as NEW_PAGE and apply its initialization redo log record.
6407  * In case of RVPGBUF_COMPENSATE_DEALLOC, we expect deallocated page.
6408  */
6409 
6410  if (rcvindex == RVPGBUF_COMPENSATE_DEALLOC)
6411  {
6413  if (page == NULL)
6414  {
6415  assert_release (false);
6416  return NULL;
6417  }
6418 
6419  return page;
6420  }
6421 
6422  /* let's first try to fix page if it is not deallocated. */
6424  != NO_ERROR)
6425  {
6426  ASSERT_ERROR ();
6427  return NULL;
6428  }
6429 
6430  if (page == NULL && RCV_IS_NEW_PAGE_INIT (rcvindex))
6431  {
6432  DISK_ISVALID isvalid;
6433 
6434  /* see case OLD_PAGE_MAYBE_DEALLOCATED of pgbuf_fix
6435  * redo recovery may try to fix an immature page, reserved, but which was not initialized
6436  * or it was reused (deallocated and allocated again).
6437  */
6438 
6440  {
6441  // forget the warning since we are going to fix the page as NEW and don't want it will bother us.
6442  er_clear ();
6443  }
6444 
6445  /* page is deallocated. however, this is redo of a new page initialization, we still have to apply it.
6446  * page must still be reserved, otherwise it means its file was completely destroyed.
6447  */
6448 
6449  isvalid = disk_is_page_sector_reserved (thread_p, vpid_rcv->volid, vpid_rcv->pageid);
6450  if (isvalid == DISK_ERROR)
6451  {
6452  ASSERT_ERROR ();
6453  return NULL;
6454  }
6455  else if (isvalid == DISK_INVALID)
6456  {
6457  /* not reserved */
6458  return NULL;
6459  }
6460 
6461  assert (isvalid == DISK_VALID);
6462 
6463  page = pgbuf_fix (thread_p, vpid_rcv, NEW_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
6464  if (page == NULL)
6465  {
6466  ASSERT_ERROR ();
6467  return NULL;
6468  }
6469  }
6470 
6471  return page;
6472 }
6473 
6474 static void
6476 {
6477  assert (thread_p != NULL);
6478  if (tdes->is_active_worker_transaction ())
6479  {
6480  thread_p->tran_index = tdes->tran_index;
6481 #if defined (SA_MODE)
6482  LOG_SET_CURRENT_TRAN_INDEX (thread_p, tdes->tran_index);
6483 #endif // SA_MODE
6484  }
6485  else if (tdes->is_system_worker_transaction ())
6486  {
6488  }
6489  else
6490  {
6491  assert (false);
6492  }
6493 }
6494 
6495 static void
6497 {
6498  assert (thread_p != NULL);
6499  thread_p->reset_system_tdes ();
6500  thread_p->tran_index = LOG_SYSTEM_TRAN_INDEX;
6501 #if defined (SA_MODE)
6503 #endif // SA_MODE
6504 }
#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
bool is_null() const
Definition: log_lsa.hpp:92
char * PAGE_PTR
LOG_REC_UNDO undo
Definition: log_record.hpp:209
int num_coord_loose_end_indices
Definition: log_impl.h:584
void fileio_make_volume_ext_name(char *vol_ext_full_name_p, const char *ext_path_p, const char *ext_name_p, VOLID vol_id)
Definition: file_io.c:5654
static void rv_delete_all_tdes_if(const rv_delete_if_func &func)
struct log_rec_header LOG_RECORD_HEADER
Definition: log_record.hpp:141
void log_2pc_recovery_analysis_info(THREAD_ENTRY *thread_p, log_tdes *tdes, LOG_LSA *upto_chain_lsa)
Definition: log_2pc.c:1988
LOG_SYSOP_END_TYPE type
Definition: log_record.hpp:297
int tran_index
Definition: log_impl.h:465
cubthread::entry * thread_get_thread_entry_info(void)
#define NO_ERROR
Definition: error_code.h:46
void reset_start_mvccid()
Definition: mvcc_table.cpp:601
int area_size
#define __attribute__(X)
Definition: porting.h:36
int logtb_find_tran_index(THREAD_ENTRY *thread_p, TRANID trid)
static bool log_rv_find_checkpoint(THREAD_ENTRY *thread_p, VOLID volid, LOG_LSA *rcv_lsa)
Definition: log_recovery.c:546
#define ER_LOG_MAYNEED_MEDIA_RECOVERY
Definition: error_code.h:155
const char * log_Db_fullname
Definition: log_global.c:89
TRANTABLE trantable
Definition: log_impl.h:650
int num_total_indices
Definition: log_impl.h:581
void logtb_rv_assign_mvccid_for_undo_recovery(THREAD_ENTRY *thread_p, MVCCID mvccid)
bool was_active_log_reset
#define ASSERT_ERROR()
void set_null()
Definition: log_lsa.hpp:98
LOG_DATA data
Definition: log_record.hpp:182
void log_recovery(THREAD_ENTRY *thread_p, int ismedia_crash, time_t *stopat)
Definition: log_recovery.c:648
LOG_LSA chkpt_redo_lsa
Definition: log_impl.h:660
char user_name[DB_MAX_USER_LENGTH+1]
Definition: log_record.hpp:390
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 int log_rv_record_modify_internal(THREAD_ENTRY *thread_p, LOG_RCV *rcv, bool is_undo)
int(* undofun)(THREAD_ENTRY *thread_p, LOG_RCV *logrcv)
Definition: recovery.h:215
void set_system_internal_with_user(const char *db_user)
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 heap_classrepr_restart_cache(void)
Definition: heap_file.c:1849
int boot_reset_db_parm(THREAD_ENTRY *thread_p)
Definition: boot_sr.c:447
#define ER_LOG_PAGE_CORRUPTED
Definition: error_code.h:140
LOG_LSA * log_startof_nxrec(THREAD_ENTRY *thread_p, LOG_LSA *lsa, bool canuse_forwaddr)
#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_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
int logpb_fetch_page(THREAD_ENTRY *thread_p, const LOG_LSA *req_lsa, LOG_CS_ACCESS_MODE access_mode, LOG_PAGE *log_pgptr)
#define ER_FAILED
Definition: error_code.h:47
const int LOG_SYSTEM_TRAN_INDEX
#define RCV_IS_LOGICAL_LOG(vpid, idx)
Definition: recovery.h:252
void logpb_vacuum_reset_log_header_cache(THREAD_ENTRY *thread_p, LOG_HEADER *loghdr)
LOG_REC_REDO redo
Definition: log_record.hpp:218
LOG_GLOBAL log_Gl
LOG_HEADER hdr
Definition: log_impl.h:653
#define ALWAYS_INLINE
#define NULL_TRANID
LOG_HDRPAGE hdr
Definition: log_storage.hpp:84
int logpb_flush_page(THREAD_ENTRY *thread_p, LOG_PAGE *log_pgptr)
void fileio_unformat(THREAD_ENTRY *thread_p, const char *vol_label_p)
Definition: file_io.c:2721
#define pgbuf_unfix(thread_p, pgptr)
Definition: page_buffer.h:276
#define ER_LOG_CORRUPTED_DB_DUE_CRASH_NOLOGGING
Definition: error_code.h:730
#define OR_BUF_INIT(buf, data, size)
#define LOG_GET_LOG_RECORD_HEADER(log_page_p, lsa)
Definition: log_record.hpp:406
LOG_LSA forw_lsa
Definition: log_record.hpp:146
static int log_rv_analysis_save_point(THREAD_ENTRY *thread_p, int tran_id, LOG_LSA *log_lsa)
static void log_recovery_finish_all_postpone(THREAD_ENTRY *thread_p)
LOG_LSA prev_tranlsa
Definition: log_record.hpp:144
bool logtb_is_system_worker_tranid(TRANID trid)
Definition: log_impl.h:1121
const log_rv_record_flag_type LOG_RV_RECORD_MODIFY_MASK
Definition: log_append.hpp:138
static void rv_final()
void logtb_clear_tdes(THREAD_ENTRY *thread_p, LOG_TDES *tdes)
#define LSA_INITIALIZER
Definition: log_lsa.hpp:76
struct log_rec_mvcc_redo LOG_REC_MVCC_REDO
Definition: log_record.hpp:215
static int log_rv_analysis_sysop_end(THREAD_ENTRY *thread_p, int tran_id, LOG_LSA *log_lsa, LOG_PAGE *log_page_p)
#define assert_release(e)
Definition: error_manager.h:96
static int log_rv_undoredo_partial_changes_recursive(THREAD_ENTRY *thread_p, OR_BUF *rcv_buf, RECDES *record, bool is_undo)
void pgbuf_set_dirty(THREAD_ENTRY *thread_p, PAGE_PTR pgptr, bool free_page)
Definition: page_buffer.c:4280
static int log_rv_analysis_postpone(THREAD_ENTRY *thread_p, int tran_id, LOG_LSA *log_lsa)
Definition: log_recovery.c:939
void LOG_CS_ENTER(THREAD_ENTRY *thread_p)
LOG_LSA analysis_last_aborted_sysop_lsa
Definition: log_impl.h:455
char user_name[LOG_USERNAME_MAX]
Definition: log_record.hpp:355
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
const VOLID LOG_DBLOG_ACTIVE_VOLID
Definition: log_volids.hpp:49
const int LOG_2PC_NULL_GTRID
Definition: log_2pc.h:40
static void log_recovery_finish_sysop_postpone(THREAD_ENTRY *thread_p, LOG_TDES *tdes)
static void log_rv_simulate_runtime_worker(THREAD_ENTRY *thread_p, LOG_TDES *tdes)
int logpb_write_page_to_disk(THREAD_ENTRY *thread_p, LOG_PAGE *log_pgptr, LOG_PAGEID logical_pageid)
VOLID volid
Definition: log_record.hpp:158
GLOBAL_UNIQUE_STATS_TABLE unique_stats_table
Definition: log_impl.h:685
LOG_LSA tail_lsa
Definition: log_impl.h:473
LOG_LSA end_lsa
Definition: log_manager.h:56
bool LOG_RV_RECORD_IS_INSERT(log_rv_record_flag_type flags)
Definition: log_append.hpp:174
#define ER_LOG_MOUNT_FAIL
Definition: error_code.h:141
LOG_PAGE * logpb_create_page(THREAD_ENTRY *thread_p, LOG_PAGEID pageid)
static int log_rv_analysis_compensate(THREAD_ENTRY *thread_p, int tran_id, LOG_LSA *log_lsa, LOG_PAGE *log_page_p)
char * data
int log_rv_undo_record_modify(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
bool fileio_is_volume_exist(const char *vol_label_p)
Definition: file_io.c:5094
LOG_TDES * LOG_FIND_TDES(int tran_index)
Definition: log_impl.h:1095
MVCCID mvcc_id
Definition: recovery.h:198
LOG_LSA atomic_sysop_start_lsa
Definition: log_record.hpp:364
const VOLID LOG_MAX_DBVOLID
Definition: log_volids.hpp:34
static int log_rv_analysis_2pc_abort_decision(THREAD_ENTRY *thread_p, int tran_id, LOG_LSA *log_lsa)
#define OR_GET_BYTE(ptr)
int32_t pageid
Definition: dbtype_def.h:879
#define LSA_AS_ARGS(lsa_ptr)
Definition: log_lsa.hpp:78
int er_errid(void)
#define LOG_TOPOP_STACK_INIT_SIZE
Definition: log_manager.h:50
#define SP_SUCCESS
Definition: slotted_page.h:50
LOG_ZIP_SIZE_T data_length
Definition: log_compress.h:55
LOG_PHY_PAGEID logpb_to_physical_pageid(LOG_PAGEID logical_pageid)
MVCCID id
Definition: mvcc.h:197
void logpb_page_get_first_null_block_lsa(THREAD_ENTRY *thread_p, LOG_PAGE *log_pgptr, LOG_LSA *first_null_block_lsa)
#define OR_SHORT_SIZE
const char * log_state_string(TRAN_STATE state)
Definition: log_comm.c:125
#define PTR_ALIGN(addr, boundary)
Definition: memory_alloc.h:77
int logpb_get_archive_number(THREAD_ENTRY *thread_p, LOG_PAGEID pageid)
bool LSA_LT(const log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:174
#define er_log_debug(...)
#define LOG_PAGE_INIT_VALUE
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 int log_rv_analysis_2pc_commit_decision(THREAD_ENTRY *thread_p, int tran_id, LOG_LSA *log_lsa)
bool has_logging_been_skipped
static int log_rv_analysis_dummy_head_postpone(THREAD_ENTRY *thread_p, int tran_id, LOG_LSA *log_lsa)
Definition: log_recovery.c:897
char * log_rv_pack_undo_record_changes(char *ptr, int offset_to_data, int old_data_size, int new_data_size, char *old_data)
int log_rv_undoredo_record_partial_changes(THREAD_ENTRY *thread_p, char *rcv_data, int rcv_data_length, RECDES *record, bool is_undo)
char * fileio_get_directory_path(char *path_p, const char *full_name_p)
Definition: file_io.c:5567
#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
#define MAX_ALIGNMENT
Definition: memory_alloc.h:70
static int log_rv_analysis_sysop_start_postpone(THREAD_ENTRY *thread_p, int tran_id, LOG_LSA *log_lsa, LOG_PAGE *log_page_p)
void logpb_set_dirty(THREAD_ENTRY *thread_p, LOG_PAGE *log_pgptr)
SCAN_CODE spage_get_record(THREAD_ENTRY *thread_p, PAGE_PTR page_p, PGSLOTID slot_id, RECDES *record_descriptor_p, int is_peeking)
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
static int log_rv_analysis_run_postpone(THREAD_ENTRY *thread_p, int tran_id, LOG_LSA *log_lsa, LOG_PAGE *log_page_p, LOG_LSA *check_point)
Definition: log_recovery.c:983
static bool log_unformat_ahead_volumes(THREAD_ENTRY *thread_p, VOLID volid, VOLID *start_volid)
struct log_rec_mvcc_undo LOG_REC_MVCC_UNDO
Definition: log_record.hpp:206
const bool LOG_2PC_OBTAIN_LOCKS
Definition: log_2pc.h:41
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
void THREAD_ENTRY
mvcctable mvcc_table
Definition: log_impl.h:684
#define NULL_PAGEID
char * log_data
Definition: log_compress.h:57
PGLENGTH offset
Definition: log_record.hpp:157
LOG_LSA tail_topresult_lsa
Definition: log_impl.h:480
const char * log_to_string(LOG_RECTYPE type)
Definition: log_manager.c:343
#define MSGCAT_LOG_INCOMPLTE_MEDIA_RECOVERY
int er_get_severity(void)
int spage_update(THREAD_ENTRY *thread_p, PAGE_PTR page_p, PGSLOTID slot_id, const RECDES *record_descriptor_p)
#define MSGCAT_SET_LOG
static void log_recovery_abort_all_atomic_sysops(THREAD_ENTRY *thread_p)
INT64 db_creation
void LOG_RESET_PREV_LSA(const LOG_LSA *lsa)
Definition: log_append.cpp:137
LOG_RECTYPE type
Definition: log_record.hpp:148
int locator_initialize(THREAD_ENTRY *thread_p)
Definition: locator_sr.c:246
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
static void log_recovery_undo(THREAD_ENTRY *thread_p)
void logpb_flush_pages_direct(THREAD_ENTRY *thread_p)
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
static int log_rv_analysis_2pc_abort_inform_particps(THREAD_ENTRY *thread_p, int tran_id, LOG_LSA *log_lsa)
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
int gtrid
Definition: log_impl.h:482
PAGE_PTR pgptr
Definition: recovery.h:199
const char * fileio_get_base_file_name(const char *full_name_p)
Definition: file_io.c:5533
#define assert(x)
LOG_RECVPHASE rcv_phase
Definition: log_impl.h:662
LOG_APPEND_INFO append
Definition: log_impl.h:651
const VOLID LOG_DBFIRST_VOLID
Definition: log_volids.hpp:38
char log_Name_info[PATH_MAX]
Definition: log_global.c:91
LOG_PAGEID fpageid
LOG_PAGE * log_pgptr
Definition: log_append.hpp:78
#define STATIC_INLINE
int logpb_fetch_start_append_page(THREAD_ENTRY *thread_p)
LOG_LSA * pgbuf_get_lsa(PAGE_PTR pgptr)
Definition: page_buffer.c:4318
LOG_LSA undo_nxlsa
Definition: log_impl.h:474
LOG_LSA start_lsa
Definition: log_manager.h:55
int or_get_short(OR_BUF *buf, int *error)
static int log_rv_analysis_atomic_sysop_start(THREAD_ENTRY *thread_p, int tran_id, LOG_LSA *log_lsa)
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_RESET_APPEND_LSA(const LOG_LSA *lsa)
Definition: log_append.cpp:129
static int log_rv_analysis_will_commit(THREAD_ENTRY *thread_p, int tran_id, LOG_LSA *log_lsa)
int last_deleted_arv_num
char area[1]
Definition: log_storage.hpp:85
int logpb_recreate_volume_info(THREAD_ENTRY *thread_p)
bool LSA_LE(const log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:167
LOG_LSA final_restored_lsa
Definition: log_impl.h:668
void logpb_invalid_all_append_pages(THREAD_ENTRY *thread_p)
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_rv_analysis_2pc_prepare(THREAD_ENTRY *thread_p, int tran_id, LOG_LSA *log_lsa)
thread_type
struct rvfun RV_fun[]
Definition: recovery.c:49
LOG_PAGEID logical_pageid
Definition: log_storage.hpp:65
void logpb_decache_archive_info(THREAD_ENTRY *thread_p)
LOG_LSA savept_lsa
Definition: log_impl.h:478
char log_Prefix[PATH_MAX]
Definition: log_global.c:87
enum log_rectype LOG_RECTYPE
Definition: log_record.hpp:138
bool LOG_RV_RECORD_IS_UPDATE_ALL(log_rv_record_flag_type flags)
Definition: log_append.hpp:186
LOG_REC_MVCC_UNDO mvcc_undo
Definition: log_record.hpp:303
int or_overflow(OR_BUF *buf)
bool LOG_RV_RECORD_IS_UPDATE_PARTIAL(log_rv_record_flag_type flags)
Definition: log_append.hpp:192
int or_align(OR_BUF *buf, int alignment)
MVCC_INFO mvccinfo
Definition: log_impl.h:463
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
void log_2pc_read_prepare(THREAD_ENTRY *thread_p, int acquire_locks, log_tdes *tdes, LOG_LSA *log_lsa, LOG_PAGE *log_page_p)
Definition: log_2pc.c:1349
int num_prepared_loose_end_indices
Definition: log_impl.h:586
LOG_LSA posp_nxlsa
Definition: log_impl.h:476
static int log_rv_analysis_log_end(int tran_id, LOG_LSA *log_lsa)
static void log_recovery_resetlog(THREAD_ENTRY *thread_p, const LOG_LSA *new_append_lsa, const LOG_LSA *new_prev_lsa)
void fileio_dismount(THREAD_ENTRY *thread_p, int vol_fd)
Definition: file_io.c:3134
LOG_PAGE * logpb_create_header_page(THREAD_ENTRY *thread_p)
static int log_recovery_find_first_postpone(THREAD_ENTRY *thread_p, LOG_LSA *ret_lsa, LOG_LSA *start_postpone_lsa, LOG_TDES *tdes)
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
LOG_PAGEID nxarv_pageid
int length
Definition: recovery.h:202
static void log_rv_undo_record(THREAD_ENTRY *thread_p, LOG_LSA *log_lsa, LOG_PAGE *log_page_p, LOG_RCVINDEX rcvindex, const VPID *rcv_vpid, LOG_RCV *rcv, const LOG_LSA *rcv_lsa_ptr, LOG_TDES *tdes, LOG_ZIP *undo_unzip_ptr)
Definition: log_recovery.c:167
static bool log_is_page_of_record_broken(THREAD_ENTRY *thread_p, const LOG_LSA *log_lsa, const LOG_RECORD_HEADER *log_rec_header)
LOG_DATA data
Definition: log_record.hpp:174
struct log_rec_redo LOG_REC_REDO
Definition: log_record.hpp:179
int log_rv_redo_record_modify(THREAD_ENTRY *thread_p, LOG_RCV *rcv)
LOG_LSA rcv_phase_lsa
Definition: log_impl.h:663
void vacuum_notify_server_crashed(LOG_LSA *recovery_lsa)
Definition: vacuum.c:7468
#define NULL
Definition: freelistheap.h:34
#define CTIME_MAX
Definition: porting.h:72
#define ER_LOG_RECOVERY_FINISHED
Definition: error_code.h:1439
UINT64 MVCCID
static void rv_simulate_system_tdes(TRANID trid)
if(extra_options)
Definition: dynamic_load.c:958
#define LOG_SYSOP_END_TYPE_CHECK(type)
Definition: log_record.hpp:283
bool log_is_in_crash_recovery(void)
Definition: log_manager.c:476
struct log_rec_mvcc_undoredo LOG_REC_MVCC_UNDOREDO
Definition: log_record.hpp:197
bool LSA_ISNULL(const log_lsa *lsa_ptr)
Definition: log_lsa.hpp:153
struct log_info_chkpt_trans LOG_INFO_CHKPT_TRANS
Definition: log_record.hpp:341
#define ER_PB_BAD_PAGEID
Definition: error_code.h:67
int log_get_num_pages_for_creation(int db_npages)
Definition: log_manager.c:696
int last_arv_num_for_syscrashes
LOG_LSA lastparent_lsa
Definition: log_record.hpp:295
#define pgbuf_fix(thread_p, vpid, fetch_mode, requestmode, condition)
Definition: page_buffer.h:255
LOG_LSA head_lsa
Definition: log_impl.h:472
#define MVCC_ID_PRECEDES(id1, id2)
Definition: mvcc.h:137
PGLENGTH offset
Definition: log_storage.hpp:66
DISK_ISVALID disk_is_page_sector_reserved(THREAD_ENTRY *thread_p, VOLID volid, PAGEID pageid)
#define db_private_free(thrd, ptr)
Definition: memory_alloc.h:229
LOG_LSA analysis_last_aborted_sysop_start_lsa
Definition: log_impl.h:456
#define LOG_IS_MVCC_OPERATION(rcvindex)
Definition: mvcc.h:255
int * ack_received
Definition: log_2pc.h:69
int disk_get_checkpoint(THREAD_ENTRY *thread_p, INT16 volid, LOG_LSA *vol_lsa)
#define RECORD_REPLACE_DATA(record, offset_to_data, old_data_size, new_data_size, new_data)
struct log_rec_undoredo LOG_REC_UNDOREDO
Definition: log_record.hpp:162
#define NULL_OFFSET
#define OR_PUT_SHORT(ptr, val)
CLIENTIDS client
Definition: log_impl.h:484
#define LOG_SET_CURRENT_TRAN_INDEX(thrd, index)
Definition: log_impl.h:178
int pgbuf_flush_all(THREAD_ENTRY *thread_p, VOLID volid)
Definition: page_buffer.c:3083
void log_find_unilaterally_largest_undo_lsa(THREAD_ENTRY *thread_p, LOG_LSA &max_undo_lsa)
#define ER_LOG_UNKNOWN_TRANINDEX
Definition: error_code.h:913
log_tdes * log_2pc_alloc_coord_info(log_tdes *tdes, int num_particps, int particp_id_length, void *block_particps_ids)
Definition: log_2pc.c:1581
#define MSGCAT_CATALOG_CUBRID
char * LOG_APPEND_PTR()
Definition: log_append.cpp:145
static int log_rv_analysis_undo_redo(THREAD_ENTRY *thread_p, int tran_id, LOG_LSA *log_lsa)
Definition: log_recovery.c:862
void log_2pc_recovery(THREAD_ENTRY *thread_p)
Definition: log_2pc.c:2262
void pgbuf_get_vpid(PAGE_PTR pgptr, VPID *vpid)
Definition: page_buffer.c:4579
static void log_recovery_abort_atomic_sysop(THREAD_ENTRY *thread_p, LOG_TDES *tdes)
LOG_REC_UNDOREDO undoredo
Definition: log_record.hpp:200
const LOG_LSA * pgbuf_set_lsa(THREAD_ENTRY *thread_p, PAGE_PTR pgptr, const LOG_LSA *lsa_ptr)
Definition: page_buffer.c:4364
void log_sysop_abort(THREAD_ENTRY *thread_p)
Definition: log_manager.c:4017
#define ER_LOG_MISSING_COMPENSATING_RECORD
Definition: error_code.h:779
bool LSA_GE(const log_lsa *plsa1, const log_lsa *plsa2)
Definition: log_lsa.hpp:181
void fileio_make_log_archive_name(char *log_archive_name_p, const char *log_path_p, const char *db_name_p, int archive_number)
Definition: file_io.c:5758
LOG_LSA reference_lsa
Definition: recovery.h:204
static void rv_delete_tdes(TRANID trid)
#define MSGCAT_LOG_LOGINFO_REMOVE_REASON
#define CAST_BUFLEN
Definition: porting.h:471
#define RCV_IS_BTREE_LOGICAL_LOG(idx)
Definition: recovery.h:228
#define NULL_TRAN_INDEX
bool LOG_CS_OWN_WRITE_MODE(THREAD_ENTRY *thread_p)
static void error(const char *msg)
Definition: gencat.c:331
static bool log_rv_get_unzip_log_data(THREAD_ENTRY *thread_p, int length, LOG_LSA *log_lsa, LOG_PAGE *log_page_p, LOG_ZIP *undo_unzip_ptr)
Definition: log_recovery.c:574
#define VPID_ISNULL(vpid_ptr)
Definition: dbtype_def.h:925
LOG_PHY_PAGEID nxarv_phy_pageid
const char * data
Definition: recovery.h:203
static void log_recovery_abort_interrupted_sysop(THREAD_ENTRY *thread_p, LOG_TDES *tdes, const LOG_LSA *postpone_start_lsa)
PGSLOTID spage_delete(THREAD_ENTRY *thread_p, PAGE_PTR page_p, PGSLOTID slot_id)
struct log_info_chkpt_sysop LOG_INFO_CHKPT_SYSOP
Definition: log_record.hpp:359
void logtb_free_tran_index(THREAD_ENTRY *thread_p, int tran_index)
#define pgbuf_fix_if_not_deallocated(thread_p, vpid, latch_mode, latch_condition, page)
Definition: page_buffer.h:441
static log_tdes * rv_get_tdes(TRANID trid)
#define LOG_FIND_THREAD_TRAN_INDEX(thrd)
Definition: perf_monitor.h:158
#define LOG_READ_ALIGN(thread_p, lsa, log_pgptr)
Definition: log_impl.h:122
#define ARG_FILE_LINE
Definition: error_manager.h:44
int logpb_page_check_corruption(THREAD_ENTRY *thread_p, LOG_PAGE *log_pgptr, bool *is_page_corrupted)
#define OR_BYTE_SIZE
STATIC_INLINE PAGE_PTR log_rv_redo_fix_page(THREAD_ENTRY *thread_p, const VPID *vpid_rcv, LOG_RCVINDEX rcvindex) __attribute__((ALWAYS_INLINE))
static const bool COPY
bool log_unzip(LOG_ZIP *log_unzip, LOG_ZIP_SIZE_T length, void *data)
Definition: log_compress.c:123
LOG_TOPOPS_STACK topops
Definition: log_impl.h:486
LOG_LSA compensate_lsa
Definition: log_record.hpp:304
static void log_recovery_analysis(THREAD_ENTRY *thread_p, LOG_LSA *start_lsa, LOG_LSA *start_redolsa, LOG_LSA *end_redo_lsa, bool ismedia_crash, time_t *stopat, bool *did_incom_recovery, INT64 *num_redo_log_records)
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
#define ER_LOG_RECOVERY_STARTED
Definition: error_code.h:1437
LOG_LSA redo_lsa
Definition: log_record.hpp:335
INT16 PGSLOTID
#define DOUBLE_ALIGNMENT
Definition: memory_alloc.h:64
void log_zip_free(LOG_ZIP *log_zip)
Definition: log_compress.c:265
bool isloose_end
Definition: log_impl.h:468
static void log_recovery_redo(THREAD_ENTRY *thread_p, const LOG_LSA *start_redolsa, const LOG_LSA *end_redo_lsa, time_t *stopat)
PAGEID pageid
Definition: log_record.hpp:156
#define free_and_init(ptr)
Definition: memory_alloc.h:147
#define DB_ALIGN(offset, align)
Definition: memory_alloc.h:84
void LSA_SET_NULL(log_lsa *lsa_ptr)
Definition: log_lsa.hpp:146
TRANID trid
Definition: log_impl.h:466
void logpb_copy_from_log(THREAD_ENTRY *thread_p, char *area, int length, LOG_LSA *log_lsa, LOG_PAGE *log_pgptr)
#define DB_PAGESIZE
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
char log_Archive_path[PATH_MAX]
Definition: log_global.c:86
void log_append_empty_record(THREAD_ENTRY *thread_p, LOG_RECTYPE logrec_type, LOG_DATA_ADDR *addr)
Definition: log_manager.c:3117
bool log_diff(LOG_ZIP_SIZE_T undo_length, const void *undo_data, LOG_ZIP_SIZE_T redo_length, void *redo_data)
Definition: log_compress.c:201
bool logpb_is_page_in_archive(LOG_PAGEID pageid)
bool prm_get_bool_value(PARAM_ID prm_id)
static int log_rv_analysis_2pc_commit_inform_particps(THREAD_ENTRY *thread_p, int tran_id, LOG_LSA *log_lsa)
#define INT_ALIGNMENT
Definition: memory_alloc.h:61
#define ZIP_CHECK(length)
Definition: log_compress.h:39
void fileio_page_hexa_dump(const char *src_data, int length)
Definition: file_io.c:3597
LOG_LSA sysop_start_postpone_lsa
Definition: log_record.hpp:363
void er_clear(void)
#define ALLOC_COPY(PTR, STR)
Definition: cas_common.h:66
static void log_recovery_notpartof_volumes(THREAD_ENTRY *thread_p)
#define ONE_K
Definition: porting.h:62
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
int i
Definition: dynamic_load.c:954
char * msgcat_message(int cat_id, int set_id, int msg_id)
static int log_rv_analysis_start_checkpoint(LOG_LSA *log_lsa, LOG_LSA *start_lsa, bool *may_use_checkpoint)
#define LOG_ISTRAN_2PC(tdes)
Definition: log_impl.h:212
INT16 type
LOG_TOPOPS_ADDRESSES * stack
Definition: log_impl.h:351
static void log_rv_redo_record(THREAD_ENTRY *thread_p, LOG_LSA *log_lsa, LOG_PAGE *log_page_p, int(*redofun)(THREAD_ENTRY *thread_p, LOG_RCV *), LOG_RCV *rcv, LOG_LSA *rcv_lsa_ptr, int undo_length, char *undo_data, LOG_ZIP *redo_unzip_ptr)
Definition: log_recovery.c:431
char * strdup(const char *str)
Definition: porting.c:901
int log_dump_log_info(const char *logname_info, bool also_stdout, const char *fmt,...)
Definition: log_comm.c:205
#define NULL_VOLID
LOG_RCVINDEX rcvindex
Definition: log_record.hpp:155
TRAN_STATE state
Definition: log_impl.h:469
TRAN_STATE
Definition: log_comm.h:36
#define IO_MAX_PAGE_SIZE
#define LOG_PAGESIZE
LOG_TDES * logtb_rv_find_allocate_tran_index(THREAD_ENTRY *thread_p, TRANID trid, const LOG_LSA *log_lsa)
int or_get_byte(OR_BUF *buf, int *error)
#define RCV_IS_LOGICAL_COMPENSATE_MANUAL(idx)
Definition: recovery.h:240
static int log_rv_analysis_complete(THREAD_ENTRY *thread_p, int tran_id, LOG_LSA *log_lsa, LOG_PAGE *log_page_p, LOG_LSA *prev_lsa, bool is_media_crash, time_t *stop_at, bool *did_incom_recovery)
int disk_get_creation_time(THREAD_ENTRY *thread_p, INT16 volid, INT64 *db_creation)
struct log_rec_undo LOG_REC_UNDO
Definition: log_record.hpp:171
static void log_rv_end_simulation(THREAD_ENTRY *thread_p)
TRANID next_trid
#define DONT_FREE
Definition: page_buffer.h:41
void logtb_free_tran_index_with_undo_lsa(THREAD_ENTRY *thread_p, const LOG_LSA *undo_lsa)
LOG_PAGEID logpb_checkpoint(THREAD_ENTRY *thread_p)
#define MVCCID_FORWARD(id)
static int log_rv_analysis_commit_with_postpone(THREAD_ENTRY *thread_p, int tran_id, LOG_LSA *log_lsa, LOG_PAGE *log_page_p)
MVCCID mvcc_next_id
int logtb_set_num_loose_end_trans(THREAD_ENTRY *thread_p)
static int log_rv_analysis_end_checkpoint(THREAD_ENTRY *thread_p, LOG_LSA *log_lsa, LOG_PAGE *log_page_p, LOG_LSA *check_point, LOG_LSA *start_redo_lsa, bool *may_use_checkpoint, bool *may_need_synch_checkpoint_2pc)
static int log_rv_analysis_2pc_start(THREAD_ENTRY *thread_p, int tran_id, LOG_LSA *log_lsa)
static void log_recovery_finish_postpone(THREAD_ENTRY *thread_p, LOG_TDES *tdes)
LOG_LSA tran_start_postpone_lsa
Definition: log_impl.h:450
#define ER_TDE_CIPHER_IS_NOT_LOADED
Definition: error_code.h:1613
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
VOLID boot_find_next_permanent_volid(THREAD_ENTRY *thread_p)
Definition: boot_sr.c:425
LOG_RCVINDEX rcvindex
Definition: log_record.hpp:252
#define VPID_SET_NULL(vpid_ptr)
Definition: dbtype_def.h:906
static void log_rv_analysis_record(THREAD_ENTRY *thread_p, LOG_RECTYPE log_type, int tran_id, LOG_LSA *log_lsa, LOG_PAGE *log_page_p, LOG_LSA *check_point, LOG_LSA *prev_lsa, LOG_LSA *start_lsa, LOG_LSA *start_redo_lsa, bool is_media_crash, time_t *stop_at, bool *did_incom_recovery, bool *may_use_checkpoint, bool *may_need_synch_checkpoint_2pc)
static int log_rv_analysis_2pc_recv_ack(THREAD_ENTRY *thread_p, int tran_id, LOG_LSA *log_lsa)
static bool log_recovery_needs_skip_logical_redo(THREAD_ENTRY *thread_p, TRANID tran_id, LOG_RECTYPE log_rtype, LOG_RCVINDEX rcv_index, const LOG_LSA *lsa)
#define MVCCID_IS_VALID(id)
LOG_LSA atomic_sysop_start_lsa
Definition: log_impl.h:454
static void map_all_tdes(const map_func &func)
const bool LOG_2PC_DONT_OBTAIN_LOCKS
Definition: log_2pc.h:42
LOG_LSA chkpt_lsa
std::int64_t offset
Definition: log_lsa.hpp:37
#define MSGCAT_LOG_STARTS
static void log_recovery_notpartof_archives(THREAD_ENTRY *thread_p, int start_arv_num, const char *info_reason)
int or_advance(OR_BUF *buf, int offset)
bool LOG_RV_RECORD_IS_DELETE(log_rv_record_flag_type flags)
Definition: log_append.hpp:180
DISK_ISVALID
Definition: disk_manager.h:53
char * log_rv_pack_redo_record_changes(char *ptr, int offset_to_data, int old_data_size, int new_data_size, char *new_data)
int spage_insert_at(THREAD_ENTRY *thread_p, PAGE_PTR page_p, PGSLOTID slot_id, RECDES *record_descriptor_p)
#define MSGCAT_LOG_RESETLOG_DUE_INCOMPLTE_MEDIA_RECOVERY
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
#define OR_PUT_BYTE(ptr, val)
#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
#define RCV_IS_NEW_PAGE_INIT(idx)
Definition: recovery.h:268
void logpb_invalidate_pool(THREAD_ENTRY *thread_p)